xref: /dragonfly/sys/net/ipfw3_basic/ip_fw3_state.c (revision de23f38f21494eb3a357ccaa7bbb4099ffea223a)
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