1
|
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
|
2
|
index 577d644..6a1d396 100644
|
3
|
--- a/sbin/ipfw/ipfw2.c
|
4
|
+++ b/sbin/ipfw/ipfw2.c
|
5
|
@@ -4115,8 +4115,9 @@ ipfw_flush(int force)
|
6
|
}
|
7
|
|
8
|
|
9
|
+static void table_list_entry(ipfw_table_xentry *);
|
10
|
static void table_list(uint16_t num, int need_header);
|
11
|
-static void table_fill_xentry(char *arg, ipfw_table_xentry *xent);
|
12
|
+static void table_fill_xentry(int ac, char *av[], ipfw_table_xentry *xent);
|
13
|
|
14
|
/*
|
15
|
* This one handles all table-related commands
|
16
|
@@ -4169,29 +4170,9 @@ ipfw_table_handler(int ac, char *av[])
|
17
|
if (_substrcmp(*av, "add") == 0 ||
|
18
|
_substrcmp(*av, "delete") == 0) {
|
19
|
do_add = **av == 'a';
|
20
|
- ac--; av++;
|
21
|
- if (!ac)
|
22
|
- errx(EX_USAGE, "address required");
|
23
|
|
24
|
- table_fill_xentry(*av, &xent);
|
25
|
+ table_fill_xentry(ac, av, &xent);
|
26
|
|
27
|
- ac--; av++;
|
28
|
- if (do_add && ac) {
|
29
|
- unsigned int tval;
|
30
|
- /* isdigit is a bit of a hack here.. */
|
31
|
- if (strchr(*av, (int)'.') == NULL && isdigit(**av)) {
|
32
|
- xent.value = strtoul(*av, NULL, 0);
|
33
|
- } else {
|
34
|
- if (lookup_host(*av, (struct in_addr *)&tval) == 0) {
|
35
|
- /* The value must be stored in host order *
|
36
|
- * so that the values < 65k can be distinguished */
|
37
|
- xent.value = ntohl(tval);
|
38
|
- } else {
|
39
|
- errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
|
40
|
- }
|
41
|
- }
|
42
|
- } else
|
43
|
- xent.value = 0;
|
44
|
if (do_setcmd3(do_add ? IP_FW_TABLE_XADD : IP_FW_TABLE_XDEL,
|
45
|
&xent, xent.len) < 0) {
|
46
|
/* If running silent, don't bomb out on these errors. */
|
47
|
@@ -4218,19 +4199,41 @@ ipfw_table_handler(int ac, char *av[])
|
48
|
do {
|
49
|
table_list(xent.tbl, is_all);
|
50
|
} while (++xent.tbl < a);
|
51
|
+ } else if (_substrcmp(*av, "entrystats") == 0) {
|
52
|
+ table_fill_xentry(ac, av, &xent);
|
53
|
+
|
54
|
+ if (do_setcmd3(IP_FW_TABLE_XLISTENTRY, &xent, xent.len) < 0) {
|
55
|
+ /* If running silent, don't bomb out on these errors. */
|
56
|
+ if (!(co.do_quiet))
|
57
|
+ err(EX_OSERR, "setsockopt(IP_FW_TABLE_XLISTENTRY)");
|
58
|
+ } else
|
59
|
+ table_list_entry(&xent);
|
60
|
+ } else if (_substrcmp(*av, "entryzerostats") == 0) {
|
61
|
+ table_fill_xentry(ac, av, &xent);
|
62
|
+
|
63
|
+ if (do_setcmd3(IP_FW_TABLE_XZEROENTRY, &xent, xent.len) < 0) {
|
64
|
+ /* If running silent, don't bomb out on these errors. */
|
65
|
+ if (!(co.do_quiet))
|
66
|
+ err(EX_OSERR, "setsockopt(IP_FW_TABLE_XZEROENTRY)");
|
67
|
+ }
|
68
|
} else
|
69
|
errx(EX_USAGE, "invalid table command %s", *av);
|
70
|
}
|
71
|
|
72
|
static void
|
73
|
-table_fill_xentry(char *arg, ipfw_table_xentry *xent)
|
74
|
+table_fill_xentry(int ac, char *av[], ipfw_table_xentry *xent)
|
75
|
{
|
76
|
- int addrlen, mask, masklen, type;
|
77
|
+ int addrlen, mask, masklen, type, do_add;
|
78
|
struct in6_addr *paddr;
|
79
|
uint32_t *pkey;
|
80
|
- char *p;
|
81
|
+ char *p, *arg;
|
82
|
uint32_t key;
|
83
|
|
84
|
+ do_add = **av == 'a';
|
85
|
+ ac--; av++;
|
86
|
+ if (!ac)
|
87
|
+ errx(EX_USAGE, "address required");
|
88
|
+
|
89
|
mask = 0;
|
90
|
type = 0;
|
91
|
addrlen = 0;
|
92
|
@@ -4245,7 +4248,23 @@ table_fill_xentry(char *arg, ipfw_table_xentry *xent)
|
93
|
* 4) port, uid/gid or other u32 key (base 10 format)
|
94
|
* 5) hostname
|
95
|
*/
|
96
|
- paddr = &xent->k.addr6;
|
97
|
+ if (ac > 1 && av) {
|
98
|
+ if (_substrcmp(*av, "mac") == 0) {
|
99
|
+ uint8_t _mask[8];
|
100
|
+
|
101
|
+ type = IPFW_TABLE_MIX;
|
102
|
+ get_mac_addr_mask(av[1], (uint8_t *)xent->k.mix.mac, _mask);
|
103
|
+ ac-=2; av+=2;
|
104
|
+ if (ac <= 0)
|
105
|
+ errx(EX_DATAERR, "wrong argument passed.");
|
106
|
+
|
107
|
+ paddr = (struct in6_addr *)&xent->k.mix.addr;
|
108
|
+ } else
|
109
|
+ errx(EX_DATAERR, "wrong argument passed.");
|
110
|
+ } else
|
111
|
+ paddr = &xent->k.addr6;
|
112
|
+
|
113
|
+ arg = *av;
|
114
|
if (ishexnumber(*arg) != 0 || *arg == ':') {
|
115
|
/* Remove / if exists */
|
116
|
if ((p = strchr(arg, '/')) != NULL) {
|
117
|
@@ -4258,7 +4277,8 @@ table_fill_xentry(char *arg, ipfw_table_xentry *xent)
|
118
|
errx(EX_DATAERR, "bad IPv4 mask width: %s",
|
119
|
p + 1);
|
120
|
|
121
|
- type = IPFW_TABLE_CIDR;
|
122
|
+ if (type == 0)
|
123
|
+ type = IPFW_TABLE_CIDR;
|
124
|
masklen = p ? mask : 32;
|
125
|
addrlen = sizeof(struct in_addr);
|
126
|
} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
|
127
|
@@ -4269,10 +4289,14 @@ table_fill_xentry(char *arg, ipfw_table_xentry *xent)
|
128
|
errx(EX_DATAERR, "bad IPv6 mask width: %s",
|
129
|
p + 1);
|
130
|
|
131
|
- type = IPFW_TABLE_CIDR;
|
132
|
+ if (type == 0)
|
133
|
+ type = IPFW_TABLE_CIDR;
|
134
|
masklen = p ? mask : 128;
|
135
|
addrlen = sizeof(struct in6_addr);
|
136
|
} else {
|
137
|
+ if (type != 0 && type != IPFW_TABLE_MIX)
|
138
|
+ errx(EX_DATAERR, "Wrong value passed as address");
|
139
|
+
|
140
|
/* Port or any other key */
|
141
|
key = strtol(arg, &p, 10);
|
142
|
/* Skip non-base 10 entries like 'fa1' */
|
143
|
@@ -4304,9 +4328,103 @@ table_fill_xentry(char *arg, ipfw_table_xentry *xent)
|
144
|
addrlen = sizeof(struct in_addr);
|
145
|
}
|
146
|
|
147
|
+ ac--; av++;
|
148
|
+ if (ac > 1 && av) {
|
149
|
+ if (_substrcmp(*av, "mac") == 0) {
|
150
|
+ uint8_t _mask[8];
|
151
|
+
|
152
|
+ if (type == 0)
|
153
|
+ type = IPFW_TABLE_CIDR;
|
154
|
+ get_mac_addr_mask(av[1], (uint8_t *)&xent->mac_addr, _mask);
|
155
|
+ ac-=2; av+=2;
|
156
|
+ }
|
157
|
+ }
|
158
|
+
|
159
|
+ if (do_add && ac > 0) {
|
160
|
+ unsigned int tval;
|
161
|
+ /* isdigit is a bit of a hack here.. */
|
162
|
+ if (strchr(*av, (int)'.') == NULL && isdigit(**av)) {
|
163
|
+ xent->value = strtoul(*av, NULL, 0);
|
164
|
+ } else {
|
165
|
+ if (lookup_host(*av, (struct in_addr *)&tval) == 0) {
|
166
|
+ /* The value must be stored in host order *
|
167
|
+ * so that the values < 65k can be distinguished */
|
168
|
+ xent->value = ntohl(tval);
|
169
|
+ } else {
|
170
|
+ errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
|
171
|
+ }
|
172
|
+ }
|
173
|
+ } else
|
174
|
+ xent->value = 0;
|
175
|
+
|
176
|
xent->type = type;
|
177
|
xent->masklen = masklen;
|
178
|
- xent->len = offsetof(ipfw_table_xentry, k) + addrlen;
|
179
|
+ if (type == IPFW_TABLE_MIX)
|
180
|
+ xent->len = offsetof(ipfw_table_xentry, k) + addrlen + ETHER_ADDR_LEN;
|
181
|
+ else
|
182
|
+ xent->len = offsetof(ipfw_table_xentry, k) + addrlen;
|
183
|
+}
|
184
|
+
|
185
|
+static void
|
186
|
+table_list_entry(ipfw_table_xentry *xent)
|
187
|
+{
|
188
|
+ struct in6_addr *addr6;
|
189
|
+ uint32_t tval;
|
190
|
+ char tbuf[128];
|
191
|
+
|
192
|
+ switch (xent->type) {
|
193
|
+ case IPFW_TABLE_CIDR:
|
194
|
+ /* IPv4 or IPv6 prefixes */
|
195
|
+ tval = xent->value;
|
196
|
+ addr6 = &xent->k.addr6;
|
197
|
+
|
198
|
+
|
199
|
+ if (IN6_IS_ADDR_V4COMPAT(addr6)) {
|
200
|
+ /* IPv4 address */
|
201
|
+ inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf, sizeof(tbuf));
|
202
|
+ } else {
|
203
|
+ /* IPv6 address */
|
204
|
+ inet_ntop(AF_INET6, addr6, tbuf, sizeof(tbuf));
|
205
|
+ }
|
206
|
+
|
207
|
+ if (co.do_value_as_ip) {
|
208
|
+ tval = htonl(tval);
|
209
|
+ printf("%s/%u %s %d %d %u\n", tbuf, xent->masklen,
|
210
|
+ inet_ntoa(*(struct in_addr *)&tval), pr_u64(&xent->packets, 0), pr_u64(&xent->bytes, 0), xent->timestamp);
|
211
|
+ } else
|
212
|
+ printf("%s/%u %u %d %d %u\n", tbuf, xent->masklen, tval,
|
213
|
+ pr_u64(&xent->packets, 0), pr_u64(&xent->bytes, 0), xent->timestamp);
|
214
|
+ break;
|
215
|
+ case IPFW_TABLE_INTERFACE:
|
216
|
+ /* Interface names */
|
217
|
+ tval = xent->value;
|
218
|
+ if (co.do_value_as_ip) {
|
219
|
+ tval = htonl(tval);
|
220
|
+ printf("%s %u %s %d %d %u\n", xent->k.iface, xent->masklen,
|
221
|
+ inet_ntoa(*(struct in_addr *)&tval), pr_u64(&xent->packets, 0), pr_u64(&xent->bytes, 0), xent->timestamp);
|
222
|
+ } else
|
223
|
+ printf("%s %u %u %d %d %u\n", xent->k.iface, xent->masklen, tval,
|
224
|
+ pr_u64(&xent->packets, 0), pr_u64(&xent->bytes, 0), xent->timestamp);
|
225
|
+
|
226
|
+ break;
|
227
|
+
|
228
|
+ case IPFW_TABLE_MIX:
|
229
|
+ /* mix of ip+mac */
|
230
|
+ tval = xent->value;
|
231
|
+
|
232
|
+ /* IPv4 address */
|
233
|
+ inet_ntop(AF_INET, &xent->k.mix.addr, tbuf, sizeof(tbuf));
|
234
|
+
|
235
|
+ if (co.do_value_as_ip) {
|
236
|
+ tval = htonl(tval);
|
237
|
+ printf("%s/%u %s %s %d %d %u\n", tbuf, xent->masklen - (8 * ETHER_ADDR_LEN), ether_ntoa((struct ether_addr *)xent->k.mix.mac),
|
238
|
+ inet_ntoa(*(struct in_addr *)&tval),
|
239
|
+ pr_u64(&xent->packets, 0), pr_u64(&xent->bytes, 0), xent->timestamp);
|
240
|
+ } else
|
241
|
+ printf("%s/%u %s %u %d %d %u\n", tbuf, xent->masklen - (8 * ETHER_ADDR_LEN), ether_ntoa((struct ether_addr *)xent->k.mix.mac), tval,
|
242
|
+ pr_u64(&xent->packets, 0), pr_u64(&xent->bytes, 0), xent->timestamp);
|
243
|
+ break;
|
244
|
+ }
|
245
|
}
|
246
|
|
247
|
static void
|
248
|
@@ -4338,6 +4456,7 @@ table_list(uint16_t num, int need_header)
|
249
|
l = *a;
|
250
|
tbl = safe_calloc(1, l);
|
251
|
tbl->opheader.opcode = IP_FW_TABLE_XLIST;
|
252
|
+ tbl->opheader.ctxid = co.ctx;
|
253
|
tbl->tbl = num;
|
254
|
if (do_cmd(IP_FW3, tbl, (uintptr_t)&l) < 0)
|
255
|
err(EX_OSERR, "getsockopt(IP_FW_TABLE_XLIST)");
|
256
|
@@ -4377,6 +4496,23 @@ table_list(uint16_t num, int need_header)
|
257
|
inet_ntoa(*(struct in_addr *)&tval));
|
258
|
} else
|
259
|
printf("%s %u\n", xent->k.iface, tval);
|
260
|
+
|
261
|
+ break;
|
262
|
+
|
263
|
+ case IPFW_TABLE_MIX:
|
264
|
+ /* mix of ip+mac */
|
265
|
+ tval = xent->value;
|
266
|
+
|
267
|
+ /* IPv4 address */
|
268
|
+ inet_ntop(AF_INET, &xent->k.mix.addr, tbuf, sizeof(tbuf));
|
269
|
+
|
270
|
+ if (co.do_value_as_ip) {
|
271
|
+ tval = htonl(tval);
|
272
|
+ printf("%s/%u %s %s\n", tbuf, xent->masklen - (8 * ETHER_ADDR_LEN), ether_ntoa((struct ether_addr *)xent->k.mix.mac),
|
273
|
+ inet_ntoa(*(struct in_addr *)&tval));
|
274
|
+ } else
|
275
|
+ printf("%s/%u %s %u\n", tbuf, xent->masklen - (8 * ETHER_ADDR_LEN), ether_ntoa((struct ether_addr *)xent->k.mix.mac), tval);
|
276
|
+ break;
|
277
|
}
|
278
|
|
279
|
if (sz < xent->len)
|
280
|
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
|
281
|
index 1a6ac08..49f678f 100644
|
282
|
--- a/sys/net/if_ethersubr.c
|
283
|
+++ b/sys/net/if_ethersubr.c
|
284
|
@@ -742,7 +742,11 @@ ether_demux(struct ifnet *ifp, struct mbuf *m)
|
285
|
|
286
|
if (i != 0 || m == NULL)
|
287
|
return;
|
288
|
- }
|
289
|
+
|
290
|
+ /* M_PROTO2 is for M_IP[6]_NEXTHOP */
|
291
|
+ i = m->m_flags & (M_FASTFWD_OURS|M_PROTO2);
|
292
|
+ } else
|
293
|
+ i = 0;
|
294
|
|
295
|
eh = mtod(m, struct ether_header *);
|
296
|
ether_type = ntohs(eh->ether_type);
|
297
|
@@ -781,6 +785,8 @@ ether_demux(struct ifnet *ifp, struct mbuf *m)
|
298
|
*/
|
299
|
m->m_flags &= ~M_VLANTAG;
|
300
|
m_clrprotoflags(m);
|
301
|
+ if (i)
|
302
|
+ m->m_flags |= M_FASTFWD_OURS|M_PROTO2;
|
303
|
m_adj(m, ETHER_HDR_LEN);
|
304
|
|
305
|
/*
|
306
|
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
|
307
|
index 14b08f5..a327f1c 100644
|
308
|
--- a/sys/netinet/ip_fw.h
|
309
|
+++ b/sys/netinet/ip_fw.h
|
310
|
@@ -74,6 +74,8 @@ typedef struct _ip_fw3_opheader {
|
311
|
#define IP_FW_TABLE_XDEL 87 /* delete entry */
|
312
|
#define IP_FW_TABLE_XGETSIZE 88 /* get table size */
|
313
|
#define IP_FW_TABLE_XLIST 89 /* list table contents */
|
314
|
+#define IP_FW_TABLE_XLISTENTRY 90 /* list one table entry contents */
|
315
|
+#define IP_FW_TABLE_XZEROENTRY 91 /* zero one table entry stats */
|
316
|
|
317
|
/*
|
318
|
* The kernel representation of ipfw rules is made of a list of
|
319
|
@@ -600,23 +602,43 @@ struct _ipfw_dyn_rule {
|
320
|
|
321
|
#define IPFW_TABLE_CIDR 1 /* Table for holding IPv4/IPv6 prefixes */
|
322
|
#define IPFW_TABLE_INTERFACE 2 /* Table for holding interface names */
|
323
|
-#define IPFW_TABLE_MAXTYPE 2 /* Maximum valid number */
|
324
|
+#define IPFW_TABLE_MIX 3 /* Table for holding IPv4/mac entries */
|
325
|
+#define IPFW_TABLE_MAC 4 /* Table for holding mac entries */
|
326
|
+#define IPFW_TABLE_MAXTYPE 5 /* Maximum valid number */
|
327
|
|
328
|
typedef struct _ipfw_table_entry {
|
329
|
in_addr_t addr; /* network address */
|
330
|
u_int32_t value; /* value */
|
331
|
u_int16_t tbl; /* table number */
|
332
|
u_int8_t masklen; /* mask length */
|
333
|
+ uint64_t mac_addr;
|
334
|
} ipfw_table_entry;
|
335
|
|
336
|
typedef struct _ipfw_table_xentry {
|
337
|
uint16_t len; /* Total entry length */
|
338
|
uint8_t type; /* entry type */
|
339
|
uint8_t masklen; /* mask length */
|
340
|
- uint16_t tbl; /* table number */
|
341
|
uint32_t value; /* value */
|
342
|
+ uint32_t timestamp;
|
343
|
+ uint64_t mac_addr;
|
344
|
+ uint64_t bytes;
|
345
|
+ uint64_t packets;
|
346
|
+ uint16_t tbl; /* table number */
|
347
|
union {
|
348
|
/* Longest field needs to be aligned by 4-byte boundary */
|
349
|
+#ifndef ETHER_ADDR_LEN
|
350
|
+#define ETHER_ADDR_LEN 6
|
351
|
+#endif
|
352
|
+#if 0
|
353
|
+ struct {
|
354
|
+ struct ether_addr addr;
|
355
|
+ struct ether_addr mask;
|
356
|
+ } mac;
|
357
|
+#endif
|
358
|
+ struct {
|
359
|
+ struct in_addr addr;
|
360
|
+ u_char mac[ETHER_ADDR_LEN];
|
361
|
+ } mix;
|
362
|
struct in6_addr addr6; /* IPv6 address */
|
363
|
char iface[IF_NAMESIZE]; /* interface name */
|
364
|
} k;
|
365
|
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
|
366
|
index cd466bd..f2f117e 100644
|
367
|
--- a/sys/netpfil/ipfw/ip_fw2.c
|
368
|
+++ b/sys/netpfil/ipfw/ip_fw2.c
|
369
|
@@ -358,8 +358,8 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd, struct ip_fw_chain *chain, uin
|
370
|
/* Check by name or by IP address */
|
371
|
if (cmd->name[0] != '\0') { /* match by name */
|
372
|
if (cmd->name[0] == '\1') /* use tablearg to match */
|
373
|
- return ipfw_lookup_table_extended(chain, cmd->p.glob,
|
374
|
- ifp->if_xname, tablearg, IPFW_TABLE_INTERFACE);
|
375
|
+ return (ipfw_lookup_table_extended(chain, cmd->p.glob,
|
376
|
+ ifp->if_xname, tablearg, IPFW_TABLE_INTERFACE, NULL) != NULL);
|
377
|
/* Check name */
|
378
|
if (cmd->p.glob) {
|
379
|
if (fnmatch(cmd->name, ifp->if_xname, 0) == 0)
|
380
|
@@ -955,6 +955,7 @@ ipfw_chk(struct ip_fw_args *args)
|
381
|
int dyn_dir = MATCH_UNKNOWN;
|
382
|
ipfw_dyn_rule *q = NULL;
|
383
|
struct ip_fw_chain *chain = &V_layer3_chain;
|
384
|
+ void *tblent = NULL;
|
385
|
|
386
|
/*
|
387
|
* We store in ulp a pointer to the upper layer protocol header.
|
388
|
@@ -1288,6 +1289,7 @@ do { \
|
389
|
continue;
|
390
|
|
391
|
skip_or = 0;
|
392
|
+ tblent = NULL;
|
393
|
for (l = f->cmd_len, cmd = f->cmd ; l > 0 ;
|
394
|
l -= cmdlen, cmd += cmdlen) {
|
395
|
int match;
|
396
|
@@ -1402,7 +1404,7 @@ do { \
|
397
|
break;
|
398
|
|
399
|
case O_IN: /* "out" is "not in" */
|
400
|
- match = (oif == NULL);
|
401
|
+ match = (args->dir == DIR_IN);
|
402
|
break;
|
403
|
|
404
|
case O_LAYER2:
|
405
|
@@ -1438,11 +1440,18 @@ do { \
|
406
|
case O_IP_SRC_LOOKUP:
|
407
|
case O_IP_DST_LOOKUP:
|
408
|
if (is_ipv4) {
|
409
|
+ struct ether_addr *ea = NULL;
|
410
|
+
|
411
|
uint32_t key =
|
412
|
(cmd->opcode == O_IP_DST_LOOKUP) ?
|
413
|
dst_ip.s_addr : src_ip.s_addr;
|
414
|
uint32_t v = 0;
|
415
|
|
416
|
+ if (args->eh) {
|
417
|
+ ea = (struct ether_addr*)((cmd->opcode == O_IP_DST_LOOKUP) ?
|
418
|
+ args->eh->ether_dhost :
|
419
|
+ args->eh->ether_shost);
|
420
|
+ }
|
421
|
if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) {
|
422
|
/* generic lookup. The key must be
|
423
|
* in 32bit big-endian format.
|
424
|
@@ -1484,22 +1493,37 @@ do { \
|
425
|
} else
|
426
|
break;
|
427
|
}
|
428
|
- match = ipfw_lookup_table(chain,
|
429
|
- cmd->arg1, key, &v);
|
430
|
- if (!match)
|
431
|
+ tblent = ipfw_lookup_table_extended(chain,
|
432
|
+ cmd->arg1, &key, &v, IPFW_TABLE_CIDR, ea);
|
433
|
+ if (tblent == NULL) {
|
434
|
+ match = 0;
|
435
|
break;
|
436
|
+ } else
|
437
|
+ match = 1;
|
438
|
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
|
439
|
match =
|
440
|
((ipfw_insn_u32 *)cmd)->d[0] == v;
|
441
|
- else
|
442
|
+ if (match)
|
443
|
tablearg = v;
|
444
|
} else if (is_ipv6) {
|
445
|
+ struct ether_addr *ea = NULL;
|
446
|
uint32_t v = 0;
|
447
|
+
|
448
|
+ if (args->eh) {
|
449
|
+ ea = (struct ether_addr*)((cmd->opcode == O_IP_DST_LOOKUP) ?
|
450
|
+ args->eh->ether_dhost :
|
451
|
+ args->eh->ether_shost);
|
452
|
+ }
|
453
|
void *pkey = (cmd->opcode == O_IP_DST_LOOKUP) ?
|
454
|
&args->f_id.dst_ip6: &args->f_id.src_ip6;
|
455
|
- match = ipfw_lookup_table_extended(chain,
|
456
|
+ tblent = ipfw_lookup_table_extended(chain,
|
457
|
cmd->arg1, pkey, &v,
|
458
|
- IPFW_TABLE_CIDR);
|
459
|
+ IPFW_TABLE_CIDR, ea);
|
460
|
+ if (tblent == NULL) {
|
461
|
+ match = 0;
|
462
|
+ break;
|
463
|
+ } else
|
464
|
+ match = 1;
|
465
|
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
|
466
|
match = ((ipfw_insn_u32 *)cmd)->d[0] == v;
|
467
|
if (match)
|
468
|
@@ -2314,8 +2338,7 @@ do { \
|
469
|
break;
|
470
|
|
471
|
case O_FORWARD_IP:
|
472
|
- if (args->eh) /* not valid on layer2 pkts */
|
473
|
- break;
|
474
|
+ if (!args->eh) {/* not valid on layer2 pkts */
|
475
|
if (q == NULL || q->rule != f ||
|
476
|
dyn_dir == MATCH_FORWARD) {
|
477
|
struct sockaddr_in *sa;
|
478
|
@@ -2330,6 +2353,48 @@ do { \
|
479
|
args->next_hop = sa;
|
480
|
}
|
481
|
}
|
482
|
+ } else if (args->eh) {
|
483
|
+ struct m_tag *fwd_tag;
|
484
|
+ struct sockaddr_in *sa;
|
485
|
+ u_short sum;
|
486
|
+
|
487
|
+ /*
|
488
|
+ * Checksum correct? (from ip_fastfwd.c)
|
489
|
+ */
|
490
|
+ if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED)
|
491
|
+ sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
|
492
|
+ else {
|
493
|
+ if (hlen == sizeof(struct ip))
|
494
|
+ sum = in_cksum_hdr(ip);
|
495
|
+ else
|
496
|
+ sum = in_cksum(m, hlen);
|
497
|
+ }
|
498
|
+ if (sum) {
|
499
|
+ IPSTAT_INC(ips_badsum);
|
500
|
+ retval = IP_FW_DENY;
|
501
|
+ break;
|
502
|
+ }
|
503
|
+
|
504
|
+ /*
|
505
|
+ * Remember that we have checked the IP header and found it valid.
|
506
|
+ */
|
507
|
+ m->m_pkthdr.csum_flags |= (CSUM_IP_CHECKED | CSUM_IP_VALID);
|
508
|
+
|
509
|
+ sa = &(((ipfw_insn_sa *)cmd)->sa);
|
510
|
+ fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
|
511
|
+ sizeof(struct sockaddr_in), M_NOWAIT);
|
512
|
+ if (fwd_tag == NULL)
|
513
|
+ retval = IP_FW_DENY;
|
514
|
+ else {
|
515
|
+ bcopy(sa, (fwd_tag+1), sizeof(struct sockaddr_in));
|
516
|
+ m_tag_prepend(m, fwd_tag);
|
517
|
+
|
518
|
+ if (in_localip(sa->sin_addr))
|
519
|
+ m->m_flags |= M_FASTFWD_OURS;
|
520
|
+ m->m_flags |= M_IP_NEXTHOP;
|
521
|
+ }
|
522
|
+ }
|
523
|
+
|
524
|
retval = IP_FW_PASS;
|
525
|
l = 0; /* exit inner loop */
|
526
|
done = 1; /* exit outer loop */
|
527
|
@@ -2337,8 +2402,7 @@ do { \
|
528
|
|
529
|
#ifdef INET6
|
530
|
case O_FORWARD_IP6:
|
531
|
- if (args->eh) /* not valid on layer2 pkts */
|
532
|
- break;
|
533
|
+ if (!args->eh) {/* not valid on layer2 pkts */
|
534
|
if (q == NULL || q->rule != f ||
|
535
|
dyn_dir == MATCH_FORWARD) {
|
536
|
struct sockaddr_in6 *sin6;
|
537
|
@@ -2346,6 +2410,24 @@ do { \
|
538
|
sin6 = &(((ipfw_insn_sa6 *)cmd)->sa);
|
539
|
args->next_hop6 = sin6;
|
540
|
}
|
541
|
+ } else if (args->eh) {
|
542
|
+ struct m_tag *fwd_tag;
|
543
|
+ struct sockaddr_in6 *sin6;
|
544
|
+
|
545
|
+ sin6 = &(((ipfw_insn_sa6 *)cmd)->sa);
|
546
|
+ fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
|
547
|
+ sizeof(struct sockaddr_in6), M_NOWAIT);
|
548
|
+ if (fwd_tag == NULL)
|
549
|
+ retval = IP_FW_DENY;
|
550
|
+ else {
|
551
|
+ bcopy(sin6, (fwd_tag+1), sizeof(struct sockaddr_in6));
|
552
|
+ m_tag_prepend(m, fwd_tag);
|
553
|
+
|
554
|
+ if (in6_localip(&sin6->sin6_addr))
|
555
|
+ m->m_flags |= M_FASTFWD_OURS;
|
556
|
+ m->m_flags |= M_IP6_NEXTHOP;
|
557
|
+ }
|
558
|
+ }
|
559
|
retval = IP_FW_PASS;
|
560
|
l = 0; /* exit inner loop */
|
561
|
done = 1; /* exit outer loop */
|
562
|
@@ -2505,6 +2587,8 @@ do { \
|
563
|
struct ip_fw *rule = chain->map[f_pos];
|
564
|
/* Update statistics */
|
565
|
IPFW_INC_RULE_COUNTER(rule, pktlen);
|
566
|
+ if (tblent != NULL)
|
567
|
+ ipfw_count_table_xentry_stats(tblent, pktlen);
|
568
|
} else {
|
569
|
retval = IP_FW_DENY;
|
570
|
printf("ipfw: ouch!, skip past end of rules, denying packet\n");
|
571
|
diff --git a/sys/netpfil/ipfw/ip_fw_pfil.c b/sys/netpfil/ipfw/ip_fw_pfil.c
|
572
|
index d1202ff..bf225b8 100644
|
573
|
--- a/sys/netpfil/ipfw/ip_fw_pfil.c
|
574
|
+++ b/sys/netpfil/ipfw/ip_fw_pfil.c
|
575
|
@@ -143,8 +143,9 @@ again:
|
576
|
}
|
577
|
|
578
|
args.m = *m0;
|
579
|
- args.oif = dir == DIR_OUT ? ifp : NULL;
|
580
|
+ args.oif = ifp;
|
581
|
args.inp = inp;
|
582
|
+ args.dir = dir;
|
583
|
|
584
|
ipfw = ipfw_chk(&args);
|
585
|
*m0 = args.m;
|
586
|
@@ -314,9 +315,8 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *dst, int dir,
|
587
|
/* XXX can we free it after use ? */
|
588
|
mtag->m_tag_id = PACKET_TAG_NONE;
|
589
|
r = (struct ipfw_rule_ref *)(mtag + 1);
|
590
|
- if (r->info & IPFW_ONEPASS)
|
591
|
- return (0);
|
592
|
- args.rule = *r;
|
593
|
+ m_tag_delete(*m0, mtag);
|
594
|
+ return (0);
|
595
|
}
|
596
|
|
597
|
/* I need some amt of data to be contiguous */
|
598
|
@@ -333,12 +333,15 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *dst, int dir,
|
599
|
save_eh = *eh; /* save copy for restore below */
|
600
|
m_adj(m, ETHER_HDR_LEN); /* strip ethernet header */
|
601
|
|
602
|
+ dir = dir == PFIL_IN ? DIR_IN : DIR_OUT;
|
603
|
+
|
604
|
args.m = m; /* the packet we are looking at */
|
605
|
- args.oif = dir == PFIL_OUT ? dst: NULL; /* destination, if any */
|
606
|
+ args.oif = dst; /* destination, if any */
|
607
|
args.next_hop = NULL; /* we do not support forward yet */
|
608
|
args.next_hop6 = NULL; /* we do not support forward yet */
|
609
|
args.eh = &save_eh; /* MAC header for bridged/MAC packets */
|
610
|
args.inp = NULL; /* used by ipfw uid/gid/jail rules */
|
611
|
+ args.dir = dir; /* pfSense addition */
|
612
|
i = ipfw_chk(&args);
|
613
|
m = args.m;
|
614
|
if (m != NULL) {
|
615
|
@@ -369,13 +372,12 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *dst, int dir,
|
616
|
|
617
|
case IP_FW_DUMMYNET:
|
618
|
ret = EACCES;
|
619
|
- int dir;
|
620
|
|
621
|
if (ip_dn_io_ptr == NULL)
|
622
|
break; /* i.e. drop */
|
623
|
|
624
|
*m0 = NULL;
|
625
|
- dir = PROTO_LAYER2 | (dst ? DIR_OUT : DIR_IN);
|
626
|
+ dir = PROTO_LAYER2 | dir;
|
627
|
ip_dn_io_ptr(&m, dir, &args);
|
628
|
return 0;
|
629
|
|
630
|
diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h
|
631
|
index a8d7eea..4830124 100644
|
632
|
--- a/sys/netpfil/ipfw/ip_fw_private.h
|
633
|
+++ b/sys/netpfil/ipfw/ip_fw_private.h
|
634
|
@@ -101,6 +101,7 @@ struct ip_fw_args {
|
635
|
|
636
|
struct ipfw_flow_id f_id; /* grabbed from IP header */
|
637
|
//uint32_t cookie; /* a cookie depending on rule action */
|
638
|
+ uint32_t dir; /* direction */
|
639
|
struct inpcb *inp;
|
640
|
|
641
|
struct _ip6dn_args dummypar; /* dummynet->ip6_output */
|
642
|
@@ -304,13 +305,17 @@ void ipfw_reap_rules(struct ip_fw *head);
|
643
|
struct radix_node;
|
644
|
int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
|
645
|
uint32_t *val);
|
646
|
-int ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
647
|
- uint32_t *val, int type);
|
648
|
+struct ether_addr;
|
649
|
+void *ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
650
|
+ uint32_t *val, int type, struct ether_addr *);
|
651
|
+void ipfw_count_table_xentry_stats(void *, int);
|
652
|
+int ipfw_zero_table_xentry_stats(struct ip_fw_chain *, ipfw_table_xentry *);
|
653
|
+int ipfw_lookup_table_xentry(struct ip_fw_chain *, ipfw_table_xentry *);
|
654
|
int ipfw_init_tables(struct ip_fw_chain *ch);
|
655
|
void ipfw_destroy_tables(struct ip_fw_chain *ch);
|
656
|
int ipfw_flush_table(struct ip_fw_chain *ch, uint16_t tbl);
|
657
|
int ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
658
|
- uint8_t plen, uint8_t mlen, uint8_t type, uint32_t value);
|
659
|
+ uint8_t plen, uint8_t mlen, uint8_t type, u_int64_t mac_addr, uint32_t value);
|
660
|
int ipfw_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
661
|
uint8_t plen, uint8_t mlen, uint8_t type);
|
662
|
int ipfw_count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt);
|
663
|
diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c
|
664
|
index cb9c89c..d98cac6 100644
|
665
|
--- a/sys/netpfil/ipfw/ip_fw_sockopt.c
|
666
|
+++ b/sys/netpfil/ipfw/ip_fw_sockopt.c
|
667
|
@@ -1124,7 +1124,7 @@ ipfw_ctl(struct sockopt *sopt)
|
668
|
break;
|
669
|
error = ipfw_add_table_entry(chain, ent.tbl,
|
670
|
&ent.addr, sizeof(ent.addr), ent.masklen,
|
671
|
- IPFW_TABLE_CIDR, ent.value);
|
672
|
+ IPFW_TABLE_CIDR, ent.mac_addr, ent.value);
|
673
|
}
|
674
|
break;
|
675
|
|
676
|
@@ -1162,7 +1162,7 @@ ipfw_ctl(struct sockopt *sopt)
|
677
|
|
678
|
error = (opt == IP_FW_TABLE_XADD) ?
|
679
|
ipfw_add_table_entry(chain, xent->tbl, &xent->k,
|
680
|
- len, xent->masklen, xent->type, xent->value) :
|
681
|
+ len, xent->masklen, xent->type, xent->mac_addr, xent->value) :
|
682
|
ipfw_del_table_entry(chain, xent->tbl, &xent->k,
|
683
|
len, xent->masklen, xent->type);
|
684
|
}
|
685
|
@@ -1245,6 +1245,47 @@ ipfw_ctl(struct sockopt *sopt)
|
686
|
}
|
687
|
break;
|
688
|
|
689
|
+ case IP_FW_TABLE_XZEROENTRY: /* IP_FW3 */
|
690
|
+ {
|
691
|
+ ipfw_table_xentry *xent = (ipfw_table_xentry *)(op3 + 1);
|
692
|
+
|
693
|
+ /* Check minimum header size */
|
694
|
+ if (IP_FW3_OPLENGTH(sopt) < offsetof(ipfw_table_xentry, k)) {
|
695
|
+ error = EINVAL;
|
696
|
+ break;
|
697
|
+ }
|
698
|
+
|
699
|
+ /* Check if len field is valid */
|
700
|
+ if (xent->len > sizeof(ipfw_table_xentry)) {
|
701
|
+ error = EINVAL;
|
702
|
+ break;
|
703
|
+ }
|
704
|
+
|
705
|
+ error = ipfw_zero_table_xentry_stats(chain, xent);
|
706
|
+ }
|
707
|
+ break;
|
708
|
+
|
709
|
+ case IP_FW_TABLE_XLISTENTRY: /* IP_FW3 */
|
710
|
+ {
|
711
|
+ ipfw_table_xentry *xent = (ipfw_table_xentry *)(op3 + 1);
|
712
|
+
|
713
|
+ /* Check minimum header size */
|
714
|
+ if (IP_FW3_OPLENGTH(sopt) < offsetof(ipfw_table_xentry, k)) {
|
715
|
+ error = EINVAL;
|
716
|
+ break;
|
717
|
+ }
|
718
|
+
|
719
|
+ /* Check if len field is valid */
|
720
|
+ if (xent->len > sizeof(ipfw_table_xentry)) {
|
721
|
+ error = EINVAL;
|
722
|
+ break;
|
723
|
+ }
|
724
|
+
|
725
|
+ error = ipfw_lookup_table_xentry(chain, xent);
|
726
|
+ xent->timestamp += boottime.tv_sec;
|
727
|
+ }
|
728
|
+ break;
|
729
|
+
|
730
|
case IP_FW_TABLE_XLIST: /* IP_FW3 */
|
731
|
{
|
732
|
ipfw_xtable *tbl;
|
733
|
diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c
|
734
|
index 95cff5c..e916749 100644
|
735
|
--- a/sys/netpfil/ipfw/ip_fw_table.c
|
736
|
+++ b/sys/netpfil/ipfw/ip_fw_table.c
|
737
|
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
|
738
|
#include <net/route.h>
|
739
|
#include <net/vnet.h>
|
740
|
|
741
|
+#include <net/ethernet.h>
|
742
|
#include <netinet/in.h>
|
743
|
#include <netinet/ip_var.h> /* struct ipfw_rule_ref */
|
744
|
#include <netinet/ip_fw.h>
|
745
|
@@ -74,7 +75,11 @@ static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
|
746
|
struct table_entry {
|
747
|
struct radix_node rn[2];
|
748
|
struct sockaddr_in addr, mask;
|
749
|
+ u_int64_t mac_addr;
|
750
|
u_int32_t value;
|
751
|
+ u_int32_t timestamp;
|
752
|
+ u_int64_t bytes;
|
753
|
+ u_int64_t packets;
|
754
|
};
|
755
|
|
756
|
struct xaddr_iface {
|
757
|
@@ -83,6 +88,22 @@ struct xaddr_iface {
|
758
|
char ifname[IF_NAMESIZE]; /* Interface name */
|
759
|
};
|
760
|
|
761
|
+#if 0
|
762
|
+struct xaddr_mac {
|
763
|
+ uint8_t mac_len; /* length of this struct */
|
764
|
+ uint8_t pad[7]; /* Align name */
|
765
|
+ struct ether_addr mac;
|
766
|
+};
|
767
|
+#endif
|
768
|
+
|
769
|
+struct xaddr_mix {
|
770
|
+ uint8_t mix_len; /* length of this struct */
|
771
|
+ sa_family_t sin_family;
|
772
|
+ uint8_t pad[6];
|
773
|
+ struct in_addr sin_addr;
|
774
|
+ u_char mac[ETHER_ADDR_LEN];
|
775
|
+};
|
776
|
+
|
777
|
struct table_xentry {
|
778
|
struct radix_node rn[2];
|
779
|
union {
|
780
|
@@ -90,14 +111,26 @@ struct table_xentry {
|
781
|
struct sockaddr_in6 addr6;
|
782
|
#endif
|
783
|
struct xaddr_iface iface;
|
784
|
+#if 0
|
785
|
+ struct xaddr_mac mac;
|
786
|
+#endif
|
787
|
+ struct xaddr_mix mix;
|
788
|
} a;
|
789
|
union {
|
790
|
#ifdef INET6
|
791
|
struct sockaddr_in6 mask6;
|
792
|
#endif
|
793
|
struct xaddr_iface ifmask;
|
794
|
+#if 0
|
795
|
+ struct xaddr_mac macmask;
|
796
|
+#endif
|
797
|
+ struct xaddr_mix mixmask;
|
798
|
} m;
|
799
|
+ u_int64_t mac_addr;
|
800
|
u_int32_t value;
|
801
|
+ u_int32_t timestamp;
|
802
|
+ u_int64_t bytes;
|
803
|
+ u_int64_t packets;
|
804
|
};
|
805
|
|
806
|
/*
|
807
|
@@ -117,10 +150,17 @@ struct table_xentry {
|
808
|
#define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t))
|
809
|
#define KEY_LEN_INET6 (offsetof(struct sockaddr_in6, sin6_addr) + sizeof(struct in6_addr))
|
810
|
#define KEY_LEN_IFACE (offsetof(struct xaddr_iface, ifname))
|
811
|
+#define KEY_LEN_MIX (offsetof(struct xaddr_mix, sin_addr) + sizeof(in_addr_t) + ETHER_ADDR_LEN)
|
812
|
+#if 0
|
813
|
+#define KEY_LEN_MAC (offsetof(struct xaddr_mac, mac) + ETHER_ADDR_LEN)
|
814
|
+#endif
|
815
|
|
816
|
#define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr))
|
817
|
#define OFF_LEN_INET6 (8 * offsetof(struct sockaddr_in6, sin6_addr))
|
818
|
#define OFF_LEN_IFACE (8 * offsetof(struct xaddr_iface, ifname))
|
819
|
+#if 0
|
820
|
+#define OFF_LEN_MAC (8 * offsetof(struct xaddr_mac, mac))
|
821
|
+#endif
|
822
|
|
823
|
|
824
|
#ifdef INET6
|
825
|
@@ -137,7 +177,7 @@ ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
|
826
|
|
827
|
int
|
828
|
ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
829
|
- uint8_t plen, uint8_t mlen, uint8_t type, uint32_t value)
|
830
|
+ uint8_t plen, uint8_t mlen, uint8_t type, u_int64_t mac_addr, uint32_t value)
|
831
|
{
|
832
|
struct radix_node_head *rnh, **rnh_ptr;
|
833
|
struct table_entry *ent;
|
834
|
@@ -161,6 +201,7 @@ ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
835
|
return (EINVAL);
|
836
|
ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
|
837
|
ent->value = value;
|
838
|
+ ent->mac_addr = mac_addr;
|
839
|
/* Set 'total' structure length */
|
840
|
KEY_LEN(ent->addr) = KEY_LEN_INET;
|
841
|
KEY_LEN(ent->mask) = KEY_LEN_INET;
|
842
|
@@ -182,6 +223,7 @@ ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
843
|
return (EINVAL);
|
844
|
xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
|
845
|
xent->value = value;
|
846
|
+ xent->mac_addr = mac_addr;
|
847
|
/* Set 'total' structure length */
|
848
|
KEY_LEN(xent->a.addr6) = KEY_LEN_INET6;
|
849
|
KEY_LEN(xent->m.mask6) = KEY_LEN_INET6;
|
850
|
@@ -233,6 +275,52 @@ ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
851
|
mask_ptr = NULL;
|
852
|
break;
|
853
|
|
854
|
+#if 0
|
855
|
+ case IPFW_TABLE_MAC:
|
856
|
+ int i;
|
857
|
+
|
858
|
+ xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
|
859
|
+ xent->value = value;
|
860
|
+ /* Set 'total' structure length */
|
861
|
+ KEY_LEN(xent->a.mac) = KEY_LEN_MAC;
|
862
|
+ KEY_LEN(xent->m.macmask) = KEY_LEN_MAC;
|
863
|
+ /* Set offset of address in bits */
|
864
|
+ offset = OFF_LEN_MAC;
|
865
|
+ xent->a.mac = (struct ether_addr)(*paddr);
|
866
|
+ xent->m.mac = (struct ether_addr)(*(((struct ether_addr *)paddr) + 1));
|
867
|
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
|
868
|
+ xent->a.mac.octet[i] &= xent->m.mac.octet[i];
|
869
|
+ /* Set pointers */
|
870
|
+ rnh_ptr = &ch->xtables[tbl];
|
871
|
+ ent_ptr = xent;
|
872
|
+ addr_ptr = (struct sockaddr *)&xent->a.mac;
|
873
|
+ mask_ptr = (struct sockaddr *)&xent->m.macmask;
|
874
|
+ break;
|
875
|
+#endif
|
876
|
+
|
877
|
+ case IPFW_TABLE_MIX:
|
878
|
+ if ((plen - ETHER_ADDR_LEN) != sizeof(in_addr_t))
|
879
|
+ return (EINVAL);
|
880
|
+
|
881
|
+ xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
|
882
|
+ xent->value = value;
|
883
|
+ /* Set 'total' structure length */
|
884
|
+ KEY_LEN(xent->a.mix) = KEY_LEN_MIX;
|
885
|
+ KEY_LEN(xent->m.mixmask) = KEY_LEN_MIX;
|
886
|
+ /* Set offset of IPv4 address in bits */
|
887
|
+ offset = OFF_LEN_INET;
|
888
|
+ /* XXX: Needs to be fixed */
|
889
|
+ memcpy(&xent->a.mix.sin_addr, paddr, ETHER_ADDR_LEN + sizeof(struct in_addr));
|
890
|
+ /* Only full ips /32 and full masks supported for mac */
|
891
|
+ memset(&xent->m.mixmask.sin_addr, 0xFF, sizeof(struct in_addr));
|
892
|
+ memset(xent->m.mixmask.mac, 0xFF, ETHER_ADDR_LEN);
|
893
|
+ /* Set pointers */
|
894
|
+ rnh_ptr = &ch->xtables[tbl];
|
895
|
+ ent_ptr = xent;
|
896
|
+ addr_ptr = (struct sockaddr *)&xent->a.mix;
|
897
|
+ mask_ptr = NULL;
|
898
|
+ break;
|
899
|
+
|
900
|
default:
|
901
|
return (EINVAL);
|
902
|
}
|
903
|
@@ -281,6 +369,19 @@ ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
904
|
IPFW_WUNLOCK(ch);
|
905
|
|
906
|
if (rn == NULL) {
|
907
|
+ if (type == IPFW_TABLE_CIDR) {
|
908
|
+ /* Just update if any new value needed */
|
909
|
+ struct table_entry *ent2;
|
910
|
+
|
911
|
+ ent2 = (struct table_entry *)(rnh->rnh_lookup(&ent->addr, NULL, rnh));
|
912
|
+ if (ent2 != NULL) {
|
913
|
+ if (ent2->mac_addr) {
|
914
|
+ if (!bcmp(&mac_addr, &ent2->mac_addr, ETHER_ADDR_LEN))
|
915
|
+ ent2->value = value;
|
916
|
+ } else
|
917
|
+ ent2->value = value;
|
918
|
+ }
|
919
|
+ }
|
920
|
free(ent_ptr, M_IPFW_TBL);
|
921
|
return (EEXIST);
|
922
|
}
|
923
|
@@ -367,6 +468,41 @@ ipfw_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
924
|
|
925
|
break;
|
926
|
|
927
|
+#if 0
|
928
|
+ case IPFW_TABLE_MAC:
|
929
|
+ struct xaddr_mac mac, macmask;
|
930
|
+ memset(&mac, 0, sizeof(mac));
|
931
|
+ memset(&macmask, 0, sizeof(macmask));
|
932
|
+
|
933
|
+ /* Set 'total' structure length */
|
934
|
+ KEY_LEN(mac) = KEY_LEN_MAC;
|
935
|
+ mac.mac.mac = (struct ether_addr)(*paddr);
|
936
|
+ KEY_LEN(macmask) = KEY_LEN_MAC;
|
937
|
+ macmask.mac.macmask = (struct ether_addr)(*(((struct ether_addr *)paddr) + 1));
|
938
|
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
|
939
|
+ mac.mac.octet[i] &= macmask.mac.octet[i];
|
940
|
+ rnh_ptr = &ch->xtables[tbl];
|
941
|
+ sa_ptr = (struct sockaddr *)&mac;
|
942
|
+ mask_ptr = (struct sockaddr *)&macmask;
|
943
|
+
|
944
|
+ break;
|
945
|
+#endif
|
946
|
+
|
947
|
+ case IPFW_TABLE_MIX:
|
948
|
+ if (mlen > (32 + ETHER_ADDR_LEN))
|
949
|
+ return (EINVAL);
|
950
|
+ struct xaddr_mix mix;
|
951
|
+ memset(&mix, 0, sizeof(mix));
|
952
|
+
|
953
|
+ /* Set 'total' structure length */
|
954
|
+ KEY_LEN(mix) = KEY_LEN_MIX;
|
955
|
+ memcpy(&mix.sin_addr, paddr, sizeof(struct in_addr) + ETHER_ADDR_LEN);
|
956
|
+ rnh_ptr = &ch->xtables[tbl];
|
957
|
+ sa_ptr = (struct sockaddr *)&mix;
|
958
|
+ mask_ptr = NULL;
|
959
|
+
|
960
|
+ break;
|
961
|
+
|
962
|
default:
|
963
|
return (EINVAL);
|
964
|
}
|
965
|
@@ -552,9 +688,152 @@ ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
|
966
|
return (0);
|
967
|
}
|
968
|
|
969
|
+void
|
970
|
+ipfw_count_table_xentry_stats(void *arg, int pktlen)
|
971
|
+{
|
972
|
+ ipfw_table_xentry *xent= arg;
|
973
|
+
|
974
|
+ xent->packets++;
|
975
|
+ xent->bytes += pktlen;
|
976
|
+ xent->timestamp = time_uptime;
|
977
|
+}
|
978
|
+
|
979
|
int
|
980
|
+ipfw_zero_table_xentry_stats(struct ip_fw_chain *ch, ipfw_table_xentry *arg)
|
981
|
+{
|
982
|
+ struct radix_node_head *rnh;
|
983
|
+ struct table_xentry *xent;
|
984
|
+ struct sockaddr_in6 sa6;
|
985
|
+ struct xaddr_iface iface;
|
986
|
+ struct xaddr_mix xm;
|
987
|
+
|
988
|
+ if (arg->tbl >= V_fw_tables_max)
|
989
|
+ return (0);
|
990
|
+ if ((rnh = ch->xtables[arg->tbl]) == NULL)
|
991
|
+ return (0);
|
992
|
+
|
993
|
+ switch (arg->type) {
|
994
|
+ case IPFW_TABLE_CIDR:
|
995
|
+ KEY_LEN(sa6) = KEY_LEN_INET6;
|
996
|
+ memcpy(&sa6.sin6_addr, &arg->k.addr6, sizeof(struct in6_addr));
|
997
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&sa6, NULL, rnh));
|
998
|
+ break;
|
999
|
+
|
1000
|
+ case IPFW_TABLE_INTERFACE:
|
1001
|
+ KEY_LEN(iface) = KEY_LEN_IFACE +
|
1002
|
+ strlcpy(iface.ifname, arg->k.iface, IF_NAMESIZE) + 1;
|
1003
|
+ /* Assume direct match */
|
1004
|
+ /* FIXME: Add interface pattern matching */
|
1005
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&iface, NULL, rnh));
|
1006
|
+ break;
|
1007
|
+
|
1008
|
+#if 0
|
1009
|
+ case IPFW_TABLE_MAC:
|
1010
|
+ {
|
1011
|
+ struct xaddr_mac mac;
|
1012
|
+
|
1013
|
+ KEY_LEN(mac) = KEY_LEN_MAC;
|
1014
|
+ &mac.mac = arg->k.mac;
|
1015
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&mac, NULL, rnh));
|
1016
|
+ }
|
1017
|
+ break;
|
1018
|
+#endif
|
1019
|
+
|
1020
|
+ case IPFW_TABLE_MIX:
|
1021
|
+ KEY_LEN(xm) = KEY_LEN_MIX;
|
1022
|
+ memcpy(&xm.sin_addr, &arg->k.mix.addr, sizeof(struct in_addr));
|
1023
|
+ memcpy(&xm.mac, arg->k.mix.mac, ETHER_ADDR_LEN);
|
1024
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&xm, NULL, rnh));
|
1025
|
+ break;
|
1026
|
+
|
1027
|
+ default:
|
1028
|
+ return (0);
|
1029
|
+ }
|
1030
|
+
|
1031
|
+ if (xent != NULL) {
|
1032
|
+ xent->bytes = 0;
|
1033
|
+ xent->packets = 0;
|
1034
|
+ xent->timestamp = time_uptime;
|
1035
|
+
|
1036
|
+ return (1);
|
1037
|
+ }
|
1038
|
+ return (0);
|
1039
|
+}
|
1040
|
+
|
1041
|
+int
|
1042
|
+ipfw_lookup_table_xentry(struct ip_fw_chain *ch, ipfw_table_xentry *arg)
|
1043
|
+{
|
1044
|
+ struct radix_node_head *rnh;
|
1045
|
+ struct table_xentry *xent;
|
1046
|
+
|
1047
|
+ if (arg->tbl >= V_fw_tables_max)
|
1048
|
+ return (0);
|
1049
|
+ if ((rnh = ch->xtables[arg->tbl]) == NULL)
|
1050
|
+ return (0);
|
1051
|
+
|
1052
|
+ switch (arg->type) {
|
1053
|
+ case IPFW_TABLE_CIDR:
|
1054
|
+ {
|
1055
|
+ struct sockaddr_in6 sa6;
|
1056
|
+ KEY_LEN(sa6) = KEY_LEN_INET6;
|
1057
|
+ memcpy(&sa6.sin6_addr, &arg->k.addr6, sizeof(struct in6_addr));
|
1058
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&sa6, NULL, rnh));
|
1059
|
+ }
|
1060
|
+ break;
|
1061
|
+
|
1062
|
+ case IPFW_TABLE_INTERFACE:
|
1063
|
+ {
|
1064
|
+ struct xaddr_iface iface;
|
1065
|
+
|
1066
|
+ KEY_LEN(iface) = KEY_LEN_IFACE +
|
1067
|
+ strlcpy(iface.ifname, arg->k.iface, IF_NAMESIZE) + 1;
|
1068
|
+ /* Assume direct match */
|
1069
|
+ /* FIXME: Add interface pattern matching */
|
1070
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&iface, NULL, rnh));
|
1071
|
+ }
|
1072
|
+ break;
|
1073
|
+
|
1074
|
+#if 0
|
1075
|
+ case IPFW_TABLE_MAC:
|
1076
|
+ {
|
1077
|
+ struct xaddr_mac mac;
|
1078
|
+
|
1079
|
+ KEY_LEN(mac) = KEY_LEN_MAC;
|
1080
|
+ mac.mac = arg->k.mac.addr;
|
1081
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&mac, NULL, rnh));
|
1082
|
+ }
|
1083
|
+ break;
|
1084
|
+#endif
|
1085
|
+
|
1086
|
+ case IPFW_TABLE_MIX:
|
1087
|
+ {
|
1088
|
+ struct xaddr_mix xm;
|
1089
|
+
|
1090
|
+ KEY_LEN(xm) = KEY_LEN_MIX;
|
1091
|
+ memcpy(&xm.sin_addr, &arg->k.mix.addr, sizeof(struct in_addr));
|
1092
|
+ memcpy(&xm.mac, arg->k.mix.mac, ETHER_ADDR_LEN);
|
1093
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&xm, NULL, rnh));
|
1094
|
+ }
|
1095
|
+ break;
|
1096
|
+
|
1097
|
+ default:
|
1098
|
+ return (0);
|
1099
|
+ }
|
1100
|
+
|
1101
|
+ if (xent != NULL) {
|
1102
|
+ arg->bytes = xent->bytes;
|
1103
|
+ arg->packets = xent->packets;
|
1104
|
+ arg->value = xent->value;
|
1105
|
+ arg->timestamp = xent->timestamp;
|
1106
|
+
|
1107
|
+ return (1);
|
1108
|
+ }
|
1109
|
+ return (0);
|
1110
|
+}
|
1111
|
+
|
1112
|
+void *
|
1113
|
ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
1114
|
- uint32_t *val, int type)
|
1115
|
+ uint32_t *val, int type, struct ether_addr *ea)
|
1116
|
{
|
1117
|
struct radix_node_head *rnh;
|
1118
|
struct table_xentry *xent;
|
1119
|
@@ -562,15 +841,21 @@ ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
1120
|
struct xaddr_iface iface;
|
1121
|
|
1122
|
if (tbl >= V_fw_tables_max)
|
1123
|
- return (0);
|
1124
|
+ return (NULL);
|
1125
|
if ((rnh = ch->xtables[tbl]) == NULL)
|
1126
|
- return (0);
|
1127
|
+ return (NULL);
|
1128
|
|
1129
|
switch (type) {
|
1130
|
case IPFW_TABLE_CIDR:
|
1131
|
KEY_LEN(sa6) = KEY_LEN_INET6;
|
1132
|
memcpy(&sa6.sin6_addr, paddr, sizeof(struct in6_addr));
|
1133
|
xent = (struct table_xentry *)(rnh->rnh_lookup(&sa6, NULL, rnh));
|
1134
|
+ if (xent != NULL) {
|
1135
|
+ if (ea && xent->mac_addr) {
|
1136
|
+ if (bcmp((u_char *)&xent->mac_addr, ea->octet, ETHER_ADDR_LEN) != 0)
|
1137
|
+ xent = NULL;
|
1138
|
+ }
|
1139
|
+ }
|
1140
|
break;
|
1141
|
|
1142
|
case IPFW_TABLE_INTERFACE:
|
1143
|
@@ -581,15 +866,37 @@ ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
1144
|
xent = (struct table_xentry *)(rnh->rnh_lookup(&iface, NULL, rnh));
|
1145
|
break;
|
1146
|
|
1147
|
+#if 0
|
1148
|
+ case IPFW_TABLE_MAC:
|
1149
|
+ {
|
1150
|
+ struct xaddr_mac mac;
|
1151
|
+
|
1152
|
+ KEY_LEN(mac) = KEY_LEN_MAC;
|
1153
|
+ mac.mac = (struct ether_addr)(*paddr);
|
1154
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&mac, NULL, rnh));
|
1155
|
+ }
|
1156
|
+ break;
|
1157
|
+#endif
|
1158
|
+
|
1159
|
+ case IPFW_TABLE_MIX:
|
1160
|
+ {
|
1161
|
+ struct xaddr_mix xm;
|
1162
|
+
|
1163
|
+ KEY_LEN(xm) = KEY_LEN_MIX;
|
1164
|
+ memcpy(((char *)&xm.sin_addr), paddr, sizeof(struct in_addr) + ETHER_ADDR_LEN);
|
1165
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&xm, NULL, rnh));
|
1166
|
+ }
|
1167
|
+ break;
|
1168
|
+
|
1169
|
default:
|
1170
|
- return (0);
|
1171
|
+ return (NULL);
|
1172
|
}
|
1173
|
|
1174
|
if (xent != NULL) {
|
1175
|
*val = xent->value;
|
1176
|
- return (1);
|
1177
|
+ return (xent);
|
1178
|
}
|
1179
|
- return (0);
|
1180
|
+ return (NULL);
|
1181
|
}
|
1182
|
|
1183
|
static int
|
1184
|
@@ -698,6 +1005,9 @@ dump_table_xentry_base(struct radix_node *rn, void *arg)
|
1185
|
/* Save IPv4 address as deprecated IPv6 compatible */
|
1186
|
xent->k.addr6.s6_addr32[3] = n->addr.sin_addr.s_addr;
|
1187
|
xent->value = n->value;
|
1188
|
+ xent->bytes = n->bytes;
|
1189
|
+ xent->packets = n->packets;
|
1190
|
+ xent->timestamp = n->timestamp;
|
1191
|
tbl->cnt++;
|
1192
|
return (0);
|
1193
|
}
|
1194
|
@@ -735,12 +1045,31 @@ dump_table_xentry_extended(struct radix_node *rn, void *arg)
|
1195
|
memcpy(&xent->k, &n->a.iface.ifname, IF_NAMESIZE);
|
1196
|
break;
|
1197
|
|
1198
|
+#if 0
|
1199
|
+ case IPFW_TABLE_MAC:
|
1200
|
+ /* Assume exact mask */
|
1201
|
+ xent->masklen = 8 * ETHER_ADDR_LEN;
|
1202
|
+ xent->k.mac.addr = n->a.mac.mac;
|
1203
|
+ xent->k.mac.mask = n->m.mac.mac;
|
1204
|
+ break;
|
1205
|
+#endif
|
1206
|
+
|
1207
|
+ case IPFW_TABLE_MIX:
|
1208
|
+ /* Assume exact mask */
|
1209
|
+ xent->masklen = 8 * (ETHER_ADDR_LEN + sizeof(struct in_addr));
|
1210
|
+ memcpy(&xent->k.mix.addr, &n->a.mix.sin_addr, sizeof(struct in_addr));
|
1211
|
+ memcpy(xent->k.mix.mac, &n->a.mix.mac, ETHER_ADDR_LEN);
|
1212
|
+ break;
|
1213
|
+
|
1214
|
default:
|
1215
|
/* unknown, skip entry */
|
1216
|
return (0);
|
1217
|
}
|
1218
|
|
1219
|
xent->value = n->value;
|
1220
|
+ xent->bytes = n->bytes;
|
1221
|
+ xent->packets = n->packets;
|
1222
|
+ xent->timestamp = n->timestamp;
|
1223
|
tbl->cnt++;
|
1224
|
return (0);
|
1225
|
}
|