diff options
author | Phil Sutter <phil@nwl.cc> | 2020-02-13 17:49:53 +0100 |
---|---|---|
committer | Phil Sutter <phil@nwl.cc> | 2020-02-18 17:03:15 +0100 |
commit | c33bae9c6c7a49c8af16df846e6112fc4727e643 (patch) | |
tree | 2e272106667f9ab63f5901c1e244a65707b3d4eb /iptables/nft.c | |
parent | 94488d4eb912f5af4c88d148b39b38eb8a3c1f0b (diff) |
ebtables: among: Support mixed MAC and MAC/IP entries
Powered by Stefano's support for concatenated ranges, a full among match
replacement can be implemented. The trick is to add MAC-only elements as
a concatenation of MAC and zero-length prefix, i.e. a range from
0.0.0.0 till 255.255.255.255.
Although not quite needed, detection of pure MAC-only matches is left in
place. For those, no implicit 'meta protocol' match is added (which is
required otherwise at least to keep nft output correct) and no concat
type is used for the set.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Diffstat (limited to 'iptables/nft.c')
-rw-r--r-- | iptables/nft.c | 20 |
1 files changed, 19 insertions, 1 deletions
diff --git a/iptables/nft.c b/iptables/nft.c index 3f2a62ae..806b77fe 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1022,19 +1022,28 @@ static int __add_nft_among(struct nft_handle *h, const char *table, }; struct nftnl_expr *e; struct nftnl_set *s; + uint32_t flags = 0; int idx = 0; if (ip) { type = type << CONCAT_TYPE_BITS | NFT_DATATYPE_IPADDR; len += sizeof(struct in_addr) + NETLINK_ALIGN - 1; len &= ~(NETLINK_ALIGN - 1); + flags = NFT_SET_INTERVAL; } - s = add_anon_set(h, table, 0, type, len, cnt); + s = add_anon_set(h, table, flags, type, len, cnt); if (!s) return -ENOMEM; set_id = nftnl_set_get_u32(s, NFTNL_SET_ID); + if (ip) { + uint8_t field_len[2] = { ETH_ALEN, sizeof(struct in_addr) }; + + nftnl_set_set_data(s, NFTNL_SET_DESC_CONCAT, + field_len, sizeof(field_len)); + } + for (idx = 0; idx < cnt; idx++) { struct nftnl_set_elem *elem = nftnl_set_elem_alloc(); @@ -1042,6 +1051,15 @@ static int __add_nft_among(struct nft_handle *h, const char *table, return -ENOMEM; nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY, &pairs[idx], len); + if (ip) { + struct in_addr tmp = pairs[idx].in; + + if (tmp.s_addr == INADDR_ANY) + pairs[idx].in.s_addr = INADDR_BROADCAST; + nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY_END, + &pairs[idx], len); + pairs[idx].in = tmp; + } nftnl_set_elem_add(s, elem); } |