1
|
diff --git a/sbin/ipfw/Makefile b/sbin/ipfw/Makefile
|
2
|
index 6aea26b..e137e08 100644
|
3
|
--- a/sbin/ipfw/Makefile
|
4
|
+++ b/sbin/ipfw/Makefile
|
5
|
@@ -3,7 +3,7 @@
|
6
|
.include <bsd.own.mk>
|
7
|
|
8
|
PROG= ipfw
|
9
|
-SRCS= ipfw2.c dummynet.c ipv6.c main.c nat.c
|
10
|
+SRCS= ipfw2.c dummynet.c ipv6.c main.c nat.c context.c
|
11
|
WARNS?= 2
|
12
|
|
13
|
.if ${MK_PF} != "no"
|
14
|
diff --git a/sbin/ipfw/context.c b/sbin/ipfw/context.c
|
15
|
new file mode 100644
|
16
|
index 0000000..f121b2e
|
17
|
--- /dev/null
|
18
|
+++ b/sbin/ipfw/context.c
|
19
|
@@ -0,0 +1,148 @@
|
20
|
+/*
|
21
|
+ * Copyright (c) 2013 Ermal Lu?i
|
22
|
+ *
|
23
|
+ * Redistribution and use in source forms, with and without modification,
|
24
|
+ * are permitted provided that this entire comment appears intact.
|
25
|
+ *
|
26
|
+ * Redistribution in binary form may occur without any restrictions.
|
27
|
+ * Obviously, it would be nice if you gave credit where credit is due
|
28
|
+ * but requiring it would be too onerous.
|
29
|
+ *
|
30
|
+ * This software is provided ``AS IS'' without any warranties of any kind.
|
31
|
+ *
|
32
|
+ * $FreeBSD$
|
33
|
+ */
|
34
|
+
|
35
|
+#include <sys/types.h>
|
36
|
+#include <sys/socket.h>
|
37
|
+
|
38
|
+#include <net/if.h>
|
39
|
+#include <net/if_var.h>
|
40
|
+
|
41
|
+#include <netinet/in.h>
|
42
|
+#include <netinet/ip_fw.h>
|
43
|
+
|
44
|
+#include "ipfw2.h"
|
45
|
+
|
46
|
+#include <stdio.h>
|
47
|
+#include <stdlib.h>
|
48
|
+#include <unistd.h>
|
49
|
+#include <sysexits.h>
|
50
|
+#include <string.h>
|
51
|
+#include <errno.h>
|
52
|
+#include <err.h>
|
53
|
+
|
54
|
+extern int ipfw_socket;
|
55
|
+
|
56
|
+int
|
57
|
+ipfw_context_handler(int ac, char **av)
|
58
|
+{
|
59
|
+ ip_fw3_opheader *op3;
|
60
|
+ int error = 0;
|
61
|
+ uint32_t action = 0;
|
62
|
+ socklen_t len, nlen;
|
63
|
+ char *ifname;
|
64
|
+
|
65
|
+ av++;
|
66
|
+ ac--;
|
67
|
+ NEED1("bad arguments, for usage summary ``ipfw''");
|
68
|
+
|
69
|
+ if (!strncmp(*av, "list", strlen(*av))) {
|
70
|
+ action = IP_FW_CTX_GET;
|
71
|
+ av++;
|
72
|
+ ac--;
|
73
|
+ if (ac > 0)
|
74
|
+ errx(EX_DATAERR, "list: does not take any extra arguments.");
|
75
|
+
|
76
|
+ } else {
|
77
|
+ co.ctx = atoi(*av);
|
78
|
+
|
79
|
+ av++;
|
80
|
+ ac--;
|
81
|
+ NEED1("bad arguments, for usage summary ``ipfw''");
|
82
|
+
|
83
|
+ if (!strncmp(*av, "create", strlen(*av)))
|
84
|
+ action = IP_FW_CTX_ADD;
|
85
|
+ else if (!strncmp(*av, "destroy", strlen(*av)))
|
86
|
+ action = IP_FW_CTX_DEL;
|
87
|
+ else {
|
88
|
+ if (!strncmp(*av, "madd", strlen(*av)))
|
89
|
+ action = IP_FW_CTX_ADDMEMBER;
|
90
|
+ else if (!strncmp(*av, "mdel", strlen(*av)))
|
91
|
+ action = IP_FW_CTX_DELMEMBER;
|
92
|
+ else
|
93
|
+ errx(EX_DATAERR, "Wrong parameters passed");
|
94
|
+
|
95
|
+ av++;
|
96
|
+ ac--;
|
97
|
+ NEED1("bad arguments, for usage summary ``ipfw''");
|
98
|
+
|
99
|
+ ifname = *av;
|
100
|
+ }
|
101
|
+
|
102
|
+ ac--;
|
103
|
+ if (ac > 0)
|
104
|
+ errx(EX_DATAERR, "context handling: Too many arguments passed");
|
105
|
+
|
106
|
+ }
|
107
|
+
|
108
|
+ if (co.test_only)
|
109
|
+ return (0);
|
110
|
+
|
111
|
+ if (ipfw_socket < 0)
|
112
|
+ ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
|
113
|
+ if (ipfw_socket < 0)
|
114
|
+ err(EX_UNAVAILABLE, "socket");
|
115
|
+
|
116
|
+ switch (action) {
|
117
|
+ case IP_FW_CTX_ADD:
|
118
|
+ case IP_FW_CTX_DEL:
|
119
|
+ case IP_FW_CTX_SET:
|
120
|
+ len = sizeof(ip_fw3_opheader);
|
121
|
+ op3 = alloca(len);
|
122
|
+ /* Zero reserved fields */
|
123
|
+ memset(op3, 0, sizeof(ip_fw3_opheader));
|
124
|
+ op3->opcode = action;
|
125
|
+ op3->ctxid = co.ctx;
|
126
|
+ error = setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len);
|
127
|
+ break;
|
128
|
+ case IP_FW_CTX_ADDMEMBER:
|
129
|
+ case IP_FW_CTX_DELMEMBER:
|
130
|
+ len = sizeof(ip_fw3_opheader) + strlen(ifname) + 1;
|
131
|
+ op3 = alloca(len);
|
132
|
+ /* Zero reserved fields */
|
133
|
+ memset(op3, 0, sizeof(ip_fw3_opheader));
|
134
|
+ memcpy((op3 + 1), ifname, strlen(ifname));
|
135
|
+ op3->opcode = action;
|
136
|
+ op3->ctxid = co.ctx;
|
137
|
+ error = setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len);
|
138
|
+ break;
|
139
|
+ case IP_FW_CTX_GET:
|
140
|
+ len = sizeof(ip_fw3_opheader) + 1000;
|
141
|
+ nlen = len;
|
142
|
+ do {
|
143
|
+ if (nlen > len) {
|
144
|
+ len = nlen;
|
145
|
+ }
|
146
|
+ op3 = alloca(len);
|
147
|
+ /* Zero reserved fields */
|
148
|
+ memset(op3, 0, sizeof(ip_fw3_opheader));
|
149
|
+ op3->opcode = action;
|
150
|
+ op3->ctxid = co.ctx;
|
151
|
+ nlen = len;
|
152
|
+ error = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, &nlen);
|
153
|
+ } while (nlen > len && !error);
|
154
|
+
|
155
|
+ if (!error) {
|
156
|
+ if (nlen == 0)
|
157
|
+ printf("There are no contextes defined\n");
|
158
|
+ else
|
159
|
+ printf("Currently defined contextes and their members:\n%s\n", (char *)op3);
|
160
|
+ } else
|
161
|
+ err(EX_UNAVAILABLE, "Error returned: %s\n", strerror(error));
|
162
|
+
|
163
|
+ break;
|
164
|
+ }
|
165
|
+
|
166
|
+ return (error);
|
167
|
+}
|
168
|
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
|
169
|
index 476f5da..8364011 100644
|
170
|
--- a/sbin/ipfw/ipfw2.c
|
171
|
+++ b/sbin/ipfw/ipfw2.c
|
172
|
@@ -54,7 +54,7 @@
|
173
|
#include <netinet/tcp.h>
|
174
|
#include <arpa/inet.h>
|
175
|
|
176
|
-struct cmdline_opts co; /* global options */
|
177
|
+struct cmdline_opts co = { 0 }; /* global options */
|
178
|
|
179
|
int resvd_set_number = RESVD_SET;
|
180
|
|
181
|
@@ -420,6 +420,7 @@ safe_realloc(void *ptr, size_t size)
|
182
|
int
|
183
|
do_cmd(int optname, void *optval, uintptr_t optlen)
|
184
|
{
|
185
|
+ ip_fw3_opheader op3;
|
186
|
int i;
|
187
|
|
188
|
if (co.test_only)
|
189
|
@@ -430,6 +431,15 @@ do_cmd(int optname, void *optval, uintptr_t optlen)
|
190
|
if (ipfw_socket < 0)
|
191
|
err(EX_UNAVAILABLE, "socket");
|
192
|
|
193
|
+ if (optname != IP_FW3 && optname != IP_DUMMYNET3 && optname != -IP_DUMMYNET3) {
|
194
|
+ memset(&op3, 0, sizeof op3);
|
195
|
+ op3.ctxid = co.ctx;
|
196
|
+ op3.opcode = IP_FW_CTX_SET;
|
197
|
+ i = setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, &op3, sizeof(op3));
|
198
|
+ if (i)
|
199
|
+ errx(EX_OSERR, "setsockopt: choosing context");
|
200
|
+ }
|
201
|
+
|
202
|
if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET ||
|
203
|
optname == IP_FW_ADD || optname == IP_FW3 ||
|
204
|
optname == IP_FW_NAT_GET_CONFIG ||
|
205
|
@@ -475,6 +485,7 @@ do_setcmd3(int optname, void *optval, socklen_t optlen)
|
206
|
memset(op3, 0, sizeof(ip_fw3_opheader));
|
207
|
memcpy(op3 + 1, optval, optlen);
|
208
|
op3->opcode = optname;
|
209
|
+ op3->ctxid = co.ctx;
|
210
|
|
211
|
return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len);
|
212
|
}
|
213
|
@@ -4435,6 +4446,7 @@ table_list(uint16_t num, int need_header)
|
214
|
a = (uint32_t *)(op3 + 1);
|
215
|
*a = num;
|
216
|
op3->opcode = IP_FW_TABLE_XGETSIZE;
|
217
|
+ op3->ctxid = co.ctx;
|
218
|
if (do_cmd(IP_FW3, op3, (uintptr_t)&l) < 0)
|
219
|
err(EX_OSERR, "getsockopt(IP_FW_TABLE_XGETSIZE)");
|
220
|
|
221
|
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
|
222
|
index 9abe6ee..013b0ec 100644
|
223
|
--- a/sbin/ipfw/ipfw2.h
|
224
|
+++ b/sbin/ipfw/ipfw2.h
|
225
|
@@ -54,6 +54,7 @@ struct cmdline_opts {
|
226
|
int use_set; /* work with specified set number */
|
227
|
/* 0 means all sets, otherwise apply to set use_set - 1 */
|
228
|
|
229
|
+ u_int ctx;
|
230
|
};
|
231
|
|
232
|
extern struct cmdline_opts co;
|
233
|
@@ -280,6 +281,9 @@ void dummynet_list(int ac, char *av[], int show_counters);
|
234
|
void dummynet_flush(void);
|
235
|
int ipfw_delete_pipe(int pipe_or_queue, int n);
|
236
|
|
237
|
+/* Contextes */
|
238
|
+int ipfw_context_handler(int, char **);
|
239
|
+
|
240
|
/* ipv6.c */
|
241
|
void print_unreach6_code(uint16_t code);
|
242
|
void print_ip6(struct _ipfw_insn_ip6 *cmd, char const *s);
|
243
|
diff --git a/sbin/ipfw/main.c b/sbin/ipfw/main.c
|
244
|
index 82a299b..ab75a1b 100644
|
245
|
--- a/sbin/ipfw/main.c
|
246
|
+++ b/sbin/ipfw/main.c
|
247
|
@@ -262,7 +262,7 @@ ipfw_main(int oldac, char **oldav)
|
248
|
save_av = av;
|
249
|
|
250
|
optind = optreset = 1; /* restart getopt() */
|
251
|
- while ((ch = getopt(ac, av, "abcdefhinNp:qs:STtv")) != -1)
|
252
|
+ while ((ch = getopt(ac, av, "abcdefhinNp:qs:STtvx:")) != -1)
|
253
|
switch (ch) {
|
254
|
case 'a':
|
255
|
do_acct = 1;
|
256
|
@@ -335,6 +335,12 @@ ipfw_main(int oldac, char **oldav)
|
257
|
co.verbose = 1;
|
258
|
break;
|
259
|
|
260
|
+ case 'x':
|
261
|
+ co.ctx = atoi(optarg);
|
262
|
+ if (co.ctx == 0)
|
263
|
+ errx(EX_USAGE, "Context 0 is invalid");
|
264
|
+ break;
|
265
|
+
|
266
|
default:
|
267
|
free(save_av);
|
268
|
return 1;
|
269
|
@@ -362,7 +368,9 @@ ipfw_main(int oldac, char **oldav)
|
270
|
co.do_nat = 0;
|
271
|
co.do_pipe = 0;
|
272
|
co.use_set = 0;
|
273
|
- if (!strncmp(*av, "nat", strlen(*av)))
|
274
|
+ if (!strncmp(*av, "zone", strlen(*av)))
|
275
|
+ return (ipfw_context_handler(ac, av));
|
276
|
+ else if (!strncmp(*av, "nat", strlen(*av)))
|
277
|
co.do_nat = 1;
|
278
|
else if (!strncmp(*av, "pipe", strlen(*av)))
|
279
|
co.do_pipe = 1;
|
280
|
@@ -389,6 +397,9 @@ ipfw_main(int oldac, char **oldav)
|
281
|
}
|
282
|
NEED1("missing command");
|
283
|
|
284
|
+ if (!co.ctx && !co.do_pipe)
|
285
|
+ err(11, "Context is mandatory");
|
286
|
+
|
287
|
/*
|
288
|
* For pipes, queues and nats we normally say 'nat|pipe NN config'
|
289
|
* but the code is easier to parse as 'nat|pipe config NN'
|
290
|
@@ -458,7 +469,7 @@ ipfw_readfile(int ac, char *av[])
|
291
|
FILE *f = NULL;
|
292
|
pid_t preproc = 0;
|
293
|
|
294
|
- while ((c = getopt(ac, av, "cfNnp:qS")) != -1) {
|
295
|
+ while ((c = getopt(ac, av, "cfNnp:qSx:")) != -1) {
|
296
|
switch(c) {
|
297
|
case 'c':
|
298
|
co.do_compact = 1;
|
299
|
@@ -509,6 +520,12 @@ ipfw_readfile(int ac, char *av[])
|
300
|
co.show_sets = 1;
|
301
|
break;
|
302
|
|
303
|
+ case 'x':
|
304
|
+ co.ctx = atoi(optarg);
|
305
|
+ if (co.ctx == 0)
|
306
|
+ errx(EX_USAGE, "Context 0 is invalid");
|
307
|
+ break;
|
308
|
+
|
309
|
default:
|
310
|
errx(EX_USAGE, "bad arguments, for usage"
|
311
|
" summary ``ipfw''");
|
312
|
diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h
|
313
|
index 7b64bf5..40b397d 100644
|
314
|
--- a/sys/netinet/ip_fw.h
|
315
|
+++ b/sys/netinet/ip_fw.h
|
316
|
@@ -65,7 +65,8 @@
|
317
|
/* IP_FW3 header/opcodes */
|
318
|
typedef struct _ip_fw3_opheader {
|
319
|
uint16_t opcode; /* Operation opcode */
|
320
|
- uint16_t reserved[3]; /* Align to 64-bit boundary */
|
321
|
+ uint16_t ctxid;
|
322
|
+ uint16_t reserved[2]; /* Align to 64-bit boundary */
|
323
|
} ip_fw3_opheader;
|
324
|
|
325
|
|
326
|
@@ -76,6 +77,12 @@ typedef struct _ip_fw3_opheader {
|
327
|
#define IP_FW_TABLE_XLIST 89 /* list table contents */
|
328
|
#define IP_FW_TABLE_XLISTENTRY 90 /* list one table entry contents */
|
329
|
#define IP_FW_TABLE_XZEROENTRY 91 /* zero one table entry stats */
|
330
|
+#define IP_FW_CTX_GET 92
|
331
|
+#define IP_FW_CTX_ADD 93
|
332
|
+#define IP_FW_CTX_DEL 94
|
333
|
+#define IP_FW_CTX_SET 95
|
334
|
+#define IP_FW_CTX_ADDMEMBER 96
|
335
|
+#define IP_FW_CTX_DELMEMBER 97
|
336
|
|
337
|
/*
|
338
|
* The kernel representation of ipfw rules is made of a list of
|
339
|
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
|
340
|
index aa5a94d..1913a26 100644
|
341
|
--- a/sys/netpfil/ipfw/ip_fw2.c
|
342
|
+++ b/sys/netpfil/ipfw/ip_fw2.c
|
343
|
@@ -140,8 +140,7 @@ VNET_DEFINE(int, fw_verbose);
|
344
|
VNET_DEFINE(u_int64_t, norule_counter);
|
345
|
VNET_DEFINE(int, verbose_limit);
|
346
|
|
347
|
-/* layer3_chain contains the list of rules for layer 3 */
|
348
|
-VNET_DEFINE(struct ip_fw_chain, layer3_chain);
|
349
|
+VNET_DEFINE(struct ip_fw_contextes, ip_fw_contexts);
|
350
|
|
351
|
VNET_DEFINE(int, ipfw_nat_ready) = 0;
|
352
|
|
353
|
@@ -182,9 +181,6 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, default_to_accept, CTLFLAG_RDTUN,
|
354
|
"Make the default rule accept all packets.");
|
355
|
TUNABLE_INT("net.inet.ip.fw.default_to_accept", &default_to_accept);
|
356
|
TUNABLE_INT("net.inet.ip.fw.tables_max", (int *)&default_fw_tables);
|
357
|
-SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, static_count,
|
358
|
- CTLFLAG_RD, &VNET_NAME(layer3_chain.n_rules), 0,
|
359
|
- "Number of static rules");
|
360
|
|
361
|
#ifdef INET6
|
362
|
SYSCTL_DECL(_net_inet6_ip6);
|
363
|
@@ -904,6 +900,9 @@ ipfw_chk(struct ip_fw_args *args)
|
364
|
*/
|
365
|
struct ifnet *oif = args->oif;
|
366
|
|
367
|
+ if (V_ip_fw_contexts.chain[oif->if_ispare[0]] == NULL)
|
368
|
+ return (IP_FW_PASS);
|
369
|
+
|
370
|
int f_pos = 0; /* index of current rule in the array */
|
371
|
int retval = 0;
|
372
|
|
373
|
@@ -954,9 +953,15 @@ ipfw_chk(struct ip_fw_args *args)
|
374
|
*/
|
375
|
int dyn_dir = MATCH_UNKNOWN;
|
376
|
ipfw_dyn_rule *q = NULL;
|
377
|
- struct ip_fw_chain *chain = &V_layer3_chain;
|
378
|
void *tblent = NULL;
|
379
|
|
380
|
+ /* XXX: WARNING - The chain is accessed unlocked here.
|
381
|
+ * There is a potential race here with context handling.
|
382
|
+ * The chain pointer will get destroyed and a NULL
|
383
|
+ * pointer dereference can happen!
|
384
|
+ */
|
385
|
+ struct ip_fw_chain *chain = V_ip_fw_contexts.chain[oif->if_ispare[0]];
|
386
|
+
|
387
|
/*
|
388
|
* We store in ulp a pointer to the upper layer protocol header.
|
389
|
* In the ipv4 case this is easy to determine from the header,
|
390
|
@@ -2501,7 +2506,7 @@ do { \
|
391
|
set_match(args, f_pos, chain);
|
392
|
/* Check if this is 'global' nat rule */
|
393
|
if (cmd->arg1 == 0) {
|
394
|
- retval = ipfw_nat_ptr(args, NULL, m);
|
395
|
+ retval = ipfw_nat_ptr(args, NULL, m, chain);
|
396
|
l = 0;
|
397
|
done = 1;
|
398
|
break;
|
399
|
@@ -2520,7 +2525,7 @@ do { \
|
400
|
if (cmd->arg1 != IP_FW_TABLEARG)
|
401
|
((ipfw_insn_nat *)cmd)->nat = t;
|
402
|
}
|
403
|
- retval = ipfw_nat_ptr(args, t, m);
|
404
|
+ retval = ipfw_nat_ptr(args, t, m, chain);
|
405
|
}
|
406
|
l = 0; /* exit inner loop */
|
407
|
done = 1; /* exit outer loop */
|
408
|
@@ -2629,7 +2634,9 @@ sysctl_ipfw_table_num(SYSCTL_HANDLER_ARGS)
|
409
|
if ((error != 0) || (req->newptr == NULL))
|
410
|
return (error);
|
411
|
|
412
|
- return (ipfw_resize_tables(&V_layer3_chain, ntables));
|
413
|
+ for (int i = 1; i < IP_FW_MAXCTX; i++)
|
414
|
+ error += ipfw_resize_tables(V_ip_fw_contexts.chain[i], ntables);
|
415
|
+ return (error);
|
416
|
}
|
417
|
#endif
|
418
|
/*
|
419
|
@@ -2707,11 +2714,6 @@ ipfw_destroy(void)
|
420
|
static int
|
421
|
vnet_ipfw_init(const void *unused)
|
422
|
{
|
423
|
- int error;
|
424
|
- struct ip_fw *rule = NULL;
|
425
|
- struct ip_fw_chain *chain;
|
426
|
-
|
427
|
- chain = &V_layer3_chain;
|
428
|
|
429
|
/* First set up some values that are compile time options */
|
430
|
V_autoinc_step = 100; /* bounded to 1..1000 in add_rule() */
|
431
|
@@ -2722,10 +2724,55 @@ vnet_ipfw_init(const void *unused)
|
432
|
#ifdef IPFIREWALL_VERBOSE_LIMIT
|
433
|
V_verbose_limit = IPFIREWALL_VERBOSE_LIMIT;
|
434
|
#endif
|
435
|
+
|
436
|
+ for (int i = 0; i < IP_FW_MAXCTX; i++)
|
437
|
+ V_ip_fw_contexts.chain[i] = NULL;
|
438
|
+
|
439
|
+ IPFW_CTX_LOCK_INIT();
|
440
|
+
|
441
|
+ V_ip_fw_contexts.ifnet_arrival = EVENTHANDLER_REGISTER(ifnet_arrival_event,
|
442
|
+ ipfw_attach_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
|
443
|
+
|
444
|
+ ipfw_dyn_init();
|
445
|
+
|
446
|
+ /* First set up some values that are compile time options */
|
447
|
+ V_ipfw_vnet_ready = 1; /* Open for business */
|
448
|
+
|
449
|
+ /*
|
450
|
+ * Hook the sockopt handler and pfil hooks for ipv4 and ipv6.
|
451
|
+ * Even if the latter two fail we still keep the module alive
|
452
|
+ * because the sockopt and layer2 paths are still useful.
|
453
|
+ * ipfw[6]_hook return 0 on success, ENOENT on failure,
|
454
|
+ * so we can ignore the exact return value and just set a flag.
|
455
|
+ *
|
456
|
+ * Note that V_fw[6]_enable are manipulated by a SYSCTL_PROC so
|
457
|
+ * changes in the underlying (per-vnet) variables trigger
|
458
|
+ * immediate hook()/unhook() calls.
|
459
|
+ * In layer2 we have the same behaviour, except that V_ether_ipfw
|
460
|
+ * is checked on each packet because there are no pfil hooks.
|
461
|
+ */
|
462
|
+ V_ip_fw_ctl_ptr = ipfw_ctl;
|
463
|
+ return ipfw_attach_hooks(1);
|
464
|
+}
|
465
|
+
|
466
|
+int
|
467
|
+ipfw_context_init(int index)
|
468
|
+{
|
469
|
+ struct ip_fw_chain *chain;
|
470
|
+ struct ip_fw *rule = NULL;
|
471
|
+
|
472
|
+ if (index > IP_FW_MAXCTX)
|
473
|
+ return (-1);
|
474
|
+
|
475
|
+ TAILQ_INIT(&V_ip_fw_contexts.iflist[index]);
|
476
|
+
|
477
|
+ chain = V_ip_fw_contexts.chain[index];
|
478
|
+
|
479
|
+ IPFW_LOCK_INIT(chain);
|
480
|
+
|
481
|
#ifdef IPFIREWALL_NAT
|
482
|
LIST_INIT(&chain->nat);
|
483
|
#endif
|
484
|
-
|
485
|
/* insert the default rule and create the initial map */
|
486
|
chain->n_rules = 1;
|
487
|
chain->static_len = sizeof(struct ip_fw);
|
488
|
@@ -2735,13 +2782,7 @@ vnet_ipfw_init(const void *unused)
|
489
|
|
490
|
/* Set initial number of tables */
|
491
|
V_fw_tables_max = default_fw_tables;
|
492
|
- error = ipfw_init_tables(chain);
|
493
|
- if (error) {
|
494
|
- printf("ipfw2: setting up tables failed\n");
|
495
|
- free(chain->map, M_IPFW);
|
496
|
- free(rule, M_IPFW);
|
497
|
- return (ENOSPC);
|
498
|
- }
|
499
|
+ ipfw_init_tables(chain);
|
500
|
|
501
|
/* fill and insert the default rule */
|
502
|
rule->act_ofs = 0;
|
503
|
@@ -2753,28 +2794,13 @@ vnet_ipfw_init(const void *unused)
|
504
|
chain->rules = chain->default_rule = chain->map[0] = rule;
|
505
|
chain->id = rule->id = 1;
|
506
|
|
507
|
- IPFW_LOCK_INIT(chain);
|
508
|
- ipfw_dyn_init(chain);
|
509
|
-
|
510
|
- /* First set up some values that are compile time options */
|
511
|
- V_ipfw_vnet_ready = 1; /* Open for business */
|
512
|
+ /*
|
513
|
+ * This can potentially be done on first dynamic rule
|
514
|
+ * being added to chain.
|
515
|
+ */
|
516
|
+ resize_dynamic_table(chain, V_curr_dyn_buckets);
|
517
|
|
518
|
- /*
|
519
|
- * Hook the sockopt handler and pfil hooks for ipv4 and ipv6.
|
520
|
- * Even if the latter two fail we still keep the module alive
|
521
|
- * because the sockopt and layer2 paths are still useful.
|
522
|
- * ipfw[6]_hook return 0 on success, ENOENT on failure,
|
523
|
- * so we can ignore the exact return value and just set a flag.
|
524
|
- *
|
525
|
- * Note that V_fw[6]_enable are manipulated by a SYSCTL_PROC so
|
526
|
- * changes in the underlying (per-vnet) variables trigger
|
527
|
- * immediate hook()/unhook() calls.
|
528
|
- * In layer2 we have the same behaviour, except that V_ether_ipfw
|
529
|
- * is checked on each packet because there are no pfil hooks.
|
530
|
- */
|
531
|
- V_ip_fw_ctl_ptr = ipfw_ctl;
|
532
|
- error = ipfw_attach_hooks(1);
|
533
|
- return (error);
|
534
|
+ return (0);
|
535
|
}
|
536
|
|
537
|
/*
|
538
|
@@ -2783,11 +2809,9 @@ vnet_ipfw_init(const void *unused)
|
539
|
static int
|
540
|
vnet_ipfw_uninit(const void *unused)
|
541
|
{
|
542
|
- struct ip_fw *reap, *rule;
|
543
|
- struct ip_fw_chain *chain = &V_layer3_chain;
|
544
|
- int i;
|
545
|
|
546
|
V_ipfw_vnet_ready = 0; /* tell new callers to go away */
|
547
|
+
|
548
|
/*
|
549
|
* disconnect from ipv4, ipv6, layer2 and sockopt.
|
550
|
* Then grab, release and grab again the WLOCK so we make
|
551
|
@@ -2795,14 +2819,51 @@ vnet_ipfw_uninit(const void *unused)
|
552
|
*/
|
553
|
(void)ipfw_attach_hooks(0 /* detach */);
|
554
|
V_ip_fw_ctl_ptr = NULL;
|
555
|
+
|
556
|
+ ipfw_dyn_uninit(0); /* run the callout_drain */
|
557
|
+
|
558
|
+ IPFW_CTX_WLOCK();
|
559
|
+ EVENTHANDLER_DEREGISTER(ifnet_arrival_event, V_ip_fw_contexts.ifnet_arrival);
|
560
|
+ for (int i = 0; i < IP_FW_MAXCTX; i++) {
|
561
|
+ ipfw_context_uninit(i);
|
562
|
+ }
|
563
|
+ IPFW_CTX_WUNLOCK();
|
564
|
+ IPFW_CTX_LOCK_DESTROY();
|
565
|
+
|
566
|
+ ipfw_dyn_uninit(1); /* free the remaining parts */
|
567
|
+
|
568
|
+ return (0);
|
569
|
+}
|
570
|
+
|
571
|
+int
|
572
|
+ipfw_context_uninit(int index)
|
573
|
+{
|
574
|
+ struct ip_fw_chain *chain;
|
575
|
+ struct ip_fw_ctx_iflist *ifl;
|
576
|
+ struct ip_fw *reap, *rule;
|
577
|
+ struct ifnet *ifp;
|
578
|
+ int i;
|
579
|
+
|
580
|
+ if (index > IP_FW_MAXCTX)
|
581
|
+ return (-1);
|
582
|
+
|
583
|
+ chain = V_ip_fw_contexts.chain[index];
|
584
|
+ if (chain == NULL)
|
585
|
+ return (0);
|
586
|
+
|
587
|
+ while (!TAILQ_EMPTY(&V_ip_fw_contexts.iflist[index])) {
|
588
|
+ ifl = TAILQ_FIRST(&V_ip_fw_contexts.iflist[index]);
|
589
|
+ TAILQ_REMOVE(&V_ip_fw_contexts.iflist[index], ifl, entry);
|
590
|
+ ifp = ifunit(ifl->ifname);
|
591
|
+ if (ifp != NULL)
|
592
|
+ ifp->if_ispare[0] = 0;
|
593
|
+ free(ifl, M_IPFW);
|
594
|
+ }
|
595
|
+
|
596
|
IPFW_UH_WLOCK(chain);
|
597
|
IPFW_UH_WUNLOCK(chain);
|
598
|
IPFW_UH_WLOCK(chain);
|
599
|
|
600
|
- IPFW_WLOCK(chain);
|
601
|
- ipfw_dyn_uninit(0); /* run the callout_drain */
|
602
|
- IPFW_WUNLOCK(chain);
|
603
|
-
|
604
|
ipfw_destroy_tables(chain);
|
605
|
reap = NULL;
|
606
|
IPFW_WLOCK(chain);
|
607
|
@@ -2818,8 +2879,10 @@ vnet_ipfw_uninit(const void *unused)
|
608
|
if (reap != NULL)
|
609
|
ipfw_reap_rules(reap);
|
610
|
IPFW_LOCK_DESTROY(chain);
|
611
|
- ipfw_dyn_uninit(1); /* free the remaining parts */
|
612
|
- return 0;
|
613
|
+
|
614
|
+ free(chain, M_IPFW);
|
615
|
+
|
616
|
+ return (0);
|
617
|
}
|
618
|
|
619
|
/*
|
620
|
diff --git a/sys/netpfil/ipfw/ip_fw_dynamic.c b/sys/netpfil/ipfw/ip_fw_dynamic.c
|
621
|
index a166d12..694362a 100644
|
622
|
--- a/sys/netpfil/ipfw/ip_fw_dynamic.c
|
623
|
+++ b/sys/netpfil/ipfw/ip_fw_dynamic.c
|
624
|
@@ -121,11 +121,9 @@ struct ipfw_dyn_bucket {
|
625
|
*/
|
626
|
static VNET_DEFINE(struct ipfw_dyn_bucket *, ipfw_dyn_v);
|
627
|
static VNET_DEFINE(u_int32_t, dyn_buckets_max);
|
628
|
-static VNET_DEFINE(u_int32_t, curr_dyn_buckets);
|
629
|
static VNET_DEFINE(struct callout, ipfw_timeout);
|
630
|
#define V_ipfw_dyn_v VNET(ipfw_dyn_v)
|
631
|
#define V_dyn_buckets_max VNET(dyn_buckets_max)
|
632
|
-#define V_curr_dyn_buckets VNET(curr_dyn_buckets)
|
633
|
#define V_ipfw_timeout VNET(ipfw_timeout)
|
634
|
|
635
|
static VNET_DEFINE(uma_zone_t, ipfw_dyn_rule_zone);
|
636
|
@@ -181,6 +179,8 @@ static VNET_DEFINE(u_int32_t, dyn_max); /* max # of dynamic rules */
|
637
|
|
638
|
static int last_log; /* Log ratelimiting */
|
639
|
|
640
|
+VNET_DEFINE(u_int32_t, curr_dyn_buckets);
|
641
|
+
|
642
|
static void ipfw_dyn_tick(void *vnetx);
|
643
|
static void check_dyn_rules(struct ip_fw_chain *, struct ip_fw *,
|
644
|
int, int, int);
|
645
|
@@ -472,7 +472,7 @@ ipfw_dyn_unlock(ipfw_dyn_rule *q)
|
646
|
IPFW_BUCK_UNLOCK(q->bucket);
|
647
|
}
|
648
|
|
649
|
-static int
|
650
|
+int
|
651
|
resize_dynamic_table(struct ip_fw_chain *chain, int nbuckets)
|
652
|
{
|
653
|
int i, k, nbuckets_old;
|
654
|
@@ -972,7 +972,6 @@ ipfw_dyn_send_ka(struct mbuf **mtailp, ipfw_dyn_rule *q)
|
655
|
static void
|
656
|
ipfw_dyn_tick(void * vnetx)
|
657
|
{
|
658
|
- struct ip_fw_chain *chain;
|
659
|
int check_ka = 0;
|
660
|
#ifdef VIMAGE
|
661
|
struct vnet *vp = vnetx;
|
662
|
@@ -980,7 +979,6 @@ ipfw_dyn_tick(void * vnetx)
|
663
|
|
664
|
CURVNET_SET(vp);
|
665
|
|
666
|
- chain = &V_layer3_chain;
|
667
|
|
668
|
/* Run keepalive checks every keepalive_period iff ka is enabled */
|
669
|
if ((V_dyn_keepalive_last + V_dyn_keepalive_period <= time_uptime) &&
|
670
|
@@ -989,7 +987,12 @@ ipfw_dyn_tick(void * vnetx)
|
671
|
check_ka = 1;
|
672
|
}
|
673
|
|
674
|
- check_dyn_rules(chain, NULL, RESVD_SET, check_ka, 1);
|
675
|
+ IPFW_CTX_RLOCK();
|
676
|
+ for (int i = 1; i < IP_FW_MAXCTX; i++) {
|
677
|
+ if (V_ip_fw_contexts.chain[i] != NULL)
|
678
|
+ check_dyn_rules(V_ip_fw_contexts.chain[i], NULL, RESVD_SET, check_ka, 1);
|
679
|
+ }
|
680
|
+ IPFW_CTX_RUNLOCK();
|
681
|
|
682
|
callout_reset_on(&V_ipfw_timeout, hz, ipfw_dyn_tick, vnetx, 0);
|
683
|
|
684
|
@@ -1305,7 +1308,7 @@ ipfw_expire_dyn_rules(struct ip_fw_chain *chain, struct ip_fw *rule, int set)
|
685
|
}
|
686
|
|
687
|
void
|
688
|
-ipfw_dyn_init(struct ip_fw_chain *chain)
|
689
|
+ipfw_dyn_init()
|
690
|
{
|
691
|
|
692
|
V_ipfw_dyn_v = NULL;
|
693
|
@@ -1334,12 +1337,6 @@ ipfw_dyn_init(struct ip_fw_chain *chain)
|
694
|
uma_zone_set_max(V_ipfw_dyn_rule_zone, V_dyn_max);
|
695
|
|
696
|
callout_init(&V_ipfw_timeout, CALLOUT_MPSAFE);
|
697
|
-
|
698
|
- /*
|
699
|
- * This can potentially be done on first dynamic rule
|
700
|
- * being added to chain.
|
701
|
- */
|
702
|
- resize_dynamic_table(chain, V_curr_dyn_buckets);
|
703
|
}
|
704
|
|
705
|
void
|
706
|
diff --git a/sys/netpfil/ipfw/ip_fw_nat.c b/sys/netpfil/ipfw/ip_fw_nat.c
|
707
|
index d4348b5..5c04a36 100644
|
708
|
--- a/sys/netpfil/ipfw/ip_fw_nat.c
|
709
|
+++ b/sys/netpfil/ipfw/ip_fw_nat.c
|
710
|
@@ -64,26 +64,33 @@ ifaddr_change(void *arg __unused, struct ifnet *ifp)
|
711
|
|
712
|
KASSERT(curvnet == ifp->if_vnet,
|
713
|
("curvnet(%p) differs from iface vnet(%p)", curvnet, ifp->if_vnet));
|
714
|
- chain = &V_layer3_chain;
|
715
|
- IPFW_WLOCK(chain);
|
716
|
- /* Check every nat entry... */
|
717
|
- LIST_FOREACH(ptr, &chain->nat, _next) {
|
718
|
- /* ...using nic 'ifp->if_xname' as dynamic alias address. */
|
719
|
- if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0)
|
720
|
+
|
721
|
+ IPFW_CTX_RLOCK();
|
722
|
+ for (int i = 1; i < IP_FW_MAXCTX; i++) {
|
723
|
+ chain = V_ip_fw_contexts.chain[i];
|
724
|
+ if (chain == NULL)
|
725
|
continue;
|
726
|
- if_addr_rlock(ifp);
|
727
|
- TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
728
|
- if (ifa->ifa_addr == NULL)
|
729
|
- continue;
|
730
|
- if (ifa->ifa_addr->sa_family != AF_INET)
|
731
|
+ IPFW_WLOCK(chain);
|
732
|
+ /* Check every nat entry... */
|
733
|
+ LIST_FOREACH(ptr, &chain->nat, _next) {
|
734
|
+ /* ...using nic 'ifp->if_xname' as dynamic alias address. */
|
735
|
+ if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0)
|
736
|
continue;
|
737
|
- ptr->ip = ((struct sockaddr_in *)
|
738
|
- (ifa->ifa_addr))->sin_addr;
|
739
|
- LibAliasSetAddress(ptr->lib, ptr->ip);
|
740
|
+ if_addr_rlock(ifp);
|
741
|
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
742
|
+ if (ifa->ifa_addr == NULL)
|
743
|
+ continue;
|
744
|
+ if (ifa->ifa_addr->sa_family != AF_INET)
|
745
|
+ continue;
|
746
|
+ ptr->ip = ((struct sockaddr_in *)
|
747
|
+ (ifa->ifa_addr))->sin_addr;
|
748
|
+ LibAliasSetAddress(ptr->lib, ptr->ip);
|
749
|
+ }
|
750
|
+ if_addr_runlock(ifp);
|
751
|
}
|
752
|
- if_addr_runlock(ifp);
|
753
|
+ IPFW_WUNLOCK(chain);
|
754
|
}
|
755
|
- IPFW_WUNLOCK(chain);
|
756
|
+ IPFW_CTX_RUNLOCK();
|
757
|
}
|
758
|
|
759
|
/*
|
760
|
@@ -206,18 +213,18 @@ add_redir_spool_cfg(char *buf, struct cfg_nat *ptr)
|
761
|
/*
|
762
|
* ipfw_nat - perform mbuf header translation.
|
763
|
*
|
764
|
- * Note V_layer3_chain has to be locked while calling ipfw_nat() in
|
765
|
+ * Note *chain has to be locked while calling ipfw_nat() in
|
766
|
* 'global' operation mode (t == NULL).
|
767
|
*
|
768
|
*/
|
769
|
static int
|
770
|
-ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
|
771
|
+ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m,
|
772
|
+ struct ip_fw_chain *chain)
|
773
|
{
|
774
|
struct mbuf *mcl;
|
775
|
struct ip *ip;
|
776
|
/* XXX - libalias duct tape */
|
777
|
int ldt, retval, found;
|
778
|
- struct ip_fw_chain *chain;
|
779
|
char *c;
|
780
|
|
781
|
ldt = 0;
|
782
|
@@ -276,7 +283,6 @@ ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
|
783
|
}
|
784
|
|
785
|
found = 0;
|
786
|
- chain = &V_layer3_chain;
|
787
|
IPFW_RLOCK_ASSERT(chain);
|
788
|
/* Check every nat entry... */
|
789
|
LIST_FOREACH(t, &chain->nat, _next) {
|
790
|
@@ -391,11 +397,10 @@ lookup_nat(struct nat_list *l, int nat_id)
|
791
|
}
|
792
|
|
793
|
static int
|
794
|
-ipfw_nat_cfg(struct sockopt *sopt)
|
795
|
+ipfw_nat_cfg(struct sockopt *sopt, struct ip_fw_chain *chain)
|
796
|
{
|
797
|
struct cfg_nat *cfg, *ptr;
|
798
|
char *buf;
|
799
|
- struct ip_fw_chain *chain = &V_layer3_chain;
|
800
|
size_t len;
|
801
|
int gencnt, error = 0;
|
802
|
|
803
|
@@ -468,10 +473,9 @@ out:
|
804
|
}
|
805
|
|
806
|
static int
|
807
|
-ipfw_nat_del(struct sockopt *sopt)
|
808
|
+ipfw_nat_del(struct sockopt *sopt, struct ip_fw_chain *chain)
|
809
|
{
|
810
|
struct cfg_nat *ptr;
|
811
|
- struct ip_fw_chain *chain = &V_layer3_chain;
|
812
|
int i;
|
813
|
|
814
|
sooptcopyin(sopt, &i, sizeof i, sizeof i);
|
815
|
@@ -492,9 +496,8 @@ ipfw_nat_del(struct sockopt *sopt)
|
816
|
}
|
817
|
|
818
|
static int
|
819
|
-ipfw_nat_get_cfg(struct sockopt *sopt)
|
820
|
+ipfw_nat_get_cfg(struct sockopt *sopt, struct ip_fw_chain *chain)
|
821
|
{
|
822
|
- struct ip_fw_chain *chain = &V_layer3_chain;
|
823
|
struct cfg_nat *n;
|
824
|
struct cfg_redir *r;
|
825
|
struct cfg_spool *s;
|
826
|
@@ -552,14 +555,11 @@ retry:
|
827
|
}
|
828
|
|
829
|
static int
|
830
|
-ipfw_nat_get_log(struct sockopt *sopt)
|
831
|
+ipfw_nat_get_log(struct sockopt *sopt, struct ip_fw_chain *chain)
|
832
|
{
|
833
|
uint8_t *data;
|
834
|
struct cfg_nat *ptr;
|
835
|
int i, size;
|
836
|
- struct ip_fw_chain *chain;
|
837
|
-
|
838
|
- chain = &V_layer3_chain;
|
839
|
|
840
|
IPFW_RLOCK(chain);
|
841
|
/* one pass to count, one to copy the data */
|
842
|
@@ -604,17 +604,22 @@ vnet_ipfw_nat_uninit(const void *arg __unused)
|
843
|
struct cfg_nat *ptr, *ptr_temp;
|
844
|
struct ip_fw_chain *chain;
|
845
|
|
846
|
- chain = &V_layer3_chain;
|
847
|
- IPFW_WLOCK(chain);
|
848
|
- LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) {
|
849
|
- LIST_REMOVE(ptr, _next);
|
850
|
- del_redir_spool_cfg(ptr, &ptr->redir_chain);
|
851
|
- LibAliasUninit(ptr->lib);
|
852
|
- free(ptr, M_IPFW);
|
853
|
+ IPFW_CTX_RLOCK();
|
854
|
+ for (int i = 1; i < IP_FW_MAXCTX; i++) {
|
855
|
+ chain = V_ip_fw_contexts.chain[i];
|
856
|
+ IPFW_WLOCK(chain);
|
857
|
+ LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) {
|
858
|
+ LIST_REMOVE(ptr, _next);
|
859
|
+ del_redir_spool_cfg(ptr, &ptr->redir_chain);
|
860
|
+ LibAliasUninit(ptr->lib);
|
861
|
+ free(ptr, M_IPFW);
|
862
|
+ }
|
863
|
+ flush_nat_ptrs(chain, -1 /* flush all */);
|
864
|
+ V_ipfw_nat_ready = 0;
|
865
|
+ IPFW_WUNLOCK(chain);
|
866
|
}
|
867
|
- flush_nat_ptrs(chain, -1 /* flush all */);
|
868
|
- V_ipfw_nat_ready = 0;
|
869
|
- IPFW_WUNLOCK(chain);
|
870
|
+ IPFW_CTX_RUNLOCK();
|
871
|
+
|
872
|
return (0);
|
873
|
}
|
874
|
|
875
|
diff --git a/sys/netpfil/ipfw/ip_fw_private.h b/sys/netpfil/ipfw/ip_fw_private.h
|
876
|
index 1d8a4aa..e7a2695 100644
|
877
|
--- a/sys/netpfil/ipfw/ip_fw_private.h
|
878
|
+++ b/sys/netpfil/ipfw/ip_fw_private.h
|
879
|
@@ -171,6 +171,9 @@ enum { /* result for matching dynamic rules */
|
880
|
MATCH_UNKNOWN,
|
881
|
};
|
882
|
|
883
|
+VNET_DECLARE(u_int32_t, curr_dyn_buckets);
|
884
|
+#define V_curr_dyn_buckets VNET(curr_dyn_buckets)
|
885
|
+
|
886
|
/*
|
887
|
* The lock for dynamic rules is only used once outside the file,
|
888
|
* and only to release the result of lookup_dyn_rule().
|
889
|
@@ -179,6 +182,7 @@ enum { /* result for matching dynamic rules */
|
890
|
struct ip_fw_chain;
|
891
|
void ipfw_expire_dyn_rules(struct ip_fw_chain *, struct ip_fw *, int);
|
892
|
void ipfw_dyn_unlock(ipfw_dyn_rule *q);
|
893
|
+int resize_dynamic_table(struct ip_fw_chain *, int);
|
894
|
|
895
|
struct tcphdr;
|
896
|
struct mbuf *ipfw_send_pkt(struct mbuf *, struct ipfw_flow_id *,
|
897
|
@@ -190,7 +194,7 @@ ipfw_dyn_rule *ipfw_lookup_dyn_rule(struct ipfw_flow_id *pkt,
|
898
|
void ipfw_remove_dyn_children(struct ip_fw *rule);
|
899
|
void ipfw_get_dynamic(struct ip_fw_chain *chain, char **bp, const char *ep);
|
900
|
|
901
|
-void ipfw_dyn_init(struct ip_fw_chain *); /* per-vnet initialization */
|
902
|
+void ipfw_dyn_init(void); /* per-vnet initialization */
|
903
|
void ipfw_dyn_uninit(int); /* per-vnet deinitialization */
|
904
|
int ipfw_dyn_len(void);
|
905
|
|
906
|
@@ -201,9 +205,6 @@ VNET_DECLARE(int, fw_one_pass);
|
907
|
VNET_DECLARE(int, fw_verbose);
|
908
|
#define V_fw_verbose VNET(fw_verbose)
|
909
|
|
910
|
-VNET_DECLARE(struct ip_fw_chain, layer3_chain);
|
911
|
-#define V_layer3_chain VNET(layer3_chain)
|
912
|
-
|
913
|
VNET_DECLARE(u_int32_t, set_disable);
|
914
|
#define V_set_disable VNET(set_disable)
|
915
|
|
916
|
@@ -235,6 +236,33 @@ struct ip_fw_chain {
|
917
|
uint32_t gencnt; /* generation count */
|
918
|
};
|
919
|
|
920
|
+struct ip_fw_ctx_iflist {
|
921
|
+ TAILQ_ENTRY(ip_fw_ctx_iflist) entry;
|
922
|
+ char ifname[IFNAMSIZ];
|
923
|
+};
|
924
|
+
|
925
|
+#define IP_FW_MAXCTX 4096
|
926
|
+struct ip_fw_contextes {
|
927
|
+ struct ip_fw_chain *chain[IP_FW_MAXCTX]; /* Arrays of contextes */
|
928
|
+ TAILQ_HEAD(, ip_fw_ctx_iflist) iflist[IP_FW_MAXCTX];
|
929
|
+ struct rwlock rwctx;
|
930
|
+ eventhandler_tag ifnet_arrival;
|
931
|
+};
|
932
|
+
|
933
|
+VNET_DECLARE(struct ip_fw_contextes, ip_fw_contexts);
|
934
|
+#define V_ip_fw_contexts VNET(ip_fw_contexts)
|
935
|
+
|
936
|
+#define IPFW_CTX_LOCK_INIT() rw_init(&V_ip_fw_contexts.rwctx, "IPFW context")
|
937
|
+#define IPFW_CTX_LOCK_DESTROY() rw_destroy(&V_ip_fw_contexts.rwctx)
|
938
|
+#define IPFW_CTX_WLOCK() rw_wlock(&V_ip_fw_contexts.rwctx)
|
939
|
+#define IPFW_CTX_WUNLOCK() rw_wunlock(&V_ip_fw_contexts.rwctx)
|
940
|
+#define IPFW_CTX_RLOCK() rw_rlock(&V_ip_fw_contexts.rwctx)
|
941
|
+#define IPFW_CTX_RUNLOCK() rw_runlock(&V_ip_fw_contexts.rwctx)
|
942
|
+
|
943
|
+void ipfw_attach_ifnet_event(void *, struct ifnet *);
|
944
|
+int ipfw_context_init(int);
|
945
|
+int ipfw_context_uninit(int);
|
946
|
+
|
947
|
struct sockopt; /* used by tcp_var.h */
|
948
|
|
949
|
/* Macro for working with various counters */
|
950
|
@@ -328,8 +356,9 @@ int ipfw_resize_tables(struct ip_fw_chain *ch, unsigned int ntables);
|
951
|
|
952
|
extern struct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int);
|
953
|
|
954
|
-typedef int ipfw_nat_t(struct ip_fw_args *, struct cfg_nat *, struct mbuf *);
|
955
|
-typedef int ipfw_nat_cfg_t(struct sockopt *);
|
956
|
+typedef int ipfw_nat_t(struct ip_fw_args *, struct cfg_nat *, struct mbuf *,
|
957
|
+ struct ip_fw_chain *);
|
958
|
+typedef int ipfw_nat_cfg_t(struct sockopt *, struct ip_fw_chain *);
|
959
|
|
960
|
VNET_DECLARE(int, ipfw_nat_ready);
|
961
|
#define V_ipfw_nat_ready VNET(ipfw_nat_ready)
|
962
|
diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c
|
963
|
index 9e6b5ca..e977df2 100644
|
964
|
--- a/sys/netpfil/ipfw/ip_fw_sockopt.c
|
965
|
+++ b/sys/netpfil/ipfw/ip_fw_sockopt.c
|
966
|
@@ -943,12 +943,15 @@ ipfw_ctl(struct sockopt *sopt)
|
967
|
#define RULE_MAXSIZE (256*sizeof(u_int32_t))
|
968
|
int error;
|
969
|
size_t size, len, valsize;
|
970
|
+ struct ifnet *ifp;
|
971
|
struct ip_fw *buf, *rule;
|
972
|
- struct ip_fw_chain *chain;
|
973
|
+ static struct ip_fw_chain *chain;
|
974
|
+ struct ip_fw_ctx_iflist *tmpifl, *tmpifl2 = NULL;
|
975
|
+ ip_fw3_opheader *op3 = NULL;
|
976
|
u_int32_t rulenum[2];
|
977
|
uint32_t opt;
|
978
|
char xbuf[128];
|
979
|
- ip_fw3_opheader *op3 = NULL;
|
980
|
+ char *ifname;
|
981
|
|
982
|
error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW);
|
983
|
if (error)
|
984
|
@@ -965,7 +968,6 @@ ipfw_ctl(struct sockopt *sopt)
|
985
|
return (error);
|
986
|
}
|
987
|
|
988
|
- chain = &V_layer3_chain;
|
989
|
error = 0;
|
990
|
|
991
|
/* Save original valsize before it is altered via sooptcopyin() */
|
992
|
@@ -980,9 +982,236 @@ ipfw_ctl(struct sockopt *sopt)
|
993
|
return (error);
|
994
|
op3 = (ip_fw3_opheader *)xbuf;
|
995
|
opt = op3->opcode;
|
996
|
+
|
997
|
+ if (op3->ctxid > IP_FW_MAXCTX)
|
998
|
+ return (EINVAL);
|
999
|
+
|
1000
|
+ if (opt != IP_FW_CTX_GET) {
|
1001
|
+ if (opt != IP_FW_CTX_ADD) {
|
1002
|
+ if (op3->ctxid == 0)
|
1003
|
+ return (ENOENT);
|
1004
|
+ }
|
1005
|
+
|
1006
|
+ chain = V_ip_fw_contexts.chain[op3->ctxid];
|
1007
|
+ }
|
1008
|
+ }
|
1009
|
+
|
1010
|
+ /* Verification needed to avoid problems */
|
1011
|
+ switch (opt) {
|
1012
|
+ case IP_FW_CTX_GET:
|
1013
|
+ case IP_FW_CTX_ADD:
|
1014
|
+ case IP_FW_CTX_DEL:
|
1015
|
+ break;
|
1016
|
+ default:
|
1017
|
+ if (chain == NULL)
|
1018
|
+ return (EINVAL);
|
1019
|
+ /* NOTREACHED */
|
1020
|
}
|
1021
|
|
1022
|
switch (opt) {
|
1023
|
+ case IP_FW_CTX_ADD:
|
1024
|
+ IPFW_CTX_WLOCK();
|
1025
|
+ if (V_ip_fw_contexts.chain[op3->ctxid] != NULL) {
|
1026
|
+ IPFW_CTX_WUNLOCK();
|
1027
|
+ return (EEXIST);
|
1028
|
+ }
|
1029
|
+
|
1030
|
+ chain = malloc(sizeof(struct ip_fw_chain), M_IPFW, M_WAITOK | M_ZERO);
|
1031
|
+ TAILQ_INIT(&V_ip_fw_contexts.iflist[op3->ctxid]);
|
1032
|
+ V_ip_fw_contexts.chain[op3->ctxid] = chain;
|
1033
|
+ ipfw_context_init(op3->ctxid); /* XXX: error checking */
|
1034
|
+ IPFW_CTX_WUNLOCK();
|
1035
|
+ break;
|
1036
|
+
|
1037
|
+ case IP_FW_CTX_DEL:
|
1038
|
+ IPFW_CTX_WLOCK();
|
1039
|
+ if (V_ip_fw_contexts.chain[op3->ctxid] == NULL) {
|
1040
|
+ IPFW_CTX_WUNLOCK();
|
1041
|
+ return (ENOENT);
|
1042
|
+ }
|
1043
|
+
|
1044
|
+ ipfw_context_uninit(op3->ctxid);
|
1045
|
+ V_ip_fw_contexts.chain[op3->ctxid] = NULL;
|
1046
|
+ IPFW_CTX_WUNLOCK();
|
1047
|
+ break;
|
1048
|
+
|
1049
|
+ case IP_FW_CTX_GET:
|
1050
|
+ {
|
1051
|
+ int i, n, len = 0, want;
|
1052
|
+ char *bufout, *tmpbuf;
|
1053
|
+
|
1054
|
+ sopt->sopt_valsize = valsize;
|
1055
|
+
|
1056
|
+ IPFW_CTX_RLOCK();
|
1057
|
+ for (i = 1; i < IP_FW_MAXCTX; i++) {
|
1058
|
+ if (op3->ctxid > 0 && op3->ctxid != i)
|
1059
|
+ continue;
|
1060
|
+ if (op3->ctxid > 0 && op3->ctxid < i)
|
1061
|
+ break;
|
1062
|
+
|
1063
|
+ if (V_ip_fw_contexts.chain[i] == NULL)
|
1064
|
+ continue;
|
1065
|
+
|
1066
|
+ /* Calculate number of bytes for the integer */
|
1067
|
+ n = i;
|
1068
|
+ while (n > 0) {
|
1069
|
+ n /= 10;
|
1070
|
+ len++;
|
1071
|
+ }
|
1072
|
+ TAILQ_FOREACH(tmpifl, &V_ip_fw_contexts.iflist[i], entry) {
|
1073
|
+ len += strlen(tmpifl->ifname) + 1;
|
1074
|
+ }
|
1075
|
+ len += 3; // newline, :, space
|
1076
|
+ }
|
1077
|
+ IPFW_CTX_RUNLOCK();
|
1078
|
+
|
1079
|
+ if (len > sopt->sopt_valsize) {
|
1080
|
+ sopt->sopt_valsize = len;
|
1081
|
+ break;
|
1082
|
+ }
|
1083
|
+
|
1084
|
+ bufout = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
|
1085
|
+ if (bufout == NULL)
|
1086
|
+ break;
|
1087
|
+
|
1088
|
+ /* Record our size for later checks */
|
1089
|
+ want = len;
|
1090
|
+ len = 0;
|
1091
|
+ IPFW_CTX_RLOCK();
|
1092
|
+ /* Recalculate length to detect if smth changed */
|
1093
|
+ for (i = 1; i < IP_FW_MAXCTX; i++) {
|
1094
|
+ if (op3->ctxid > 0 && op3->ctxid != i)
|
1095
|
+ continue;
|
1096
|
+ if (op3->ctxid > 0 && op3->ctxid < i)
|
1097
|
+ break;
|
1098
|
+
|
1099
|
+ if (V_ip_fw_contexts.chain[i] == NULL)
|
1100
|
+ continue;
|
1101
|
+
|
1102
|
+ /* Calculate number of bytes for the integer */
|
1103
|
+ n = i;
|
1104
|
+ while (n > 0) {
|
1105
|
+ n /= 10;
|
1106
|
+ len++;
|
1107
|
+ }
|
1108
|
+ TAILQ_FOREACH(tmpifl, &V_ip_fw_contexts.iflist[i], entry) {
|
1109
|
+ len += strlen(tmpifl->ifname) + 1;
|
1110
|
+ }
|
1111
|
+ len += 3; // newline, :, space
|
1112
|
+ }
|
1113
|
+
|
1114
|
+ if (want >= len) {
|
1115
|
+ tmpbuf = bufout;
|
1116
|
+ for (i = 1; i < IP_FW_MAXCTX; i++) {
|
1117
|
+ if (op3->ctxid > 0 && op3->ctxid != i)
|
1118
|
+ continue;
|
1119
|
+ if (op3->ctxid > 0 && op3->ctxid < i)
|
1120
|
+ break;
|
1121
|
+
|
1122
|
+ if (V_ip_fw_contexts.chain[i] == NULL)
|
1123
|
+ continue;
|
1124
|
+
|
1125
|
+ sprintf(tmpbuf, "%d: ", i);
|
1126
|
+ tmpbuf += strlen(tmpbuf);
|
1127
|
+ TAILQ_FOREACH(tmpifl, &V_ip_fw_contexts.iflist[i], entry) {
|
1128
|
+ sprintf(tmpbuf, "%s,", tmpifl->ifname);
|
1129
|
+ tmpbuf += strlen(tmpifl->ifname) + 1;
|
1130
|
+ }
|
1131
|
+ sprintf(tmpbuf, "\n");
|
1132
|
+ tmpbuf++;
|
1133
|
+ }
|
1134
|
+ }
|
1135
|
+ IPFW_CTX_RUNLOCK();
|
1136
|
+
|
1137
|
+ if (want >= len)
|
1138
|
+ error = sooptcopyout(sopt, bufout, len);
|
1139
|
+ else
|
1140
|
+ len = 0;
|
1141
|
+ free(bufout, M_TEMP);
|
1142
|
+ }
|
1143
|
+ break;
|
1144
|
+
|
1145
|
+ case IP_FW_CTX_SET:
|
1146
|
+ /* XXX: Maybe not use this option at all? */
|
1147
|
+ IPFW_CTX_RLOCK();
|
1148
|
+ if (V_ip_fw_contexts.chain[op3->ctxid] == NULL)
|
1149
|
+ error = ENOENT;
|
1150
|
+ else
|
1151
|
+ chain = V_ip_fw_contexts.chain[op3->ctxid];
|
1152
|
+ IPFW_CTX_RUNLOCK();
|
1153
|
+ break;
|
1154
|
+
|
1155
|
+ case IP_FW_CTX_ADDMEMBER:
|
1156
|
+ {
|
1157
|
+ int i;
|
1158
|
+
|
1159
|
+ ifname = (char *)(op3 + 1);
|
1160
|
+ ifp = ifunit(ifname);
|
1161
|
+ if (ifp == NULL)
|
1162
|
+ return (ENOENT);
|
1163
|
+
|
1164
|
+ tmpifl = malloc(sizeof(*tmpifl), M_IPFW, M_WAITOK | M_ZERO);
|
1165
|
+
|
1166
|
+ IPFW_CTX_WLOCK();
|
1167
|
+ if (V_ip_fw_contexts.chain[op3->ctxid] == NULL) {
|
1168
|
+ IPFW_CTX_WUNLOCK();
|
1169
|
+ free(tmpifl, M_IPFW);
|
1170
|
+ return (ENOENT);
|
1171
|
+ }
|
1172
|
+
|
1173
|
+ for (i = 1; i < IP_FW_MAXCTX; i++) {
|
1174
|
+ if (V_ip_fw_contexts.chain[i] == NULL)
|
1175
|
+ continue;
|
1176
|
+
|
1177
|
+ TAILQ_FOREACH(tmpifl2, &V_ip_fw_contexts.iflist[i], entry) {
|
1178
|
+ if (strlen(tmpifl2->ifname) != strlen(ifname))
|
1179
|
+ continue;
|
1180
|
+ if (!strcmp(tmpifl2->ifname, ifname))
|
1181
|
+ goto ctxifacefound;
|
1182
|
+ }
|
1183
|
+ }
|
1184
|
+ctxifacefound:
|
1185
|
+ if (tmpifl2 != NULL) {
|
1186
|
+ IPFW_CTX_WUNLOCK();
|
1187
|
+ free(tmpifl, M_IPFW);
|
1188
|
+ return (EEXIST);
|
1189
|
+ }
|
1190
|
+
|
1191
|
+ strlcpy(tmpifl->ifname, ifname, IFNAMSIZ);
|
1192
|
+ TAILQ_INSERT_HEAD(&V_ip_fw_contexts.iflist[op3->ctxid], tmpifl, entry);
|
1193
|
+ ifp->if_ispare[0] = op3->ctxid;
|
1194
|
+ IPFW_CTX_WUNLOCK();
|
1195
|
+ }
|
1196
|
+ break;
|
1197
|
+
|
1198
|
+ case IP_FW_CTX_DELMEMBER:
|
1199
|
+ IPFW_CTX_WLOCK();
|
1200
|
+ if (V_ip_fw_contexts.chain[op3->ctxid] == NULL) {
|
1201
|
+ IPFW_CTX_WUNLOCK();
|
1202
|
+ return (ENOENT);
|
1203
|
+ }
|
1204
|
+
|
1205
|
+ ifname = (char *)(op3 + 1);
|
1206
|
+ TAILQ_FOREACH(tmpifl2, &V_ip_fw_contexts.iflist[op3->ctxid], entry) {
|
1207
|
+ if (strlen(tmpifl2->ifname) != strlen(ifname))
|
1208
|
+ continue;
|
1209
|
+ if (!strcmp(tmpifl2->ifname, ifname))
|
1210
|
+ break;
|
1211
|
+ }
|
1212
|
+ if (tmpifl2 == NULL) {
|
1213
|
+ IPFW_CTX_WUNLOCK();
|
1214
|
+ return (ENOENT);
|
1215
|
+ }
|
1216
|
+
|
1217
|
+ TAILQ_REMOVE(&V_ip_fw_contexts.iflist[op3->ctxid], tmpifl2, entry);
|
1218
|
+ IPFW_CTX_WUNLOCK();
|
1219
|
+ free(tmpifl2, M_IPFW);
|
1220
|
+
|
1221
|
+ ifp = ifunit(ifname);
|
1222
|
+ if (ifp != NULL)
|
1223
|
+ ifp->if_ispare[0] = 0;
|
1224
|
+ break;
|
1225
|
+
|
1226
|
case IP_FW_GET:
|
1227
|
/*
|
1228
|
* pass up a copy of the current rules. Static rules
|
1229
|
@@ -1321,7 +1550,7 @@ ipfw_ctl(struct sockopt *sopt)
|
1230
|
/*--- NAT operations are protected by the IPFW_LOCK ---*/
|
1231
|
case IP_FW_NAT_CFG:
|
1232
|
if (IPFW_NAT_LOADED)
|
1233
|
- error = ipfw_nat_cfg_ptr(sopt);
|
1234
|
+ error = ipfw_nat_cfg_ptr(sopt, chain);
|
1235
|
else {
|
1236
|
printf("IP_FW_NAT_CFG: %s\n",
|
1237
|
"ipfw_nat not present, please load it");
|
1238
|
@@ -1331,7 +1560,7 @@ ipfw_ctl(struct sockopt *sopt)
|
1239
|
|
1240
|
case IP_FW_NAT_DEL:
|
1241
|
if (IPFW_NAT_LOADED)
|
1242
|
- error = ipfw_nat_del_ptr(sopt);
|
1243
|
+ error = ipfw_nat_del_ptr(sopt, chain);
|
1244
|
else {
|
1245
|
printf("IP_FW_NAT_DEL: %s\n",
|
1246
|
"ipfw_nat not present, please load it");
|
1247
|
@@ -1341,7 +1570,7 @@ ipfw_ctl(struct sockopt *sopt)
|
1248
|
|
1249
|
case IP_FW_NAT_GET_CONFIG:
|
1250
|
if (IPFW_NAT_LOADED)
|
1251
|
- error = ipfw_nat_get_cfg_ptr(sopt);
|
1252
|
+ error = ipfw_nat_get_cfg_ptr(sopt, chain);
|
1253
|
else {
|
1254
|
printf("IP_FW_NAT_GET_CFG: %s\n",
|
1255
|
"ipfw_nat not present, please load it");
|
1256
|
@@ -1351,7 +1580,7 @@ ipfw_ctl(struct sockopt *sopt)
|
1257
|
|
1258
|
case IP_FW_NAT_GET_LOG:
|
1259
|
if (IPFW_NAT_LOADED)
|
1260
|
- error = ipfw_nat_get_log_ptr(sopt);
|
1261
|
+ error = ipfw_nat_get_log_ptr(sopt, chain);
|
1262
|
else {
|
1263
|
printf("IP_FW_NAT_GET_LOG: %s\n",
|
1264
|
"ipfw_nat not present, please load it");
|
1265
|
@@ -1368,6 +1597,33 @@ ipfw_ctl(struct sockopt *sopt)
|
1266
|
#undef RULE_MAXSIZE
|
1267
|
}
|
1268
|
|
1269
|
+void
|
1270
|
+ipfw_attach_ifnet_event(void *arg __unused, struct ifnet *ifp)
|
1271
|
+{
|
1272
|
+ struct ip_fw_ctx_iflist *tmpifl;
|
1273
|
+
|
1274
|
+ CURVNET_SET(ifp->if_vnet);
|
1275
|
+
|
1276
|
+ IPFW_CTX_RLOCK();
|
1277
|
+ for (int i = 1; i < IP_FW_MAXCTX; i++) {
|
1278
|
+ if (V_ip_fw_contexts.chain[i] == NULL)
|
1279
|
+ continue;
|
1280
|
+ TAILQ_FOREACH(tmpifl, &V_ip_fw_contexts.iflist[i], entry) {
|
1281
|
+ if (strlen(tmpifl->ifname) != strlen(ifp->if_xname))
|
1282
|
+ continue;
|
1283
|
+ if (!strcmp(tmpifl->ifname, ifp->if_xname)) {
|
1284
|
+ printf("Restoring context for interface %s to %d\n", ifp->if_xname, i);
|
1285
|
+ ifp->if_ispare[0] = i;
|
1286
|
+ goto ifctxdone;
|
1287
|
+ break;
|
1288
|
+ }
|
1289
|
+ }
|
1290
|
+ }
|
1291
|
+ifctxdone:
|
1292
|
+ IPFW_CTX_RUNLOCK();
|
1293
|
+
|
1294
|
+ CURVNET_RESTORE();
|
1295
|
+}
|
1296
|
|
1297
|
#define RULE_MAXSIZE (256*sizeof(u_int32_t))
|
1298
|
|