diff options
author | Phil Sutter <phil@nwl.cc> | 2022-08-04 17:01:26 +0200 |
---|---|---|
committer | Phil Sutter <phil@nwl.cc> | 2022-09-28 19:21:16 +0200 |
commit | eddbb27651b93ac6f329bf8113223e7360ea7613 (patch) | |
tree | c408ed4144ecd52b77d85cd17166bae77bfeb4b0 | |
parent | aa0b8b03f7c7e741ccd96360bd64d90ea8c3c3aa (diff) |
ebtables: Fix among match
Fixed commit broke among match in two ways:
1) The two lookup sizes are 12 and 6, not 12 and 4 - among supports
either ether+IP or ether only, not IP only.
2) Adding two to sreg_count to get the second register is too simple: It
works only for four byte regs, not the 16 byte ones. The first
register is always a 16 byte one, though.
Fixing (1) is trivial, fix (2) by introduction of nft_get_next_reg()
doing the right thing. For consistency, use it for among match creation,
too.
Fixes: f315af1cf8871 ("nft: track each register individually")
Signed-off-by: Phil Sutter <phil@nwl.cc>
-rw-r--r-- | iptables/nft-bridge.c | 4 | ||||
-rw-r--r-- | iptables/nft-shared.c | 16 | ||||
-rw-r--r-- | iptables/nft-shared.h | 5 | ||||
-rw-r--r-- | iptables/nft.c | 6 |
4 files changed, 25 insertions, 6 deletions
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index 659c5b58..596dfdf8 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -349,7 +349,7 @@ static int lookup_analyze_payloads(struct nft_xt_ctx *ctx, return -1; } - sreg_count += 2; + sreg_count = nft_get_next_reg(sreg_count, ETH_ALEN); reg = nft_xt_ctx_get_sreg(ctx, sreg_count); if (!reg) { @@ -375,7 +375,7 @@ static int lookup_analyze_payloads(struct nft_xt_ctx *ctx, return -1; } break; - case 4: /* ipv4addr */ + case 6: /* ether */ val = lookup_check_ether_payload(reg->payload.base, reg->payload.offset, reg->payload.len); diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index f8de2b71..909fe648 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -10,6 +10,7 @@ * This code has been sponsored by Sophos Astaro <http://www.sophos.com> */ +#include <assert.h> #include <string.h> #include <stdio.h> #include <stdlib.h> @@ -1603,3 +1604,18 @@ int nft_parse_hl(struct nft_xt_ctx *ctx, return 0; } + +enum nft_registers nft_get_next_reg(enum nft_registers reg, size_t size) +{ + /* convert size to NETLINK_ALIGN-sized chunks */ + size = (size + NETLINK_ALIGN - 1) / NETLINK_ALIGN; + + /* map 16byte reg to 4byte one */ + if (reg < __NFT_REG_MAX) + reg = NFT_REG32_00 + (reg - 1) * NFT_REG_SIZE / NFT_REG32_SIZE; + + reg += size; + assert(reg <= NFT_REG32_15); + + return reg; +} diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 8fcedcdd..c07d3270 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -276,4 +276,9 @@ int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e, struct iptables_c #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) +/* simplified nftables:include/netlink.h, netlink_padded_len() */ +#define NETLINK_ALIGN 4 + +enum nft_registers nft_get_next_reg(enum nft_registers reg, size_t size); + #endif diff --git a/iptables/nft.c b/iptables/nft.c index 2165733f..09cb19c9 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1133,9 +1133,6 @@ gen_lookup(uint32_t sreg, const char *set_name, uint32_t set_id, uint32_t flags) return e; } -/* simplified nftables:include/netlink.h, netlink_padded_len() */ -#define NETLINK_ALIGN 4 - /* from nftables:include/datatype.h, TYPE_BITS */ #define CONCAT_TYPE_BITS 6 @@ -1208,8 +1205,9 @@ static int __add_nft_among(struct nft_handle *h, const char *table, nftnl_rule_add_expr(r, e); if (ip) { + reg = nft_get_next_reg(reg, ETH_ALEN); e = __gen_payload(NFT_PAYLOAD_NETWORK_HEADER, ip_addr_off[dst], - sizeof(struct in_addr), NFT_REG32_02); + sizeof(struct in_addr), reg); if (!e) return -ENOMEM; nftnl_rule_add_expr(r, e); |