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 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 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 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 337 ip_fw3_state_append_dispatch(netmsg_t nmsg) 338 { 339 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 340 } 341 342 void 343 ip_fw3_state_delete_dispatch(netmsg_t nmsg) 344 { 345 netisr_forwardmsg_all(&nmsg->base, mycpuid + 1); 346 } 347 348 int 349 ip_fw3_ctl_state_add(struct sockopt *sopt) 350 { 351 return 0; 352 } 353 354 int 355 ip_fw3_ctl_state_delete(struct sockopt *sopt) 356 { 357 return 0; 358 } 359 360 void 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 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 415 ip_fw3_ctl_state_flush(struct sockopt *sopt) 416 { 417 418 return 0; 419 } 420 421 int 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 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 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 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 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 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 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 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 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