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