diff options
author | Florian Westphal <fw@strlen.de> | 2022-09-12 10:58:44 +0200 |
---|---|---|
committer | Florian Westphal <fw@strlen.de> | 2022-09-13 14:14:38 +0200 |
commit | b4fd0f682b53609c747e6dd69cc5024545d4b90c (patch) | |
tree | 22ffb65b47917d61393b42d6171dbb96b0ae22ce | |
parent | 0da2d1a35bd70d37f72d594927c0649d1dea4f7c (diff) |
nft: support ttl/hoplimit dissection
xlate raw "nft ... ttl eq 1" and so on to the ttl/hl matches.
Signed-off-by: Florian Westphal <fw@strlen.de>
Reviewed-by: Phil Sutter <phil@nwl.cc>
-rw-r--r-- | iptables/nft-ipv4.c | 3 | ||||
-rw-r--r-- | iptables/nft-ipv6.c | 3 | ||||
-rw-r--r-- | iptables/nft-shared.c | 68 | ||||
-rw-r--r-- | iptables/nft-shared.h | 2 |
4 files changed, 76 insertions, 0 deletions
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c index 59c4a41f..1865d151 100644 --- a/iptables/nft-ipv4.c +++ b/iptables/nft-ipv4.c @@ -206,6 +206,9 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx, if (inv) cs->fw.ip.invflags |= IPT_INV_FRAG; break; + case offsetof(struct iphdr, ttl): + nft_parse_hl(ctx, e, cs); + break; default: DEBUGP("unknown payload offset %d\n", ctx->payload.offset); break; diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c index 9a29d18b..0ab1f971 100644 --- a/iptables/nft-ipv6.c +++ b/iptables/nft-ipv6.c @@ -169,6 +169,9 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx, cs->fw6.ipv6.proto = proto; if (inv) cs->fw6.ipv6.invflags |= IP6T_INV_PROTO; + case offsetof(struct ip6_hdr, ip6_hlim): + nft_parse_hl(ctx, e, cs); + break; default: DEBUGP("unknown payload offset %d\n", ctx->payload.offset); break; diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 79c93fe8..71e2f18d 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -27,6 +27,8 @@ #include <linux/netfilter/xt_mark.h> #include <linux/netfilter/xt_pkttype.h> +#include <linux/netfilter_ipv6/ip6t_hl.h> + #include <libmnl/libmnl.h> #include <libnftnl/rule.h> #include <libnftnl/expr.h> @@ -1449,3 +1451,69 @@ void nft_check_xt_legacy(int family, bool is_ipt_save) prefix, prefix, is_ipt_save ? "-save" : ""); fclose(fp); } + +int nft_parse_hl(struct nft_xt_ctx *ctx, + struct nftnl_expr *e, + struct iptables_command_state *cs) +{ + struct xtables_match *match; + struct ip6t_hl_info *info; + uint8_t hl, mode; + int op; + + hl = nftnl_expr_get_u8(e, NFTNL_EXPR_CMP_DATA); + op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP); + + switch (op) { + case NFT_CMP_NEQ: + mode = IP6T_HL_NE; + break; + case NFT_CMP_EQ: + mode = IP6T_HL_EQ; + break; + case NFT_CMP_LT: + mode = IP6T_HL_LT; + break; + case NFT_CMP_GT: + mode = IP6T_HL_GT; + break; + case NFT_CMP_LTE: + mode = IP6T_HL_LT; + if (hl == 255) + return -1; + hl++; + break; + case NFT_CMP_GTE: + mode = IP6T_HL_GT; + if (hl == 0) + return -1; + hl--; + break; + default: + return -1; + } + + /* ipt_ttl_info and ip6t_hl_info have same layout, + * IPT_TTL_x and IP6T_HL_x are aliases as well, so + * just use HL for both ipv4 and ipv6. + */ + switch (ctx->h->family) { + case NFPROTO_IPV4: + match = nft_create_match(ctx, ctx->cs, "ttl"); + break; + case NFPROTO_IPV6: + match = nft_create_match(ctx, ctx->cs, "hl"); + break; + default: + return -1; + } + + if (!match) + return -1; + + info = (void*)match->m->data; + info->hop_limit = hl; + info->mode = mode; + + return 0; +} diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index b0404904..0718dc23 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -212,6 +212,8 @@ void xtables_restore_parse(struct nft_handle *h, void nft_check_xt_legacy(int family, bool is_ipt_save); +int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e, struct iptables_command_state *cs); + #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) |