From d96d0791901c10d4edf599b3da069ca3d9acfcc5 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 15 Dec 2022 13:20:21 +0100 Subject: nft: Parse icmp header matches These were previously ignored. Signed-off-by: Phil Sutter --- iptables/nft-shared.c | 74 ++++++++++++++++++++++ .../testcases/nft-only/0010-iptables-nft-save.txt | 6 +- 2 files changed, 77 insertions(+), 3 deletions(-) (limited to 'iptables') diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 56acbd45..d4b21921 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -833,6 +833,65 @@ static void nft_parse_tcp(struct nft_xt_ctx *ctx, op, dport, XT_TCP_INV_DSTPT); } +static void nft_parse_icmp(struct nft_xt_ctx *ctx, + struct iptables_command_state *cs, + struct nft_xt_ctx_reg *sreg, + uint8_t op, const char *data, size_t dlen) +{ + struct xtables_match *match; + struct ipt_icmp icmp = { + .type = UINT8_MAX, + .code = { 0, UINT8_MAX }, + }; + + if (dlen < 1) + goto out_err_len; + + switch (sreg->payload.offset) { + case 0: + icmp.type = data[0]; + if (dlen == 1) + break; + dlen--; + data++; + /* fall through */ + case 1: + if (dlen > 1) + goto out_err_len; + icmp.code[0] = icmp.code[1] = data[0]; + break; + default: + ctx->errmsg = "unexpected payload offset"; + return; + } + + switch (ctx->h->family) { + case NFPROTO_IPV4: + match = nft_create_match(ctx, cs, "icmp"); + break; + case NFPROTO_IPV6: + if (icmp.type == UINT8_MAX) { + ctx->errmsg = "icmp6 code with any type match not supported"; + return; + } + match = nft_create_match(ctx, cs, "icmp6"); + break; + default: + ctx->errmsg = "unexpected family for icmp match"; + return; + } + + if (!match) { + ctx->errmsg = "icmp match extension not found"; + return; + } + memcpy(match->m->data, &icmp, sizeof(icmp)); + return; + +out_err_len: + ctx->errmsg = "unexpected RHS data length"; +} + static void nft_parse_th_port(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, uint8_t proto, @@ -915,6 +974,21 @@ static void nft_parse_transport(struct nft_xt_ctx *ctx, return; } + switch (proto) { + case IPPROTO_UDP: + case IPPROTO_TCP: + break; + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + nft_parse_icmp(ctx, cs, sreg, op, + nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len), + len); + return; + default: + ctx->errmsg = "unsupported layer 4 protocol value"; + return; + } + switch(sreg->payload.offset) { case 0: /* th->sport */ switch (len) { diff --git a/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt b/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt index 73d7108c..5ee4c231 100644 --- a/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt +++ b/iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt @@ -13,9 +13,9 @@ -A INPUT -d 0.0.0.0/2 -m ttl --ttl-gt 2 -j ACCEPT -A INPUT -d 0.0.0.0/3 -m ttl --ttl-lt 254 -j ACCEPT -A INPUT -d 0.0.0.0/4 -m ttl ! --ttl-eq 255 -j DROP --A INPUT -d 8.0.0.0/5 -p icmp -j ACCEPT --A INPUT -d 8.0.0.0/6 -p icmp -j ACCEPT --A INPUT -d 10.0.0.0/7 -p icmp -j ACCEPT +-A INPUT -d 8.0.0.0/5 -p icmp -m icmp --icmp-type 1 -j ACCEPT +-A INPUT -d 8.0.0.0/6 -p icmp -m icmp --icmp-type 2/3 -j ACCEPT +-A INPUT -d 10.0.0.0/7 -p icmp -m icmp --icmp-type 8 -j ACCEPT -A INPUT -m pkttype --pkt-type broadcast -j ACCEPT -A INPUT -m pkttype ! --pkt-type unicast -j DROP -A INPUT -p tcp -- cgit v1.2.3