summaryrefslogtreecommitdiffstats
path: root/iptables
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2022-12-15 13:20:21 +0100
committerPhil Sutter <phil@nwl.cc>2022-12-20 21:49:38 +0100
commitd96d0791901c10d4edf599b3da069ca3d9acfcc5 (patch)
treeed43fb29145d6a025e414aae6c61dceaacc51540 /iptables
parente1eaa04e31e44eab729e4a39a9967c6f1e24d499 (diff)
nft: Parse icmp header matches
These were previously ignored. Signed-off-by: Phil Sutter <phil@nwl.cc>
Diffstat (limited to 'iptables')
-rw-r--r--iptables/nft-shared.c74
-rw-r--r--iptables/tests/shell/testcases/nft-only/0010-iptables-nft-save.txt6
2 files changed, 77 insertions, 3 deletions
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