1 /*
2 * Copyright (c) 2014 - 2018 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Bill Yuan <bycn82@dragonflybsd.org>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/mbuf.h>
39 #include <sys/socketvar.h>
40 #include <sys/sysctl.h>
41 #include <sys/systimer.h>
42 #include <sys/in_cksum.h>
43 #include <sys/systm.h>
44 #include <sys/proc.h>
45 #include <sys/socket.h>
46 #include <sys/syslog.h>
47 #include <sys/ucred.h>
48 #include <sys/lock.h>
49
50 #include <net/if.h>
51 #include <net/ethernet.h>
52 #include <net/netmsg2.h>
53 #include <net/netisr2.h>
54 #include <net/route.h>
55
56 #include <netinet/ip.h>
57 #include <netinet/in.h>
58 #include <netinet/in_systm.h>
59 #include <netinet/in_var.h>
60 #include <netinet/in_pcb.h>
61 #include <netinet/ip_var.h>
62 #include <netinet/ip_icmp.h>
63 #include <netinet/tcp.h>
64 #include <netinet/tcp_timer.h>
65 #include <netinet/tcp_var.h>
66 #include <netinet/tcpip.h>
67 #include <netinet/udp.h>
68 #include <netinet/udp_var.h>
69 #include <netinet/ip_divert.h>
70 #include <netinet/if_ether.h>
71
72 #include <net/ipfw3/ip_fw.h>
73 #include <net/ipfw3_basic/ip_fw3_state.h>
74
75 MALLOC_DEFINE(M_IPFW3_STATE, "M_IPFW3_STATE", "mem for ipfw3 states");
76
77
78 struct ipfw3_state_context *fw3_state_ctx[MAXCPU];
79 extern struct ipfw3_context *fw3_ctx[MAXCPU];
80 extern ip_fw_ctl_t *ip_fw3_ctl_state_ptr;
81
82 static struct callout ip_fw3_state_cleanup_callout;
83 static int sysctl_var_cleanup_interval = 1;
84
85 static int sysctl_var_state_max_tcp_in = 4096;
86 static int sysctl_var_state_max_udp_in = 4096;
87 static int sysctl_var_state_max_icmp_in = 10;
88
89 static int sysctl_var_state_max_tcp_out = 4096;
90 static int sysctl_var_state_max_udp_out = 4096;
91 static int sysctl_var_state_max_icmp_out = 10;
92
93 static int sysctl_var_icmp_timeout = 10;
94 static int sysctl_var_tcp_timeout = 60;
95 static int sysctl_var_udp_timeout = 30;
96
97
98 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw3_basic, CTLFLAG_RW, 0, "Firewall Basic");
99
100 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, state_max_tcp_in, CTLFLAG_RW,
101 &sysctl_var_state_max_tcp_in, 0, "maximum of tcp state in");
102 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, state_max_tcp_out, CTLFLAG_RW,
103 &sysctl_var_state_max_tcp_out, 0, "maximum of tcp state out");
104 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, state_max_udp_in, CTLFLAG_RW,
105 &sysctl_var_state_max_udp_in, 0, "maximum of udp state in");
106 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, state_max_udp_out, CTLFLAG_RW,
107 &sysctl_var_state_max_udp_out, 0, "maximum of udp state out");
108 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, state_max_icmp_in, CTLFLAG_RW,
109 &sysctl_var_state_max_icmp_in, 0, "maximum of icmp state in");
110 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, state_max_icmp_out, CTLFLAG_RW,
111 &sysctl_var_state_max_icmp_out, 0, "maximum of icmp state out");
112
113 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, cleanup_interval, CTLFLAG_RW,
114 &sysctl_var_cleanup_interval, 0,
115 "default state expiry check interval");
116 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, icmp_timeout, CTLFLAG_RW,
117 &sysctl_var_icmp_timeout, 0, "default icmp state life time");
118 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, tcp_timeout, CTLFLAG_RW,
119 &sysctl_var_tcp_timeout, 0, "default tcp state life time");
120 SYSCTL_INT(_net_inet_ip_fw3_basic, OID_AUTO, udp_timeout, CTLFLAG_RW,
121 &sysctl_var_udp_timeout, 0, "default udp state life time");
122
123 RB_GENERATE(fw3_state_tree, ipfw3_state, entries, ip_fw3_state_cmp);
124
125
126 int
ip_fw3_state_cmp(struct ipfw3_state * s1,struct ipfw3_state * s2)127 ip_fw3_state_cmp(struct ipfw3_state *s1, struct ipfw3_state *s2)
128 {
129 if (s1->src_addr > s2->src_addr)
130 return 1;
131 if (s1->src_addr < s2->src_addr)
132 return -1;
133
134 if (s1->dst_addr > s2->dst_addr)
135 return 1;
136 if (s1->dst_addr < s2->dst_addr)
137 return -1;
138
139 if (s1->src_port > s2->src_port)
140 return 1;
141 if (s1->src_port < s2->src_port)
142 return -1;
143
144 if (s1->dst_port > s2->dst_port)
145 return 1;
146 if (s1->dst_port < s2->dst_port)
147 return -1;
148
149 return 0;
150 }
151
152 void
check_check_state(int * cmd_ctl,int * cmd_val,struct ip_fw_args ** args,struct ip_fw ** f,ipfw_insn * cmd,uint16_t ip_len)153 check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
154 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
155 {
156 /* state_tree 1 same direction, state_tree2 opposite direction */
157 struct fw3_state_tree *state_tree1, *state_tree2;
158 struct ip *ip = mtod((*args)->m, struct ip *);
159 struct ipfw3_state_context *state_ctx = fw3_state_ctx[mycpuid];
160 struct ipfw3_state *s, *k, key;
161
162 k = &key;
163 memset(k, 0, LEN_FW3_STATE);
164
165 if ((*args)->oif == NULL) {
166 switch (ip->ip_p) {
167 case IPPROTO_TCP:
168 state_tree1 = &state_ctx->rb_tcp_in;
169 state_tree2 = &state_ctx->rb_tcp_out;
170 break;
171 case IPPROTO_UDP:
172 state_tree1 = &state_ctx->rb_udp_in;
173 state_tree2 = &state_ctx->rb_udp_out;
174 break;
175 case IPPROTO_ICMP:
176 state_tree1 = &state_ctx->rb_icmp_in;
177 state_tree2 = &state_ctx->rb_icmp_out;
178 break;
179 default:
180 goto oops;
181 }
182 } else {
183 switch (ip->ip_p) {
184 case IPPROTO_TCP:
185 state_tree1 = &state_ctx->rb_tcp_out;
186 state_tree2 = &state_ctx->rb_tcp_in;
187 break;
188 case IPPROTO_UDP:
189 state_tree1 = &state_ctx->rb_udp_out;
190 state_tree2 = &state_ctx->rb_udp_in;
191 break;
192 case IPPROTO_ICMP:
193 state_tree1 = &state_ctx->rb_icmp_out;
194 state_tree2 = &state_ctx->rb_icmp_in;
195 break;
196 default:
197 goto oops;
198 }
199 }
200
201 k->src_addr = (*args)->f_id.src_ip;
202 k->dst_addr = (*args)->f_id.dst_ip;
203 k->src_port = (*args)->f_id.src_port;
204 k->dst_port = (*args)->f_id.dst_port;
205 s = RB_FIND(fw3_state_tree, state_tree1, k);
206 if (s != NULL) {
207 (*f)->pcnt++;
208 (*f)->bcnt += ip_len;
209 (*f)->timestamp = time_second;
210 *f = s->stub;
211 s->timestamp = time_uptime;
212 *cmd_val = IP_FW_PASS;
213 *cmd_ctl = IP_FW_CTL_CHK_STATE;
214 return;
215 }
216 k->dst_addr = (*args)->f_id.src_ip;
217 k->src_addr = (*args)->f_id.dst_ip;
218 k->dst_port = (*args)->f_id.src_port;
219 k->src_port = (*args)->f_id.dst_port;
220 s = RB_FIND(fw3_state_tree, state_tree2, k);
221 if (s != NULL) {
222 (*f)->pcnt++;
223 (*f)->bcnt += ip_len;
224 (*f)->timestamp = time_second;
225 *f = s->stub;
226 s->timestamp = time_uptime;
227 *cmd_val = IP_FW_PASS;
228 *cmd_ctl = IP_FW_CTL_CHK_STATE;
229 return;
230 }
231 oops:
232 *cmd_val = IP_FW_NOT_MATCH;
233 *cmd_ctl = IP_FW_CTL_NEXT;
234 }
235
236 void
check_keep_state(int * cmd_ctl,int * cmd_val,struct ip_fw_args ** args,struct ip_fw ** f,ipfw_insn * cmd,uint16_t ip_len)237 check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
238 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
239 {
240 /* state_tree 1 same direction, state_tree2 opposite direction */
241 struct fw3_state_tree *the_tree = NULL;
242 struct ip *ip = mtod((*args)->m, struct ip *);
243 struct ipfw3_state_context *state_ctx = fw3_state_ctx[mycpuid];
244 struct ipfw3_state *s, *k, key;
245 int states_matched = 0, *the_count, the_max;
246
247 k = &key;
248 memset(k, 0, LEN_FW3_STATE);
249 if ((*args)->oif == NULL) {
250 switch (ip->ip_p) {
251 case IPPROTO_TCP:
252 the_tree = &state_ctx->rb_tcp_in;
253 the_count = &state_ctx->count_tcp_in;
254 the_max = sysctl_var_state_max_tcp_in;
255 break;
256 case IPPROTO_UDP:
257 the_tree = &state_ctx->rb_udp_in;
258 the_count = &state_ctx->count_udp_in;
259 the_max = sysctl_var_state_max_udp_in;
260 break;
261 case IPPROTO_ICMP:
262 the_tree = &state_ctx->rb_icmp_in;
263 the_count = &state_ctx->count_icmp_in;
264 the_max = sysctl_var_state_max_icmp_in;
265 break;
266 default:
267 goto done;
268 }
269 } else {
270 switch (ip->ip_p) {
271 case IPPROTO_TCP:
272 the_tree = &state_ctx->rb_tcp_out;
273 the_count = &state_ctx->count_tcp_out;
274 the_max = sysctl_var_state_max_tcp_out;
275 break;
276 case IPPROTO_UDP:
277 the_tree = &state_ctx->rb_udp_out;
278 the_count = &state_ctx->count_udp_out;
279 the_max = sysctl_var_state_max_udp_out;
280 break;
281 case IPPROTO_ICMP:
282 the_tree = &state_ctx->rb_icmp_out;
283 the_count = &state_ctx->count_icmp_out;
284 the_max = sysctl_var_state_max_icmp_out;
285 break;
286 default:
287 goto done;
288 }
289 }
290 *cmd_ctl = IP_FW_CTL_NO;
291 k->src_addr = (*args)->f_id.src_ip;
292 k->dst_addr = (*args)->f_id.dst_ip;
293 k->src_port = (*args)->f_id.src_port;
294 k->dst_port = (*args)->f_id.dst_port;
295 /* cmd->arg3 is `limit type` */
296 if (cmd->arg3 == 0) {
297 s = RB_FIND(fw3_state_tree, the_tree, k);
298 if (s != NULL) {
299 goto done;
300 }
301 } else {
302 RB_FOREACH(s, fw3_state_tree, the_tree) {
303 if (cmd->arg3 == 1 && s->src_addr == k->src_addr) {
304 states_matched++;
305 } else if (cmd->arg3 == 2 && s->src_port == k->src_port) {
306 states_matched++;
307 } else if (cmd->arg3 == 3 && s->dst_addr == k->dst_addr) {
308 states_matched++;
309 } else if (cmd->arg3 == 4 && s->dst_port == k->dst_port) {
310 states_matched++;
311 }
312 }
313 if (states_matched >= cmd->arg1) {
314 goto done;
315 }
316 }
317 if (*the_count <= the_max) {
318 (*the_count)++;
319 s = kmalloc(LEN_FW3_STATE, M_IPFW3_STATE,
320 M_INTWAIT | M_NULLOK | M_ZERO);
321 s->src_addr = k->src_addr;
322 s->dst_addr = k->dst_addr;
323 s->src_port = k->src_port;
324 s->dst_port = k->dst_port;
325 s->stub = *f;
326 s->timestamp = time_uptime;
327 if (RB_INSERT(fw3_state_tree, the_tree, s)) {
328 kprintf("oops\n");
329 }
330 }
331 done:
332 *cmd_ctl = IP_FW_CTL_NO;
333 *cmd_val = IP_FW_MATCH;
334 }
335
336 void
ip_fw3_state_append_dispatch(netmsg_t nmsg)337 ip_fw3_state_append_dispatch(netmsg_t nmsg)
338 {
339 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
340 }
341
342 void
ip_fw3_state_delete_dispatch(netmsg_t nmsg)343 ip_fw3_state_delete_dispatch(netmsg_t nmsg)
344 {
345 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
346 }
347
348 int
ip_fw3_ctl_state_add(struct sockopt * sopt)349 ip_fw3_ctl_state_add(struct sockopt *sopt)
350 {
351 return 0;
352 }
353
354 int
ip_fw3_ctl_state_delete(struct sockopt * sopt)355 ip_fw3_ctl_state_delete(struct sockopt *sopt)
356 {
357 return 0;
358 }
359
360 void
ip_fw3_state_flush_dispatch(netmsg_t nmsg)361 ip_fw3_state_flush_dispatch(netmsg_t nmsg)
362 {
363 struct ipfw3_state_context *state_ctx = fw3_state_ctx[mycpuid];
364 struct ipfw3_state *s, *tmp;
365
366 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_icmp_in, tmp) {
367 RB_REMOVE(fw3_state_tree, &state_ctx->rb_icmp_in, s);
368 if (s != NULL) {
369 kfree(s, M_IPFW3_STATE);
370 }
371 }
372 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_icmp_out, tmp) {
373 RB_REMOVE(fw3_state_tree, &state_ctx->rb_icmp_out, s);
374 if (s != NULL) {
375 kfree(s, M_IPFW3_STATE);
376 }
377 }
378 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_tcp_in, tmp) {
379 RB_REMOVE(fw3_state_tree, &state_ctx->rb_tcp_in, s);
380 if (s != NULL) {
381 kfree(s, M_IPFW3_STATE);
382 }
383 }
384 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_tcp_out, tmp) {
385 RB_REMOVE(fw3_state_tree, &state_ctx->rb_tcp_out, s);
386 if (s != NULL) {
387 kfree(s, M_IPFW3_STATE);
388 }
389 }
390 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_udp_in, tmp) {
391 RB_REMOVE(fw3_state_tree, &state_ctx->rb_udp_in, s);
392 if (s != NULL) {
393 kfree(s, M_IPFW3_STATE);
394 }
395 }
396 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_udp_out, tmp) {
397 RB_REMOVE(fw3_state_tree, &state_ctx->rb_udp_out, s);
398 if (s != NULL) {
399 kfree(s, M_IPFW3_STATE);
400 }
401 }
402 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
403 }
404
405 void
ip_fw3_state_flush(struct ip_fw * rule)406 ip_fw3_state_flush(struct ip_fw *rule)
407 {
408 struct netmsg_base msg;
409 netmsg_init(&msg, NULL, &curthread->td_msgport, 0,
410 ip_fw3_state_flush_dispatch);
411 netisr_domsg(&msg, 0);
412 }
413
414 int
ip_fw3_ctl_state_flush(struct sockopt * sopt)415 ip_fw3_ctl_state_flush(struct sockopt *sopt)
416 {
417
418 return 0;
419 }
420
421 int
ip_fw3_ctl_state_get(struct sockopt * sopt)422 ip_fw3_ctl_state_get(struct sockopt *sopt)
423 {
424 struct ipfw3_state_context *state_ctx;
425 struct ipfw3_state *s;
426
427 size_t sopt_size, total_len = 0;
428 struct ipfw3_ioc_state *ioc;
429 int ioc_rule_id;
430
431 ioc_rule_id = *((int *)(sopt->sopt_val));
432 sopt_size = sopt->sopt_valsize;
433 ioc = (struct ipfw3_ioc_state *)sopt->sopt_val;
434 /* icmp states only in CPU 0 */
435 int cpu = 0;
436
437 /* icmp states */
438 for (cpu = 0; cpu < ncpus; cpu++) {
439 state_ctx = fw3_state_ctx[cpu];
440 RB_FOREACH(s, fw3_state_tree, &state_ctx->rb_icmp_in) {
441 total_len += LEN_IOC_FW3_STATE;
442 if (total_len > sopt_size)
443 goto nospace;
444 ioc->src_addr.s_addr = ntohl(s->src_addr);
445 ioc->dst_addr.s_addr = ntohl(s->dst_addr);
446 ioc->src_port = ntohs(s->src_port);
447 ioc->dst_port = ntohs(s->dst_port);
448 ioc->cpu_id = cpu;
449 ioc->rule_id = s->stub->rulenum;
450 ioc->proto = IPPROTO_ICMP;
451 ioc->life = s->timestamp +
452 sysctl_var_udp_timeout - time_uptime;
453 ioc++;
454 }
455 RB_FOREACH(s, fw3_state_tree, &state_ctx->rb_icmp_out) {
456 total_len += LEN_IOC_FW3_STATE;
457 if (total_len > sopt_size)
458 goto nospace;
459 ioc->src_addr.s_addr = ntohl(s->src_addr);
460 ioc->dst_addr.s_addr = ntohl(s->dst_addr);
461 ioc->src_port = ntohs(s->src_port);
462 ioc->dst_port = ntohs(s->dst_port);
463 ioc->cpu_id = cpu;
464 ioc->rule_id = s->stub->rulenum;
465 ioc->proto = IPPROTO_ICMP;
466 ioc->life = s->timestamp +
467 sysctl_var_udp_timeout - time_uptime;
468 ioc++;
469 }
470 RB_FOREACH(s, fw3_state_tree, &state_ctx->rb_tcp_in) {
471 total_len += LEN_IOC_FW3_STATE;
472 if (total_len > sopt_size)
473 goto nospace;
474 ioc->src_addr.s_addr = ntohl(s->src_addr);
475 ioc->dst_addr.s_addr = ntohl(s->dst_addr);
476 ioc->src_port = ntohs(s->src_port);
477 ioc->dst_port = ntohs(s->dst_port);
478 ioc->cpu_id = cpu;
479 ioc->rule_id = s->stub->rulenum;
480 ioc->proto = IPPROTO_TCP;
481 ioc->life = s->timestamp +
482 sysctl_var_udp_timeout - time_uptime;
483 ioc++;
484 }
485 RB_FOREACH(s, fw3_state_tree, &state_ctx->rb_tcp_out) {
486 total_len += LEN_IOC_FW3_STATE;
487 if (total_len > sopt_size)
488 goto nospace;
489 ioc->src_addr.s_addr = ntohl(s->src_addr);
490 ioc->dst_addr.s_addr = ntohl(s->dst_addr);
491 ioc->src_port = ntohs(s->src_port);
492 ioc->dst_port = ntohs(s->dst_port);
493 ioc->cpu_id = cpu;
494 ioc->rule_id = s->stub->rulenum;
495 ioc->proto = IPPROTO_TCP;
496 ioc->life = s->timestamp +
497 sysctl_var_udp_timeout - time_uptime;
498 ioc++;
499 }
500 RB_FOREACH(s, fw3_state_tree, &state_ctx->rb_udp_in) {
501 total_len += LEN_IOC_FW3_STATE;
502 if (total_len > sopt_size)
503 goto nospace;
504 ioc->src_addr.s_addr = ntohl(s->src_addr);
505 ioc->dst_addr.s_addr = ntohl(s->dst_addr);
506 ioc->src_port = ntohs(s->src_port);
507 ioc->dst_port = ntohs(s->dst_port);
508 ioc->cpu_id = cpu;
509 ioc->rule_id = s->stub->rulenum;
510 ioc->proto = IPPROTO_UDP;
511 ioc->life = s->timestamp +
512 sysctl_var_udp_timeout - time_uptime;
513 ioc++;
514 }
515 RB_FOREACH(s, fw3_state_tree, &state_ctx->rb_udp_out) {
516 total_len += LEN_IOC_FW3_STATE;
517 if (total_len > sopt_size)
518 goto nospace;
519 ioc->src_addr.s_addr = ntohl(s->src_addr);
520 ioc->dst_addr.s_addr = ntohl(s->dst_addr);
521 ioc->src_port = ntohs(s->src_port);
522 ioc->dst_port = ntohs(s->dst_port);
523 ioc->cpu_id = cpu;
524 ioc->rule_id = s->stub->rulenum;
525 ioc->proto = IPPROTO_UDP;
526 ioc->life = s->timestamp +
527 sysctl_var_udp_timeout - time_uptime;
528 ioc++;
529 }
530 }
531
532 sopt->sopt_valsize = total_len;
533 return 0;
534 nospace:
535 return 0;
536 }
537
538 void
ip_fw3_state_cleanup_dispatch(netmsg_t nmsg)539 ip_fw3_state_cleanup_dispatch(netmsg_t nmsg)
540 {
541
542 struct ipfw3_state_context *state_ctx = fw3_state_ctx[mycpuid];
543 struct ipfw3_state *s, *tmp;
544
545 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_icmp_in, tmp) {
546 if (time_uptime - s->timestamp > sysctl_var_icmp_timeout) {
547 RB_REMOVE(fw3_state_tree, &state_ctx->rb_icmp_in, s);
548 kfree(s, M_IPFW3_STATE);
549 }
550 }
551 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_icmp_out, tmp) {
552 if (time_uptime - s->timestamp > sysctl_var_icmp_timeout) {
553 RB_REMOVE(fw3_state_tree, &state_ctx->rb_icmp_out, s);
554 kfree(s, M_IPFW3_STATE);
555 }
556 }
557 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_tcp_in, tmp) {
558 if (time_uptime - s->timestamp > sysctl_var_tcp_timeout) {
559 RB_REMOVE(fw3_state_tree, &state_ctx->rb_tcp_in, s);
560 kfree(s, M_IPFW3_STATE);
561 }
562 }
563 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_tcp_out, tmp) {
564 if (time_uptime - s->timestamp > sysctl_var_tcp_timeout) {
565 RB_REMOVE(fw3_state_tree, &state_ctx->rb_tcp_out, s);
566 kfree(s, M_IPFW3_STATE);
567 }
568 }
569 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_udp_in, tmp) {
570 if (time_uptime - s->timestamp > sysctl_var_udp_timeout) {
571 RB_REMOVE(fw3_state_tree, &state_ctx->rb_udp_in, s);
572 kfree(s, M_IPFW3_STATE);
573 }
574 }
575 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_udp_out, tmp) {
576 if (time_uptime - s->timestamp > sysctl_var_udp_timeout) {
577 RB_REMOVE(fw3_state_tree, &state_ctx->rb_udp_out, s);
578 kfree(s, M_IPFW3_STATE);
579 }
580 }
581 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1);
582 }
583
584 void
ip_fw3_state_cleanup(void * dummy __unused)585 ip_fw3_state_cleanup(void *dummy __unused)
586 {
587 struct netmsg_base msg;
588 netmsg_init(&msg, NULL, &curthread->td_msgport, 0,
589 ip_fw3_state_cleanup_dispatch);
590 netisr_domsg(&msg, 0);
591
592 callout_reset(&ip_fw3_state_cleanup_callout,
593 sysctl_var_cleanup_interval * hz,
594 ip_fw3_state_cleanup, NULL);
595 }
596
597 int
ip_fw3_ctl_state_sockopt(struct sockopt * sopt)598 ip_fw3_ctl_state_sockopt(struct sockopt *sopt)
599 {
600 int error = 0;
601 switch (sopt->sopt_name) {
602 case IP_FW_STATE_ADD:
603 error = ip_fw3_ctl_state_add(sopt);
604 break;
605 case IP_FW_STATE_DEL:
606 error = ip_fw3_ctl_state_delete(sopt);
607 break;
608 case IP_FW_STATE_FLUSH:
609 error = ip_fw3_ctl_state_flush(sopt);
610 break;
611 case IP_FW_STATE_GET:
612 error = ip_fw3_ctl_state_get(sopt);
613 break;
614 }
615 return error;
616 }
617
618 void
ip_fw3_state_init_dispatch(netmsg_t msg)619 ip_fw3_state_init_dispatch(netmsg_t msg)
620 {
621 struct ipfw3_state_context *tmp;
622
623 tmp = kmalloc(LEN_STATE_CTX, M_IPFW3_STATE, M_WAITOK | M_ZERO);
624 RB_INIT(&tmp->rb_icmp_in);
625 RB_INIT(&tmp->rb_icmp_out);
626 RB_INIT(&tmp->rb_tcp_in);
627 RB_INIT(&tmp->rb_tcp_out);
628 RB_INIT(&tmp->rb_udp_in);
629 RB_INIT(&tmp->rb_udp_out);
630 fw3_state_ctx[mycpuid] = tmp;
631 netisr_forwardmsg_all(&msg->base, mycpuid + 1);
632 }
633
634 void
ip_fw3_state_fini_dispatch(netmsg_t msg)635 ip_fw3_state_fini_dispatch(netmsg_t msg)
636 {
637 struct ipfw3_state_context *state_ctx = fw3_state_ctx[mycpuid];
638 struct ipfw3_state *s, *tmp;
639
640 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_icmp_in, tmp) {
641 RB_REMOVE(fw3_state_tree, &state_ctx->rb_icmp_in, s);
642 if (s != NULL) {
643 kfree(s, M_IPFW3_STATE);
644 }
645 }
646 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_icmp_out, tmp) {
647 RB_REMOVE(fw3_state_tree, &state_ctx->rb_icmp_out, s);
648 if (s != NULL) {
649 kfree(s, M_IPFW3_STATE);
650 }
651 }
652 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_tcp_in, tmp) {
653 RB_REMOVE(fw3_state_tree, &state_ctx->rb_tcp_in, s);
654 if (s != NULL) {
655 kfree(s, M_IPFW3_STATE);
656 }
657 }
658 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_tcp_out, tmp) {
659 RB_REMOVE(fw3_state_tree, &state_ctx->rb_tcp_out, s);
660 if (s != NULL) {
661 kfree(s, M_IPFW3_STATE);
662 }
663 }
664 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_udp_in, tmp) {
665 RB_REMOVE(fw3_state_tree, &state_ctx->rb_udp_in, s);
666 if (s != NULL) {
667 kfree(s, M_IPFW3_STATE);
668 }
669 }
670 RB_FOREACH_SAFE(s, fw3_state_tree, &state_ctx->rb_udp_out, tmp) {
671 RB_REMOVE(fw3_state_tree, &state_ctx->rb_udp_out, s);
672 if (s != NULL) {
673 kfree(s, M_IPFW3_STATE);
674 }
675 }
676 kfree(fw3_state_ctx[mycpuid], M_IPFW3_STATE);
677 fw3_state_ctx[mycpuid] = NULL;
678 netisr_forwardmsg_all(&msg->base, mycpuid + 1);
679 }
680
681
682 void
ip_fw3_state_fini(void)683 ip_fw3_state_fini(void)
684 {
685 struct netmsg_base msg;
686
687 netmsg_init(&msg, NULL, &curthread->td_msgport,
688 0, ip_fw3_state_fini_dispatch);
689
690 netisr_domsg(&msg, 0);
691 callout_stop(&ip_fw3_state_cleanup_callout);
692 }
693
694 void
ip_fw3_state_init(void)695 ip_fw3_state_init(void)
696 {
697 struct netmsg_base msg;
698
699 ip_fw3_ctl_state_ptr = ip_fw3_ctl_state_sockopt;
700 callout_init_mp(&ip_fw3_state_cleanup_callout);
701 callout_reset(&ip_fw3_state_cleanup_callout,
702 sysctl_var_cleanup_interval * hz,
703 ip_fw3_state_cleanup,
704 NULL);
705 netmsg_init(&msg, NULL, &curthread->td_msgport,
706 0, ip_fw3_state_init_dispatch);
707 netisr_domsg(&msg, 0);
708 }
709
710
711 void
ip_fw3_state_modevent(int type)712 ip_fw3_state_modevent(int type)
713 {
714 switch (type) {
715 case MOD_LOAD:
716 ip_fw3_state_init();
717 break;
718 case MOD_UNLOAD:
719 ip_fw3_state_fini();
720 break;
721 }
722 }
723
724