]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
nft: Parse icmp header matches
authorPhil Sutter <phil@nwl.cc>
Thu, 15 Dec 2022 12:20:21 +0000 (13:20 +0100)
committerPhil Sutter <phil@nwl.cc>
Tue, 20 Dec 2022 20:49:38 +0000 (21:49 +0100)
These were previously ignored.

Signed-off-by: Phil Sutter <phil@nwl.cc>
iptables/nft-shared.c
iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt

index 56acbd4555f4bbfa8de5830c6bc2a45d0c1bb3c0..d4b21921077d94d8a8ebedd1e86175df6ab164c6 100644 (file)
@@ -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) {
index 73d7108c5094e7dd95a7f0587f69115cbd69d26f..5ee4c23113aa8ffec7c1852fd84fd1c81b015bac 100644 (file)
@@ -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