aboutsummaryrefslogtreecommitdiff
path: root/sys/netpfil
diff options
context:
space:
mode:
authorBoris Lytochkin <lytboris@gmail.com>2026-03-01 18:54:24 +0000
committerAndrey V. Elsukov <ae@FreeBSD.org>2026-03-01 19:04:58 +0000
commit32cd3ee5901ea33d41ff550e5f40ce743c8d4165 (patch)
treeb86c94ef16be5a15f28da063cfc9cc3bad74dc0f /sys/netpfil
parente81e724358e43dcf951e244a9df9df3eaa983fe9 (diff)
Diffstat (limited to 'sys/netpfil')
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c231
-rw-r--r--sys/netpfil/ipfw/ip_fw_sockopt.c32
-rw-r--r--sys/netpfil/ipfw/ip_fw_table.c26
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,