16a03354eSMatthew Dillon /* 26a03354eSMatthew Dillon * Copyright (c) 2014 The DragonFly Project. All rights reserved. 36a03354eSMatthew Dillon * 46a03354eSMatthew Dillon * This code is derived from software contributed to The DragonFly Project 56a03354eSMatthew Dillon * by Bill Yuan <bycn82@gmail.com> 66a03354eSMatthew Dillon * 76a03354eSMatthew Dillon * Redistribution and use in source and binary forms, with or without 86a03354eSMatthew Dillon * modification, are permitted provided that the following conditions 96a03354eSMatthew Dillon * are met: 106a03354eSMatthew Dillon * 116a03354eSMatthew Dillon * 1. Redistributions of source code must retain the above copyright 126a03354eSMatthew Dillon * notice, this list of conditions and the following disclaimer. 136a03354eSMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 146a03354eSMatthew Dillon * notice, this list of conditions and the following disclaimer in 156a03354eSMatthew Dillon * the documentation and/or other materials provided with the 166a03354eSMatthew Dillon * distribution. 176a03354eSMatthew Dillon * 3. Neither the name of The DragonFly Project nor the names of its 186a03354eSMatthew Dillon * contributors may be used to endorse or promote products derived 196a03354eSMatthew Dillon * from this software without specific, prior written permission. 206a03354eSMatthew Dillon * 216a03354eSMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 226a03354eSMatthew Dillon * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 236a03354eSMatthew Dillon * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 246a03354eSMatthew Dillon * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 256a03354eSMatthew Dillon * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 266a03354eSMatthew Dillon * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 276a03354eSMatthew Dillon * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 286a03354eSMatthew Dillon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 296a03354eSMatthew Dillon * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 306a03354eSMatthew Dillon * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 316a03354eSMatthew Dillon * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 326a03354eSMatthew Dillon * SUCH DAMAGE. 336a03354eSMatthew Dillon */ 346a03354eSMatthew Dillon 356a03354eSMatthew Dillon #include <sys/param.h> 366a03354eSMatthew Dillon #include <sys/kernel.h> 376a03354eSMatthew Dillon #include <sys/malloc.h> 386a03354eSMatthew Dillon #include <sys/mbuf.h> 396a03354eSMatthew Dillon #include <sys/socketvar.h> 406a03354eSMatthew Dillon #include <sys/sysctl.h> 416a03354eSMatthew Dillon #include <sys/syslog.h> 426a03354eSMatthew Dillon #include <sys/systimer.h> 436a03354eSMatthew Dillon #include <sys/thread2.h> 446a03354eSMatthew Dillon #include <sys/in_cksum.h> 456a03354eSMatthew Dillon 466a03354eSMatthew Dillon #include <net/if.h> 476a03354eSMatthew Dillon #include <net/ethernet.h> 486a03354eSMatthew Dillon #include <net/netmsg2.h> 496a03354eSMatthew Dillon #include <net/netisr2.h> 506a03354eSMatthew Dillon #include <net/route.h> 516a03354eSMatthew Dillon 526a03354eSMatthew Dillon #include <netinet/ip.h> 536a03354eSMatthew Dillon #include <netinet/in.h> 546a03354eSMatthew Dillon #include <netinet/in_systm.h> 556a03354eSMatthew Dillon #include <netinet/in_var.h> 566a03354eSMatthew Dillon #include <netinet/in_pcb.h> 576a03354eSMatthew Dillon #include <netinet/ip_var.h> 586a03354eSMatthew Dillon #include <netinet/ip_icmp.h> 596a03354eSMatthew Dillon #include <netinet/tcp.h> 606a03354eSMatthew Dillon #include <netinet/tcp_timer.h> 616a03354eSMatthew Dillon #include <netinet/tcp_var.h> 626a03354eSMatthew Dillon #include <netinet/tcpip.h> 636a03354eSMatthew Dillon #include <netinet/udp.h> 646a03354eSMatthew Dillon #include <netinet/udp_var.h> 656a03354eSMatthew Dillon #include <netinet/ip_divert.h> 666a03354eSMatthew Dillon #include <netinet/if_ether.h> 676a03354eSMatthew Dillon 686a03354eSMatthew Dillon #include <net/ipfw3/ip_fw.h> 695284582fSBill Yuan #include <net/ipfw3/ip_fw3_table.h> 706a03354eSMatthew Dillon 716a03354eSMatthew Dillon #include "ip_fw3_basic.h" 726a03354eSMatthew Dillon 736a03354eSMatthew Dillon #define TIME_LEQ(a, b) ((int)((a) - (b)) <= 0) 746a03354eSMatthew Dillon 756a03354eSMatthew Dillon extern struct ipfw_context *ipfw_ctx[MAXCPU]; 766a03354eSMatthew Dillon extern int fw_verbose; 776a03354eSMatthew Dillon extern ipfw_basic_delete_state_t *ipfw_basic_flush_state_prt; 786a03354eSMatthew Dillon extern ipfw_basic_append_state_t *ipfw_basic_append_state_prt; 796a03354eSMatthew Dillon 806a03354eSMatthew Dillon static int ip_fw_basic_loaded; 816a03354eSMatthew Dillon static struct netmsg_base ipfw_timeout_netmsg; /* schedule ipfw timeout */ 826a03354eSMatthew Dillon static struct callout ipfw_tick_callout; 836a03354eSMatthew Dillon static int state_lifetime = 20; 846a03354eSMatthew Dillon static int state_expiry_check_interval = 10; 856a03354eSMatthew Dillon static int state_count_max = 4096; 866a03354eSMatthew Dillon static int state_hash_size_old = 0; 876a03354eSMatthew Dillon static int state_hash_size = 4096; 886a03354eSMatthew Dillon 896a03354eSMatthew Dillon 906a03354eSMatthew Dillon static int ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS); 916a03354eSMatthew Dillon void adjust_hash_size_dispatch(netmsg_t nmsg); 926a03354eSMatthew Dillon 936a03354eSMatthew Dillon SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw_basic, 946a03354eSMatthew Dillon CTLFLAG_RW, 0, "Firewall Basic"); 956a03354eSMatthew Dillon SYSCTL_PROC(_net_inet_ip_fw_basic, OID_AUTO, state_hash_size, 966a03354eSMatthew Dillon CTLTYPE_INT | CTLFLAG_RW, &state_hash_size, 0, 976a03354eSMatthew Dillon ipfw_sysctl_adjust_hash_size, "I", "Adjust hash size"); 986a03354eSMatthew Dillon 996a03354eSMatthew Dillon SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_lifetime, CTLFLAG_RW, 1006a03354eSMatthew Dillon &state_lifetime, 0, "default life time"); 1016a03354eSMatthew Dillon SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, 1026a03354eSMatthew Dillon state_expiry_check_interval, CTLFLAG_RW, 1036a03354eSMatthew Dillon &state_expiry_check_interval, 0, 1046a03354eSMatthew Dillon "default state expiry check interval"); 1056a03354eSMatthew Dillon SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_count_max, CTLFLAG_RW, 1066a03354eSMatthew Dillon &state_count_max, 0, "maximum of state"); 1076a03354eSMatthew Dillon 1086a03354eSMatthew Dillon static int 1096a03354eSMatthew Dillon ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS) 1106a03354eSMatthew Dillon { 1116a03354eSMatthew Dillon int error, value = 0; 1126a03354eSMatthew Dillon 1136a03354eSMatthew Dillon state_hash_size_old = state_hash_size; 1146a03354eSMatthew Dillon value = state_hash_size; 1156a03354eSMatthew Dillon error = sysctl_handle_int(oidp, &value, 0, req); 1166a03354eSMatthew Dillon if (error || !req->newptr) { 1176a03354eSMatthew Dillon goto back; 1186a03354eSMatthew Dillon } 1196a03354eSMatthew Dillon /* 1206a03354eSMatthew Dillon * Make sure we have a power of 2 and 1216a03354eSMatthew Dillon * do not allow more than 64k entries. 1226a03354eSMatthew Dillon */ 1236a03354eSMatthew Dillon error = EINVAL; 1246a03354eSMatthew Dillon if (value <= 1 || value > 65536) { 1256a03354eSMatthew Dillon goto back; 1266a03354eSMatthew Dillon } 1276a03354eSMatthew Dillon if ((value & (value - 1)) != 0) { 1286a03354eSMatthew Dillon goto back; 1296a03354eSMatthew Dillon } 1306a03354eSMatthew Dillon 1316a03354eSMatthew Dillon error = 0; 1326a03354eSMatthew Dillon if (state_hash_size != value) { 1336a03354eSMatthew Dillon state_hash_size = value; 1346a03354eSMatthew Dillon 1356a03354eSMatthew Dillon struct netmsg_base *msg, the_msg; 1366a03354eSMatthew Dillon msg = &the_msg; 1376a03354eSMatthew Dillon bzero(msg,sizeof(struct netmsg_base)); 1386a03354eSMatthew Dillon 1396a03354eSMatthew Dillon netmsg_init(msg, NULL, &curthread->td_msgport, 1406a03354eSMatthew Dillon 0, adjust_hash_size_dispatch); 1416a03354eSMatthew Dillon ifnet_domsg(&msg->lmsg, 0); 1426a03354eSMatthew Dillon } 1436a03354eSMatthew Dillon back: 1446a03354eSMatthew Dillon return error; 1456a03354eSMatthew Dillon } 1466a03354eSMatthew Dillon 1476a03354eSMatthew Dillon void 1486a03354eSMatthew Dillon adjust_hash_size_dispatch(netmsg_t nmsg) 1496a03354eSMatthew Dillon { 1506a03354eSMatthew Dillon struct ipfw_state_context *state_ctx; 1516a03354eSMatthew Dillon struct ip_fw_state *the_state, *state; 1526a03354eSMatthew Dillon struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 1536a03354eSMatthew Dillon int i; 1546a03354eSMatthew Dillon 1556a03354eSMatthew Dillon for (i = 0; i < state_hash_size_old; i++) { 1566a03354eSMatthew Dillon state_ctx = &ctx->state_ctx[i]; 1576a03354eSMatthew Dillon if (state_ctx != NULL) { 1586a03354eSMatthew Dillon state = state_ctx->state; 1596a03354eSMatthew Dillon while (state != NULL) { 1606a03354eSMatthew Dillon the_state = state; 1616a03354eSMatthew Dillon state = state->next; 1626a03354eSMatthew Dillon kfree(the_state, M_IPFW3_BASIC); 1636a03354eSMatthew Dillon the_state = NULL; 1646a03354eSMatthew Dillon } 1656a03354eSMatthew Dillon } 1666a03354eSMatthew Dillon } 1676a03354eSMatthew Dillon kfree(ctx->state_ctx,M_IPFW3_BASIC); 1686a03354eSMatthew Dillon ctx->state_ctx = kmalloc(state_hash_size * 1696a03354eSMatthew Dillon sizeof(struct ipfw_state_context), 1706a03354eSMatthew Dillon M_IPFW3_BASIC, M_WAITOK | M_ZERO); 1716a03354eSMatthew Dillon ctx->state_hash_size = state_hash_size; 1726a03354eSMatthew Dillon ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1); 1736a03354eSMatthew Dillon } 1746a03354eSMatthew Dillon 1756a03354eSMatthew Dillon 1766a03354eSMatthew Dillon /* prototype of the checker functions */ 1776a03354eSMatthew Dillon void check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 1786a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 1796a03354eSMatthew Dillon void check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 1806a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 1816a03354eSMatthew Dillon void check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 1826a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 1836a03354eSMatthew Dillon void check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 1846a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 1856a03354eSMatthew Dillon 1866a03354eSMatthew Dillon void check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 1876a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 1886a03354eSMatthew Dillon void check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 1896a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 1906a03354eSMatthew Dillon void check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 1916a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 1926a03354eSMatthew Dillon void check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 1936a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 1946a03354eSMatthew Dillon void check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 1956a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 1966a03354eSMatthew Dillon void check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 1976a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 1985284582fSBill Yuan void check_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 1995284582fSBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 20063317b93SBill Yuan void check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 20163317b93SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 20263317b93SBill Yuan void check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 20363317b93SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 2046a03354eSMatthew Dillon void check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 2056a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 2065284582fSBill Yuan void check_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 2075284582fSBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 20863317b93SBill Yuan void check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 20963317b93SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 21063317b93SBill Yuan void check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 21163317b93SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 2126a03354eSMatthew Dillon void check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 2136a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 2146a03354eSMatthew Dillon void check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 2156a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 2166a03354eSMatthew Dillon void check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 2176a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 2186a03354eSMatthew Dillon void check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 2196a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 220*c1bde762SBill Yuan void check_src_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 221*c1bde762SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 222*c1bde762SBill Yuan void check_dst_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 223*c1bde762SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 224*c1bde762SBill Yuan void check_src_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 225*c1bde762SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 226*c1bde762SBill Yuan void check_dst_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 227*c1bde762SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len); 2286a03354eSMatthew Dillon 2296a03354eSMatthew Dillon /* prototype of the utility functions */ 2306a03354eSMatthew Dillon static struct ip_fw *lookup_next_rule(struct ip_fw *me); 2316a03354eSMatthew Dillon static int iface_match(struct ifnet *ifp, ipfw_insn_if *cmd); 2326a03354eSMatthew Dillon static __inline int hash_packet(struct ipfw_flow_id *id); 2336a03354eSMatthew Dillon 2346a03354eSMatthew Dillon static __inline int 2356a03354eSMatthew Dillon hash_packet(struct ipfw_flow_id *id) 2366a03354eSMatthew Dillon { 2376a03354eSMatthew Dillon uint32_t i; 2386a03354eSMatthew Dillon i = (id->proto) ^ (id->dst_ip) ^ (id->src_ip) ^ 2396a03354eSMatthew Dillon (id->dst_port) ^ (id->src_port); 2406a03354eSMatthew Dillon i &= state_hash_size - 1; 2416a03354eSMatthew Dillon return i; 2426a03354eSMatthew Dillon } 2436a03354eSMatthew Dillon 2446a03354eSMatthew Dillon static struct ip_fw * 2456a03354eSMatthew Dillon lookup_next_rule(struct ip_fw *me) 2466a03354eSMatthew Dillon { 2476a03354eSMatthew Dillon struct ip_fw *rule = NULL; 2486a03354eSMatthew Dillon ipfw_insn *cmd; 2496a03354eSMatthew Dillon 2506a03354eSMatthew Dillon /* look for action, in case it is a skipto */ 2516a03354eSMatthew Dillon cmd = ACTION_PTR(me); 2526a03354eSMatthew Dillon if ((int)cmd->module == MODULE_BASIC_ID && 2536a03354eSMatthew Dillon (int)cmd->opcode == O_BASIC_SKIPTO) { 2546a03354eSMatthew Dillon for (rule = me->next; rule; rule = rule->next) { 2556a03354eSMatthew Dillon if (rule->rulenum >= cmd->arg1) 2566a03354eSMatthew Dillon break; 2576a03354eSMatthew Dillon } 2586a03354eSMatthew Dillon } 2596a03354eSMatthew Dillon if (rule == NULL) /* failure or not a skipto */ 2606a03354eSMatthew Dillon rule = me->next; 2616a03354eSMatthew Dillon 2626a03354eSMatthew Dillon me->next_rule = rule; 2636a03354eSMatthew Dillon return rule; 2646a03354eSMatthew Dillon } 2656a03354eSMatthew Dillon 2666a03354eSMatthew Dillon /* 2676a03354eSMatthew Dillon * when all = 1, it will check all the state_ctx 2686a03354eSMatthew Dillon */ 2696a03354eSMatthew Dillon static struct ip_fw_state * 2706a03354eSMatthew Dillon lookup_state(struct ip_fw_args *args, ipfw_insn *cmd, int *limited, int all) 2716a03354eSMatthew Dillon { 2726a03354eSMatthew Dillon struct ip_fw_state *state = NULL; 2736a03354eSMatthew Dillon struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 2746a03354eSMatthew Dillon struct ipfw_state_context *state_ctx; 2756a03354eSMatthew Dillon int start, end, i, count = 0; 2766a03354eSMatthew Dillon 2776a03354eSMatthew Dillon if (all && cmd->arg1) { 2786a03354eSMatthew Dillon start = 0; 2796a03354eSMatthew Dillon end = state_hash_size - 1; 2806a03354eSMatthew Dillon } else { 2816a03354eSMatthew Dillon start = hash_packet(&args->f_id); 2826a03354eSMatthew Dillon end = hash_packet(&args->f_id); 2836a03354eSMatthew Dillon } 2846a03354eSMatthew Dillon for (i = start; i <= end; i++) { 2856a03354eSMatthew Dillon state_ctx = &ctx->state_ctx[i]; 2866a03354eSMatthew Dillon if (state_ctx != NULL) { 2876a03354eSMatthew Dillon state = state_ctx->state; 2886a03354eSMatthew Dillon struct ipfw_flow_id *fid = &args->f_id; 2896a03354eSMatthew Dillon while (state != NULL) { 2906a03354eSMatthew Dillon if (cmd->arg1) { 2916a03354eSMatthew Dillon if ((cmd->arg3 == 1 && 2926a03354eSMatthew Dillon fid->src_ip == 2936a03354eSMatthew Dillon state->flow_id.src_ip) || 2946a03354eSMatthew Dillon (cmd->arg3 == 2 && 2956a03354eSMatthew Dillon fid->src_port == 2966a03354eSMatthew Dillon state->flow_id.src_port) || 2976a03354eSMatthew Dillon (cmd->arg3 == 3 && 2986a03354eSMatthew Dillon fid->dst_ip == 2996a03354eSMatthew Dillon state->flow_id.dst_ip) || 3006a03354eSMatthew Dillon (cmd->arg3 == 4 && 3016a03354eSMatthew Dillon fid->dst_port == 3026a03354eSMatthew Dillon state->flow_id.dst_port)) { 3036a03354eSMatthew Dillon 3046a03354eSMatthew Dillon count++; 3056a03354eSMatthew Dillon if (count >= cmd->arg1) { 3066a03354eSMatthew Dillon *limited = 1; 3076a03354eSMatthew Dillon goto done; 3086a03354eSMatthew Dillon } 3096a03354eSMatthew Dillon } 3106a03354eSMatthew Dillon } 3116a03354eSMatthew Dillon 3126a03354eSMatthew Dillon if (fid->proto == state->flow_id.proto) { 3136a03354eSMatthew Dillon if (fid->src_ip == 3146a03354eSMatthew Dillon state->flow_id.src_ip && 3156a03354eSMatthew Dillon fid->dst_ip == 3166a03354eSMatthew Dillon state->flow_id.dst_ip && 3176a03354eSMatthew Dillon (fid->src_port == 3186a03354eSMatthew Dillon state->flow_id.src_port || 3196a03354eSMatthew Dillon state->flow_id.src_port == 0) && 3206a03354eSMatthew Dillon (fid->dst_port == 3216a03354eSMatthew Dillon state->flow_id.dst_port || 3226a03354eSMatthew Dillon state->flow_id.dst_port == 0)) { 3236a03354eSMatthew Dillon goto done; 3246a03354eSMatthew Dillon } 3256a03354eSMatthew Dillon if (fid->src_ip == 3266a03354eSMatthew Dillon state->flow_id.dst_ip && 3276a03354eSMatthew Dillon fid->dst_ip == 3286a03354eSMatthew Dillon state->flow_id.src_ip && 3296a03354eSMatthew Dillon (fid->src_port == 3306a03354eSMatthew Dillon state->flow_id.dst_port || 3316a03354eSMatthew Dillon state->flow_id.dst_port == 0) && 3326a03354eSMatthew Dillon (fid->dst_port == 3336a03354eSMatthew Dillon state->flow_id.src_port || 3346a03354eSMatthew Dillon state->flow_id.src_port == 0)) { 3356a03354eSMatthew Dillon goto done; 3366a03354eSMatthew Dillon } 3376a03354eSMatthew Dillon } 3386a03354eSMatthew Dillon state = state->next; 3396a03354eSMatthew Dillon } 3406a03354eSMatthew Dillon } 3416a03354eSMatthew Dillon } 3426a03354eSMatthew Dillon done: 3436a03354eSMatthew Dillon return state; 3446a03354eSMatthew Dillon } 3456a03354eSMatthew Dillon 3466a03354eSMatthew Dillon static struct ip_fw_state * 3476a03354eSMatthew Dillon install_state(struct ip_fw *rule, ipfw_insn *cmd, struct ip_fw_args *args) 3486a03354eSMatthew Dillon { 3496a03354eSMatthew Dillon struct ip_fw_state *state; 3506a03354eSMatthew Dillon struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 3516a03354eSMatthew Dillon struct ipfw_state_context *state_ctx; 3526a03354eSMatthew Dillon state_ctx = &ctx->state_ctx[hash_packet(&args->f_id)]; 3536a03354eSMatthew Dillon state = kmalloc(sizeof(struct ip_fw_state), 3546a03354eSMatthew Dillon M_IPFW3_BASIC, M_NOWAIT | M_ZERO); 3556a03354eSMatthew Dillon if (state == NULL) { 3566a03354eSMatthew Dillon return NULL; 3576a03354eSMatthew Dillon } 3586a03354eSMatthew Dillon state->stub = rule; 3596a03354eSMatthew Dillon state->lifetime = cmd->arg2 == 0 ? state_lifetime : cmd->arg2 ; 3606a03354eSMatthew Dillon state->timestamp = time_second; 3616a03354eSMatthew Dillon state->expiry = 0; 3626a03354eSMatthew Dillon bcopy(&args->f_id,&state->flow_id,sizeof(struct ipfw_flow_id)); 3636a03354eSMatthew Dillon //append the state into the state chian 3646a03354eSMatthew Dillon if (state_ctx->last != NULL) 3656a03354eSMatthew Dillon state_ctx->last->next = state; 3666a03354eSMatthew Dillon else 3676a03354eSMatthew Dillon state_ctx->state = state; 3686a03354eSMatthew Dillon state_ctx->last = state; 3696a03354eSMatthew Dillon state_ctx->count++; 3706a03354eSMatthew Dillon return state; 3716a03354eSMatthew Dillon } 3726a03354eSMatthew Dillon 3736a03354eSMatthew Dillon 3746a03354eSMatthew Dillon static int 3756a03354eSMatthew Dillon iface_match(struct ifnet *ifp, ipfw_insn_if *cmd) 3766a03354eSMatthew Dillon { 3776a03354eSMatthew Dillon if (ifp == NULL) /* no iface with this packet, match fails */ 3786a03354eSMatthew Dillon return 0; 3796a03354eSMatthew Dillon 3806a03354eSMatthew Dillon /* Check by name or by IP address */ 3816a03354eSMatthew Dillon if (cmd->name[0] != '\0') { /* match by name */ 3826a03354eSMatthew Dillon /* Check name */ 3836a03354eSMatthew Dillon if (cmd->p.glob) { 3846a03354eSMatthew Dillon if (kfnmatch(cmd->name, ifp->if_xname, 0) == 0) 3856a03354eSMatthew Dillon return(1); 3866a03354eSMatthew Dillon } else { 3876a03354eSMatthew Dillon if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0) 3886a03354eSMatthew Dillon return(1); 3896a03354eSMatthew Dillon } 3906a03354eSMatthew Dillon } else { 3916a03354eSMatthew Dillon struct ifaddr_container *ifac; 3926a03354eSMatthew Dillon 3936a03354eSMatthew Dillon TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) { 3946a03354eSMatthew Dillon struct ifaddr *ia = ifac->ifa; 3956a03354eSMatthew Dillon 3966a03354eSMatthew Dillon if (ia->ifa_addr == NULL) 3976a03354eSMatthew Dillon continue; 3986a03354eSMatthew Dillon if (ia->ifa_addr->sa_family != AF_INET) 3996a03354eSMatthew Dillon continue; 4006a03354eSMatthew Dillon if (cmd->p.ip.s_addr == 4016a03354eSMatthew Dillon ((struct sockaddr_in *) 4026a03354eSMatthew Dillon (ia->ifa_addr))->sin_addr.s_addr) 4036a03354eSMatthew Dillon return(1); /* match */ 4046a03354eSMatthew Dillon 4056a03354eSMatthew Dillon } 4066a03354eSMatthew Dillon } 4076a03354eSMatthew Dillon return 0; /* no match, fail ... */ 4086a03354eSMatthew Dillon } 4096a03354eSMatthew Dillon 4106a03354eSMatthew Dillon /* implimentation of the checker functions */ 4116a03354eSMatthew Dillon void 4126a03354eSMatthew Dillon check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 4136a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 4146a03354eSMatthew Dillon { 4156a03354eSMatthew Dillon (*f)->pcnt++; 4166a03354eSMatthew Dillon (*f)->bcnt += ip_len; 4176a03354eSMatthew Dillon (*f)->timestamp = time_second; 4186a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_NEXT; 4196a03354eSMatthew Dillon } 4206a03354eSMatthew Dillon 4216a03354eSMatthew Dillon void 4226a03354eSMatthew Dillon check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 4236a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 4246a03354eSMatthew Dillon { 4256a03354eSMatthew Dillon (*f)->pcnt++; 4266a03354eSMatthew Dillon (*f)->bcnt += ip_len; 4276a03354eSMatthew Dillon (*f)->timestamp = time_second; 4286a03354eSMatthew Dillon if ((*f)->next_rule == NULL) 4296a03354eSMatthew Dillon lookup_next_rule(*f); 4306a03354eSMatthew Dillon 4316a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_AGAIN; 4326a03354eSMatthew Dillon } 4336a03354eSMatthew Dillon 4346a03354eSMatthew Dillon void 4356a03354eSMatthew Dillon check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 4366a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 4376a03354eSMatthew Dillon { 4386a03354eSMatthew Dillon struct sockaddr_in *sin, *sa; 4396a03354eSMatthew Dillon struct m_tag *mtag; 4406a03354eSMatthew Dillon 4416a03354eSMatthew Dillon if ((*args)->eh) { /* not valid on layer2 pkts */ 4426a03354eSMatthew Dillon *cmd_ctl=IP_FW_CTL_NEXT; 4436a03354eSMatthew Dillon return; 4446a03354eSMatthew Dillon } 4456a03354eSMatthew Dillon 4466a03354eSMatthew Dillon (*f)->pcnt++; 4476a03354eSMatthew Dillon (*f)->bcnt += ip_len; 4486a03354eSMatthew Dillon (*f)->timestamp = time_second; 4496a03354eSMatthew Dillon if ((*f)->next_rule == NULL) 4506a03354eSMatthew Dillon lookup_next_rule(*f); 4516a03354eSMatthew Dillon 4526a03354eSMatthew Dillon mtag = m_tag_get(PACKET_TAG_IPFORWARD, 4536a03354eSMatthew Dillon sizeof(*sin), M_NOWAIT); 4546a03354eSMatthew Dillon if (mtag == NULL) { 4556a03354eSMatthew Dillon *cmd_val = IP_FW_DENY; 4566a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_DONE; 4576a03354eSMatthew Dillon return; 4586a03354eSMatthew Dillon } 4596a03354eSMatthew Dillon sin = m_tag_data(mtag); 4606a03354eSMatthew Dillon sa = &((ipfw_insn_sa *)cmd)->sa; 4616a03354eSMatthew Dillon /* arg3: count of the dest, arg1: type of fwd */ 4626a03354eSMatthew Dillon int i = 0; 4636a03354eSMatthew Dillon if(cmd->arg3 > 1) { 4646a03354eSMatthew Dillon if (cmd->arg1 == 0) { /* type: random */ 4656a03354eSMatthew Dillon i = krandom() % cmd->arg3; 4666a03354eSMatthew Dillon } else if (cmd->arg1 == 1) { /* type: round-robin */ 4676a03354eSMatthew Dillon i = cmd->arg2++ % cmd->arg3; 4686a03354eSMatthew Dillon } else if (cmd->arg1 == 2) { /* type: sticky */ 4696a03354eSMatthew Dillon struct ip *ip = mtod((*args)->m, struct ip *); 4706a03354eSMatthew Dillon i = ip->ip_src.s_addr & (cmd->arg3 - 1); 4716a03354eSMatthew Dillon } 4726a03354eSMatthew Dillon sa += i; 4736a03354eSMatthew Dillon } 4746a03354eSMatthew Dillon *sin = *sa; /* apply the destination */ 4756a03354eSMatthew Dillon m_tag_prepend((*args)->m, mtag); 4766a03354eSMatthew Dillon (*args)->m->m_pkthdr.fw_flags |= IPFORWARD_MBUF_TAGGED; 4776a03354eSMatthew Dillon (*args)->m->m_pkthdr.fw_flags &= ~BRIDGE_MBUF_TAGGED; 4786a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_DONE; 4796a03354eSMatthew Dillon *cmd_val = IP_FW_PASS; 4806a03354eSMatthew Dillon } 4816a03354eSMatthew Dillon 4826a03354eSMatthew Dillon void 4836a03354eSMatthew Dillon check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 4846a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 4856a03354eSMatthew Dillon { 4866a03354eSMatthew Dillon struct ip_fw_state *state=NULL; 4876a03354eSMatthew Dillon int limited = 0 ; 4886a03354eSMatthew Dillon state = lookup_state(*args, cmd, &limited, 0); 4896a03354eSMatthew Dillon if (state != NULL) { 4906a03354eSMatthew Dillon state->pcnt++; 4916a03354eSMatthew Dillon state->bcnt += ip_len; 4926a03354eSMatthew Dillon state->timestamp = time_second; 4936a03354eSMatthew Dillon (*f)->pcnt++; 4946a03354eSMatthew Dillon (*f)->bcnt += ip_len; 4956a03354eSMatthew Dillon (*f)->timestamp = time_second; 4966a03354eSMatthew Dillon *f = state->stub; 4976a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_CHK_STATE; 4986a03354eSMatthew Dillon } else { 4996a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_NEXT; 5006a03354eSMatthew Dillon } 5016a03354eSMatthew Dillon } 5026a03354eSMatthew Dillon 5036a03354eSMatthew Dillon void 5046a03354eSMatthew Dillon check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 5056a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 5066a03354eSMatthew Dillon { 5076a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_NO; 5086a03354eSMatthew Dillon *cmd_val = ((*args)->oif == NULL); 5096a03354eSMatthew Dillon } 5106a03354eSMatthew Dillon 5116a03354eSMatthew Dillon void 5126a03354eSMatthew Dillon check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 5136a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 5146a03354eSMatthew Dillon { 5156a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_NO; 5166a03354eSMatthew Dillon *cmd_val = ((*args)->oif != NULL); 5176a03354eSMatthew Dillon } 5186a03354eSMatthew Dillon 5196a03354eSMatthew Dillon void 5206a03354eSMatthew Dillon check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 5216a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 5226a03354eSMatthew Dillon { 5236a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_NO; 5246a03354eSMatthew Dillon *cmd_val = iface_match((*args)->oif ? 5256a03354eSMatthew Dillon (*args)->oif : (*args)->m->m_pkthdr.rcvif, 5266a03354eSMatthew Dillon (ipfw_insn_if *)cmd); 5276a03354eSMatthew Dillon } 5286a03354eSMatthew Dillon 5296a03354eSMatthew Dillon void 5306a03354eSMatthew Dillon check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 5316a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 5326a03354eSMatthew Dillon { 5336a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_NO; 5346a03354eSMatthew Dillon *cmd_val = ((*args)->f_id.proto == cmd->arg1); 5356a03354eSMatthew Dillon } 5366a03354eSMatthew Dillon 5376a03354eSMatthew Dillon void 5386a03354eSMatthew Dillon check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 5396a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 5406a03354eSMatthew Dillon { 5416a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_NO; 5426a03354eSMatthew Dillon *cmd_val = (krandom() % 100) < cmd->arg1; 5436a03354eSMatthew Dillon } 5446a03354eSMatthew Dillon 5456a03354eSMatthew Dillon void 5466a03354eSMatthew Dillon check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 5476a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 5486a03354eSMatthew Dillon { 5496a03354eSMatthew Dillon struct in_addr src_ip; 5506a03354eSMatthew Dillon u_int hlen = 0; 5516a03354eSMatthew Dillon struct mbuf *m = (*args)->m; 5526a03354eSMatthew Dillon struct ip *ip = mtod(m, struct ip *); 5536a03354eSMatthew Dillon src_ip = ip->ip_src; 5546a03354eSMatthew Dillon if ((*args)->eh == NULL || 5556a03354eSMatthew Dillon (m->m_pkthdr.len >= sizeof(struct ip) && 5566a03354eSMatthew Dillon ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 5576a03354eSMatthew Dillon hlen = ip->ip_hl << 2; 5586a03354eSMatthew Dillon } 5596a03354eSMatthew Dillon *cmd_val = (hlen > 0 && 5606a03354eSMatthew Dillon ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr); 5616a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_NO; 5626a03354eSMatthew Dillon } 5636a03354eSMatthew Dillon 5646a03354eSMatthew Dillon void 5655284582fSBill Yuan check_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 5665284582fSBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 5675284582fSBill Yuan { 5685284582fSBill Yuan struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 5695284582fSBill Yuan struct ipfw_table_context *table_ctx; 5705284582fSBill Yuan struct radix_node_head *rnh; 5715284582fSBill Yuan struct sockaddr_in sa; 5725284582fSBill Yuan 5735284582fSBill Yuan struct mbuf *m = (*args)->m; 5745284582fSBill Yuan struct ip *ip = mtod(m, struct ip *); 5755284582fSBill Yuan struct in_addr src_ip = ip->ip_src; 5765284582fSBill Yuan 5775284582fSBill Yuan *cmd_val = IP_FW_NOT_MATCH; 5785284582fSBill Yuan 5795284582fSBill Yuan table_ctx = ctx->table_ctx; 5805284582fSBill Yuan table_ctx += cmd->arg1; 5815284582fSBill Yuan 5825284582fSBill Yuan if (table_ctx->type != 0) { 5835284582fSBill Yuan rnh = table_ctx->node; 5845284582fSBill Yuan sa.sin_len = 8; 5855284582fSBill Yuan sa.sin_addr.s_addr = src_ip.s_addr; 5865284582fSBill Yuan if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL) 5875284582fSBill Yuan *cmd_val = IP_FW_MATCH; 5885284582fSBill Yuan } 5895284582fSBill Yuan *cmd_ctl = IP_FW_CTL_NO; 5905284582fSBill Yuan } 5915284582fSBill Yuan 5925284582fSBill Yuan void 59363317b93SBill Yuan check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 59463317b93SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 59563317b93SBill Yuan { 59663317b93SBill Yuan struct in_addr src_ip; 59763317b93SBill Yuan u_int hlen = 0; 59863317b93SBill Yuan struct mbuf *m = (*args)->m; 59963317b93SBill Yuan struct ip *ip = mtod(m, struct ip *); 60063317b93SBill Yuan src_ip = ip->ip_src; 60163317b93SBill Yuan if ((*args)->eh == NULL || 60263317b93SBill Yuan (m->m_pkthdr.len >= sizeof(struct ip) && 60363317b93SBill Yuan ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 60463317b93SBill Yuan hlen = ip->ip_hl << 2; 60563317b93SBill Yuan } 60663317b93SBill Yuan *cmd_ctl = IP_FW_CTL_NO; 60763317b93SBill Yuan if (hlen > 0) { 60863317b93SBill Yuan struct ifnet *tif; 60963317b93SBill Yuan tif = INADDR_TO_IFP(&src_ip); 61063317b93SBill Yuan *cmd_val = (tif != NULL); 61163317b93SBill Yuan } else { 61263317b93SBill Yuan *cmd_val = IP_FW_NOT_MATCH; 61363317b93SBill Yuan } 61463317b93SBill Yuan } 61563317b93SBill Yuan 61663317b93SBill Yuan void 61763317b93SBill Yuan check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 61863317b93SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 61963317b93SBill Yuan { 62063317b93SBill Yuan struct in_addr src_ip; 62163317b93SBill Yuan u_int hlen = 0; 62263317b93SBill Yuan struct mbuf *m = (*args)->m; 62363317b93SBill Yuan struct ip *ip = mtod(m, struct ip *); 62463317b93SBill Yuan src_ip = ip->ip_src; 62563317b93SBill Yuan if ((*args)->eh == NULL || 62663317b93SBill Yuan (m->m_pkthdr.len >= sizeof(struct ip) && 62763317b93SBill Yuan ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 62863317b93SBill Yuan hlen = ip->ip_hl << 2; 62963317b93SBill Yuan } 63063317b93SBill Yuan 63163317b93SBill Yuan *cmd_ctl = IP_FW_CTL_NO; 63263317b93SBill Yuan *cmd_val = (hlen > 0 && 63363317b93SBill Yuan ((ipfw_insn_ip *)cmd)->addr.s_addr == 63463317b93SBill Yuan (src_ip.s_addr & 63563317b93SBill Yuan ((ipfw_insn_ip *)cmd)->mask.s_addr)); 63663317b93SBill Yuan } 63763317b93SBill Yuan 63863317b93SBill Yuan void 6396a03354eSMatthew Dillon check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 6406a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 6416a03354eSMatthew Dillon { 6426a03354eSMatthew Dillon struct in_addr dst_ip; 6436a03354eSMatthew Dillon u_int hlen = 0; 6446a03354eSMatthew Dillon struct mbuf *m = (*args)->m; 6456a03354eSMatthew Dillon struct ip *ip = mtod(m, struct ip *); 6466a03354eSMatthew Dillon dst_ip = ip->ip_dst; 6476a03354eSMatthew Dillon if ((*args)->eh == NULL || 6486a03354eSMatthew Dillon (m->m_pkthdr.len >= sizeof(struct ip) && 6496a03354eSMatthew Dillon ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 6506a03354eSMatthew Dillon hlen = ip->ip_hl << 2; 6516a03354eSMatthew Dillon } 6526a03354eSMatthew Dillon *cmd_val = (hlen > 0 && 6536a03354eSMatthew Dillon ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr); 6546a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_NO; 6556a03354eSMatthew Dillon } 6566a03354eSMatthew Dillon 6576a03354eSMatthew Dillon void 6585284582fSBill Yuan check_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 6595284582fSBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 6605284582fSBill Yuan { 6615284582fSBill Yuan struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 6625284582fSBill Yuan struct ipfw_table_context *table_ctx; 6635284582fSBill Yuan struct radix_node_head *rnh; 6645284582fSBill Yuan struct sockaddr_in sa; 6655284582fSBill Yuan 6665284582fSBill Yuan struct mbuf *m = (*args)->m; 6675284582fSBill Yuan struct ip *ip = mtod(m, struct ip *); 6685284582fSBill Yuan struct in_addr dst_ip = ip->ip_dst; 6695284582fSBill Yuan 6705284582fSBill Yuan *cmd_val = IP_FW_NOT_MATCH; 6715284582fSBill Yuan 6725284582fSBill Yuan table_ctx = ctx->table_ctx; 6735284582fSBill Yuan table_ctx += cmd->arg1; 6745284582fSBill Yuan 6755284582fSBill Yuan if (table_ctx->type != 0) { 6765284582fSBill Yuan rnh = table_ctx->node; 6775284582fSBill Yuan sa.sin_len = 8; 6785284582fSBill Yuan sa.sin_addr.s_addr = dst_ip.s_addr; 6795284582fSBill Yuan if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL) 6805284582fSBill Yuan *cmd_val = IP_FW_MATCH; 6815284582fSBill Yuan } 6825284582fSBill Yuan *cmd_ctl = IP_FW_CTL_NO; 6835284582fSBill Yuan } 6845284582fSBill Yuan 6855284582fSBill Yuan void 68663317b93SBill Yuan check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 68763317b93SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 68863317b93SBill Yuan { 68963317b93SBill Yuan struct in_addr dst_ip; 69063317b93SBill Yuan u_int hlen = 0; 69163317b93SBill Yuan struct mbuf *m = (*args)->m; 69263317b93SBill Yuan struct ip *ip = mtod(m, struct ip *); 69363317b93SBill Yuan dst_ip = ip->ip_src; 69463317b93SBill Yuan if ((*args)->eh == NULL || 69563317b93SBill Yuan (m->m_pkthdr.len >= sizeof(struct ip) && 69663317b93SBill Yuan ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 69763317b93SBill Yuan hlen = ip->ip_hl << 2; 69863317b93SBill Yuan } 69963317b93SBill Yuan *cmd_ctl = IP_FW_CTL_NO; 70063317b93SBill Yuan if (hlen > 0) { 70163317b93SBill Yuan struct ifnet *tif; 70263317b93SBill Yuan tif = INADDR_TO_IFP(&dst_ip); 70363317b93SBill Yuan *cmd_val = (tif != NULL); 70463317b93SBill Yuan } else { 70563317b93SBill Yuan *cmd_val = IP_FW_NOT_MATCH; 70663317b93SBill Yuan } 70763317b93SBill Yuan } 70863317b93SBill Yuan 70963317b93SBill Yuan void 71063317b93SBill Yuan check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 71163317b93SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 71263317b93SBill Yuan { 71363317b93SBill Yuan struct in_addr dst_ip; 71463317b93SBill Yuan u_int hlen = 0; 71563317b93SBill Yuan struct mbuf *m = (*args)->m; 71663317b93SBill Yuan struct ip *ip = mtod(m, struct ip *); 71763317b93SBill Yuan dst_ip = ip->ip_src; 71863317b93SBill Yuan if ((*args)->eh == NULL || 71963317b93SBill Yuan (m->m_pkthdr.len >= sizeof(struct ip) && 72063317b93SBill Yuan ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 72163317b93SBill Yuan hlen = ip->ip_hl << 2; 72263317b93SBill Yuan } 72363317b93SBill Yuan 72463317b93SBill Yuan *cmd_ctl = IP_FW_CTL_NO; 72563317b93SBill Yuan *cmd_val = (hlen > 0 && 72663317b93SBill Yuan ((ipfw_insn_ip *)cmd)->addr.s_addr == 72763317b93SBill Yuan (dst_ip.s_addr & 72863317b93SBill Yuan ((ipfw_insn_ip *)cmd)->mask.s_addr)); 72963317b93SBill Yuan } 73063317b93SBill Yuan 73163317b93SBill Yuan void 7326a03354eSMatthew Dillon check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 7336a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 7346a03354eSMatthew Dillon { 7356a03354eSMatthew Dillon struct ip_fw_state *state; 7366a03354eSMatthew Dillon int limited = 0; 7376a03354eSMatthew Dillon 7386a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_NO; 7396a03354eSMatthew Dillon state = lookup_state(*args, cmd, &limited, 1); 7406a03354eSMatthew Dillon if (limited == 1) { 7416a03354eSMatthew Dillon *cmd_val = IP_FW_NOT_MATCH; 7426a03354eSMatthew Dillon } else { 7436a03354eSMatthew Dillon if (state == NULL) 7446a03354eSMatthew Dillon state = install_state(*f, cmd, *args); 7456a03354eSMatthew Dillon 7466a03354eSMatthew Dillon if (state != NULL) { 7476a03354eSMatthew Dillon state->pcnt++; 7486a03354eSMatthew Dillon state->bcnt += ip_len; 7496a03354eSMatthew Dillon state->timestamp = time_second; 7506a03354eSMatthew Dillon *cmd_val = IP_FW_MATCH; 7516a03354eSMatthew Dillon } else { 7526a03354eSMatthew Dillon *cmd_val = IP_FW_NOT_MATCH; 7536a03354eSMatthew Dillon } 7546a03354eSMatthew Dillon } 7556a03354eSMatthew Dillon } 7566a03354eSMatthew Dillon 7576a03354eSMatthew Dillon void 7586a03354eSMatthew Dillon check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 7596a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 7606a03354eSMatthew Dillon { 7616a03354eSMatthew Dillon struct m_tag *mtag = m_tag_locate((*args)->m, 7626a03354eSMatthew Dillon MTAG_IPFW, cmd->arg1, NULL); 7636a03354eSMatthew Dillon if (mtag == NULL) { 7646a03354eSMatthew Dillon mtag = m_tag_alloc(MTAG_IPFW,cmd->arg1, 0, M_NOWAIT); 7656a03354eSMatthew Dillon if (mtag != NULL) 7666a03354eSMatthew Dillon m_tag_prepend((*args)->m, mtag); 7676a03354eSMatthew Dillon 7686a03354eSMatthew Dillon } 7696a03354eSMatthew Dillon (*f)->pcnt++; 7706a03354eSMatthew Dillon (*f)->bcnt += ip_len; 7716a03354eSMatthew Dillon (*f)->timestamp = time_second; 7726a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_NEXT; 7736a03354eSMatthew Dillon } 7746a03354eSMatthew Dillon 7756a03354eSMatthew Dillon void 7766a03354eSMatthew Dillon check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 7776a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 7786a03354eSMatthew Dillon { 7796a03354eSMatthew Dillon struct m_tag *mtag = m_tag_locate((*args)->m, 7806a03354eSMatthew Dillon MTAG_IPFW, cmd->arg1, NULL); 7816a03354eSMatthew Dillon if (mtag != NULL) 7826a03354eSMatthew Dillon m_tag_delete((*args)->m, mtag); 7836a03354eSMatthew Dillon 7846a03354eSMatthew Dillon (*f)->pcnt++; 7856a03354eSMatthew Dillon (*f)->bcnt += ip_len; 7866a03354eSMatthew Dillon (*f)->timestamp = time_second; 7876a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_NEXT; 7886a03354eSMatthew Dillon } 7896a03354eSMatthew Dillon 7906a03354eSMatthew Dillon void 7916a03354eSMatthew Dillon check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 7926a03354eSMatthew Dillon struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 7936a03354eSMatthew Dillon { 7946a03354eSMatthew Dillon *cmd_ctl = IP_FW_CTL_NO; 7956a03354eSMatthew Dillon if (m_tag_locate( (*args)->m, MTAG_IPFW,cmd->arg1, NULL) != NULL ) 7966a03354eSMatthew Dillon *cmd_val = IP_FW_MATCH; 7976a03354eSMatthew Dillon else 7986a03354eSMatthew Dillon *cmd_val = IP_FW_NOT_MATCH; 7996a03354eSMatthew Dillon } 8006a03354eSMatthew Dillon 801*c1bde762SBill Yuan void 802*c1bde762SBill Yuan check_src_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 803*c1bde762SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 804*c1bde762SBill Yuan { 805*c1bde762SBill Yuan *cmd_ctl = IP_FW_CTL_NO; 806*c1bde762SBill Yuan if ((*args)->f_id.src_port == cmd->arg1) 807*c1bde762SBill Yuan *cmd_val = IP_FW_MATCH; 808*c1bde762SBill Yuan else 809*c1bde762SBill Yuan *cmd_val = IP_FW_NOT_MATCH; 810*c1bde762SBill Yuan } 811*c1bde762SBill Yuan 812*c1bde762SBill Yuan void 813*c1bde762SBill Yuan check_dst_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 814*c1bde762SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 815*c1bde762SBill Yuan { 816*c1bde762SBill Yuan *cmd_ctl = IP_FW_CTL_NO; 817*c1bde762SBill Yuan if ((*args)->f_id.dst_port == cmd->arg1) 818*c1bde762SBill Yuan *cmd_val = IP_FW_MATCH; 819*c1bde762SBill Yuan else 820*c1bde762SBill Yuan *cmd_val = IP_FW_NOT_MATCH; 821*c1bde762SBill Yuan } 822*c1bde762SBill Yuan 823*c1bde762SBill Yuan void 824*c1bde762SBill Yuan check_src_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 825*c1bde762SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 826*c1bde762SBill Yuan { 827*c1bde762SBill Yuan struct in_addr src_ip; 828*c1bde762SBill Yuan u_int hlen = 0; 829*c1bde762SBill Yuan struct mbuf *m = (*args)->m; 830*c1bde762SBill Yuan struct ip *ip = mtod(m, struct ip *); 831*c1bde762SBill Yuan src_ip = ip->ip_src; 832*c1bde762SBill Yuan if ((*args)->eh == NULL || 833*c1bde762SBill Yuan (m->m_pkthdr.len >= sizeof(struct ip) && 834*c1bde762SBill Yuan ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 835*c1bde762SBill Yuan hlen = ip->ip_hl << 2; 836*c1bde762SBill Yuan } 837*c1bde762SBill Yuan *cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr); 838*c1bde762SBill Yuan *cmd_ctl = IP_FW_CTL_NO; 839*c1bde762SBill Yuan if (*cmd_val && (*args)->f_id.src_port == cmd->arg1) 840*c1bde762SBill Yuan *cmd_val = IP_FW_MATCH; 841*c1bde762SBill Yuan else 842*c1bde762SBill Yuan *cmd_val = IP_FW_NOT_MATCH; 843*c1bde762SBill Yuan } 844*c1bde762SBill Yuan 845*c1bde762SBill Yuan void 846*c1bde762SBill Yuan check_dst_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 847*c1bde762SBill Yuan struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 848*c1bde762SBill Yuan { 849*c1bde762SBill Yuan struct in_addr dst_ip; 850*c1bde762SBill Yuan u_int hlen = 0; 851*c1bde762SBill Yuan struct mbuf *m = (*args)->m; 852*c1bde762SBill Yuan struct ip *ip = mtod(m, struct ip *); 853*c1bde762SBill Yuan dst_ip = ip->ip_dst; 854*c1bde762SBill Yuan if ((*args)->eh == NULL || 855*c1bde762SBill Yuan (m->m_pkthdr.len >= sizeof(struct ip) && 856*c1bde762SBill Yuan ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) { 857*c1bde762SBill Yuan hlen = ip->ip_hl << 2; 858*c1bde762SBill Yuan } 859*c1bde762SBill Yuan *cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr); 860*c1bde762SBill Yuan *cmd_ctl = IP_FW_CTL_NO; 861*c1bde762SBill Yuan if (*cmd_val && (*args)->f_id.dst_port == cmd->arg1) 862*c1bde762SBill Yuan *cmd_val = IP_FW_MATCH; 863*c1bde762SBill Yuan else 864*c1bde762SBill Yuan *cmd_val = IP_FW_NOT_MATCH; 865*c1bde762SBill Yuan } 866*c1bde762SBill Yuan 867*c1bde762SBill Yuan 868*c1bde762SBill Yuan 8696a03354eSMatthew Dillon static void 8706a03354eSMatthew Dillon ipfw_basic_add_state(struct ipfw_ioc_state *ioc_state) 8716a03354eSMatthew Dillon { 8726a03354eSMatthew Dillon struct ip_fw_state *state; 8736a03354eSMatthew Dillon struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 8746a03354eSMatthew Dillon struct ipfw_state_context *state_ctx; 8756a03354eSMatthew Dillon state_ctx = &ctx->state_ctx[hash_packet(&(ioc_state->flow_id))]; 8766a03354eSMatthew Dillon state = kmalloc(sizeof(struct ip_fw_state), 8776a03354eSMatthew Dillon M_IPFW3_BASIC, M_WAITOK | M_ZERO); 8786a03354eSMatthew Dillon struct ip_fw *rule = ctx->ipfw_rule_chain; 8796a03354eSMatthew Dillon while (rule != NULL) { 8806a03354eSMatthew Dillon if (rule->rulenum == ioc_state->rulenum) { 8816a03354eSMatthew Dillon break; 8826a03354eSMatthew Dillon } 8836a03354eSMatthew Dillon rule = rule->next; 8846a03354eSMatthew Dillon } 8856a03354eSMatthew Dillon if (rule == NULL) 8866a03354eSMatthew Dillon return; 8876a03354eSMatthew Dillon 8886a03354eSMatthew Dillon state->stub = rule; 8896a03354eSMatthew Dillon 8906a03354eSMatthew Dillon state->lifetime = ioc_state->lifetime == 0 ? 8916a03354eSMatthew Dillon state_lifetime : ioc_state->lifetime ; 8926a03354eSMatthew Dillon state->timestamp = time_second; 8936a03354eSMatthew Dillon state->expiry = ioc_state->expiry; 8946a03354eSMatthew Dillon bcopy(&ioc_state->flow_id, &state->flow_id, 8956a03354eSMatthew Dillon sizeof(struct ipfw_flow_id)); 8966a03354eSMatthew Dillon //append the state into the state chian 8976a03354eSMatthew Dillon if (state_ctx->last != NULL) 8986a03354eSMatthew Dillon state_ctx->last->next = state; 8996a03354eSMatthew Dillon else 9006a03354eSMatthew Dillon state_ctx->state = state; 9016a03354eSMatthew Dillon 9026a03354eSMatthew Dillon state_ctx->last = state; 9036a03354eSMatthew Dillon state_ctx->count++; 9046a03354eSMatthew Dillon } 9056a03354eSMatthew Dillon 9066a03354eSMatthew Dillon /* 9076a03354eSMatthew Dillon * if rule is NULL 9086a03354eSMatthew Dillon * flush all states 9096a03354eSMatthew Dillon * else 9106a03354eSMatthew Dillon * flush states which stub is the rule 9116a03354eSMatthew Dillon */ 9126a03354eSMatthew Dillon static void 9136a03354eSMatthew Dillon ipfw_basic_flush_state(struct ip_fw *rule) 9146a03354eSMatthew Dillon { 9156a03354eSMatthew Dillon struct ipfw_state_context *state_ctx; 9166a03354eSMatthew Dillon struct ip_fw_state *state,*the_state, *prev_state; 9176a03354eSMatthew Dillon struct ipfw_context *ctx; 9186a03354eSMatthew Dillon int i; 9196a03354eSMatthew Dillon 9206a03354eSMatthew Dillon ctx = ipfw_ctx[mycpuid]; 9216a03354eSMatthew Dillon for (i = 0; i < state_hash_size; i++) { 9226a03354eSMatthew Dillon state_ctx = &ctx->state_ctx[i]; 9236a03354eSMatthew Dillon if (state_ctx != NULL) { 9246a03354eSMatthew Dillon state = state_ctx->state; 9256a03354eSMatthew Dillon prev_state = NULL; 9266a03354eSMatthew Dillon while (state != NULL) { 9276a03354eSMatthew Dillon if (rule != NULL && state->stub != rule) { 9286a03354eSMatthew Dillon prev_state = state; 9296a03354eSMatthew Dillon state = state->next; 9306a03354eSMatthew Dillon } else { 9316a03354eSMatthew Dillon if (prev_state == NULL) 9326a03354eSMatthew Dillon state_ctx->state = state->next; 9336a03354eSMatthew Dillon else 9346a03354eSMatthew Dillon prev_state->next = state->next; 9356a03354eSMatthew Dillon 9366a03354eSMatthew Dillon the_state = state; 9376a03354eSMatthew Dillon state = state->next; 9386a03354eSMatthew Dillon kfree(the_state, M_IPFW3_BASIC); 9396a03354eSMatthew Dillon state_ctx->count--; 9406a03354eSMatthew Dillon if (state == NULL) 9416a03354eSMatthew Dillon state_ctx->last = prev_state; 9426a03354eSMatthew Dillon 9436a03354eSMatthew Dillon } 9446a03354eSMatthew Dillon } 9456a03354eSMatthew Dillon } 9466a03354eSMatthew Dillon } 9476a03354eSMatthew Dillon } 9486a03354eSMatthew Dillon 9496a03354eSMatthew Dillon /* 9506a03354eSMatthew Dillon * clean up expired state in every tick 9516a03354eSMatthew Dillon */ 9526a03354eSMatthew Dillon static void 9536a03354eSMatthew Dillon ipfw_cleanup_expired_state(netmsg_t nmsg) 9546a03354eSMatthew Dillon { 9556a03354eSMatthew Dillon struct ip_fw_state *state,*the_state,*prev_state; 9566a03354eSMatthew Dillon struct ipfw_context *ctx = ipfw_ctx[mycpuid]; 9576a03354eSMatthew Dillon struct ipfw_state_context *state_ctx; 9586a03354eSMatthew Dillon int i; 9596a03354eSMatthew Dillon 9606a03354eSMatthew Dillon for (i = 0; i < state_hash_size; i++) { 9616a03354eSMatthew Dillon prev_state = NULL; 9626a03354eSMatthew Dillon state_ctx = &(ctx->state_ctx[i]); 9636a03354eSMatthew Dillon if (ctx->state_ctx != NULL) { 9646a03354eSMatthew Dillon state = state_ctx->state; 9656a03354eSMatthew Dillon while (state != NULL) { 9666a03354eSMatthew Dillon if (IS_EXPIRED(state)) { 9676a03354eSMatthew Dillon if (prev_state == NULL) 9686a03354eSMatthew Dillon state_ctx->state = state->next; 9696a03354eSMatthew Dillon else 9706a03354eSMatthew Dillon prev_state->next = state->next; 9716a03354eSMatthew Dillon 9726a03354eSMatthew Dillon the_state =state; 9736a03354eSMatthew Dillon state = state->next; 9746a03354eSMatthew Dillon 9756a03354eSMatthew Dillon if (the_state == state_ctx->last) 9766a03354eSMatthew Dillon state_ctx->last = NULL; 9776a03354eSMatthew Dillon 9786a03354eSMatthew Dillon 9796a03354eSMatthew Dillon kfree(the_state, M_IPFW3_BASIC); 9806a03354eSMatthew Dillon state_ctx->count--; 9816a03354eSMatthew Dillon } else { 9826a03354eSMatthew Dillon prev_state = state; 9836a03354eSMatthew Dillon state = state->next; 9846a03354eSMatthew Dillon } 9856a03354eSMatthew Dillon } 9866a03354eSMatthew Dillon } 9876a03354eSMatthew Dillon } 9886a03354eSMatthew Dillon ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1); 9896a03354eSMatthew Dillon } 9906a03354eSMatthew Dillon 9916a03354eSMatthew Dillon static void 9926a03354eSMatthew Dillon ipfw_tick(void *dummy __unused) 9936a03354eSMatthew Dillon { 9946a03354eSMatthew Dillon struct lwkt_msg *lmsg = &ipfw_timeout_netmsg.lmsg; 9956a03354eSMatthew Dillon KKASSERT(mycpuid == IPFW_CFGCPUID); 9966a03354eSMatthew Dillon 9976a03354eSMatthew Dillon crit_enter(); 9986a03354eSMatthew Dillon KKASSERT(lmsg->ms_flags & MSGF_DONE); 9996a03354eSMatthew Dillon if (IPFW_BASIC_LOADED) { 10006a03354eSMatthew Dillon lwkt_sendmsg_oncpu(IPFW_CFGPORT, lmsg); 10016a03354eSMatthew Dillon /* ipfw_timeout_netmsg's handler reset this callout */ 10026a03354eSMatthew Dillon } 10036a03354eSMatthew Dillon crit_exit(); 10046a03354eSMatthew Dillon 10056a03354eSMatthew Dillon struct netmsg_base *msg; 10066a03354eSMatthew Dillon struct netmsg_base the_msg; 10076a03354eSMatthew Dillon msg = &the_msg; 10086a03354eSMatthew Dillon bzero(msg,sizeof(struct netmsg_base)); 10096a03354eSMatthew Dillon 10106a03354eSMatthew Dillon netmsg_init(msg, NULL, &curthread->td_msgport, 0, 10116a03354eSMatthew Dillon ipfw_cleanup_expired_state); 10126a03354eSMatthew Dillon ifnet_domsg(&msg->lmsg, 0); 10136a03354eSMatthew Dillon } 10146a03354eSMatthew Dillon 10156a03354eSMatthew Dillon static void 10166a03354eSMatthew Dillon ipfw_tick_dispatch(netmsg_t nmsg) 10176a03354eSMatthew Dillon { 10186a03354eSMatthew Dillon IPFW_ASSERT_CFGPORT(&curthread->td_msgport); 10196a03354eSMatthew Dillon KKASSERT(IPFW_BASIC_LOADED); 10206a03354eSMatthew Dillon 10216a03354eSMatthew Dillon /* Reply ASAP */ 10226a03354eSMatthew Dillon crit_enter(); 10236a03354eSMatthew Dillon lwkt_replymsg(&nmsg->lmsg, 0); 10246a03354eSMatthew Dillon crit_exit(); 10256a03354eSMatthew Dillon 10266a03354eSMatthew Dillon callout_reset(&ipfw_tick_callout, 10276a03354eSMatthew Dillon state_expiry_check_interval * hz, ipfw_tick, NULL); 10286a03354eSMatthew Dillon } 10296a03354eSMatthew Dillon 10306a03354eSMatthew Dillon static void 10316a03354eSMatthew Dillon ipfw_basic_init_dispatch(netmsg_t nmsg) 10326a03354eSMatthew Dillon { 10336a03354eSMatthew Dillon IPFW_ASSERT_CFGPORT(&curthread->td_msgport); 10346a03354eSMatthew Dillon KKASSERT(IPFW3_LOADED); 10356a03354eSMatthew Dillon 10366a03354eSMatthew Dillon int error = 0; 10376a03354eSMatthew Dillon callout_init_mp(&ipfw_tick_callout); 10386a03354eSMatthew Dillon netmsg_init(&ipfw_timeout_netmsg, NULL, &netisr_adone_rport, 10396a03354eSMatthew Dillon MSGF_DROPABLE | MSGF_PRIORITY, ipfw_tick_dispatch); 10406a03354eSMatthew Dillon callout_reset(&ipfw_tick_callout, 10416a03354eSMatthew Dillon state_expiry_check_interval * hz, ipfw_tick, NULL); 10426a03354eSMatthew Dillon lwkt_replymsg(&nmsg->lmsg, error); 10436a03354eSMatthew Dillon ip_fw_basic_loaded=1; 10446a03354eSMatthew Dillon } 10456a03354eSMatthew Dillon 10466a03354eSMatthew Dillon static int 10476a03354eSMatthew Dillon ipfw_basic_init(void) 10486a03354eSMatthew Dillon { 10496a03354eSMatthew Dillon ipfw_basic_flush_state_prt = ipfw_basic_flush_state; 10506a03354eSMatthew Dillon ipfw_basic_append_state_prt = ipfw_basic_add_state; 10516a03354eSMatthew Dillon 10526a03354eSMatthew Dillon register_ipfw_module(MODULE_BASIC_ID, MODULE_BASIC_NAME); 10536a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_COUNT, 10546a03354eSMatthew Dillon (filter_func)check_count); 10556a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_SKIPTO, 10566a03354eSMatthew Dillon (filter_func)check_skipto); 10576a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_FORWARD, 10586a03354eSMatthew Dillon (filter_func)check_forward); 10596a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_KEEP_STATE, 10606a03354eSMatthew Dillon (filter_func)check_keep_state); 10616a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_CHECK_STATE, 10626a03354eSMatthew Dillon (filter_func)check_check_state); 10636a03354eSMatthew Dillon 10646a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, 10656a03354eSMatthew Dillon O_BASIC_IN, (filter_func)check_in); 10666a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, 10676a03354eSMatthew Dillon O_BASIC_OUT, (filter_func)check_out); 10686a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, 10696a03354eSMatthew Dillon O_BASIC_VIA, (filter_func)check_via); 10706a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, 10716a03354eSMatthew Dillon O_BASIC_XMIT, (filter_func)check_via); 10726a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, 10736a03354eSMatthew Dillon O_BASIC_RECV, (filter_func)check_via); 10746a03354eSMatthew Dillon 10756a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, 10766a03354eSMatthew Dillon O_BASIC_PROTO, (filter_func)check_proto); 10776a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, 10786a03354eSMatthew Dillon O_BASIC_PROB, (filter_func)check_prob); 10796a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, 10806a03354eSMatthew Dillon O_BASIC_IP_SRC, (filter_func)check_from); 10816a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, 10825284582fSBill Yuan O_BASIC_IP_SRC_LOOKUP, (filter_func)check_from_lookup); 10835284582fSBill Yuan register_ipfw_filter_funcs(MODULE_BASIC_ID, 108463317b93SBill Yuan O_BASIC_IP_SRC_ME, (filter_func)check_from_me); 108563317b93SBill Yuan register_ipfw_filter_funcs(MODULE_BASIC_ID, 108663317b93SBill Yuan O_BASIC_IP_SRC_MASK, (filter_func)check_from_mask); 108763317b93SBill Yuan register_ipfw_filter_funcs(MODULE_BASIC_ID, 10886a03354eSMatthew Dillon O_BASIC_IP_DST, (filter_func)check_to); 108963317b93SBill Yuan register_ipfw_filter_funcs(MODULE_BASIC_ID, 10905284582fSBill Yuan O_BASIC_IP_DST_LOOKUP, (filter_func)check_to_lookup); 10915284582fSBill Yuan register_ipfw_filter_funcs(MODULE_BASIC_ID, 109263317b93SBill Yuan O_BASIC_IP_DST_ME, (filter_func)check_to_me); 109363317b93SBill Yuan register_ipfw_filter_funcs(MODULE_BASIC_ID, 109463317b93SBill Yuan O_BASIC_IP_DST_MASK, (filter_func)check_to_mask); 10956a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, 10966a03354eSMatthew Dillon O_BASIC_TAG, (filter_func)check_tag); 10976a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, 10986a03354eSMatthew Dillon O_BASIC_UNTAG, (filter_func)check_untag); 10996a03354eSMatthew Dillon register_ipfw_filter_funcs(MODULE_BASIC_ID, 11006a03354eSMatthew Dillon O_BASIC_TAGGED, (filter_func)check_tagged); 1101*c1bde762SBill Yuan register_ipfw_filter_funcs(MODULE_BASIC_ID, 1102*c1bde762SBill Yuan O_BASIC_IP_SRCPORT, (filter_func)check_src_port); 1103*c1bde762SBill Yuan register_ipfw_filter_funcs(MODULE_BASIC_ID, 1104*c1bde762SBill Yuan O_BASIC_IP_DSTPORT, (filter_func)check_dst_port); 1105*c1bde762SBill Yuan register_ipfw_filter_funcs(MODULE_BASIC_ID, 1106*c1bde762SBill Yuan O_BASIC_IP_SRC_N_PORT, (filter_func)check_src_n_port); 1107*c1bde762SBill Yuan register_ipfw_filter_funcs(MODULE_BASIC_ID, 1108*c1bde762SBill Yuan O_BASIC_IP_DST_N_PORT, (filter_func)check_dst_n_port); 11096a03354eSMatthew Dillon 11106a03354eSMatthew Dillon int cpu; 11116a03354eSMatthew Dillon struct ipfw_context *ctx; 11126a03354eSMatthew Dillon 11136a03354eSMatthew Dillon for (cpu = 0; cpu < ncpus; cpu++) { 11146a03354eSMatthew Dillon ctx = ipfw_ctx[cpu]; 11156a03354eSMatthew Dillon if (ctx != NULL) { 11166a03354eSMatthew Dillon ctx->state_ctx = kmalloc(state_hash_size * 11176a03354eSMatthew Dillon sizeof(struct ipfw_state_context), 11186a03354eSMatthew Dillon M_IPFW3_BASIC, M_WAITOK | M_ZERO); 11196a03354eSMatthew Dillon ctx->state_hash_size = state_hash_size; 11206a03354eSMatthew Dillon } 11216a03354eSMatthew Dillon } 11226a03354eSMatthew Dillon 11236a03354eSMatthew Dillon struct netmsg_base smsg; 11246a03354eSMatthew Dillon netmsg_init(&smsg, NULL, &curthread->td_msgport, 11256a03354eSMatthew Dillon 0, ipfw_basic_init_dispatch); 11266a03354eSMatthew Dillon lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0); 11276a03354eSMatthew Dillon return 0; 11286a03354eSMatthew Dillon } 11296a03354eSMatthew Dillon 11306a03354eSMatthew Dillon static void 11316a03354eSMatthew Dillon ipfw_basic_stop_dispatch(netmsg_t nmsg) 11326a03354eSMatthew Dillon { 11336a03354eSMatthew Dillon IPFW_ASSERT_CFGPORT(&curthread->td_msgport); 11346a03354eSMatthew Dillon KKASSERT(IPFW3_LOADED); 11356a03354eSMatthew Dillon int error = 0; 11366a03354eSMatthew Dillon callout_stop(&ipfw_tick_callout); 11376a03354eSMatthew Dillon netmsg_service_sync(); 11386a03354eSMatthew Dillon crit_enter(); 11396a03354eSMatthew Dillon lwkt_dropmsg(&ipfw_timeout_netmsg.lmsg); 11406a03354eSMatthew Dillon crit_exit(); 11416a03354eSMatthew Dillon lwkt_replymsg(&nmsg->lmsg, error); 11426a03354eSMatthew Dillon ip_fw_basic_loaded=0; 11436a03354eSMatthew Dillon } 11446a03354eSMatthew Dillon 11456a03354eSMatthew Dillon static int 11466a03354eSMatthew Dillon ipfw_basic_stop(void) 11476a03354eSMatthew Dillon { 11486a03354eSMatthew Dillon int cpu,i; 11496a03354eSMatthew Dillon struct ipfw_state_context *state_ctx; 11506a03354eSMatthew Dillon struct ip_fw_state *state,*the_state; 11516a03354eSMatthew Dillon struct ipfw_context *ctx; 11526a03354eSMatthew Dillon if (unregister_ipfw_module(MODULE_BASIC_ID) ==0 ) { 11536a03354eSMatthew Dillon ipfw_basic_flush_state_prt = NULL; 11546a03354eSMatthew Dillon ipfw_basic_append_state_prt = NULL; 11556a03354eSMatthew Dillon 11566a03354eSMatthew Dillon for (cpu = 0; cpu < ncpus; cpu++) { 11576a03354eSMatthew Dillon ctx = ipfw_ctx[cpu]; 11586a03354eSMatthew Dillon if (ctx != NULL) { 11596a03354eSMatthew Dillon for (i = 0; i < state_hash_size; i++) { 11606a03354eSMatthew Dillon state_ctx = &ctx->state_ctx[i]; 11616a03354eSMatthew Dillon if (state_ctx != NULL) { 11626a03354eSMatthew Dillon state = state_ctx->state; 11636a03354eSMatthew Dillon while (state != NULL) { 11646a03354eSMatthew Dillon the_state = state; 11656a03354eSMatthew Dillon state = state->next; 11666a03354eSMatthew Dillon if (the_state == 11676a03354eSMatthew Dillon state_ctx->last) 11686a03354eSMatthew Dillon state_ctx->last = NULL; 11696a03354eSMatthew Dillon 11706a03354eSMatthew Dillon kfree(the_state, 11716a03354eSMatthew Dillon M_IPFW3_BASIC); 11726a03354eSMatthew Dillon } 11736a03354eSMatthew Dillon } 11746a03354eSMatthew Dillon } 11756a03354eSMatthew Dillon ctx->state_hash_size = 0; 11766a03354eSMatthew Dillon kfree(ctx->state_ctx, M_IPFW3_BASIC); 11776a03354eSMatthew Dillon ctx->state_ctx = NULL; 11786a03354eSMatthew Dillon } 11796a03354eSMatthew Dillon } 11806a03354eSMatthew Dillon struct netmsg_base smsg; 11816a03354eSMatthew Dillon netmsg_init(&smsg, NULL, &curthread->td_msgport, 11826a03354eSMatthew Dillon 0, ipfw_basic_stop_dispatch); 11836a03354eSMatthew Dillon return lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0); 11846a03354eSMatthew Dillon } 11856a03354eSMatthew Dillon return 1; 11866a03354eSMatthew Dillon } 11876a03354eSMatthew Dillon 11886a03354eSMatthew Dillon 11896a03354eSMatthew Dillon static int 11906a03354eSMatthew Dillon ipfw3_basic_modevent(module_t mod, int type, void *data) 11916a03354eSMatthew Dillon { 11926a03354eSMatthew Dillon int err; 11936a03354eSMatthew Dillon switch (type) { 11946a03354eSMatthew Dillon case MOD_LOAD: 11956a03354eSMatthew Dillon err = ipfw_basic_init(); 11966a03354eSMatthew Dillon break; 11976a03354eSMatthew Dillon case MOD_UNLOAD: 11986a03354eSMatthew Dillon err = ipfw_basic_stop(); 11996a03354eSMatthew Dillon break; 12006a03354eSMatthew Dillon default: 12016a03354eSMatthew Dillon err = 1; 12026a03354eSMatthew Dillon } 12036a03354eSMatthew Dillon return err; 12046a03354eSMatthew Dillon } 12056a03354eSMatthew Dillon 12066a03354eSMatthew Dillon static moduledata_t ipfw3_basic_mod = { 12076a03354eSMatthew Dillon "ipfw3_basic", 12086a03354eSMatthew Dillon ipfw3_basic_modevent, 12096a03354eSMatthew Dillon NULL 12106a03354eSMatthew Dillon }; 12116a03354eSMatthew Dillon DECLARE_MODULE(ipfw3_basic, ipfw3_basic_mod, SI_SUB_PROTO_END, SI_ORDER_ANY); 12126a03354eSMatthew Dillon MODULE_DEPEND(ipfw3_basic, ipfw3, 1, 1, 1); 12136a03354eSMatthew Dillon MODULE_VERSION(ipfw3_basic, 1); 1214