1 /* 2 * Copyright (c) 2014 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Bill Yuan <bycn82@gmail.com> 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/syslog.h> 42 #include <sys/systimer.h> 43 #include <sys/thread2.h> 44 #include <sys/in_cksum.h> 45 46 #include <net/if.h> 47 #include <net/ethernet.h> 48 #include <net/netmsg2.h> 49 #include <net/netisr2.h> 50 #include <net/route.h> 51 52 #include <netinet/ip.h> 53 #include <netinet/in.h> 54 #include <netinet/in_systm.h> 55 #include <netinet/in_var.h> 56 #include <netinet/in_pcb.h> 57 #include <netinet/ip_var.h> 58 #include <netinet/ip_icmp.h> 59 #include <netinet/tcp.h> 60 #include <netinet/tcp_timer.h> 61 #include <netinet/tcp_var.h> 62 #include <netinet/tcpip.h> 63 #include <netinet/udp.h> 64 #include <netinet/udp_var.h> 65 #include <netinet/ip_divert.h> 66 #include <netinet/if_ether.h> 67 68 #include <net/ipfw3/ip_fw.h> 69 70 #include "ip_fw3_basic.h" 71 72 #define TIME_LEQ(a, b) ((int)((a) - (b)) <= 0) 73 74 extern struct ipfw_context *ipfw_ctx[MAXCPU]; 75 extern int fw_verbose; 76 extern ipfw_basic_delete_state_t *ipfw_basic_flush_state_prt; 77 extern ipfw_basic_append_state_t *ipfw_basic_append_state_prt; 78 79 static int ip_fw_basic_loaded; 80 static struct netmsg_base ipfw_timeout_netmsg; /* schedule ipfw timeout */ 81 static struct callout ipfw_tick_callout; 82 static int state_lifetime = 20; 83 static int state_expiry_check_interval = 10; 84 static int state_count_max = 4096; 85 static int state_hash_size_old = 0; 86 static int state_hash_size = 4096; 87 88 89 static int ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS); 90 void adjust_hash_size_dispatch(netmsg_t nmsg); 91 92 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw_basic, 93 CTLFLAG_RW, 0, "Firewall Basic"); 94 SYSCTL_PROC(_net_inet_ip_fw_basic, OID_AUTO, state_hash_size, 95 CTLTYPE_INT | CTLFLAG_RW, &state_hash_size, 0, 96 ipfw_sysctl_adjust_hash_size, "I", "Adjust hash size"); 97 98 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_lifetime, CTLFLAG_RW, 99 &state_lifetime, 0, "default life time"); 100 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, 101 state_expiry_check_interval, CTLFLAG_RW, 102 &state_expiry_check_interval, 0, 103 "default state expiry check interval"); 104 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_count_max, CTLFLAG_RW, 105 &state_count_max, 0, "maximum of state"); 106 107 static int 108 ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS) 109 { 110 int error, value = 0; 111 112 state_hash_size_old = state_hash_size; 113 value = state_hash_size; 114 error = sysctl_handle_int(oidp, &value, 0, req); 115 if (error || !req->newptr) { 116 goto back; 117 } 118 /* 119 * Make sure we have a power of 2 and 120 * do not allow more than 64k entries. 121 */ 122 error = EINVAL; 123 if (value <= 1 || value > 65536) { 124 goto back; 125 } 126 if ((value & (value - 1)) != 0) { 127 goto back; 128 } 129 130 error = 0; 131 if (state_hash_size != value) { 132 state_hash_size = value; 133 134 struct netmsg_base *msg, the_msg; 135 msg = &the_msg; 136 bzero(msg,sizeof(struct netmsg_base)); 137 138 netmsg_init(msg, NULL, &curthread->td_msgport, 139 0, adjust_hash_size_dispatch); 140 ifnet_domsg(&msg->lmsg, 0); 141 } 142 back: 143 return error; 144 } 145 146 void 147 adjust_hash_size_dispatch(netmsg_t nmsg) 148 { 149 struct ipfw_state_context *state_ctx; 150 struct ip_fw_state *the_state, *state; 151 struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 152 int i; 153 154 for (i = 0; i < state_hash_size_old; i++) { 155 state_ctx = &ctx->state_ctx[i]; 156 if (state_ctx != NULL) { 157 state = state_ctx->state; 158 while (state != NULL) { 159 the_state = state; 160 state = state->next; 161 kfree(the_state, M_IPFW3_BASIC); 162 the_state = NULL; 163 } 164 } 165 } 166 kfree(ctx->state_ctx,M_IPFW3_BASIC); 167 ctx->state_ctx = kmalloc(state_hash_size * 168 sizeof(struct ipfw_state_context), 169 M_IPFW3_BASIC, M_WAITOK | M_ZERO); 170 ctx->state_hash_size = state_hash_size; 171 ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1); 172 } 173 174 175 /* prototype of the checker functions */ 176 void check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 177 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 178 void check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 179 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 180 void check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 181 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 182 void check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 183 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 184 185 void check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 186 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 187 void check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 188 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 189 void check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 190 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 191 void check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 192 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 193 void check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 194 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 195 void check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 196 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 197 void check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 198 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 199 void check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 200 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 201 void check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 202 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 203 void check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 204 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 205 void check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 206 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 207 void check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 208 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 209 void check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 210 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 211 void check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 212 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 213 void check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 214 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 215 216 /* prototype of the utility functions */ 217 static struct ip_fw *lookup_next_rule(struct ip_fw *me); 218 static int iface_match(struct ifnet *ifp, ipfw_insn_if *cmd); 219 static __inline int hash_packet(struct ipfw_flow_id *id); 220 221 static __inline int 222 hash_packet(struct ipfw_flow_id *id) 223 { 224 uint32_t i; 225 i = (id->proto) ^ (id->dst_ip) ^ (id->src_ip) ^ 226 (id->dst_port) ^ (id->src_port); 227 i &= state_hash_size - 1; 228 return i; 229 } 230 231 static struct ip_fw * 232 lookup_next_rule(struct ip_fw *me) 233 { 234 struct ip_fw *rule = NULL; 235 ipfw_insn *cmd; 236 237 /* look for action, in case it is a skipto */ 238 cmd = ACTION_PTR(me); 239 if ((int)cmd->module == MODULE_BASIC_ID && 240 (int)cmd->opcode == O_BASIC_SKIPTO) { 241 for (rule = me->next; rule; rule = rule->next) { 242 if (rule->rulenum >= cmd->arg1) 243 break; 244 } 245 } 246 if (rule == NULL) /* failure or not a skipto */ 247 rule = me->next; 248 249 me->next_rule = rule; 250 return rule; 251 } 252 253 /* 254 * when all = 1, it will check all the state_ctx 255 */ 256 static struct ip_fw_state * 257 lookup_state(struct ip_fw_args *args, ipfw_insn *cmd, int *limited, int all) 258 { 259 struct ip_fw_state *state = NULL; 260 struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 261 struct ipfw_state_context *state_ctx; 262 int start, end, i, count = 0; 263 264 if (all && cmd->arg1) { 265 start = 0; 266 end = state_hash_size - 1; 267 } else { 268 start = hash_packet(&args->f_id); 269 end = hash_packet(&args->f_id); 270 } 271 for (i = start; i <= end; i++) { 272 state_ctx = &ctx->state_ctx[i]; 273 if (state_ctx != NULL) { 274 state = state_ctx->state; 275 struct ipfw_flow_id *fid = &args->f_id; 276 while (state != NULL) { 277 if (cmd->arg1) { 278 if ((cmd->arg3 == 1 && 279 fid->src_ip == 280 state->flow_id.src_ip) || 281 (cmd->arg3 == 2 && 282 fid->src_port == 283 state->flow_id.src_port) || 284 (cmd->arg3 == 3 && 285 fid->dst_ip == 286 state->flow_id.dst_ip) || 287 (cmd->arg3 == 4 && 288 fid->dst_port == 289 state->flow_id.dst_port)) { 290 291 count++; 292 if (count >= cmd->arg1) { 293 *limited = 1; 294 goto done; 295 } 296 } 297 } 298 299 if (fid->proto == state->flow_id.proto) { 300 if (fid->src_ip == 301 state->flow_id.src_ip && 302 fid->dst_ip == 303 state->flow_id.dst_ip && 304 (fid->src_port == 305 state->flow_id.src_port || 306 state->flow_id.src_port == 0) && 307 (fid->dst_port == 308 state->flow_id.dst_port || 309 state->flow_id.dst_port == 0)) { 310 goto done; 311 } 312 if (fid->src_ip == 313 state->flow_id.dst_ip && 314 fid->dst_ip == 315 state->flow_id.src_ip && 316 (fid->src_port == 317 state->flow_id.dst_port || 318 state->flow_id.dst_port == 0) && 319 (fid->dst_port == 320 state->flow_id.src_port || 321 state->flow_id.src_port == 0)) { 322 goto done; 323 } 324 } 325 state = state->next; 326 } 327 } 328 } 329 done: 330 return state; 331 } 332 333 static struct ip_fw_state * 334 install_state(struct ip_fw *rule, ipfw_insn *cmd, struct ip_fw_args *args) 335 { 336 struct ip_fw_state *state; 337 struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 338 struct ipfw_state_context *state_ctx; 339 state_ctx = &ctx->state_ctx[hash_packet(&args->f_id)]; 340 state = kmalloc(sizeof(struct ip_fw_state), 341 M_IPFW3_BASIC, M_NOWAIT | M_ZERO); 342 if (state == NULL) { 343 return NULL; 344 } 345 state->stub = rule; 346 state->lifetime = cmd->arg2 == 0 ? state_lifetime : cmd->arg2 ; 347 state->timestamp = time_second; 348 state->expiry = 0; 349 bcopy(&args->f_id,&state->flow_id,sizeof(struct ipfw_flow_id)); 350 //append the state into the state chian 351 if (state_ctx->last != NULL) 352 state_ctx->last->next = state; 353 else 354 state_ctx->state = state; 355 state_ctx->last = state; 356 state_ctx->count++; 357 return state; 358 } 359 360 361 static int 362 iface_match(struct ifnet *ifp, ipfw_insn_if *cmd) 363 { 364 if (ifp == NULL) /* no iface with this packet, match fails */ 365 return 0; 366 367 /* Check by name or by IP address */ 368 if (cmd->name[0] != '\0') { /* match by name */ 369 /* Check name */ 370 if (cmd->p.glob) { 371 if (kfnmatch(cmd->name, ifp->if_xname, 0) == 0) 372 return(1); 373 } else { 374 if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0) 375 return(1); 376 } 377 } else { 378 struct ifaddr_container *ifac; 379 380 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) { 381 struct ifaddr *ia = ifac->ifa; 382 383 if (ia->ifa_addr == NULL) 384 continue; 385 if (ia->ifa_addr->sa_family != AF_INET) 386 continue; 387 if (cmd->p.ip.s_addr == 388 ((struct sockaddr_in *) 389 (ia->ifa_addr))->sin_addr.s_addr) 390 return(1); /* match */ 391 392 } 393 } 394 return 0; /* no match, fail ... */ 395 } 396 397 /* implimentation of the checker functions */ 398 void 399 check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 400 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 401 { 402 (*f)->pcnt++; 403 (*f)->bcnt += ip_len; 404 (*f)->timestamp = time_second; 405 *cmd_ctl = IP_FW_CTL_NEXT; 406 } 407 408 void 409 check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 410 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 411 { 412 (*f)->pcnt++; 413 (*f)->bcnt += ip_len; 414 (*f)->timestamp = time_second; 415 if ((*f)->next_rule == NULL) 416 lookup_next_rule(*f); 417 418 *cmd_ctl = IP_FW_CTL_AGAIN; 419 } 420 421 void 422 check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 423 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 424 { 425 struct sockaddr_in *sin, *sa; 426 struct m_tag *mtag; 427 428 if ((*args)->eh) { /* not valid on layer2 pkts */ 429 *cmd_ctl=IP_FW_CTL_NEXT; 430 return; 431 } 432 433 (*f)->pcnt++; 434 (*f)->bcnt += ip_len; 435 (*f)->timestamp = time_second; 436 if ((*f)->next_rule == NULL) 437 lookup_next_rule(*f); 438 439 mtag = m_tag_get(PACKET_TAG_IPFORWARD, 440 sizeof(*sin), M_NOWAIT); 441 if (mtag == NULL) { 442 *cmd_val = IP_FW_DENY; 443 *cmd_ctl = IP_FW_CTL_DONE; 444 return; 445 } 446 sin = m_tag_data(mtag); 447 sa = &((ipfw_insn_sa *)cmd)->sa; 448 /* arg3: count of the dest, arg1: type of fwd */ 449 int i = 0; 450 if(cmd->arg3 > 1) { 451 if (cmd->arg1 == 0) { /* type: random */ 452 i = krandom() % cmd->arg3; 453 } else if (cmd->arg1 == 1) { /* type: round-robin */ 454 i = cmd->arg2++ % cmd->arg3; 455 } else if (cmd->arg1 == 2) { /* type: sticky */ 456 struct ip *ip = mtod((*args)->m, struct ip *); 457 i = ip->ip_src.s_addr & (cmd->arg3 - 1); 458 } 459 sa += i; 460 } 461 *sin = *sa; /* apply the destination */ 462 m_tag_prepend((*args)->m, mtag); 463 (*args)->m->m_pkthdr.fw_flags |= IPFORWARD_MBUF_TAGGED; 464 (*args)->m->m_pkthdr.fw_flags &= ~BRIDGE_MBUF_TAGGED; 465 *cmd_ctl = IP_FW_CTL_DONE; 466 *cmd_val = IP_FW_PASS; 467 } 468 469 void 470 check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 471 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 472 { 473 struct ip_fw_state *state=NULL; 474 int limited = 0 ; 475 state = lookup_state(*args, cmd, &limited, 0); 476 if (state != NULL) { 477 state->pcnt++; 478 state->bcnt += ip_len; 479 state->timestamp = time_second; 480 (*f)->pcnt++; 481 (*f)->bcnt += ip_len; 482 (*f)->timestamp = time_second; 483 *f = state->stub; 484 *cmd_ctl = IP_FW_CTL_CHK_STATE; 485 } else { 486 *cmd_ctl = IP_FW_CTL_NEXT; 487 } 488 } 489 490 void 491 check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 492 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 493 { 494 *cmd_ctl = IP_FW_CTL_NO; 495 *cmd_val = ((*args)->oif == NULL); 496 } 497 498 void 499 check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 500 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 501 { 502 *cmd_ctl = IP_FW_CTL_NO; 503 *cmd_val = ((*args)->oif != NULL); 504 } 505 506 void 507 check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 508 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 509 { 510 *cmd_ctl = IP_FW_CTL_NO; 511 *cmd_val = iface_match((*args)->oif ? 512 (*args)->oif : (*args)->m->m_pkthdr.rcvif, 513 (ipfw_insn_if *)cmd); 514 } 515 516 void 517 check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 518 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 519 { 520 *cmd_ctl = IP_FW_CTL_NO; 521 *cmd_val = ((*args)->f_id.proto == cmd->arg1); 522 } 523 524 void 525 check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 526 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 527 { 528 *cmd_ctl = IP_FW_CTL_NO; 529 *cmd_val = (krandom() % 100) < cmd->arg1; 530 } 531 532 void 533 check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 534 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 535 { 536 struct in_addr src_ip; 537 u_int hlen = 0; 538 struct mbuf *m = (*args)->m; 539 struct ip *ip = mtod(m, struct ip *); 540 src_ip = ip->ip_src; 541 if ((*args)->eh == NULL || 542 (m->m_pkthdr.len >= sizeof(struct ip) && 543 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 544 hlen = ip->ip_hl << 2; 545 } 546 *cmd_val = (hlen > 0 && 547 ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr); 548 *cmd_ctl = IP_FW_CTL_NO; 549 } 550 551 void 552 check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 553 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 554 { 555 struct in_addr src_ip; 556 u_int hlen = 0; 557 struct mbuf *m = (*args)->m; 558 struct ip *ip = mtod(m, struct ip *); 559 src_ip = ip->ip_src; 560 if ((*args)->eh == NULL || 561 (m->m_pkthdr.len >= sizeof(struct ip) && 562 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 563 hlen = ip->ip_hl << 2; 564 } 565 *cmd_ctl = IP_FW_CTL_NO; 566 if (hlen > 0) { 567 struct ifnet *tif; 568 tif = INADDR_TO_IFP(&src_ip); 569 *cmd_val = (tif != NULL); 570 } else { 571 *cmd_val = IP_FW_NOT_MATCH; 572 } 573 } 574 575 void 576 check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 577 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 578 { 579 struct in_addr src_ip; 580 u_int hlen = 0; 581 struct mbuf *m = (*args)->m; 582 struct ip *ip = mtod(m, struct ip *); 583 src_ip = ip->ip_src; 584 if ((*args)->eh == NULL || 585 (m->m_pkthdr.len >= sizeof(struct ip) && 586 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 587 hlen = ip->ip_hl << 2; 588 } 589 590 *cmd_ctl = IP_FW_CTL_NO; 591 *cmd_val = (hlen > 0 && 592 ((ipfw_insn_ip *)cmd)->addr.s_addr == 593 (src_ip.s_addr & 594 ((ipfw_insn_ip *)cmd)->mask.s_addr)); 595 } 596 597 void 598 check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 599 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 600 { 601 struct in_addr dst_ip; 602 u_int hlen = 0; 603 struct mbuf *m = (*args)->m; 604 struct ip *ip = mtod(m, struct ip *); 605 dst_ip = ip->ip_dst; 606 if ((*args)->eh == NULL || 607 (m->m_pkthdr.len >= sizeof(struct ip) && 608 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 609 hlen = ip->ip_hl << 2; 610 } 611 *cmd_val = (hlen > 0 && 612 ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr); 613 *cmd_ctl = IP_FW_CTL_NO; 614 } 615 616 void 617 check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 618 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 619 { 620 struct in_addr dst_ip; 621 u_int hlen = 0; 622 struct mbuf *m = (*args)->m; 623 struct ip *ip = mtod(m, struct ip *); 624 dst_ip = ip->ip_src; 625 if ((*args)->eh == NULL || 626 (m->m_pkthdr.len >= sizeof(struct ip) && 627 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 628 hlen = ip->ip_hl << 2; 629 } 630 *cmd_ctl = IP_FW_CTL_NO; 631 if (hlen > 0) { 632 struct ifnet *tif; 633 tif = INADDR_TO_IFP(&dst_ip); 634 *cmd_val = (tif != NULL); 635 } else { 636 *cmd_val = IP_FW_NOT_MATCH; 637 } 638 } 639 640 void 641 check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 642 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 643 { 644 struct in_addr dst_ip; 645 u_int hlen = 0; 646 struct mbuf *m = (*args)->m; 647 struct ip *ip = mtod(m, struct ip *); 648 dst_ip = ip->ip_src; 649 if ((*args)->eh == NULL || 650 (m->m_pkthdr.len >= sizeof(struct ip) && 651 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 652 hlen = ip->ip_hl << 2; 653 } 654 655 *cmd_ctl = IP_FW_CTL_NO; 656 *cmd_val = (hlen > 0 && 657 ((ipfw_insn_ip *)cmd)->addr.s_addr == 658 (dst_ip.s_addr & 659 ((ipfw_insn_ip *)cmd)->mask.s_addr)); 660 } 661 662 void 663 check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 664 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 665 { 666 struct ip_fw_state *state; 667 int limited = 0; 668 669 *cmd_ctl = IP_FW_CTL_NO; 670 state = lookup_state(*args, cmd, &limited, 1); 671 if (limited == 1) { 672 *cmd_val = IP_FW_NOT_MATCH; 673 } else { 674 if (state == NULL) 675 state = install_state(*f, cmd, *args); 676 677 if (state != NULL) { 678 state->pcnt++; 679 state->bcnt += ip_len; 680 state->timestamp = time_second; 681 *cmd_val = IP_FW_MATCH; 682 } else { 683 *cmd_val = IP_FW_NOT_MATCH; 684 } 685 } 686 } 687 688 void 689 check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 690 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 691 { 692 struct m_tag *mtag = m_tag_locate((*args)->m, 693 MTAG_IPFW, cmd->arg1, NULL); 694 if (mtag == NULL) { 695 mtag = m_tag_alloc(MTAG_IPFW,cmd->arg1, 0, M_NOWAIT); 696 if (mtag != NULL) 697 m_tag_prepend((*args)->m, mtag); 698 699 } 700 (*f)->pcnt++; 701 (*f)->bcnt += ip_len; 702 (*f)->timestamp = time_second; 703 *cmd_ctl = IP_FW_CTL_NEXT; 704 } 705 706 void 707 check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 708 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 709 { 710 struct m_tag *mtag = m_tag_locate((*args)->m, 711 MTAG_IPFW, cmd->arg1, NULL); 712 if (mtag != NULL) 713 m_tag_delete((*args)->m, mtag); 714 715 (*f)->pcnt++; 716 (*f)->bcnt += ip_len; 717 (*f)->timestamp = time_second; 718 *cmd_ctl = IP_FW_CTL_NEXT; 719 } 720 721 void 722 check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 723 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 724 { 725 *cmd_ctl = IP_FW_CTL_NO; 726 if (m_tag_locate( (*args)->m, MTAG_IPFW,cmd->arg1, NULL) != NULL ) 727 *cmd_val = IP_FW_MATCH; 728 else 729 *cmd_val = IP_FW_NOT_MATCH; 730 } 731 732 static void 733 ipfw_basic_add_state(struct ipfw_ioc_state *ioc_state) 734 { 735 struct ip_fw_state *state; 736 struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 737 struct ipfw_state_context *state_ctx; 738 state_ctx = &ctx->state_ctx[hash_packet(&(ioc_state->flow_id))]; 739 state = kmalloc(sizeof(struct ip_fw_state), 740 M_IPFW3_BASIC, M_WAITOK | M_ZERO); 741 struct ip_fw *rule = ctx->ipfw_rule_chain; 742 while (rule != NULL) { 743 if (rule->rulenum == ioc_state->rulenum) { 744 break; 745 } 746 rule = rule->next; 747 } 748 if (rule == NULL) 749 return; 750 751 state->stub = rule; 752 753 state->lifetime = ioc_state->lifetime == 0 ? 754 state_lifetime : ioc_state->lifetime ; 755 state->timestamp = time_second; 756 state->expiry = ioc_state->expiry; 757 bcopy(&ioc_state->flow_id, &state->flow_id, 758 sizeof(struct ipfw_flow_id)); 759 //append the state into the state chian 760 if (state_ctx->last != NULL) 761 state_ctx->last->next = state; 762 else 763 state_ctx->state = state; 764 765 state_ctx->last = state; 766 state_ctx->count++; 767 } 768 769 /* 770 * if rule is NULL 771 * flush all states 772 * else 773 * flush states which stub is the rule 774 */ 775 static void 776 ipfw_basic_flush_state(struct ip_fw *rule) 777 { 778 struct ipfw_state_context *state_ctx; 779 struct ip_fw_state *state,*the_state, *prev_state; 780 struct ipfw_context *ctx; 781 int i; 782 783 ctx = ipfw_ctx[mycpuid]; 784 for (i = 0; i < state_hash_size; i++) { 785 state_ctx = &ctx->state_ctx[i]; 786 if (state_ctx != NULL) { 787 state = state_ctx->state; 788 prev_state = NULL; 789 while (state != NULL) { 790 if (rule != NULL && state->stub != rule) { 791 prev_state = state; 792 state = state->next; 793 } else { 794 if (prev_state == NULL) 795 state_ctx->state = state->next; 796 else 797 prev_state->next = state->next; 798 799 the_state = state; 800 state = state->next; 801 kfree(the_state, M_IPFW3_BASIC); 802 state_ctx->count--; 803 if (state == NULL) 804 state_ctx->last = prev_state; 805 806 } 807 } 808 } 809 } 810 } 811 812 /* 813 * clean up expired state in every tick 814 */ 815 static void 816 ipfw_cleanup_expired_state(netmsg_t nmsg) 817 { 818 struct ip_fw_state *state,*the_state,*prev_state; 819 struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 820 struct ipfw_state_context *state_ctx; 821 int i; 822 823 for (i = 0; i < state_hash_size; i++) { 824 prev_state = NULL; 825 state_ctx = &(ctx->state_ctx[i]); 826 if (ctx->state_ctx != NULL) { 827 state = state_ctx->state; 828 while (state != NULL) { 829 if (IS_EXPIRED(state)) { 830 if (prev_state == NULL) 831 state_ctx->state = state->next; 832 else 833 prev_state->next = state->next; 834 835 the_state =state; 836 state = state->next; 837 838 if (the_state == state_ctx->last) 839 state_ctx->last = NULL; 840 841 842 kfree(the_state, M_IPFW3_BASIC); 843 state_ctx->count--; 844 } else { 845 prev_state = state; 846 state = state->next; 847 } 848 } 849 } 850 } 851 ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1); 852 } 853 854 static void 855 ipfw_tick(void *dummy __unused) 856 { 857 struct lwkt_msg *lmsg = &ipfw_timeout_netmsg.lmsg; 858 KKASSERT(mycpuid == IPFW_CFGCPUID); 859 860 crit_enter(); 861 KKASSERT(lmsg->ms_flags & MSGF_DONE); 862 if (IPFW_BASIC_LOADED) { 863 lwkt_sendmsg_oncpu(IPFW_CFGPORT, lmsg); 864 /* ipfw_timeout_netmsg's handler reset this callout */ 865 } 866 crit_exit(); 867 868 struct netmsg_base *msg; 869 struct netmsg_base the_msg; 870 msg = &the_msg; 871 bzero(msg,sizeof(struct netmsg_base)); 872 873 netmsg_init(msg, NULL, &curthread->td_msgport, 0, 874 ipfw_cleanup_expired_state); 875 ifnet_domsg(&msg->lmsg, 0); 876 } 877 878 static void 879 ipfw_tick_dispatch(netmsg_t nmsg) 880 { 881 IPFW_ASSERT_CFGPORT(&curthread->td_msgport); 882 KKASSERT(IPFW_BASIC_LOADED); 883 884 /* Reply ASAP */ 885 crit_enter(); 886 lwkt_replymsg(&nmsg->lmsg, 0); 887 crit_exit(); 888 889 callout_reset(&ipfw_tick_callout, 890 state_expiry_check_interval * hz, ipfw_tick, NULL); 891 } 892 893 static void 894 ipfw_basic_init_dispatch(netmsg_t nmsg) 895 { 896 IPFW_ASSERT_CFGPORT(&curthread->td_msgport); 897 KKASSERT(IPFW3_LOADED); 898 899 int error = 0; 900 callout_init_mp(&ipfw_tick_callout); 901 netmsg_init(&ipfw_timeout_netmsg, NULL, &netisr_adone_rport, 902 MSGF_DROPABLE | MSGF_PRIORITY, ipfw_tick_dispatch); 903 callout_reset(&ipfw_tick_callout, 904 state_expiry_check_interval * hz, ipfw_tick, NULL); 905 lwkt_replymsg(&nmsg->lmsg, error); 906 ip_fw_basic_loaded=1; 907 } 908 909 static int 910 ipfw_basic_init(void) 911 { 912 ipfw_basic_flush_state_prt = ipfw_basic_flush_state; 913 ipfw_basic_append_state_prt = ipfw_basic_add_state; 914 915 register_ipfw_module(MODULE_BASIC_ID, MODULE_BASIC_NAME); 916 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_COUNT, 917 (filter_func)check_count); 918 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_SKIPTO, 919 (filter_func)check_skipto); 920 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_FORWARD, 921 (filter_func)check_forward); 922 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_KEEP_STATE, 923 (filter_func)check_keep_state); 924 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_CHECK_STATE, 925 (filter_func)check_check_state); 926 927 register_ipfw_filter_funcs(MODULE_BASIC_ID, 928 O_BASIC_IN, (filter_func)check_in); 929 register_ipfw_filter_funcs(MODULE_BASIC_ID, 930 O_BASIC_OUT, (filter_func)check_out); 931 register_ipfw_filter_funcs(MODULE_BASIC_ID, 932 O_BASIC_VIA, (filter_func)check_via); 933 register_ipfw_filter_funcs(MODULE_BASIC_ID, 934 O_BASIC_XMIT, (filter_func)check_via); 935 register_ipfw_filter_funcs(MODULE_BASIC_ID, 936 O_BASIC_RECV, (filter_func)check_via); 937 938 register_ipfw_filter_funcs(MODULE_BASIC_ID, 939 O_BASIC_PROTO, (filter_func)check_proto); 940 register_ipfw_filter_funcs(MODULE_BASIC_ID, 941 O_BASIC_PROB, (filter_func)check_prob); 942 register_ipfw_filter_funcs(MODULE_BASIC_ID, 943 O_BASIC_IP_SRC, (filter_func)check_from); 944 register_ipfw_filter_funcs(MODULE_BASIC_ID, 945 O_BASIC_IP_SRC_ME, (filter_func)check_from_me); 946 register_ipfw_filter_funcs(MODULE_BASIC_ID, 947 O_BASIC_IP_SRC_MASK, (filter_func)check_from_mask); 948 register_ipfw_filter_funcs(MODULE_BASIC_ID, 949 O_BASIC_IP_DST, (filter_func)check_to); 950 register_ipfw_filter_funcs(MODULE_BASIC_ID, 951 O_BASIC_IP_DST_ME, (filter_func)check_to_me); 952 register_ipfw_filter_funcs(MODULE_BASIC_ID, 953 O_BASIC_IP_DST_MASK, (filter_func)check_to_mask); 954 register_ipfw_filter_funcs(MODULE_BASIC_ID, 955 O_BASIC_TAG, (filter_func)check_tag); 956 register_ipfw_filter_funcs(MODULE_BASIC_ID, 957 O_BASIC_UNTAG, (filter_func)check_untag); 958 register_ipfw_filter_funcs(MODULE_BASIC_ID, 959 O_BASIC_TAGGED, (filter_func)check_tagged); 960 961 int cpu; 962 struct ipfw_context *ctx; 963 964 for (cpu = 0; cpu < ncpus; cpu++) { 965 ctx = ipfw_ctx[cpu]; 966 if (ctx != NULL) { 967 ctx->state_ctx = kmalloc(state_hash_size * 968 sizeof(struct ipfw_state_context), 969 M_IPFW3_BASIC, M_WAITOK | M_ZERO); 970 ctx->state_hash_size = state_hash_size; 971 } 972 } 973 974 struct netmsg_base smsg; 975 netmsg_init(&smsg, NULL, &curthread->td_msgport, 976 0, ipfw_basic_init_dispatch); 977 lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0); 978 return 0; 979 } 980 981 static void 982 ipfw_basic_stop_dispatch(netmsg_t nmsg) 983 { 984 IPFW_ASSERT_CFGPORT(&curthread->td_msgport); 985 KKASSERT(IPFW3_LOADED); 986 int error = 0; 987 callout_stop(&ipfw_tick_callout); 988 netmsg_service_sync(); 989 crit_enter(); 990 lwkt_dropmsg(&ipfw_timeout_netmsg.lmsg); 991 crit_exit(); 992 lwkt_replymsg(&nmsg->lmsg, error); 993 ip_fw_basic_loaded=0; 994 } 995 996 static int 997 ipfw_basic_stop(void) 998 { 999 int cpu,i; 1000 struct ipfw_state_context *state_ctx; 1001 struct ip_fw_state *state,*the_state; 1002 struct ipfw_context *ctx; 1003 if (unregister_ipfw_module(MODULE_BASIC_ID) ==0 ) { 1004 ipfw_basic_flush_state_prt = NULL; 1005 ipfw_basic_append_state_prt = NULL; 1006 1007 for (cpu = 0; cpu < ncpus; cpu++) { 1008 ctx = ipfw_ctx[cpu]; 1009 if (ctx != NULL) { 1010 for (i = 0; i < state_hash_size; i++) { 1011 state_ctx = &ctx->state_ctx[i]; 1012 if (state_ctx != NULL) { 1013 state = state_ctx->state; 1014 while (state != NULL) { 1015 the_state = state; 1016 state = state->next; 1017 if (the_state == 1018 state_ctx->last) 1019 state_ctx->last = NULL; 1020 1021 kfree(the_state, 1022 M_IPFW3_BASIC); 1023 } 1024 } 1025 } 1026 ctx->state_hash_size = 0; 1027 kfree(ctx->state_ctx, M_IPFW3_BASIC); 1028 ctx->state_ctx = NULL; 1029 } 1030 } 1031 struct netmsg_base smsg; 1032 netmsg_init(&smsg, NULL, &curthread->td_msgport, 1033 0, ipfw_basic_stop_dispatch); 1034 return lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0); 1035 } 1036 return 1; 1037 } 1038 1039 1040 static int 1041 ipfw3_basic_modevent(module_t mod, int type, void *data) 1042 { 1043 int err; 1044 switch (type) { 1045 case MOD_LOAD: 1046 err = ipfw_basic_init(); 1047 break; 1048 case MOD_UNLOAD: 1049 err = ipfw_basic_stop(); 1050 break; 1051 default: 1052 err = 1; 1053 } 1054 return err; 1055 } 1056 1057 static moduledata_t ipfw3_basic_mod = { 1058 "ipfw3_basic", 1059 ipfw3_basic_modevent, 1060 NULL 1061 }; 1062 DECLARE_MODULE(ipfw3_basic, ipfw3_basic_mod, SI_SUB_PROTO_END, SI_ORDER_ANY); 1063 MODULE_DEPEND(ipfw3_basic, ipfw3, 1, 1, 1); 1064 MODULE_VERSION(ipfw3_basic, 1); 1065