diff options
| author | Boris Lytochkin <lytboris@gmail.com> | 2026-03-01 18:54:24 +0000 |
|---|---|---|
| committer | Andrey V. Elsukov <ae@FreeBSD.org> | 2026-03-01 19:04:58 +0000 |
| commit | 32cd3ee5901ea33d41ff550e5f40ce743c8d4165 (patch) | |
| tree | b86c94ef16be5a15f28da063cfc9cc3bad74dc0f /sys/netpfil | |
| parent | e81e724358e43dcf951e244a9df9df3eaa983fe9 (diff) | |
Diffstat (limited to 'sys/netpfil')
| -rw-r--r-- | sys/netpfil/ipfw/ip_fw2.c | 231 | ||||
| -rw-r--r-- | sys/netpfil/ipfw/ip_fw_sockopt.c | 32 | ||||
| -rw-r--r-- | sys/netpfil/ipfw/ip_fw_table.c | 26 |
3 files changed, 191 insertions, 98 deletions
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c index fe707abc7682..10690920e6fd 100644 --- a/sys/netpfil/ipfw/ip_fw2.c +++ b/sys/netpfil/ipfw/ip_fw2.c @@ -1309,7 +1309,7 @@ jump(struct ip_fw_chain *chain, struct ip_fw *f, uint32_t num, #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, +tvalue_match(struct ip_fw_chain *ch, const ipfw_insn_lookup *cmd, uint32_t tablearg) { uint32_t tvalue; @@ -1336,6 +1336,11 @@ tvalue_match(struct ip_fw_chain *ch, const ipfw_insn_table *cmd, case TVALUE_NH4: tvalue = TARG_VAL(ch, tablearg, nh4); break; + case TVALUE_NH6: + if (F_LEN(&cmd->o) != F_INSN_SIZE(ipfw_insn_lookup)) + return (0); + return (0 == memcmp(&TARG_VAL(ch, tablearg, nh6), + &cmd->ip6, sizeof(struct in6_addr))); case TVALUE_DSCP: tvalue = TARG_VAL(ch, tablearg, dscp); break; @@ -1350,7 +1355,13 @@ tvalue_match(struct ip_fw_chain *ch, const ipfw_insn_table *cmd, tvalue = TARG_VAL(ch, tablearg, tag); break; } - return (tvalue == cmd->value); + /* + * XXX: compatibility layer, to be removed. + * Match u32 values specified as ipfw_insn_table structure. + */ + if (F_LEN(&cmd->o) == F_INSN_SIZE(ipfw_insn_table)) + return (tvalue == insntoc(cmd, table)->value); + return (tvalue == cmd->u32); } /* @@ -2097,45 +2108,101 @@ do { \ break; case O_IP_DST_LOOKUP: - if (IPFW_LOOKUP_TYPE(cmd) != LOOKUP_NONE) { - void *pkey = NULL; - uint32_t key, vidx; - uint16_t keylen = 0; /* zero if can't match the packet */ - uint8_t lookup_type; + case O_IP_SRC_LOOKUP: + /* + * XXX: compatibility layer, to be removed. + * The following if and subsequent fallthrough + * are here for backward opcode compatibility + * used for lookup opcode until O_TABLE_LOOKUP + * appeared. + */ + if (IPFW_LOOKUP_TYPE(cmd) == LOOKUP_NONE) { + void *pkey; + uint32_t vidx; + uint16_t keylen; + + if (is_ipv4) { + keylen = sizeof(in_addr_t); + if (cmd->opcode == O_IP_DST_LOOKUP) + pkey = &dst_ip; + else + pkey = &src_ip; + } else if (is_ipv6) { + keylen = sizeof(struct in6_addr); + if (cmd->opcode == O_IP_DST_LOOKUP) + pkey = &args->f_id.dst_ip6; + else + pkey = &args->f_id.src_ip6; + } else + break; + match = ipfw_lookup_table(chain, + insntod(cmd, kidx)->kidx, + keylen, pkey, &vidx); + if (!match) + break; + if (IPFW_LOOKUP_MATCH_TVALUE(cmd) != 0) { + match = tvalue_match(chain, + insntod(cmd, lookup), vidx); + if (!match) + break; + } + tablearg = vidx; + break; + } + /* FALLTHROUGH */ + case O_TABLE_LOOKUP: + { + ipfw_insn_lookup key; + uint32_t vidx; + uint16_t keylen = 0; /* zero if can't match the packet */ + uint8_t lookup_type; lookup_type = IPFW_LOOKUP_TYPE(cmd); switch (lookup_type) { case LOOKUP_DST_IP: + case LOOKUP_DST_IP4: + if (is_ipv4) { + keylen = sizeof(in_addr_t); + key.ip4 = dst_ip; + break; + } + if (lookup_type == LOOKUP_DST_IP4) + break; + /* FALLTHOUGH */ + case LOOKUP_DST_IP6: + if (is_ipv6 == 0) + break; + keylen = sizeof(struct in6_addr); + key.ip6 = args->f_id.dst_ip6; + break; case LOOKUP_SRC_IP: + case LOOKUP_SRC_IP4: if (is_ipv4) { 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; + key.ip4 = src_ip; + break; } + if (lookup_type == LOOKUP_SRC_IP4) + break; + /* FALLTHOUGH */ + case LOOKUP_SRC_IP6: + if (is_ipv6 == 0) + break; + keylen = sizeof(struct in6_addr); + key.ip6 = args->f_id.src_ip6; break; case LOOKUP_DSCP: if (is_ipv4) - key = ip->ip_tos >> 2; + key.u32 = ip->ip_tos >> 2; else if (is_ipv6) - key = IPV6_DSCP( + key.u32 = IPV6_DSCP( (struct ip6_hdr *)ip) >> 2; else break; /* only for L3 */ - key &= 0x3f; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) - key &= insntod(cmd, table)->value; - pkey = &key; - keylen = sizeof(key); + keylen = sizeof(key.u32); + key.u32 &= 0x3f; break; case LOOKUP_DST_PORT: case LOOKUP_SRC_PORT: @@ -2154,23 +2221,26 @@ do { \ proto != IPPROTO_SCTP) break; if (lookup_type == LOOKUP_DST_PORT) - key = dst_port; + key.u32 = dst_port; else - key = src_port; - pkey = &key; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) - key &= insntod(cmd, table)->value; - keylen = sizeof(key); + key.u32 = src_port; + keylen = sizeof(key.u32); break; case LOOKUP_DST_MAC: + /* only for L2 */ + if ((args->flags & IPFW_ARGS_ETHER) == 0) + break; + keylen = ETHER_ADDR_LEN; + memcpy(key.mac, eh->ether_dhost, + sizeof(key.mac)); + break; 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; + memcpy(key.mac, eh->ether_shost, + sizeof(key.mac)); break; #ifndef USERSPACE case LOOKUP_UID: @@ -2180,84 +2250,61 @@ do { \ #ifdef __FreeBSD__ &ucred_cache); if (lookup_type == LOOKUP_UID) - key = ucred_cache->cr_uid; + key.u32 = ucred_cache->cr_uid; else if (lookup_type == LOOKUP_JAIL) - key = ucred_cache->cr_prison->pr_id; + key.u32 = ucred_cache->cr_prison->pr_id; #else /* !__FreeBSD__ */ (void *)&ucred_cache); if (lookup_type == LOOKUP_UID) - key = ucred_cache.uid; + key.u32 = ucred_cache.uid; else if (lookup_type == LOOKUP_JAIL) - key = ucred_cache.xid; + key.u32 = ucred_cache.xid; #endif /* !__FreeBSD__ */ - pkey = &key; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) - key &= insntod(cmd, table)->value; - keylen = sizeof(key); + keylen = sizeof(key.u32); break; #endif /* !USERSPACE */ case LOOKUP_MARK: - key = args->rule.pkt_mark; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) - key &= insntod(cmd, table)->value; - pkey = &key; - keylen = sizeof(key); + key.u32 = args->rule.pkt_mark; + keylen = sizeof(key.u32); break; case LOOKUP_RULENUM: - key = f->rulenum; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) - key &= insntod(cmd, table)->value; - pkey = &key; - keylen = sizeof(key); + key.u32 = f->rulenum; + keylen = sizeof(key.u32); break; } /* unknown key type */ if (keylen == 0) break; - match = ipfw_lookup_table(chain, - insntod(cmd, kidx)->kidx, keylen, - pkey, &vidx); - if (match) - tablearg = vidx; - break; - } - /* LOOKUP_NONE */ - /* FALLTHROUGH */ - case O_IP_SRC_LOOKUP: - { - void *pkey; - uint32_t vidx; - uint16_t keylen; + if (IPFW_LOOKUP_MASKING(cmd) == 0) { + /* no masking needed */ + } else if (cmdlen == + F_INSN_SIZE(ipfw_insn_table)) { + /* + * XXX: compatibility layer, + * to be removed. + */ + key.u32 &= insntod(cmd, table)->value; + } else { + key.__mask64[0] &= + insntod(cmd, lookup)->__mask64[0]; + key.__mask64[1] &= + insntod(cmd, lookup)->__mask64[1]; + } - if (is_ipv4) { - keylen = sizeof(in_addr_t); - if (cmd->opcode == O_IP_DST_LOOKUP) - pkey = &dst_ip; - else - pkey = &src_ip; - } else if (is_ipv6) { - keylen = sizeof(struct in6_addr); - if (cmd->opcode == O_IP_DST_LOOKUP) - pkey = &args->f_id.dst_ip6; - else - pkey = &args->f_id.src_ip6; - } else - break; match = ipfw_lookup_table(chain, - insntod(cmd, kidx)->kidx, - keylen, pkey, &vidx); + insntod(cmd, kidx)->kidx, keylen, + key.__mask64, &vidx); + if (!match) break; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) { - match = tvalue_match(chain, - insntod(cmd, table), vidx); - if (!match) - break; - } + /* + * XXX should we support check for value + * simultaneously with masked lookup? + */ tablearg = vidx; break; - } + } /* O_TABLE_LOOKUP */ case O_MAC_SRC_LOOKUP: case O_MAC_DST_LOOKUP: @@ -2280,9 +2327,9 @@ do { \ keylen, pkey, &vidx); if (!match) break; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) { + if (IPFW_LOOKUP_MATCH_TVALUE(cmd) != 0) { match = tvalue_match(chain, - insntod(cmd, table), vidx); + insntod(cmd, lookup), vidx); if (!match) break; } @@ -2299,9 +2346,9 @@ do { \ &args->f_id, &vidx); if (!match) break; - if (cmdlen == F_INSN_SIZE(ipfw_insn_table)) + if (IPFW_LOOKUP_MATCH_TVALUE(cmd) != 0) match = tvalue_match(chain, - insntod(cmd, table), vidx); + insntod(cmd, lookup), vidx); if (match) tablearg = vidx; break; diff --git a/sys/netpfil/ipfw/ip_fw_sockopt.c b/sys/netpfil/ipfw/ip_fw_sockopt.c index 2941444a7bd3..a5892bb387e5 100644 --- a/sys/netpfil/ipfw/ip_fw_sockopt.c +++ b/sys/netpfil/ipfw/ip_fw_sockopt.c @@ -1418,6 +1418,7 @@ ipfw_check_opcode(ipfw_insn **pcmd, int *plen, struct rule_check_info *ci) case O_MAC_SRC_LOOKUP: case O_MAC_DST_LOOKUP: if (cmdlen != F_INSN_SIZE(ipfw_insn_kidx) && + cmdlen != F_INSN_SIZE(ipfw_insn_lookup) && cmdlen != F_INSN_SIZE(ipfw_insn_table)) return (BAD_SIZE); if (insntod(cmd, kidx)->kidx >= V_fw_tables_max) { @@ -1426,6 +1427,37 @@ ipfw_check_opcode(ipfw_insn **pcmd, int *plen, struct rule_check_info *ci) return (FAILED); } ci->object_opcodes++; + /* + * XXX: compatibility layer, to be removed. + + * ipfw_insn_table was used to match table value for u32 + * values and cmdlen was used to detect such intention. + * A special flag is now used for that in module so + * adopt legacy sbin/ipfw behavior and set it for all + * lookup instructions with ipfw_insn_table opcode. + * + * Lookup type different from LOOKUP_NONE was used for + * 32-bit bitmasking prior to lookup. + * Table value matching was expected otherwise. + */ + if (cmdlen != F_INSN_SIZE(ipfw_insn_table)) + break; + + if (IPFW_LOOKUP_TYPE(cmd) != LOOKUP_NONE) + IPFW_SET_LOOKUP_MASKING(cmd, 1); + else + IPFW_SET_LOOKUP_MATCH_TVALUE(cmd, 1); + break; + case O_TABLE_LOOKUP: + if (cmdlen != F_INSN_SIZE(ipfw_insn_kidx) && + cmdlen != F_INSN_SIZE(ipfw_insn_lookup)) + return (BAD_SIZE); + if (insntod(cmd, kidx)->kidx >= V_fw_tables_max) { + printf("ipfw: invalid table index %u\n", + insntod(cmd, kidx)->kidx); + return (FAILED); + } + ci->object_opcodes++; break; case O_MACADDR2: if (cmdlen != F_INSN_SIZE(ipfw_insn_mac)) diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c index dde18d41ab15..29fbab1676b9 100644 --- a/sys/netpfil/ipfw/ip_fw_table.c +++ b/sys/netpfil/ipfw/ip_fw_table.c @@ -2169,14 +2169,18 @@ list_table_algo(struct ip_fw_chain *ch, ip_fw3_opheader *op3, static int classify_srcdst(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) { - ipfw_insn_table *cmd; + ipfw_insn_lookup *cmd; /* Basic IPv4/IPv6 or u32 lookups */ - cmd = insntod(cmd0, table); + cmd = insntod(cmd0, lookup); *puidx = cmd->kidx; - switch(cmd0->arg1) { + switch(IPFW_LOOKUP_TYPE(cmd0)) { case LOOKUP_DST_IP: case LOOKUP_SRC_IP: + case LOOKUP_DST_IP4: + case LOOKUP_SRC_IP4: + case LOOKUP_DST_IP6: + case LOOKUP_SRC_IP6: default: /* IPv4 src/dst */ *ptype = IPFW_TABLE_ADDR; @@ -2216,7 +2220,7 @@ classify_via(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) static int classify_flow(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) { - *puidx = insntod(cmd0, table)->kidx; + *puidx = insntod(cmd0, kidx)->kidx; *ptype = IPFW_TABLE_FLOW; return (0); } @@ -2224,7 +2228,7 @@ classify_flow(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) static int classify_mac_lookup(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) { - *puidx = insntod(cmd0, table)->kidx; + *puidx = insntod(cmd0, kidx)->kidx; *ptype = IPFW_TABLE_MAC; return (0); } @@ -2232,7 +2236,7 @@ classify_mac_lookup(ipfw_insn *cmd0, uint32_t *puidx, uint8_t *ptype) static void update_kidx(ipfw_insn *cmd0, uint32_t idx) { - insntod(cmd0, table)->kidx = idx; + insntod(cmd0, kidx)->kidx = idx; } static void @@ -2366,6 +2370,16 @@ static struct opcode_obj_rewrite opcodes[] = { .manage_sets = table_manage_sets, }, { + .opcode = O_TABLE_LOOKUP, + .etlv = IPFW_TLV_TBL_NAME, + .classifier = classify_srcdst, + .update = update_kidx, + .find_byname = table_findbyname, + .find_bykidx = table_findbykidx, + .create_object = create_table_compat, + .manage_sets = table_manage_sets, + }, + { .opcode = O_IP_FLOW_LOOKUP, .etlv = IPFW_TLV_TBL_NAME, .classifier = classify_flow, |
