Changeset View
Changeset View
Standalone View
Standalone View
sys/netpfil/ipfw/ip_fw2.c
| Show First 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | |||||
| VNET_DEFINE(int, autoinc_step); | VNET_DEFINE(int, autoinc_step); | ||||
| VNET_DEFINE(int, fw_one_pass) = 1; | VNET_DEFINE(int, fw_one_pass) = 1; | ||||
| VNET_DEFINE(unsigned int, fw_tables_max); | VNET_DEFINE(unsigned int, fw_tables_max); | ||||
| VNET_DEFINE(unsigned int, fw_tables_sets) = 0; /* Don't use set-aware tables */ | VNET_DEFINE(unsigned int, fw_tables_sets) = 0; /* Don't use set-aware tables */ | ||||
| /* Use 128 tables by default */ | /* Use 128 tables by default */ | ||||
| static unsigned int default_fw_tables = IPFW_TABLES_DEFAULT; | static unsigned int default_fw_tables = IPFW_TABLES_DEFAULT; | ||||
| static int jump_lookup_pos(struct ip_fw_chain *chain, struct ip_fw *f, int num, | #ifndef IPFIREWALL_LINEAR_SKIPTO | ||||
| int tablearg, int jump_backwards); | VNET_DEFINE(int, skipto_cache) = 0; | ||||
| #ifndef LINEAR_SKIPTO | |||||
| static int jump_cached(struct ip_fw_chain *chain, struct ip_fw *f, int num, | |||||
| int tablearg, int jump_backwards); | |||||
| #define JUMP(ch, f, num, targ, back) jump_cached(ch, f, num, targ, back) | |||||
| #else | #else | ||||
| #define JUMP(ch, f, num, targ, back) jump_lookup_pos(ch, f, num, targ, back) | VNET_DEFINE(int, skipto_cache) = 1; | ||||
| #endif | #endif | ||||
| static uint32_t jump(struct ip_fw_chain *chain, struct ip_fw *f, | |||||
| uint32_t num, int tablearg, bool jump_backwards); | |||||
| /* | /* | ||||
| * Each rule belongs to one of 32 different sets (0..31). | * Each rule belongs to one of 32 different sets (0..31). | ||||
| * The variable set_disable contains one bit per set. | * The variable set_disable contains one bit per set. | ||||
| * If the bit is set, all rules in the corresponding set | * If the bit is set, all rules in the corresponding set | ||||
| * are disabled. Set RESVD_SET(31) is reserved for the default rule | * are disabled. Set RESVD_SET(31) is reserved for the default rule | ||||
| * and rules that are not deleted by the flush command, | * and rules that are not deleted by the flush command, | ||||
| * and CANNOT be disabled. | * and CANNOT be disabled. | ||||
| * Rules in set RESVD_SET can only be deleted individually. | * Rules in set RESVD_SET can only be deleted individually. | ||||
| Show All 37 Lines | SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step, | ||||
| CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(autoinc_step), 0, | CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(autoinc_step), 0, | ||||
| "Rule number auto-increment step"); | "Rule number auto-increment step"); | ||||
| SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, | SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose, | ||||
| CTLFLAG_VNET | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_verbose), 0, | CTLFLAG_VNET | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_verbose), 0, | ||||
| "Log matches to ipfw rules"); | "Log matches to ipfw rules"); | ||||
| SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, | SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, | ||||
| CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(verbose_limit), 0, | CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(verbose_limit), 0, | ||||
| "Set upper limit of matches of ipfw rules logged"); | "Set upper limit of matches of ipfw rules logged"); | ||||
| SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, skipto_cache, | |||||
| CTLFLAG_VNET | CTLFLAG_RD, &VNET_NAME(skipto_cache), 0, | |||||
| "Status of linear skipto cache: 1 - enabled, 0 - disabled."); | |||||
| SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, default_rule, CTLFLAG_RD, | SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, default_rule, CTLFLAG_RD, | ||||
| &dummy_def, 0, | &dummy_def, 0, | ||||
| "The default/max possible rule number."); | "The default/max possible rule number."); | ||||
| SYSCTL_PROC(_net_inet_ip_fw, OID_AUTO, tables_max, | SYSCTL_PROC(_net_inet_ip_fw, OID_AUTO, tables_max, | ||||
| CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, | CTLFLAG_VNET | CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, | ||||
| 0, 0, sysctl_ipfw_table_num, "IU", | 0, 0, sysctl_ipfw_table_num, "IU", | ||||
| "Maximum number of concurrently used tables"); | "Maximum number of concurrently used tables"); | ||||
| SYSCTL_PROC(_net_inet_ip_fw, OID_AUTO, tables_sets, | SYSCTL_PROC(_net_inet_ip_fw, OID_AUTO, tables_sets, | ||||
| ▲ Show 20 Lines • Show All 1,013 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| args->rule.chain_id = chain->id; | args->rule.chain_id = chain->id; | ||||
| args->rule.slot = slot + 1; /* we use 0 as a marker */ | args->rule.slot = slot + 1; /* we use 0 as a marker */ | ||||
| args->rule.rule_id = 1 + chain->map[slot]->id; | args->rule.rule_id = 1 + chain->map[slot]->id; | ||||
| args->rule.rulenum = chain->map[slot]->rulenum; | args->rule.rulenum = chain->map[slot]->rulenum; | ||||
| args->flags |= IPFW_ARGS_REF; | args->flags |= IPFW_ARGS_REF; | ||||
| } | } | ||||
| static int | static uint32_t | ||||
| jump_lookup_pos(struct ip_fw_chain *chain, struct ip_fw *f, int num, | jump_lookup_pos(struct ip_fw_chain *chain, struct ip_fw *f, uint32_t num, | ||||
| int tablearg, int jump_backwards) | int tablearg, bool jump_backwards) | ||||
| { | { | ||||
| int f_pos, i; | int f_pos, i; | ||||
| /* | |||||
| * Make sure we do not jump backward. | |||||
| */ | |||||
| i = IP_FW_ARG_TABLEARG(chain, num, skipto); | i = IP_FW_ARG_TABLEARG(chain, num, skipto); | ||||
| /* make sure we do not jump backward */ | if (!jump_backwards && i <= f->rulenum) | ||||
| if (jump_backwards == 0 && i <= f->rulenum) | |||||
| i = f->rulenum + 1; | i = f->rulenum + 1; | ||||
| #ifndef LINEAR_SKIPTO | if (V_skipto_cache == 0) | ||||
| if (chain->idxmap != NULL) | |||||
| f_pos = chain->idxmap[i]; | |||||
| else | |||||
| f_pos = ipfw_find_rule(chain, i, 0); | f_pos = ipfw_find_rule(chain, i, 0); | ||||
| #else | else { | ||||
| /* | |||||
| * Make sure we do not do out of bounds access. | |||||
| */ | |||||
| if (i >= IPFW_DEFAULT_RULE) | |||||
| i = IPFW_DEFAULT_RULE - 1; | |||||
| f_pos = chain->idxmap[i]; | f_pos = chain->idxmap[i]; | ||||
| #endif /* LINEAR_SKIPTO */ | } | ||||
| return (f_pos); | return (f_pos); | ||||
| } | } | ||||
| static uint32_t | |||||
| #ifndef LINEAR_SKIPTO | jump(struct ip_fw_chain *chain, struct ip_fw *f, uint32_t num, | ||||
| /* | int tablearg, bool jump_backwards) | ||||
| * Helper function to enable cached rule lookups using | |||||
| * cache.id and cache.pos fields in ipfw rule. | |||||
| */ | |||||
| static int | |||||
| jump_cached(struct ip_fw_chain *chain, struct ip_fw *f, int num, | |||||
| int tablearg, int jump_backwards) | |||||
| { | { | ||||
| int f_pos; | int f_pos; | ||||
| /* Can't use cache with IP_FW_TARG */ | /* Can't use cache with IP_FW_TARG */ | ||||
| if (num == IP_FW_TARG) | if (num == IP_FW_TARG) | ||||
| return jump_lookup_pos(chain, f, num, tablearg, jump_backwards); | return jump_lookup_pos(chain, f, num, tablearg, jump_backwards); | ||||
| /* | /* | ||||
| Show All 28 Lines | #else | ||||
| f->cache.pos = f_pos; | f->cache.pos = f_pos; | ||||
| /* Store id after pos */ | /* Store id after pos */ | ||||
| atomic_thread_fence_rel(); | atomic_thread_fence_rel(); | ||||
| f->cache.id = chain->id; | f->cache.id = chain->id; | ||||
| #endif /* !__LP64__ */ | #endif /* !__LP64__ */ | ||||
| return (f_pos); | return (f_pos); | ||||
| } | } | ||||
| #endif /* !LINEAR_SKIPTO */ | |||||
| #define TARG(k, f) IP_FW_ARG_TABLEARG(chain, k, f) | #define TARG(k, f) IP_FW_ARG_TABLEARG(chain, k, f) | ||||
| static inline int | |||||
| tvalue_match(struct ip_fw_chain *ch, const ipfw_insn_table *cmd, | |||||
| uint32_t tablearg) | |||||
| { | |||||
| uint32_t tvalue; | |||||
| switch (IPFW_TVALUE_TYPE(&cmd->o)) { | |||||
| case TVALUE_PIPE: | |||||
| tvalue = TARG_VAL(ch, tablearg, pipe); | |||||
| break; | |||||
| case TVALUE_DIVERT: | |||||
| tvalue = TARG_VAL(ch, tablearg, divert); | |||||
| break; | |||||
| case TVALUE_SKIPTO: | |||||
| tvalue = TARG_VAL(ch, tablearg, skipto); | |||||
| break; | |||||
| case TVALUE_NETGRAPH: | |||||
| tvalue = TARG_VAL(ch, tablearg, netgraph); | |||||
| break; | |||||
| case TVALUE_FIB: | |||||
| tvalue = TARG_VAL(ch, tablearg, fib); | |||||
| break; | |||||
| case TVALUE_NAT: | |||||
| tvalue = TARG_VAL(ch, tablearg, nat); | |||||
| break; | |||||
| case TVALUE_NH4: | |||||
| tvalue = TARG_VAL(ch, tablearg, nh4); | |||||
| break; | |||||
| case TVALUE_DSCP: | |||||
| tvalue = TARG_VAL(ch, tablearg, dscp); | |||||
| break; | |||||
| case TVALUE_LIMIT: | |||||
| tvalue = TARG_VAL(ch, tablearg, limit); | |||||
| break; | |||||
| case TVALUE_MARK: | |||||
| tvalue = TARG_VAL(ch, tablearg, mark); | |||||
| break; | |||||
| case TVALUE_TAG: | |||||
| default: | |||||
| tvalue = TARG_VAL(ch, tablearg, tag); | |||||
| break; | |||||
| } | |||||
| return (tvalue == cmd->value); | |||||
| } | |||||
| /* | /* | ||||
| * The main check routine for the firewall. | * The main check routine for the firewall. | ||||
| * | * | ||||
| * All arguments are in args so we can modify them and return them | * All arguments are in args so we can modify them and return them | ||||
| * back to the caller. | * back to the caller. | ||||
| * | * | ||||
| * Parameters: | * Parameters: | ||||
| * | * | ||||
| ▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | ipfw_chk(struct ip_fw_args *args) | ||||
| * these types of constraints, as well as decrease contention | * these types of constraints, as well as decrease contention | ||||
| * on pcb related locks. | * on pcb related locks. | ||||
| */ | */ | ||||
| #ifndef __FreeBSD__ | #ifndef __FreeBSD__ | ||||
| struct bsd_ucred ucred_cache; | struct bsd_ucred ucred_cache; | ||||
| #else | #else | ||||
| struct ucred *ucred_cache = NULL; | struct ucred *ucred_cache = NULL; | ||||
| #endif | #endif | ||||
| uint32_t f_pos = 0; /* index of current rule in the array */ | |||||
| int ucred_lookup = 0; | int ucred_lookup = 0; | ||||
| int f_pos = 0; /* index of current rule in the array */ | |||||
| int retval = 0; | int retval = 0; | ||||
| struct ifnet *oif, *iif; | struct ifnet *oif, *iif; | ||||
| /* | /* | ||||
| * hlen The length of the IP header. | * hlen The length of the IP header. | ||||
| */ | */ | ||||
| u_int hlen = 0; /* hlen >0 means we have an IP pkt */ | u_int hlen = 0; /* hlen >0 means we have an IP pkt */ | ||||
| ▲ Show 20 Lines • Show All 643 Lines • ▼ Show 20 Lines | #endif | ||||
| case O_IP_SRC: | case O_IP_SRC: | ||||
| match = is_ipv4 && | match = is_ipv4 && | ||||
| (((ipfw_insn_ip *)cmd)->addr.s_addr == | (((ipfw_insn_ip *)cmd)->addr.s_addr == | ||||
| src_ip.s_addr); | src_ip.s_addr); | ||||
| break; | break; | ||||
| case O_IP_DST_LOOKUP: | case O_IP_DST_LOOKUP: | ||||
| { | if (IPFW_LOOKUP_TYPE(cmd) != LOOKUP_NONE) { | ||||
| if (cmdlen > F_INSN_SIZE(ipfw_insn_u32)) { | void *pkey = NULL; | ||||
| void *pkey; | uint32_t key, vidx; | ||||
| uint32_t vidx, key; | |||||
| uint16_t keylen = 0; /* zero if can't match the packet */ | uint16_t keylen = 0; /* zero if can't match the packet */ | ||||
| uint8_t lookup_type; | |||||
| /* Determine lookup key type */ | lookup_type = IPFW_LOOKUP_TYPE(cmd); | ||||
| vidx = ((ipfw_insn_u32 *)cmd)->d[1]; | |||||
| switch (vidx) { | switch (lookup_type) { | ||||
| case LOOKUP_DST_IP: | case LOOKUP_DST_IP: | ||||
| case LOOKUP_SRC_IP: | case LOOKUP_SRC_IP: | ||||
| /* Need IP frame */ | if (is_ipv4) { | ||||
| if (is_ipv6 == 0 && is_ipv4 == 0) | keylen = sizeof(in_addr_t); | ||||
| if (lookup_type == LOOKUP_DST_IP) | |||||
| pkey = &dst_ip; | |||||
| else | |||||
| pkey = &src_ip; | |||||
| } else if (is_ipv6) { | |||||
| keylen = sizeof(struct in6_addr); | |||||
| if (lookup_type == LOOKUP_DST_IP) | |||||
| pkey = &args->f_id.dst_ip6; | |||||
| else | |||||
| pkey = &args->f_id.src_ip6; | |||||
| } else /* only for L3 */ | |||||
| break; | break; | ||||
| if (vidx == LOOKUP_DST_IP) | case LOOKUP_DSCP: | ||||
| pkey = is_ipv6 ? | if (is_ipv4) | ||||
| (void *)&args->f_id.dst_ip6: | key = ip->ip_tos >> 2; | ||||
| (void *)&dst_ip; | else if (is_ipv6) | ||||
| key = IPV6_DSCP( | |||||
| (struct ip6_hdr *)ip) >> 2; | |||||
| else | else | ||||
| pkey = is_ipv6 ? | break; /* only for L3 */ | ||||
| (void *)&args->f_id.src_ip6: | |||||
| (void *)&src_ip; | key &= 0x3f; | ||||
| keylen = is_ipv6 ? | if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) | ||||
| sizeof(struct in6_addr): | key &= insntod(cmd, table)->value; | ||||
| sizeof(in_addr_t); | pkey = &key; | ||||
| keylen = sizeof(key); | |||||
| break; | break; | ||||
| case LOOKUP_DST_PORT: | case LOOKUP_DST_PORT: | ||||
| case LOOKUP_SRC_PORT: | case LOOKUP_SRC_PORT: | ||||
| /* Need IP frame */ | /* only for L3 */ | ||||
| if (is_ipv6 == 0 && is_ipv4 == 0) | if (is_ipv6 == 0 && is_ipv4 == 0) { | ||||
| break; | break; | ||||
| } | |||||
| /* Skip fragments */ | /* Skip fragments */ | ||||
| if (offset != 0) | if (offset != 0) { | ||||
| break; | break; | ||||
| } | |||||
| /* Skip proto without ports */ | /* Skip proto without ports */ | ||||
| if (proto != IPPROTO_TCP && | if (proto != IPPROTO_TCP && | ||||
| proto != IPPROTO_UDP && | proto != IPPROTO_UDP && | ||||
| proto != IPPROTO_UDPLITE && | proto != IPPROTO_UDPLITE && | ||||
| proto != IPPROTO_SCTP) | proto != IPPROTO_SCTP) | ||||
| break; | break; | ||||
| key = vidx == LOOKUP_DST_PORT ? | if (lookup_type == LOOKUP_DST_PORT) | ||||
| dst_port: | key = dst_port; | ||||
| src_port; | else | ||||
| key = src_port; | |||||
| pkey = &key; | pkey = &key; | ||||
| if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) | |||||
| key &= insntod(cmd, table)->value; | |||||
| keylen = sizeof(key); | keylen = sizeof(key); | ||||
| break; | break; | ||||
| case LOOKUP_DST_MAC: | |||||
| case LOOKUP_SRC_MAC: | |||||
| /* only for L2 */ | |||||
| if ((args->flags & IPFW_ARGS_ETHER) == 0) | |||||
| break; | |||||
| pkey = lookup_type == LOOKUP_DST_MAC ? | |||||
| eh->ether_dhost : eh->ether_shost; | |||||
| keylen = ETHER_ADDR_LEN; | |||||
| break; | |||||
| #ifndef USERSPACE | |||||
| case LOOKUP_UID: | case LOOKUP_UID: | ||||
| case LOOKUP_JAIL: | case LOOKUP_JAIL: | ||||
| check_uidgid( | check_uidgid(insntod(cmd, u32), | ||||
| (ipfw_insn_u32 *)cmd, | |||||
| args, &ucred_lookup, | args, &ucred_lookup, | ||||
| #ifdef __FreeBSD__ | |||||
| &ucred_cache); | &ucred_cache); | ||||
| key = vidx == LOOKUP_UID ? | if (lookup_type == LOOKUP_UID) | ||||
| ucred_cache->cr_uid: | key = ucred_cache->cr_uid; | ||||
| ucred_cache->cr_prison->pr_id; | else if (lookup_type == LOOKUP_JAIL) | ||||
| key = ucred_cache->cr_prison->pr_id; | |||||
| #else /* !__FreeBSD__ */ | |||||
| (void *)&ucred_cache); | |||||
| if (lookup_type == LOOKUP_UID) | |||||
| key = ucred_cache.uid; | |||||
| else if (lookup_type == LOOKUP_JAIL) | |||||
| key = ucred_cache.xid; | |||||
| #endif /* !__FreeBSD__ */ | |||||
| pkey = &key; | pkey = &key; | ||||
| if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) | |||||
| key &= insntod(cmd, table)->value; | |||||
| keylen = sizeof(key); | keylen = sizeof(key); | ||||
| break; | break; | ||||
| case LOOKUP_DSCP: | #endif /* !USERSPACE */ | ||||
| /* Need IP frame */ | case LOOKUP_MARK: | ||||
| if (is_ipv6 == 0 && is_ipv4 == 0) | key = args->rule.pkt_mark; | ||||
| break; | if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) | ||||
| if (is_ipv6) | key &= insntod(cmd, table)->value; | ||||
| key = IPV6_DSCP( | |||||
| (struct ip6_hdr *)ip) >> 2; | |||||
| else | |||||
| key = ip->ip_tos >> 2; | |||||
| pkey = &key; | pkey = &key; | ||||
| keylen = sizeof(key); | keylen = sizeof(key); | ||||
| break; | break; | ||||
| case LOOKUP_DST_MAC: | case LOOKUP_RULENUM: | ||||
| case LOOKUP_SRC_MAC: | key = f->rulenum; | ||||
| /* Need ether frame */ | if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) | ||||
| if ((args->flags & IPFW_ARGS_ETHER) == 0) | key &= insntod(cmd, table)->value; | ||||
| break; | |||||
| pkey = vidx == LOOKUP_DST_MAC ? | |||||
| eh->ether_dhost: | |||||
| eh->ether_shost; | |||||
| keylen = ETHER_ADDR_LEN; | |||||
| break; | |||||
| case LOOKUP_MARK: | |||||
| key = args->rule.pkt_mark; | |||||
| pkey = &key; | pkey = &key; | ||||
| keylen = sizeof(key); | keylen = sizeof(key); | ||||
| break; | break; | ||||
| } | } | ||||
| /* unknown key type */ | |||||
| if (keylen == 0) | if (keylen == 0) | ||||
| break; | break; | ||||
| match = ipfw_lookup_table(chain, | match = ipfw_lookup_table(chain, | ||||
| cmd->arg1, keylen, pkey, &vidx); | insntod(cmd, kidx)->kidx, keylen, | ||||
| if (!match) | pkey, &vidx); | ||||
| break; | |||||
| if (match) | |||||
| tablearg = vidx; | tablearg = vidx; | ||||
| break; | break; | ||||
| } | } | ||||
| /* cmdlen =< F_INSN_SIZE(ipfw_insn_u32) */ | /* LOOKUP_NONE */ | ||||
| /* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
| } | |||||
| case O_IP_SRC_LOOKUP: | case O_IP_SRC_LOOKUP: | ||||
| { | { | ||||
| void *pkey; | void *pkey; | ||||
| uint32_t vidx; | uint32_t vidx; | ||||
| uint16_t keylen; | uint16_t keylen; | ||||
| if (is_ipv4) { | if (is_ipv4) { | ||||
| keylen = sizeof(in_addr_t); | keylen = sizeof(in_addr_t); | ||||
| if (cmd->opcode == O_IP_DST_LOOKUP) | if (cmd->opcode == O_IP_DST_LOOKUP) | ||||
| pkey = &dst_ip; | pkey = &dst_ip; | ||||
| else | else | ||||
| pkey = &src_ip; | pkey = &src_ip; | ||||
| } else if (is_ipv6) { | } else if (is_ipv6) { | ||||
| keylen = sizeof(struct in6_addr); | keylen = sizeof(struct in6_addr); | ||||
| if (cmd->opcode == O_IP_DST_LOOKUP) | if (cmd->opcode == O_IP_DST_LOOKUP) | ||||
| pkey = &args->f_id.dst_ip6; | pkey = &args->f_id.dst_ip6; | ||||
| else | else | ||||
| pkey = &args->f_id.src_ip6; | pkey = &args->f_id.src_ip6; | ||||
| } else | } else | ||||
| break; | break; | ||||
| match = ipfw_lookup_table(chain, cmd->arg1, | match = ipfw_lookup_table(chain, | ||||
| insntod(cmd, kidx)->kidx, | |||||
| keylen, pkey, &vidx); | keylen, pkey, &vidx); | ||||
| if (!match) | if (!match) | ||||
| break; | break; | ||||
| if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) { | if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) { | ||||
| match = ((ipfw_insn_u32 *)cmd)->d[0] == | match = tvalue_match(chain, | ||||
| TARG_VAL(chain, vidx, tag); | insntod(cmd, table), vidx); | ||||
| if (!match) | if (!match) | ||||
| break; | break; | ||||
| } | } | ||||
| tablearg = vidx; | tablearg = vidx; | ||||
| break; | break; | ||||
| } | } | ||||
| case O_MAC_SRC_LOOKUP: | case O_MAC_SRC_LOOKUP: | ||||
| case O_MAC_DST_LOOKUP: | case O_MAC_DST_LOOKUP: | ||||
| { | { | ||||
| void *pkey; | void *pkey; | ||||
| uint32_t vidx; | uint32_t vidx; | ||||
| uint16_t keylen = ETHER_ADDR_LEN; | uint16_t keylen = ETHER_ADDR_LEN; | ||||
| /* Need ether frame */ | /* Need ether frame */ | ||||
| if ((args->flags & IPFW_ARGS_ETHER) == 0) | if ((args->flags & IPFW_ARGS_ETHER) == 0) | ||||
| break; | break; | ||||
| if (cmd->opcode == O_MAC_DST_LOOKUP) | if (cmd->opcode == O_MAC_DST_LOOKUP) | ||||
| pkey = eh->ether_dhost; | pkey = eh->ether_dhost; | ||||
| else | else | ||||
| pkey = eh->ether_shost; | pkey = eh->ether_shost; | ||||
| match = ipfw_lookup_table(chain, cmd->arg1, | match = ipfw_lookup_table(chain, | ||||
| insntod(cmd, kidx)->kidx, | |||||
| keylen, pkey, &vidx); | keylen, pkey, &vidx); | ||||
| if (!match) | if (!match) | ||||
| break; | break; | ||||
| if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) { | if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) { | ||||
| match = ((ipfw_insn_u32 *)cmd)->d[0] == | match = tvalue_match(chain, | ||||
| TARG_VAL(chain, vidx, tag); | insntod(cmd, table), vidx); | ||||
| if (!match) | if (!match) | ||||
| break; | break; | ||||
| } | } | ||||
| tablearg = vidx; | tablearg = vidx; | ||||
| break; | break; | ||||
| } | } | ||||
| case O_IP_FLOW_LOOKUP: | case O_IP_FLOW_LOOKUP: | ||||
| { | { | ||||
| uint32_t v = 0; | uint32_t vidx = 0; | ||||
| match = ipfw_lookup_table(chain, | match = ipfw_lookup_table(chain, | ||||
| cmd->arg1, 0, &args->f_id, &v); | insntod(cmd, kidx)->kidx, 0, | ||||
| &args->f_id, &vidx); | |||||
| if (!match) | if (!match) | ||||
| break; | break; | ||||
| if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) | if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) | ||||
| match = ((ipfw_insn_u32 *)cmd)->d[0] == | match = tvalue_match(chain, | ||||
| TARG_VAL(chain, v, tag); | insntod(cmd, table), vidx); | ||||
| if (match) | if (match) | ||||
| tablearg = v; | tablearg = vidx; | ||||
| } | |||||
| break; | break; | ||||
| } | |||||
| case O_IP_SRC_MASK: | case O_IP_SRC_MASK: | ||||
| case O_IP_DST_MASK: | case O_IP_DST_MASK: | ||||
| if (is_ipv4) { | if (is_ipv4) { | ||||
| uint32_t a = | uint32_t a = | ||||
| (cmd->opcode == O_IP_DST_MASK) ? | (cmd->opcode == O_IP_DST_MASK) ? | ||||
| dst_ip.s_addr : src_ip.s_addr; | dst_ip.s_addr : src_ip.s_addr; | ||||
| uint32_t *p = ((ipfw_insn_u32 *)cmd)->d; | uint32_t *p = ((ipfw_insn_u32 *)cmd)->d; | ||||
| int i = cmdlen-1; | int i = cmdlen-1; | ||||
| ▲ Show 20 Lines • Show All 306 Lines • ▼ Show 20 Lines | #endif /* INET6 */ | ||||
| at = (struct pf_mtag *)(mtag + 1); | at = (struct pf_mtag *)(mtag + 1); | ||||
| at->qid = altq->qid; | at->qid = altq->qid; | ||||
| at->hdr = ip; | at->hdr = ip; | ||||
| break; | break; | ||||
| } | } | ||||
| case O_LOG: | case O_LOG: | ||||
| ipfw_log(chain, f, hlen, args, | ipfw_log(chain, f, hlen, args, | ||||
| offset | ip6f_mf, tablearg, ip); | offset | ip6f_mf, tablearg, ip, eh); | ||||
| match = 1; | match = 1; | ||||
| break; | break; | ||||
| case O_PROB: | case O_PROB: | ||||
| match = (random()<((ipfw_insn_u32 *)cmd)->d[0]); | match = (random()<((ipfw_insn_u32 *)cmd)->d[0]); | ||||
| break; | break; | ||||
| case O_VERREVPATH: | case O_VERREVPATH: | ||||
| ▲ Show 20 Lines • Show All 222 Lines • ▼ Show 20 Lines | #endif /* !USERSPACE */ | ||||
| break; | break; | ||||
| } | } | ||||
| case O_MARK: { | case O_MARK: { | ||||
| uint32_t mark; | uint32_t mark; | ||||
| if (cmd->arg1 == IP_FW_TARG) | if (cmd->arg1 == IP_FW_TARG) | ||||
| mark = TARG_VAL(chain, tablearg, mark); | mark = TARG_VAL(chain, tablearg, mark); | ||||
| else | else | ||||
| mark = ((ipfw_insn_u32 *)cmd)->d[0]; | mark = insntoc(cmd, u32)->d[0]; | ||||
| match = | match = | ||||
| (args->rule.pkt_mark & | (args->rule.pkt_mark & | ||||
| ((ipfw_insn_u32 *)cmd)->d[1]) == | insntoc(cmd, u32)->d[1]) == | ||||
| (mark & ((ipfw_insn_u32 *)cmd)->d[1]); | (mark & insntoc(cmd, u32)->d[1]); | ||||
| break; | break; | ||||
| } | } | ||||
| /* | /* | ||||
| * The second set of opcodes represents 'actions', | * The second set of opcodes represents 'actions', | ||||
| * i.e. the terminal part of a rule once the packet | * i.e. the terminal part of a rule once the packet | ||||
| * matches all previous patterns. | * matches all previous patterns. | ||||
| * Typically there is only one action for each rule, | * Typically there is only one action for each rule, | ||||
| * and the opcode is stored at the end of the rule | * and the opcode is stored at the end of the rule | ||||
| * (but there are exceptions -- see below). | * (but there are exceptions -- see below). | ||||
| * | * | ||||
| ▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | #endif /* !USERSPACE */ | ||||
| case O_COUNT: | case O_COUNT: | ||||
| IPFW_INC_RULE_COUNTER(f, pktlen); | IPFW_INC_RULE_COUNTER(f, pktlen); | ||||
| l = 0; /* exit inner loop */ | l = 0; /* exit inner loop */ | ||||
| break; | break; | ||||
| case O_SKIPTO: | case O_SKIPTO: | ||||
| IPFW_INC_RULE_COUNTER(f, pktlen); | IPFW_INC_RULE_COUNTER(f, pktlen); | ||||
| f_pos = JUMP(chain, f, cmd->arg1, tablearg, 0); | f_pos = jump(chain, f, | ||||
| insntod(cmd, u32)->d[0], tablearg, false); | |||||
| /* | /* | ||||
| * Skip disabled rules, and re-enter | * Skip disabled rules, and re-enter | ||||
| * the inner loop with the correct | * the inner loop with the correct | ||||
| * f_pos, f, l and cmd. | * f_pos, f, l and cmd. | ||||
| * Also clear cmdlen and skip_or | * Also clear cmdlen and skip_or | ||||
| */ | */ | ||||
| for (; f_pos < chain->n_rules - 1 && | for (; f_pos < chain->n_rules - 1 && | ||||
| (V_set_disable & | (V_set_disable & | ||||
| Show All 17 Lines | #endif /* !USERSPACE */ | ||||
| * is different from `skipto' in that any call | * is different from `skipto' in that any call | ||||
| * address is possible (`skipto' must prevent | * address is possible (`skipto' must prevent | ||||
| * backward jumps to avoid endless loops). | * backward jumps to avoid endless loops). | ||||
| * We have `return' action when F_NOT flag is | * We have `return' action when F_NOT flag is | ||||
| * present. The `m_tag_id' field is used as | * present. The `m_tag_id' field is used as | ||||
| * stack pointer. | * stack pointer. | ||||
| */ | */ | ||||
| struct m_tag *mtag; | struct m_tag *mtag; | ||||
| uint16_t jmpto, *stack; | uint32_t jmpto, *stack; | ||||
| #define IS_CALL ((cmd->len & F_NOT) == 0) | #define IS_CALL ((cmd->len & F_NOT) == 0) | ||||
| #define IS_RETURN ((cmd->len & F_NOT) != 0) | #define IS_RETURN ((cmd->len & F_NOT) != 0) | ||||
| /* | /* | ||||
| * Hand-rolled version of m_tag_locate() with | * Hand-rolled version of m_tag_locate() with | ||||
| * wildcard `type'. | * wildcard `type'. | ||||
| * If not already tagged, allocate new tag. | * If not already tagged, allocate new tag. | ||||
| */ | */ | ||||
| mtag = m_tag_first(m); | mtag = m_tag_first(m); | ||||
| while (mtag != NULL) { | while (mtag != NULL) { | ||||
| if (mtag->m_tag_cookie == | if (mtag->m_tag_cookie == | ||||
| MTAG_IPFW_CALL) | MTAG_IPFW_CALL) | ||||
| break; | break; | ||||
| mtag = m_tag_next(m, mtag); | mtag = m_tag_next(m, mtag); | ||||
| } | } | ||||
| /* | |||||
| * We keep ruleset id in the first element | |||||
| * of stack. If it doesn't match chain->id, | |||||
| * then we can't trust information in the | |||||
| * stack, since rules were changed. | |||||
| * We reset stack pointer to be able reuse | |||||
| * tag if it will be needed. | |||||
| */ | |||||
| if (mtag != NULL) { | |||||
| stack = (uint32_t *)(mtag + 1); | |||||
| if (stack[0] != chain->id) { | |||||
| stack[0] = chain->id; | |||||
| mtag->m_tag_id = 0; | |||||
| } | |||||
| } | |||||
| if (mtag == NULL && IS_CALL) { | if (mtag == NULL && IS_CALL) { | ||||
| mtag = m_tag_alloc(MTAG_IPFW_CALL, 0, | mtag = m_tag_alloc(MTAG_IPFW_CALL, 0, | ||||
| IPFW_CALLSTACK_SIZE * | IPFW_CALLSTACK_SIZE * | ||||
| sizeof(uint16_t), M_NOWAIT); | sizeof(uint32_t), M_NOWAIT); | ||||
| if (mtag != NULL) | if (mtag != NULL) | ||||
| m_tag_prepend(m, mtag); | m_tag_prepend(m, mtag); | ||||
| stack = (uint32_t *)(mtag + 1); | |||||
| stack[0] = chain->id; | |||||
| } | } | ||||
| /* | /* | ||||
| * On error both `call' and `return' just | * On error both `call' and `return' just | ||||
| * continue with next rule. | * continue with next rule. | ||||
| */ | */ | ||||
| if (IS_RETURN && (mtag == NULL || | if (IS_RETURN && (mtag == NULL || | ||||
| mtag->m_tag_id == 0)) { | mtag->m_tag_id == 0)) { | ||||
| l = 0; /* exit inner loop */ | l = 0; /* exit inner loop */ | ||||
| break; | break; | ||||
| } | } | ||||
| if (IS_CALL && (mtag == NULL || | if (IS_CALL && (mtag == NULL || | ||||
| mtag->m_tag_id >= IPFW_CALLSTACK_SIZE)) { | mtag->m_tag_id >= | ||||
| IPFW_CALLSTACK_SIZE - 1)) { | |||||
| printf("ipfw: call stack error, " | printf("ipfw: call stack error, " | ||||
| "go to next rule\n"); | "go to next rule\n"); | ||||
| l = 0; /* exit inner loop */ | l = 0; /* exit inner loop */ | ||||
| break; | break; | ||||
| } | } | ||||
| IPFW_INC_RULE_COUNTER(f, pktlen); | IPFW_INC_RULE_COUNTER(f, pktlen); | ||||
| stack = (uint16_t *)(mtag + 1); | stack = (uint32_t *)(mtag + 1); | ||||
| /* | |||||
| * The `call' action may use cached f_pos | |||||
| * (in f->next_rule), whose version is written | |||||
| * in f->next_rule. | |||||
| * The `return' action, however, doesn't have | |||||
| * fixed jump address in cmd->arg1 and can't use | |||||
| * cache. | |||||
| */ | |||||
| if (IS_CALL) { | if (IS_CALL) { | ||||
| stack[mtag->m_tag_id] = f->rulenum; | stack[++mtag->m_tag_id] = f_pos; | ||||
| mtag->m_tag_id++; | f_pos = jump(chain, f, | ||||
| f_pos = JUMP(chain, f, cmd->arg1, | insntod(cmd, u32)->d[0], | ||||
| tablearg, 1); | tablearg, true); | ||||
| } else { /* `return' action */ | } else { /* `return' action */ | ||||
| mtag->m_tag_id--; | jmpto = stack[mtag->m_tag_id--]; | ||||
| jmpto = stack[mtag->m_tag_id] + 1; | if (cmd->arg1 == RETURN_NEXT_RULE) | ||||
| f_pos = ipfw_find_rule(chain, jmpto, 0); | f_pos = jmpto + 1; | ||||
| else /* RETURN_NEXT_RULENUM */ | |||||
| f_pos = ipfw_find_rule(chain, | |||||
| chain->map[ | |||||
| jmpto]->rulenum + 1, 0); | |||||
| } | } | ||||
| /* | /* | ||||
| * Skip disabled rules, and re-enter | * Skip disabled rules, and re-enter | ||||
| * the inner loop with the correct | * the inner loop with the correct | ||||
| * f_pos, f, l and cmd. | * f_pos, f, l and cmd. | ||||
| * Also clear cmdlen and skip_or | * Also clear cmdlen and skip_or | ||||
| */ | */ | ||||
| MPASS(f_pos < chain->n_rules - 1); | |||||
| for (; f_pos < chain->n_rules - 1 && | for (; f_pos < chain->n_rules - 1 && | ||||
| (V_set_disable & | (V_set_disable & | ||||
| (1 << chain->map[f_pos]->set)); f_pos++) | (1 << chain->map[f_pos]->set)); f_pos++) | ||||
| ; | ; | ||||
| /* Re-enter the inner loop at the dest rule. */ | /* | ||||
| * Re-enter the inner loop at the dest | |||||
| * rule. | |||||
| */ | |||||
| f = chain->map[f_pos]; | f = chain->map[f_pos]; | ||||
| l = f->cmd_len; | l = f->cmd_len; | ||||
| cmd = f->cmd; | cmd = f->cmd; | ||||
| cmdlen = 0; | cmdlen = 0; | ||||
| skip_or = 0; | skip_or = 0; | ||||
| continue; | continue; | ||||
| break; /* NOTREACHED */ | break; /* NOTREACHED */ | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 236 Lines • ▼ Show 20 Lines | #endif | ||||
| break; | break; | ||||
| } | } | ||||
| case O_SETMARK: { | case O_SETMARK: { | ||||
| l = 0; /* exit inner loop */ | l = 0; /* exit inner loop */ | ||||
| args->rule.pkt_mark = ( | args->rule.pkt_mark = ( | ||||
| (cmd->arg1 == IP_FW_TARG) ? | (cmd->arg1 == IP_FW_TARG) ? | ||||
| TARG_VAL(chain, tablearg, mark) : | TARG_VAL(chain, tablearg, mark) : | ||||
| ((ipfw_insn_u32 *)cmd)->d[0]); | insntoc(cmd, u32)->d[0]); | ||||
| IPFW_INC_RULE_COUNTER(f, pktlen); | IPFW_INC_RULE_COUNTER(f, pktlen); | ||||
| break; | break; | ||||
| } | } | ||||
| case O_EXTERNAL_ACTION: | case O_EXTERNAL_ACTION: | ||||
| l = 0; /* in any case exit inner loop */ | l = 0; /* in any case exit inner loop */ | ||||
| retval = ipfw_run_eaction(chain, args, | retval = ipfw_run_eaction(chain, args, | ||||
| ▲ Show 20 Lines • Show All 235 Lines • ▼ Show 20 Lines | #endif | ||||
| rule->cmd_len = 1; | rule->cmd_len = 1; | ||||
| rule->cmd[0].len = 1; | rule->cmd[0].len = 1; | ||||
| rule->cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY; | rule->cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY; | ||||
| chain->default_rule = rule; | chain->default_rule = rule; | ||||
| ipfw_add_protected_rule(chain, rule, 0); | ipfw_add_protected_rule(chain, rule, 0); | ||||
| ipfw_dyn_init(chain); | ipfw_dyn_init(chain); | ||||
| ipfw_eaction_init(chain, first); | ipfw_eaction_init(chain, first); | ||||
| #ifdef LINEAR_SKIPTO | |||||
| ipfw_init_skipto_cache(chain); | ipfw_init_skipto_cache(chain); | ||||
| #endif | |||||
| ipfw_bpf_init(first); | ipfw_bpf_init(first); | ||||
| /* First set up some values that are compile time options */ | /* First set up some values that are compile time options */ | ||||
| V_ipfw_vnet_ready = 1; /* Open for business */ | V_ipfw_vnet_ready = 1; /* Open for business */ | ||||
| /* | /* | ||||
| * Hook the sockopt handler and pfil hooks for ipv4 and ipv6. | * Hook the sockopt handler and pfil hooks for ipv4 and ipv6. | ||||
| * Even if the latter two fail we still keep the module alive | * Even if the latter two fail we still keep the module alive | ||||
| Show All 40 Lines | vnet_ipfw_uninit(const void *unused) | ||||
| IPFW_UH_WLOCK(chain); | IPFW_UH_WLOCK(chain); | ||||
| reap = NULL; | reap = NULL; | ||||
| IPFW_WLOCK(chain); | IPFW_WLOCK(chain); | ||||
| for (i = 0; i < chain->n_rules; i++) | for (i = 0; i < chain->n_rules; i++) | ||||
| ipfw_reap_add(chain, &reap, chain->map[i]); | ipfw_reap_add(chain, &reap, chain->map[i]); | ||||
| free(chain->map, M_IPFW); | free(chain->map, M_IPFW); | ||||
| #ifdef LINEAR_SKIPTO | |||||
| ipfw_destroy_skipto_cache(chain); | ipfw_destroy_skipto_cache(chain); | ||||
| #endif | |||||
| IPFW_WUNLOCK(chain); | IPFW_WUNLOCK(chain); | ||||
| IPFW_UH_WUNLOCK(chain); | IPFW_UH_WUNLOCK(chain); | ||||
| ipfw_destroy_tables(chain, last); | ipfw_destroy_tables(chain, last); | ||||
| ipfw_eaction_uninit(chain, last); | ipfw_eaction_uninit(chain, last); | ||||
| if (reap != NULL) | if (reap != NULL) | ||||
| ipfw_reap_rules(reap); | ipfw_reap_rules(reap); | ||||
| vnet_ipfw_iface_destroy(chain); | vnet_ipfw_iface_destroy(chain); | ||||
| ipfw_destroy_srv(chain); | ipfw_destroy_srv(chain); | ||||
| ▲ Show 20 Lines • Show All 79 Lines • Show Last 20 Lines | |||||