1
|
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
|
2
|
index 577d644..7d82d34 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..226bb21 100644
|
282
|
--- a/sys/net/if_ethersubr.c
|
283
|
+++ b/sys/net/if_ethersubr.c
|
284
|
@@ -742,6 +742,8 @@ ether_demux(struct ifnet *ifp, struct mbuf *m)
|
285
|
|
286
|
if (i != 0 || m == NULL)
|
287
|
return;
|
288
|
+
|
289
|
+ i = m->m_flags & M_FASTFWD_OURS;
|
290
|
}
|
291
|
|
292
|
eh = mtod(m, struct ether_header *);
|
293
|
@@ -781,6 +783,8 @@ ether_demux(struct ifnet *ifp, struct mbuf *m)
|
294
|
*/
|
295
|
m->m_flags &= ~M_VLANTAG;
|
296
|
m_clrprotoflags(m);
|
297
|
+ if (i)
|
298
|
+ m->m_flags |= M_FASTFWD_OURS;
|
299
|
m_adj(m, ETHER_HDR_LEN);
|
300
|
|
301
|
/*
|
302
|
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
|
303
|
index 14b08f5..f868bc4 100644
|
304
|
--- a/sys/netinet/ip_fw.h
|
305
|
+++ b/sys/netinet/ip_fw.h
|
306
|
@@ -74,6 +74,8 @@ typedef struct _ip_fw3_opheader {
|
307
|
#define IP_FW_TABLE_XDEL 87 /* delete entry */
|
308
|
#define IP_FW_TABLE_XGETSIZE 88 /* get table size */
|
309
|
#define IP_FW_TABLE_XLIST 89 /* list table contents */
|
310
|
+#define IP_FW_TABLE_XLISTENTRY 90 /* list one table entry contents */
|
311
|
+#define IP_FW_TABLE_XZEROENTRY 91 /* zero one table entry stats */
|
312
|
|
313
|
/*
|
314
|
* The kernel representation of ipfw rules is made of a list of
|
315
|
@@ -600,7 +602,9 @@ struct _ipfw_dyn_rule {
|
316
|
|
317
|
#define IPFW_TABLE_CIDR 1 /* Table for holding IPv4/IPv6 prefixes */
|
318
|
#define IPFW_TABLE_INTERFACE 2 /* Table for holding interface names */
|
319
|
-#define IPFW_TABLE_MAXTYPE 2 /* Maximum valid number */
|
320
|
+#define IPFW_TABLE_MIX 3 /* Table for holding IPv4/mac entries */
|
321
|
+#define IPFW_TABLE_MAC 4 /* Table for holding mac entries */
|
322
|
+#define IPFW_TABLE_MAXTYPE 5 /* Maximum valid number */
|
323
|
|
324
|
typedef struct _ipfw_table_entry {
|
325
|
in_addr_t addr; /* network address */
|
326
|
@@ -617,9 +621,26 @@ typedef struct _ipfw_table_xentry {
|
327
|
uint32_t value; /* value */
|
328
|
union {
|
329
|
/* Longest field needs to be aligned by 4-byte boundary */
|
330
|
+#ifndef ETHER_ADDR_LEN
|
331
|
+#define ETHER_ADDR_LEN 6
|
332
|
+#endif
|
333
|
+#if 0
|
334
|
+ struct {
|
335
|
+ struct ether_addr addr;
|
336
|
+ struct ether_addr mask;
|
337
|
+ } mac;
|
338
|
+#endif
|
339
|
+ struct {
|
340
|
+ struct in_addr addr;
|
341
|
+ u_char mac[ETHER_ADDR_LEN];
|
342
|
+ } mix;
|
343
|
struct in6_addr addr6; /* IPv6 address */
|
344
|
char iface[IF_NAMESIZE]; /* interface name */
|
345
|
} k;
|
346
|
+ uint64_t mac_addr;
|
347
|
+ uint64_t bytes;
|
348
|
+ uint64_t packets;
|
349
|
+ uint32_t timestamp;
|
350
|
} ipfw_table_xentry;
|
351
|
|
352
|
typedef struct _ipfw_table {
|
353
|
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
|
354
|
index cd466bd..f2f117e 100644
|
355
|
--- a/sys/netpfil/ipfw/ip_fw2.c
|
356
|
+++ b/sys/netpfil/ipfw/ip_fw2.c
|
357
|
@@ -358,8 +358,8 @@ iface_match(struct ifnet *ifp, ipfw_insn_if *cmd, struct ip_fw_chain *chain, uin
|
358
|
/* Check by name or by IP address */
|
359
|
if (cmd->name[0] != '\0') { /* match by name */
|
360
|
if (cmd->name[0] == '\1') /* use tablearg to match */
|
361
|
- return ipfw_lookup_table_extended(chain, cmd->p.glob,
|
362
|
- ifp->if_xname, tablearg, IPFW_TABLE_INTERFACE);
|
363
|
+ return (ipfw_lookup_table_extended(chain, cmd->p.glob,
|
364
|
+ ifp->if_xname, tablearg, IPFW_TABLE_INTERFACE, NULL) != NULL);
|
365
|
/* Check name */
|
366
|
if (cmd->p.glob) {
|
367
|
if (fnmatch(cmd->name, ifp->if_xname, 0) == 0)
|
368
|
@@ -955,6 +955,7 @@ ipfw_chk(struct ip_fw_args *args)
|
369
|
int dyn_dir = MATCH_UNKNOWN;
|
370
|
ipfw_dyn_rule *q = NULL;
|
371
|
struct ip_fw_chain *chain = &V_layer3_chain;
|
372
|
+ void *tblent = NULL;
|
373
|
|
374
|
/*
|
375
|
* We store in ulp a pointer to the upper layer protocol header.
|
376
|
@@ -1288,6 +1289,7 @@ do { \
|
377
|
continue;
|
378
|
|
379
|
skip_or = 0;
|
380
|
+ tblent = NULL;
|
381
|
for (l = f->cmd_len, cmd = f->cmd ; l > 0 ;
|
382
|
l -= cmdlen, cmd += cmdlen) {
|
383
|
int match;
|
384
|
@@ -1402,7 +1404,7 @@ do { \
|
385
|
break;
|
386
|
|
387
|
case O_IN: /* "out" is "not in" */
|
388
|
- match = (oif == NULL);
|
389
|
+ match = (args->dir == DIR_IN);
|
390
|
break;
|
391
|
|
392
|
case O_LAYER2:
|
393
|
@@ -1438,11 +1440,18 @@ do { \
|
394
|
case O_IP_SRC_LOOKUP:
|
395
|
case O_IP_DST_LOOKUP:
|
396
|
if (is_ipv4) {
|
397
|
+ struct ether_addr *ea = NULL;
|
398
|
+
|
399
|
uint32_t key =
|
400
|
(cmd->opcode == O_IP_DST_LOOKUP) ?
|
401
|
dst_ip.s_addr : src_ip.s_addr;
|
402
|
uint32_t v = 0;
|
403
|
|
404
|
+ if (args->eh) {
|
405
|
+ ea = (struct ether_addr*)((cmd->opcode == O_IP_DST_LOOKUP) ?
|
406
|
+ args->eh->ether_dhost :
|
407
|
+ args->eh->ether_shost);
|
408
|
+ }
|
409
|
if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) {
|
410
|
/* generic lookup. The key must be
|
411
|
* in 32bit big-endian format.
|
412
|
@@ -1484,22 +1493,37 @@ do { \
|
413
|
} else
|
414
|
break;
|
415
|
}
|
416
|
- match = ipfw_lookup_table(chain,
|
417
|
- cmd->arg1, key, &v);
|
418
|
- if (!match)
|
419
|
+ tblent = ipfw_lookup_table_extended(chain,
|
420
|
+ cmd->arg1, &key, &v, IPFW_TABLE_CIDR, ea);
|
421
|
+ if (tblent == NULL) {
|
422
|
+ match = 0;
|
423
|
break;
|
424
|
+ } else
|
425
|
+ match = 1;
|
426
|
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
|
427
|
match =
|
428
|
((ipfw_insn_u32 *)cmd)->d[0] == v;
|
429
|
- else
|
430
|
+ if (match)
|
431
|
tablearg = v;
|
432
|
} else if (is_ipv6) {
|
433
|
+ struct ether_addr *ea = NULL;
|
434
|
uint32_t v = 0;
|
435
|
+
|
436
|
+ if (args->eh) {
|
437
|
+ ea = (struct ether_addr*)((cmd->opcode == O_IP_DST_LOOKUP) ?
|
438
|
+ args->eh->ether_dhost :
|
439
|
+ args->eh->ether_shost);
|
440
|
+ }
|
441
|
void *pkey = (cmd->opcode == O_IP_DST_LOOKUP) ?
|
442
|
&args->f_id.dst_ip6: &args->f_id.src_ip6;
|
443
|
- match = ipfw_lookup_table_extended(chain,
|
444
|
+ tblent = ipfw_lookup_table_extended(chain,
|
445
|
cmd->arg1, pkey, &v,
|
446
|
- IPFW_TABLE_CIDR);
|
447
|
+ IPFW_TABLE_CIDR, ea);
|
448
|
+ if (tblent == NULL) {
|
449
|
+ match = 0;
|
450
|
+ break;
|
451
|
+ } else
|
452
|
+ match = 1;
|
453
|
if (cmdlen == F_INSN_SIZE(ipfw_insn_u32))
|
454
|
match = ((ipfw_insn_u32 *)cmd)->d[0] == v;
|
455
|
if (match)
|
456
|
@@ -2314,8 +2338,7 @@ do { \
|
457
|
break;
|
458
|
|
459
|
case O_FORWARD_IP:
|
460
|
- if (args->eh) /* not valid on layer2 pkts */
|
461
|
- break;
|
462
|
+ if (!args->eh) {/* not valid on layer2 pkts */
|
463
|
if (q == NULL || q->rule != f ||
|
464
|
dyn_dir == MATCH_FORWARD) {
|
465
|
struct sockaddr_in *sa;
|
466
|
@@ -2330,6 +2353,48 @@ do { \
|
467
|
args->next_hop = sa;
|
468
|
}
|
469
|
}
|
470
|
+ } else if (args->eh) {
|
471
|
+ struct m_tag *fwd_tag;
|
472
|
+ struct sockaddr_in *sa;
|
473
|
+ u_short sum;
|
474
|
+
|
475
|
+ /*
|
476
|
+ * Checksum correct? (from ip_fastfwd.c)
|
477
|
+ */
|
478
|
+ if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED)
|
479
|
+ sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
|
480
|
+ else {
|
481
|
+ if (hlen == sizeof(struct ip))
|
482
|
+ sum = in_cksum_hdr(ip);
|
483
|
+ else
|
484
|
+ sum = in_cksum(m, hlen);
|
485
|
+ }
|
486
|
+ if (sum) {
|
487
|
+ IPSTAT_INC(ips_badsum);
|
488
|
+ retval = IP_FW_DENY;
|
489
|
+ break;
|
490
|
+ }
|
491
|
+
|
492
|
+ /*
|
493
|
+ * Remember that we have checked the IP header and found it valid.
|
494
|
+ */
|
495
|
+ m->m_pkthdr.csum_flags |= (CSUM_IP_CHECKED | CSUM_IP_VALID);
|
496
|
+
|
497
|
+ sa = &(((ipfw_insn_sa *)cmd)->sa);
|
498
|
+ fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
|
499
|
+ sizeof(struct sockaddr_in), M_NOWAIT);
|
500
|
+ if (fwd_tag == NULL)
|
501
|
+ retval = IP_FW_DENY;
|
502
|
+ else {
|
503
|
+ bcopy(sa, (fwd_tag+1), sizeof(struct sockaddr_in));
|
504
|
+ m_tag_prepend(m, fwd_tag);
|
505
|
+
|
506
|
+ if (in_localip(sa->sin_addr))
|
507
|
+ m->m_flags |= M_FASTFWD_OURS;
|
508
|
+ m->m_flags |= M_IP_NEXTHOP;
|
509
|
+ }
|
510
|
+ }
|
511
|
+
|
512
|
retval = IP_FW_PASS;
|
513
|
l = 0; /* exit inner loop */
|
514
|
done = 1; /* exit outer loop */
|
515
|
@@ -2337,8 +2402,7 @@ do { \
|
516
|
|
517
|
#ifdef INET6
|
518
|
case O_FORWARD_IP6:
|
519
|
- if (args->eh) /* not valid on layer2 pkts */
|
520
|
- break;
|
521
|
+ if (!args->eh) {/* not valid on layer2 pkts */
|
522
|
if (q == NULL || q->rule != f ||
|
523
|
dyn_dir == MATCH_FORWARD) {
|
524
|
struct sockaddr_in6 *sin6;
|
525
|
@@ -2346,6 +2410,24 @@ do { \
|
526
|
sin6 = &(((ipfw_insn_sa6 *)cmd)->sa);
|
527
|
args->next_hop6 = sin6;
|
528
|
}
|
529
|
+ } else if (args->eh) {
|
530
|
+ struct m_tag *fwd_tag;
|
531
|
+ struct sockaddr_in6 *sin6;
|
532
|
+
|
533
|
+ sin6 = &(((ipfw_insn_sa6 *)cmd)->sa);
|
534
|
+ fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
|
535
|
+ sizeof(struct sockaddr_in6), M_NOWAIT);
|
536
|
+ if (fwd_tag == NULL)
|
537
|
+ retval = IP_FW_DENY;
|
538
|
+ else {
|
539
|
+ bcopy(sin6, (fwd_tag+1), sizeof(struct sockaddr_in6));
|
540
|
+ m_tag_prepend(m, fwd_tag);
|
541
|
+
|
542
|
+ if (in6_localip(&sin6->sin6_addr))
|
543
|
+ m->m_flags |= M_FASTFWD_OURS;
|
544
|
+ m->m_flags |= M_IP6_NEXTHOP;
|
545
|
+ }
|
546
|
+ }
|
547
|
retval = IP_FW_PASS;
|
548
|
l = 0; /* exit inner loop */
|
549
|
done = 1; /* exit outer loop */
|
550
|
@@ -2505,6 +2587,8 @@ do { \
|
551
|
struct ip_fw *rule = chain->map[f_pos];
|
552
|
/* Update statistics */
|
553
|
IPFW_INC_RULE_COUNTER(rule, pktlen);
|
554
|
+ if (tblent != NULL)
|
555
|
+ ipfw_count_table_xentry_stats(tblent, pktlen);
|
556
|
} else {
|
557
|
retval = IP_FW_DENY;
|
558
|
printf("ipfw: ouch!, skip past end of rules, denying packet\n");
|
559
|
diff --git a/sys/netpfil/ipfw/ip_fw_pfil.c b/sys/netpfil/ipfw/ip_fw_pfil.c
|
560
|
index d1202ff..bf225b8 100644
|
561
|
--- a/sys/netpfil/ipfw/ip_fw_pfil.c
|
562
|
+++ b/sys/netpfil/ipfw/ip_fw_pfil.c
|
563
|
@@ -143,8 +143,9 @@ again:
|
564
|
}
|
565
|
|
566
|
args.m = *m0;
|
567
|
- args.oif = dir == DIR_OUT ? ifp : NULL;
|
568
|
+ args.oif = ifp;
|
569
|
args.inp = inp;
|
570
|
+ args.dir = dir;
|
571
|
|
572
|
ipfw = ipfw_chk(&args);
|
573
|
*m0 = args.m;
|
574
|
@@ -314,9 +315,8 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *dst, int dir,
|
575
|
/* XXX can we free it after use ? */
|
576
|
mtag->m_tag_id = PACKET_TAG_NONE;
|
577
|
r = (struct ipfw_rule_ref *)(mtag + 1);
|
578
|
- if (r->info & IPFW_ONEPASS)
|
579
|
- return (0);
|
580
|
- args.rule = *r;
|
581
|
+ m_tag_delete(*m0, mtag);
|
582
|
+ return (0);
|
583
|
}
|
584
|
|
585
|
/* I need some amt of data to be contiguous */
|
586
|
@@ -333,12 +333,15 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *dst, int dir,
|
587
|
save_eh = *eh; /* save copy for restore below */
|
588
|
m_adj(m, ETHER_HDR_LEN); /* strip ethernet header */
|
589
|
|
590
|
+ dir = dir == PFIL_IN ? DIR_IN : DIR_OUT;
|
591
|
+
|
592
|
args.m = m; /* the packet we are looking at */
|
593
|
- args.oif = dir == PFIL_OUT ? dst: NULL; /* destination, if any */
|
594
|
+ args.oif = dst; /* destination, if any */
|
595
|
args.next_hop = NULL; /* we do not support forward yet */
|
596
|
args.next_hop6 = NULL; /* we do not support forward yet */
|
597
|
args.eh = &save_eh; /* MAC header for bridged/MAC packets */
|
598
|
args.inp = NULL; /* used by ipfw uid/gid/jail rules */
|
599
|
+ args.dir = dir; /* pfSense addition */
|
600
|
i = ipfw_chk(&args);
|
601
|
m = args.m;
|
602
|
if (m != NULL) {
|
603
|
@@ -369,13 +372,12 @@ ipfw_check_frame(void *arg, struct mbuf **m0, struct ifnet *dst, int dir,
|
604
|
|
605
|
case IP_FW_DUMMYNET:
|
606
|
ret = EACCES;
|
607
|
- int dir;
|
608
|
|
609
|
if (ip_dn_io_ptr == NULL)
|
610
|
break; /* i.e. drop */
|
611
|
|
612
|
*m0 = NULL;
|
613
|
- dir = PROTO_LAYER2 | (dst ? DIR_OUT : DIR_IN);
|
614
|
+ dir = PROTO_LAYER2 | dir;
|
615
|
ip_dn_io_ptr(&m, dir, &args);
|
616
|
return 0;
|
617
|
|
618
|
diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h
|
619
|
index a8d7eea..9504249 100644
|
620
|
--- a/sys/netpfil/ipfw/ip_fw_private.h
|
621
|
+++ b/sys/netpfil/ipfw/ip_fw_private.h
|
622
|
@@ -101,6 +101,7 @@ struct ip_fw_args {
|
623
|
|
624
|
struct ipfw_flow_id f_id; /* grabbed from IP header */
|
625
|
//uint32_t cookie; /* a cookie depending on rule action */
|
626
|
+ uint32_t dir; /* direction */
|
627
|
struct inpcb *inp;
|
628
|
|
629
|
struct _ip6dn_args dummypar; /* dummynet->ip6_output */
|
630
|
@@ -304,8 +305,11 @@ void ipfw_reap_rules(struct ip_fw *head);
|
631
|
struct radix_node;
|
632
|
int ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
|
633
|
uint32_t *val);
|
634
|
-int ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
635
|
- uint32_t *val, int type);
|
636
|
+void *ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
637
|
+ uint32_t *val, int type, struct ether_addr *);
|
638
|
+void ipfw_count_table_xentry_stats(void *, int);
|
639
|
+int ipfw_zero_table_xentry_stats(struct ip_fw_chain *, ipfw_table_xentry *);
|
640
|
+int ipfw_lookup_table_xentry(struct ip_fw_chain *, ipfw_table_xentry *);
|
641
|
int ipfw_init_tables(struct ip_fw_chain *ch);
|
642
|
void ipfw_destroy_tables(struct ip_fw_chain *ch);
|
643
|
int ipfw_flush_table(struct ip_fw_chain *ch, uint16_t tbl);
|
644
|
diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c
|
645
|
index cb9c89c..e55f455 100644
|
646
|
--- a/sys/netpfil/ipfw/ip_fw_sockopt.c
|
647
|
+++ b/sys/netpfil/ipfw/ip_fw_sockopt.c
|
648
|
@@ -1162,7 +1162,7 @@ ipfw_ctl(struct sockopt *sopt)
|
649
|
|
650
|
error = (opt == IP_FW_TABLE_XADD) ?
|
651
|
ipfw_add_table_entry(chain, xent->tbl, &xent->k,
|
652
|
- len, xent->masklen, xent->type, xent->value) :
|
653
|
+ len, xent->masklen, xent->type, xentry->mac_addr, xent->value) :
|
654
|
ipfw_del_table_entry(chain, xent->tbl, &xent->k,
|
655
|
len, xent->masklen, xent->type);
|
656
|
}
|
657
|
@@ -1245,6 +1245,47 @@ ipfw_ctl(struct sockopt *sopt)
|
658
|
}
|
659
|
break;
|
660
|
|
661
|
+ case IP_FW_TABLE_XZEROENTRY: /* IP_FW3 */
|
662
|
+ {
|
663
|
+ ipfw_table_xentry *xent = (ipfw_table_xentry *)(op3 + 1);
|
664
|
+
|
665
|
+ /* Check minimum header size */
|
666
|
+ if (IP_FW3_OPLENGTH(sopt) < offsetof(ipfw_table_xentry, k)) {
|
667
|
+ error = EINVAL;
|
668
|
+ break;
|
669
|
+ }
|
670
|
+
|
671
|
+ /* Check if len field is valid */
|
672
|
+ if (xent->len > sizeof(ipfw_table_xentry)) {
|
673
|
+ error = EINVAL;
|
674
|
+ break;
|
675
|
+ }
|
676
|
+
|
677
|
+ error = ipfw_zero_table_xentry_stats(chain, xent);
|
678
|
+ }
|
679
|
+ break;
|
680
|
+
|
681
|
+ case IP_FW_TABLE_XLISTENTRY: /* IP_FW3 */
|
682
|
+ {
|
683
|
+ ipfw_table_xentry *xent = (ipfw_table_xentry *)(op3 + 1);
|
684
|
+
|
685
|
+ /* Check minimum header size */
|
686
|
+ if (IP_FW3_OPLENGTH(sopt) < offsetof(ipfw_table_xentry, k)) {
|
687
|
+ error = EINVAL;
|
688
|
+ break;
|
689
|
+ }
|
690
|
+
|
691
|
+ /* Check if len field is valid */
|
692
|
+ if (xent->len > sizeof(ipfw_table_xentry)) {
|
693
|
+ error = EINVAL;
|
694
|
+ break;
|
695
|
+ }
|
696
|
+
|
697
|
+ error = ipfw_lookup_table_xentry(chain, xent);
|
698
|
+ xent->timestamp += boottime.tv_sec;
|
699
|
+ }
|
700
|
+ break;
|
701
|
+
|
702
|
case IP_FW_TABLE_XLIST: /* IP_FW3 */
|
703
|
{
|
704
|
ipfw_xtable *tbl;
|
705
|
diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c
|
706
|
index 95cff5c..7b8b961 100644
|
707
|
--- a/sys/netpfil/ipfw/ip_fw_table.c
|
708
|
+++ b/sys/netpfil/ipfw/ip_fw_table.c
|
709
|
@@ -74,7 +74,11 @@ static MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables");
|
710
|
struct table_entry {
|
711
|
struct radix_node rn[2];
|
712
|
struct sockaddr_in addr, mask;
|
713
|
+ u_int64_t mac_addr;
|
714
|
u_int32_t value;
|
715
|
+ u_int32_t timestamp;
|
716
|
+ u_int64_t bytes;
|
717
|
+ u_int64_t packets;
|
718
|
};
|
719
|
|
720
|
struct xaddr_iface {
|
721
|
@@ -83,6 +87,22 @@ struct xaddr_iface {
|
722
|
char ifname[IF_NAMESIZE]; /* Interface name */
|
723
|
};
|
724
|
|
725
|
+#if 0
|
726
|
+struct xaddr_mac {
|
727
|
+ uint8_t mac_len; /* length of this struct */
|
728
|
+ uint8_t pad[7]; /* Align name */
|
729
|
+ struct ether_addr mac;
|
730
|
+};
|
731
|
+#endif
|
732
|
+
|
733
|
+struct xaddr_mix {
|
734
|
+ uint8_t mix_len; /* length of this struct */
|
735
|
+ sa_family_t sin_family;
|
736
|
+ uint8_t pad[6];
|
737
|
+ struct in_addr sin_addr;
|
738
|
+ u_char mac[ETHER_ADDR_LEN];
|
739
|
+};
|
740
|
+
|
741
|
struct table_xentry {
|
742
|
struct radix_node rn[2];
|
743
|
union {
|
744
|
@@ -90,14 +110,26 @@ struct table_xentry {
|
745
|
struct sockaddr_in6 addr6;
|
746
|
#endif
|
747
|
struct xaddr_iface iface;
|
748
|
+#if 0
|
749
|
+ struct xaddr_mac mac;
|
750
|
+#endif
|
751
|
+ struct xaddr_mix mix;
|
752
|
} a;
|
753
|
union {
|
754
|
#ifdef INET6
|
755
|
struct sockaddr_in6 mask6;
|
756
|
#endif
|
757
|
struct xaddr_iface ifmask;
|
758
|
+#if 0
|
759
|
+ struct xaddr_mac macmask;
|
760
|
+#endif
|
761
|
+ struct xaddr_mix mixmask;
|
762
|
} m;
|
763
|
+ u_int64_t mac_addr;
|
764
|
u_int32_t value;
|
765
|
+ u_int32_t timestamp;
|
766
|
+ u_int64_t bytes;
|
767
|
+ u_int64_t packets;
|
768
|
};
|
769
|
|
770
|
/*
|
771
|
@@ -117,10 +149,17 @@ struct table_xentry {
|
772
|
#define KEY_LEN_INET (offsetof(struct sockaddr_in, sin_addr) + sizeof(in_addr_t))
|
773
|
#define KEY_LEN_INET6 (offsetof(struct sockaddr_in6, sin6_addr) + sizeof(struct in6_addr))
|
774
|
#define KEY_LEN_IFACE (offsetof(struct xaddr_iface, ifname))
|
775
|
+#define KEY_LEN_MIX (offsetof(struct xaddr_mix, sin_addr) + sizeof(in_addr_t) + ETHER_ADDR_LEN)
|
776
|
+#if 0
|
777
|
+#define KEY_LEN_MAC (offsetof(struct xaddr_mac, mac) + ETHER_ADDR_LEN)
|
778
|
+#endif
|
779
|
|
780
|
#define OFF_LEN_INET (8 * offsetof(struct sockaddr_in, sin_addr))
|
781
|
#define OFF_LEN_INET6 (8 * offsetof(struct sockaddr_in6, sin6_addr))
|
782
|
#define OFF_LEN_IFACE (8 * offsetof(struct xaddr_iface, ifname))
|
783
|
+#if 0
|
784
|
+#define OFF_LEN_MAC (8 * offsetof(struct xaddr_mac, mac))
|
785
|
+#endif
|
786
|
|
787
|
|
788
|
#ifdef INET6
|
789
|
@@ -137,7 +176,7 @@ ipv6_writemask(struct in6_addr *addr6, uint8_t mask)
|
790
|
|
791
|
int
|
792
|
ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
793
|
- uint8_t plen, uint8_t mlen, uint8_t type, uint32_t value)
|
794
|
+ uint8_t plen, uint8_t mlen, uint8_t type, u_int64_t mac_addr, uint32_t value)
|
795
|
{
|
796
|
struct radix_node_head *rnh, **rnh_ptr;
|
797
|
struct table_entry *ent;
|
798
|
@@ -161,6 +200,7 @@ ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
799
|
return (EINVAL);
|
800
|
ent = malloc(sizeof(*ent), M_IPFW_TBL, M_WAITOK | M_ZERO);
|
801
|
ent->value = value;
|
802
|
+ ent->mac_addr = mac_addr;
|
803
|
/* Set 'total' structure length */
|
804
|
KEY_LEN(ent->addr) = KEY_LEN_INET;
|
805
|
KEY_LEN(ent->mask) = KEY_LEN_INET;
|
806
|
@@ -182,6 +222,7 @@ ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
807
|
return (EINVAL);
|
808
|
xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
|
809
|
xent->value = value;
|
810
|
+ ent->mac_addr = mac_addr;
|
811
|
/* Set 'total' structure length */
|
812
|
KEY_LEN(xent->a.addr6) = KEY_LEN_INET6;
|
813
|
KEY_LEN(xent->m.mask6) = KEY_LEN_INET6;
|
814
|
@@ -233,6 +274,52 @@ ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
815
|
mask_ptr = NULL;
|
816
|
break;
|
817
|
|
818
|
+#if 0
|
819
|
+ case IPFW_TABLE_MAC:
|
820
|
+ int i;
|
821
|
+
|
822
|
+ xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
|
823
|
+ xent->value = value;
|
824
|
+ /* Set 'total' structure length */
|
825
|
+ KEY_LEN(xent->a.mac) = KEY_LEN_MAC;
|
826
|
+ KEY_LEN(xent->m.macmask) = KEY_LEN_MAC;
|
827
|
+ /* Set offset of address in bits */
|
828
|
+ offset = OFF_LEN_MAC;
|
829
|
+ xent->a.mac = (struct ether_addr)(*paddr);
|
830
|
+ xent->m.mac = (struct ether_addr)(*(((struct ether_addr *)paddr) + 1));
|
831
|
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
|
832
|
+ xent->a.mac.octet[i] &= xent->m.mac.octet[i];
|
833
|
+ /* Set pointers */
|
834
|
+ rnh_ptr = &ch->xtables[tbl];
|
835
|
+ ent_ptr = xent;
|
836
|
+ addr_ptr = (struct sockaddr *)&xent->a.mac;
|
837
|
+ mask_ptr = (struct sockaddr *)&xent->m.macmask;
|
838
|
+ break;
|
839
|
+#endif
|
840
|
+
|
841
|
+ case IPFW_TABLE_MIX:
|
842
|
+ if ((plen - ETHER_ADDR_LEN) != sizeof(in_addr_t))
|
843
|
+ return (EINVAL);
|
844
|
+
|
845
|
+ xent = malloc(sizeof(*xent), M_IPFW_TBL, M_WAITOK | M_ZERO);
|
846
|
+ xent->value = value;
|
847
|
+ /* Set 'total' structure length */
|
848
|
+ KEY_LEN(xent->a.mix) = KEY_LEN_MIX;
|
849
|
+ KEY_LEN(xent->m.mixmask) = KEY_LEN_MIX;
|
850
|
+ /* Set offset of IPv4 address in bits */
|
851
|
+ offset = OFF_LEN_INET;
|
852
|
+ /* XXX: Needs to be fixed */
|
853
|
+ memcpy(&xent->a.mix.sin_addr, paddr, ETHER_ADDR_LEN + sizeof(struct in_addr));
|
854
|
+ /* Only full ips /32 and full masks supported for mac */
|
855
|
+ memset(&xent->m.mixmask.sin_addr, 0xFF, sizeof(struct in_addr));
|
856
|
+ memset(xent->m.mixmask.mac, 0xFF, ETHER_ADDR_LEN);
|
857
|
+ /* Set pointers */
|
858
|
+ rnh_ptr = &ch->xtables[tbl];
|
859
|
+ ent_ptr = xent;
|
860
|
+ addr_ptr = (struct sockaddr *)&xent->a.mix;
|
861
|
+ mask_ptr = NULL;
|
862
|
+ break;
|
863
|
+
|
864
|
default:
|
865
|
return (EINVAL);
|
866
|
}
|
867
|
@@ -281,6 +368,18 @@ ipfw_add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
868
|
IPFW_WUNLOCK(ch);
|
869
|
|
870
|
if (rn == NULL) {
|
871
|
+ if (type == IPFW_TABLE_CIDR) {
|
872
|
+ /* Just update if any new value needed */
|
873
|
+ struct table_entry *ent2;
|
874
|
+
|
875
|
+ ent2 = (struct table_entry *)(rnh->rnh_lookup(&ent->addr, NULL, rnh));
|
876
|
+ if (ent2 != NULL) {
|
877
|
+ if (ent2->mac_addr) {
|
878
|
+ if (!bcmp(&mac_addr, &ent2->mac_addr, ETHER_ADDR_LEN))
|
879
|
+ ent2->value = value;
|
880
|
+ } else
|
881
|
+ ent2->value = value;
|
882
|
+ }
|
883
|
free(ent_ptr, M_IPFW_TBL);
|
884
|
return (EEXIST);
|
885
|
}
|
886
|
@@ -367,6 +466,41 @@ ipfw_del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
887
|
|
888
|
break;
|
889
|
|
890
|
+#if 0
|
891
|
+ case IPFW_TABLE_MAC:
|
892
|
+ struct xaddr_mac mac, macmask;
|
893
|
+ memset(&mac, 0, sizeof(mac));
|
894
|
+ memset(&macmask, 0, sizeof(macmask));
|
895
|
+
|
896
|
+ /* Set 'total' structure length */
|
897
|
+ KEY_LEN(mac) = KEY_LEN_MAC;
|
898
|
+ mac.mac.mac = (struct ether_addr)(*paddr);
|
899
|
+ KEY_LEN(macmask) = KEY_LEN_MAC;
|
900
|
+ macmask.mac.macmask = (struct ether_addr)(*(((struct ether_addr *)paddr) + 1));
|
901
|
+ for (i = 0; i < ETHER_ADDR_LEN; i++)
|
902
|
+ mac.mac.octet[i] &= macmask.mac.octet[i];
|
903
|
+ rnh_ptr = &ch->xtables[tbl];
|
904
|
+ sa_ptr = (struct sockaddr *)&mac;
|
905
|
+ mask_ptr = (struct sockaddr *)&macmask;
|
906
|
+
|
907
|
+ break;
|
908
|
+#endif
|
909
|
+
|
910
|
+ case IPFW_TABLE_MIX:
|
911
|
+ if (mlen > (32 + ETHER_ADDR_LEN))
|
912
|
+ return (EINVAL);
|
913
|
+ struct xaddr_mix mix;
|
914
|
+ memset(&mix, 0, sizeof(mix));
|
915
|
+
|
916
|
+ /* Set 'total' structure length */
|
917
|
+ KEY_LEN(mix) = KEY_LEN_MIX;
|
918
|
+ memcpy(&mix.sin_addr, paddr, sizeof(struct in_addr) + ETHER_ADDR_LEN);
|
919
|
+ rnh_ptr = &ch->xtables[tbl];
|
920
|
+ sa_ptr = (struct sockaddr *)&mix;
|
921
|
+ mask_ptr = NULL;
|
922
|
+
|
923
|
+ break;
|
924
|
+
|
925
|
default:
|
926
|
return (EINVAL);
|
927
|
}
|
928
|
@@ -552,9 +686,152 @@ ipfw_lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr,
|
929
|
return (0);
|
930
|
}
|
931
|
|
932
|
+void
|
933
|
+ipfw_count_table_xentry_stats(void *arg, int pktlen)
|
934
|
+{
|
935
|
+ ipfw_table_xentry *xent= arg;
|
936
|
+
|
937
|
+ xent->packets++;
|
938
|
+ xent->bytes += pktlen;
|
939
|
+ xent->timestamp = time_uptime;
|
940
|
+}
|
941
|
+
|
942
|
+int
|
943
|
+ipfw_zero_table_xentry_stats(struct ip_fw_chain *ch, ipfw_table_xentry *arg)
|
944
|
+{
|
945
|
+ struct radix_node_head *rnh;
|
946
|
+ struct table_xentry *xent;
|
947
|
+ struct sockaddr_in6 sa6;
|
948
|
+ struct xaddr_iface iface;
|
949
|
+ struct xaddr_mix xm;
|
950
|
+
|
951
|
+ if (arg->tbl >= V_fw_tables_max)
|
952
|
+ return (0);
|
953
|
+ if ((rnh = ch->xtables[arg->tbl]) == NULL)
|
954
|
+ return (0);
|
955
|
+
|
956
|
+ switch (arg->type) {
|
957
|
+ case IPFW_TABLE_CIDR:
|
958
|
+ KEY_LEN(sa6) = KEY_LEN_INET6;
|
959
|
+ memcpy(&sa6.sin6_addr, &arg->k.addr6, sizeof(struct in6_addr));
|
960
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&sa6, NULL, rnh));
|
961
|
+ break;
|
962
|
+
|
963
|
+ case IPFW_TABLE_INTERFACE:
|
964
|
+ KEY_LEN(iface) = KEY_LEN_IFACE +
|
965
|
+ strlcpy(iface.ifname, arg->k.iface, IF_NAMESIZE) + 1;
|
966
|
+ /* Assume direct match */
|
967
|
+ /* FIXME: Add interface pattern matching */
|
968
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&iface, NULL, rnh));
|
969
|
+ break;
|
970
|
+
|
971
|
+#if 0
|
972
|
+ case IPFW_TABLE_MAC:
|
973
|
+ {
|
974
|
+ struct xaddr_mac mac;
|
975
|
+
|
976
|
+ KEY_LEN(mac) = KEY_LEN_MAC;
|
977
|
+ &mac.mac = arg->k.mac;
|
978
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&mac, NULL, rnh));
|
979
|
+ }
|
980
|
+ break;
|
981
|
+#endif
|
982
|
+
|
983
|
+ case IPFW_TABLE_MIX:
|
984
|
+ KEY_LEN(xm) = KEY_LEN_MIX;
|
985
|
+ memcpy(&xm.sin_addr, &arg->k.mix.addr, sizeof(struct in_addr));
|
986
|
+ memcpy(&xm.mac, arg->k.mix.mac, ETHER_ADDR_LEN);
|
987
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&xm, NULL, rnh));
|
988
|
+ break;
|
989
|
+
|
990
|
+ default:
|
991
|
+ return (0);
|
992
|
+ }
|
993
|
+
|
994
|
+ if (xent != NULL) {
|
995
|
+ xent->bytes = 0;
|
996
|
+ xent->packets = 0;
|
997
|
+ xent->timestamp = time_uptime;
|
998
|
+
|
999
|
+ return (1);
|
1000
|
+ }
|
1001
|
+ return (0);
|
1002
|
+}
|
1003
|
+
|
1004
|
int
|
1005
|
+ipfw_lookup_table_xentry(struct ip_fw_chain *ch, ipfw_table_xentry *arg)
|
1006
|
+{
|
1007
|
+ struct radix_node_head *rnh;
|
1008
|
+ struct table_xentry *xent;
|
1009
|
+
|
1010
|
+ if (arg->tbl >= V_fw_tables_max)
|
1011
|
+ return (0);
|
1012
|
+ if ((rnh = ch->xtables[arg->tbl]) == NULL)
|
1013
|
+ return (0);
|
1014
|
+
|
1015
|
+ switch (arg->type) {
|
1016
|
+ case IPFW_TABLE_CIDR:
|
1017
|
+ {
|
1018
|
+ struct sockaddr_in6 sa6;
|
1019
|
+ KEY_LEN(sa6) = KEY_LEN_INET6;
|
1020
|
+ memcpy(&sa6.sin6_addr, &arg->k.addr6, sizeof(struct in6_addr));
|
1021
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&sa6, NULL, rnh));
|
1022
|
+ }
|
1023
|
+ break;
|
1024
|
+
|
1025
|
+ case IPFW_TABLE_INTERFACE:
|
1026
|
+ {
|
1027
|
+ struct xaddr_iface iface;
|
1028
|
+
|
1029
|
+ KEY_LEN(iface) = KEY_LEN_IFACE +
|
1030
|
+ strlcpy(iface.ifname, arg->k.iface, IF_NAMESIZE) + 1;
|
1031
|
+ /* Assume direct match */
|
1032
|
+ /* FIXME: Add interface pattern matching */
|
1033
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&iface, NULL, rnh));
|
1034
|
+ }
|
1035
|
+ break;
|
1036
|
+
|
1037
|
+#if 0
|
1038
|
+ case IPFW_TABLE_MAC:
|
1039
|
+ {
|
1040
|
+ struct xaddr_mac mac;
|
1041
|
+
|
1042
|
+ KEY_LEN(mac) = KEY_LEN_MAC;
|
1043
|
+ mac.mac = arg->k.mac.addr;
|
1044
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&mac, NULL, rnh));
|
1045
|
+ }
|
1046
|
+ break;
|
1047
|
+#endif
|
1048
|
+
|
1049
|
+ case IPFW_TABLE_MIX:
|
1050
|
+ {
|
1051
|
+ struct xaddr_mix xm;
|
1052
|
+
|
1053
|
+ KEY_LEN(xm) = KEY_LEN_MIX;
|
1054
|
+ memcpy(&xm.sin_addr, &arg->k.mix.addr, sizeof(struct in_addr));
|
1055
|
+ memcpy(&xm.mac, arg->k.mix.mac, ETHER_ADDR_LEN);
|
1056
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&xm, NULL, rnh));
|
1057
|
+ }
|
1058
|
+ break;
|
1059
|
+
|
1060
|
+ default:
|
1061
|
+ return (0);
|
1062
|
+ }
|
1063
|
+
|
1064
|
+ if (xent != NULL) {
|
1065
|
+ arg->bytes = xent->bytes;
|
1066
|
+ arg->packets = xent->packets;
|
1067
|
+ arg->value = xent->value;
|
1068
|
+ arg->timestamp = xent->timestamp;
|
1069
|
+
|
1070
|
+ return (1);
|
1071
|
+ }
|
1072
|
+ return (0);
|
1073
|
+}
|
1074
|
+
|
1075
|
+void *
|
1076
|
ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
1077
|
- uint32_t *val, int type)
|
1078
|
+ uint32_t *val, int type, struct ether_addr *ea)
|
1079
|
{
|
1080
|
struct radix_node_head *rnh;
|
1081
|
struct table_xentry *xent;
|
1082
|
@@ -562,15 +839,21 @@ ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
1083
|
struct xaddr_iface iface;
|
1084
|
|
1085
|
if (tbl >= V_fw_tables_max)
|
1086
|
- return (0);
|
1087
|
+ return (NULL);
|
1088
|
if ((rnh = ch->xtables[tbl]) == NULL)
|
1089
|
- return (0);
|
1090
|
+ return (NULL);
|
1091
|
|
1092
|
switch (type) {
|
1093
|
case IPFW_TABLE_CIDR:
|
1094
|
KEY_LEN(sa6) = KEY_LEN_INET6;
|
1095
|
memcpy(&sa6.sin6_addr, paddr, sizeof(struct in6_addr));
|
1096
|
xent = (struct table_xentry *)(rnh->rnh_lookup(&sa6, NULL, rnh));
|
1097
|
+ if (xent != NULL) {
|
1098
|
+ if (ea && xent->mac_addr) {
|
1099
|
+ if (bcmp((u_char *)&xent->mac_addr, ea->octet, ETHER_ADDR_LEN) != 0)
|
1100
|
+ xent = NULL;
|
1101
|
+ }
|
1102
|
+ }
|
1103
|
break;
|
1104
|
|
1105
|
case IPFW_TABLE_INTERFACE:
|
1106
|
@@ -581,15 +864,37 @@ ipfw_lookup_table_extended(struct ip_fw_chain *ch, uint16_t tbl, void *paddr,
|
1107
|
xent = (struct table_xentry *)(rnh->rnh_lookup(&iface, NULL, rnh));
|
1108
|
break;
|
1109
|
|
1110
|
+#if 0
|
1111
|
+ case IPFW_TABLE_MAC:
|
1112
|
+ {
|
1113
|
+ struct xaddr_mac mac;
|
1114
|
+
|
1115
|
+ KEY_LEN(mac) = KEY_LEN_MAC;
|
1116
|
+ mac.mac = (struct ether_addr)(*paddr);
|
1117
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&mac, NULL, rnh));
|
1118
|
+ }
|
1119
|
+ break;
|
1120
|
+#endif
|
1121
|
+
|
1122
|
+ case IPFW_TABLE_MIX:
|
1123
|
+ {
|
1124
|
+ struct xaddr_mix xm;
|
1125
|
+
|
1126
|
+ KEY_LEN(xm) = KEY_LEN_MIX;
|
1127
|
+ memcpy(((char *)&xm.sin_addr), paddr, sizeof(struct in_addr) + ETHER_ADDR_LEN);
|
1128
|
+ xent = (struct table_xentry *)(rnh->rnh_lookup(&xm, NULL, rnh));
|
1129
|
+ }
|
1130
|
+ break;
|
1131
|
+
|
1132
|
default:
|
1133
|
- return (0);
|
1134
|
+ return (NULL);
|
1135
|
}
|
1136
|
|
1137
|
if (xent != NULL) {
|
1138
|
*val = xent->value;
|
1139
|
- return (1);
|
1140
|
+ return (xent);
|
1141
|
}
|
1142
|
- return (0);
|
1143
|
+ return (NULL);
|
1144
|
}
|
1145
|
|
1146
|
static int
|
1147
|
@@ -698,6 +1003,9 @@ dump_table_xentry_base(struct radix_node *rn, void *arg)
|
1148
|
/* Save IPv4 address as deprecated IPv6 compatible */
|
1149
|
xent->k.addr6.s6_addr32[3] = n->addr.sin_addr.s_addr;
|
1150
|
xent->value = n->value;
|
1151
|
+ xent->bytes = n->bytes;
|
1152
|
+ xent->packets = n->packets;
|
1153
|
+ xent->timestamp = n->timestamp;
|
1154
|
tbl->cnt++;
|
1155
|
return (0);
|
1156
|
}
|
1157
|
@@ -735,12 +1043,31 @@ dump_table_xentry_extended(struct radix_node *rn, void *arg)
|
1158
|
memcpy(&xent->k, &n->a.iface.ifname, IF_NAMESIZE);
|
1159
|
break;
|
1160
|
|
1161
|
+#if 0
|
1162
|
+ case IPFW_TABLE_MAC:
|
1163
|
+ /* Assume exact mask */
|
1164
|
+ xent->masklen = 8 * ETHER_ADDR_LEN;
|
1165
|
+ xent->k.mac.addr = n->a.mac.mac;
|
1166
|
+ xent->k.mac.mask = n->m.mac.mac;
|
1167
|
+ break;
|
1168
|
+#endif
|
1169
|
+
|
1170
|
+ case IPFW_TABLE_MIX:
|
1171
|
+ /* Assume exact mask */
|
1172
|
+ xent->masklen = 8 * (ETHER_ADDR_LEN + sizeof(struct in_addr));
|
1173
|
+ memcpy(&xent->k.mix.addr, &n->a.mix.sin_addr, sizeof(struct in_addr));
|
1174
|
+ memcpy(xent->k.mix.mac, &n->a.mix.mac, ETHER_ADDR_LEN);
|
1175
|
+ break;
|
1176
|
+
|
1177
|
default:
|
1178
|
/* unknown, skip entry */
|
1179
|
return (0);
|
1180
|
}
|
1181
|
|
1182
|
xent->value = n->value;
|
1183
|
+ xent->bytes = n->bytes;
|
1184
|
+ xent->packets = n->packets;
|
1185
|
+ xent->timestamp = n->timestamp;
|
1186
|
tbl->cnt++;
|
1187
|
return (0);
|
1188
|
}
|