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