nftables: backport a few ICMP & ICMPv6 fixes

- assign network ctx for ICMP & ICMPv6
- additional ICMPv6 types
- allow update of net base w. meta l4proto ipv6-icmp
- l4 proto fixes

The initial trigger was that ICMPv6 type 143
(mld2-listener-report) wasn't working as expected.

Signed-off-by: André Draszik <adraszik@tycoint.com>
Acked-by: Sylvain Lemieux <slemieux@tycoint.com>
Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com>
Signed-off-by: Joe MacDonald <joe_macdonald@mentor.com>
Signed-off-by: Armin Kuster <akuster808@gmail.com>
This commit is contained in:
André Draszik 2017-06-19 11:24:47 +01:00 committed by Armin Kuster
parent 0a2c51bf8c
commit 2a1179c429
8 changed files with 874 additions and 0 deletions

View File

@ -0,0 +1,323 @@
From 0011985554e269e1cc8f8e5b41eb9dcd795ebe8c Mon Sep 17 00:00:00 2001
From: Arturo Borrero Gonzalez <arturo@debian.org>
Date: Wed, 25 Jan 2017 12:51:08 +0100
Subject: [PATCH] payload: explicit network ctx assignment for icmp/icmp6 in
special families
In the inet, bridge and netdev families, we can add rules like these:
% nft add rule inet t c ip protocol icmp icmp type echo-request
% nft add rule inet t c ip6 nexthdr icmpv6 icmpv6 type echo-request
However, when we print the ruleset:
% nft list ruleset
table inet t {
chain c {
icmpv6 type echo-request
icmp type echo-request
}
}
These rules we obtain can't be added again:
% nft add rule inet t c icmp type echo-request
<cmdline>:1:19-27: Error: conflicting protocols specified: inet-service vs. icmp
add rule inet t c icmp type echo-request
^^^^^^^^^
% nft add rule inet t c icmpv6 type echo-request
<cmdline>:1:19-29: Error: conflicting protocols specified: inet-service vs. icmpv6
add rule inet t c icmpv6 type echo-request
^^^^^^^^^^^
Since I wouldn't expect an IP packet carrying ICMPv6, or IPv6 packet
carrying ICMP, if the link layer is inet, the network layer protocol context
can be safely update to 'ip' or 'ip6'.
Moreover, nft currently generates a 'meta nfproto ipvX' depedency when
using icmp or icmp6 in the inet family, and similar in netdev and bridge
families.
While at it, a bit of code factorization is introduced.
Fixes: https://bugzilla.netfilter.org/show_bug.cgi?id=1073
Signed-off-by: Arturo Borrero Gonzalez <arturo@debian.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
Upstream-Status: Backport
Signed-off-by: André Draszik <adraszik@tycoint.com>
src/payload.c | 70 ++++++++++++++++---------------------
tests/py/any/icmpX.t.netdev | 8 +++++
tests/py/any/icmpX.t.netdev.payload | 36 +++++++++++++++++++
tests/py/bridge/icmpX.t | 8 +++++
tests/py/bridge/icmpX.t.payload | 36 +++++++++++++++++++
tests/py/inet/icmpX.t | 8 +++++
tests/py/inet/icmpX.t.payload | 36 +++++++++++++++++++
7 files changed, 162 insertions(+), 40 deletions(-)
create mode 100644 tests/py/any/icmpX.t.netdev
create mode 100644 tests/py/any/icmpX.t.netdev.payload
create mode 100644 tests/py/bridge/icmpX.t
create mode 100644 tests/py/bridge/icmpX.t.payload
create mode 100644 tests/py/inet/icmpX.t
create mode 100644 tests/py/inet/icmpX.t.payload
diff --git a/src/payload.c b/src/payload.c
index af533b2..74f8254 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -223,6 +223,34 @@ static int payload_add_dependency(struct eval_ctx *ctx,
return 0;
}
+static const struct proto_desc *
+payload_gen_special_dependency(struct eval_ctx *ctx, const struct expr *expr)
+{
+ switch (expr->payload.base) {
+ case PROTO_BASE_LL_HDR:
+ switch (ctx->pctx.family) {
+ case NFPROTO_INET:
+ return &proto_inet;
+ case NFPROTO_BRIDGE:
+ return &proto_eth;
+ case NFPROTO_NETDEV:
+ return &proto_netdev;
+ default:
+ break;
+ }
+ break;
+ case PROTO_BASE_TRANSPORT_HDR:
+ if (expr->payload.desc == &proto_icmp)
+ return &proto_ip;
+ if (expr->payload.desc == &proto_icmp6)
+ return &proto_ip6;
+ return &proto_inet_service;
+ default:
+ break;
+ }
+ return NULL;
+}
+
/**
* payload_gen_dependency - generate match expression on payload dependency
*
@@ -276,46 +304,8 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
desc = ctx->pctx.protocol[expr->payload.base - 1].desc;
/* Special case for mixed IPv4/IPv6 and bridge tables */
- if (desc == NULL) {
- switch (ctx->pctx.family) {
- case NFPROTO_INET:
- switch (expr->payload.base) {
- case PROTO_BASE_LL_HDR:
- desc = &proto_inet;
- break;
- case PROTO_BASE_TRANSPORT_HDR:
- desc = &proto_inet_service;
- break;
- default:
- break;
- }
- break;
- case NFPROTO_BRIDGE:
- switch (expr->payload.base) {
- case PROTO_BASE_LL_HDR:
- desc = &proto_eth;
- break;
- case PROTO_BASE_TRANSPORT_HDR:
- desc = &proto_inet_service;
- break;
- default:
- break;
- }
- break;
- case NFPROTO_NETDEV:
- switch (expr->payload.base) {
- case PROTO_BASE_LL_HDR:
- desc = &proto_netdev;
- break;
- case PROTO_BASE_TRANSPORT_HDR:
- desc = &proto_inet_service;
- break;
- default:
- break;
- }
- break;
- }
- }
+ if (desc == NULL)
+ desc = payload_gen_special_dependency(ctx, expr);
if (desc == NULL)
return expr_error(ctx->msgs, expr,
diff --git a/tests/py/any/icmpX.t.netdev b/tests/py/any/icmpX.t.netdev
new file mode 100644
index 0000000..a327ce6
--- /dev/null
+++ b/tests/py/any/icmpX.t.netdev
@@ -0,0 +1,8 @@
+:ingress;type filter hook ingress device lo priority 0
+
+*netdev;test-netdev;ingress
+
+ip protocol icmp icmp type echo-request;ok;icmp type echo-request
+icmp type echo-request;ok
+ip6 nexthdr icmpv6 icmpv6 type echo-request;ok;icmpv6 type echo-request
+icmpv6 type echo-request;ok
diff --git a/tests/py/any/icmpX.t.netdev.payload b/tests/py/any/icmpX.t.netdev.payload
new file mode 100644
index 0000000..8b8107c
--- /dev/null
+++ b/tests/py/any/icmpX.t.netdev.payload
@@ -0,0 +1,36 @@
+# ip protocol icmp icmp type echo-request
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# icmp type echo-request
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# ip6 nexthdr icmpv6 icmpv6 type echo-request
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# icmpv6 type echo-request
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
diff --git a/tests/py/bridge/icmpX.t b/tests/py/bridge/icmpX.t
new file mode 100644
index 0000000..8c0a597
--- /dev/null
+++ b/tests/py/bridge/icmpX.t
@@ -0,0 +1,8 @@
+:input;type filter hook input priority 0
+
+*bridge;test-bridge;input
+
+ip protocol icmp icmp type echo-request;ok;icmp type echo-request
+icmp type echo-request;ok
+ip6 nexthdr icmpv6 icmpv6 type echo-request;ok;icmpv6 type echo-request
+icmpv6 type echo-request;ok
diff --git a/tests/py/bridge/icmpX.t.payload b/tests/py/bridge/icmpX.t.payload
new file mode 100644
index 0000000..19efdd8
--- /dev/null
+++ b/tests/py/bridge/icmpX.t.payload
@@ -0,0 +1,36 @@
+# ip protocol icmp icmp type echo-request
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# icmp type echo-request
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# ip6 nexthdr icmpv6 icmpv6 type echo-request
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# icmpv6 type echo-request
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
diff --git a/tests/py/inet/icmpX.t b/tests/py/inet/icmpX.t
new file mode 100644
index 0000000..1b467a1
--- /dev/null
+++ b/tests/py/inet/icmpX.t
@@ -0,0 +1,8 @@
+:input;type filter hook input priority 0
+
+*inet;test-inet;input
+
+ip protocol icmp icmp type echo-request;ok;icmp type echo-request
+icmp type echo-request;ok
+ip6 nexthdr icmpv6 icmpv6 type echo-request;ok;icmpv6 type echo-request
+icmpv6 type echo-request;ok
diff --git a/tests/py/inet/icmpX.t.payload b/tests/py/inet/icmpX.t.payload
new file mode 100644
index 0000000..81ca774
--- /dev/null
+++ b/tests/py/inet/icmpX.t.payload
@@ -0,0 +1,36 @@
+# ip protocol icmp icmp type echo-request
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# icmp type echo-request
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# ip6 nexthdr icmpv6 icmpv6 type echo-request
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# icmpv6 type echo-request
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
--
2.11.0

View File

@ -0,0 +1,147 @@
From 9ade8fb75f8963375b45b3f2973b8bb7aa66ad76 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Thu, 16 Mar 2017 13:43:20 +0100
Subject: [PATCH] proto: Add some exotic ICMPv6 types
This adds support for matching on inverse ND messages as defined by
RFC3122 (not implemented in Linux) and MLDv2 as defined by RFC3810.
Note that ICMPV6_MLD2_REPORT macro is defined in linux/icmpv6.h but
including that header leads to conflicts with symbols defined in
netinet/icmp6.h.
In addition to the above, "mld-listener-done" is introduced as an alias
for "mld-listener-reduction".
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
Upstream-Status: Backport
Signed-off-by: André Draszik <adraszik@tycoint.com>
src/proto.c | 8 ++++++++
tests/py/ip6/icmpv6.t | 8 ++++++--
tests/py/ip6/icmpv6.t.payload.ip6 | 34 +++++++++++++++++++++++++++++++++-
3 files changed, 47 insertions(+), 3 deletions(-)
diff --git a/src/proto.c b/src/proto.c
index fb96530..79e9dbf 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -632,6 +632,10 @@ const struct proto_desc proto_ip = {
#include <netinet/icmp6.h>
+#define IND_NEIGHBOR_SOLICIT 141
+#define IND_NEIGHBOR_ADVERT 142
+#define ICMPV6_MLD2_REPORT 143
+
static const struct symbol_table icmp6_type_tbl = {
.base = BASE_DECIMAL,
.symbols = {
@@ -643,6 +647,7 @@ static const struct symbol_table icmp6_type_tbl = {
SYMBOL("echo-reply", ICMP6_ECHO_REPLY),
SYMBOL("mld-listener-query", MLD_LISTENER_QUERY),
SYMBOL("mld-listener-report", MLD_LISTENER_REPORT),
+ SYMBOL("mld-listener-done", MLD_LISTENER_REDUCTION),
SYMBOL("mld-listener-reduction", MLD_LISTENER_REDUCTION),
SYMBOL("nd-router-solicit", ND_ROUTER_SOLICIT),
SYMBOL("nd-router-advert", ND_ROUTER_ADVERT),
@@ -650,6 +655,9 @@ static const struct symbol_table icmp6_type_tbl = {
SYMBOL("nd-neighbor-advert", ND_NEIGHBOR_ADVERT),
SYMBOL("nd-redirect", ND_REDIRECT),
SYMBOL("router-renumbering", ICMP6_ROUTER_RENUMBERING),
+ SYMBOL("ind-neighbor-solicit", IND_NEIGHBOR_SOLICIT),
+ SYMBOL("ind-neighbor-advert", IND_NEIGHBOR_ADVERT),
+ SYMBOL("mld2-listener-report", ICMPV6_MLD2_REPORT),
SYMBOL_LIST_END
},
};
diff --git a/tests/py/ip6/icmpv6.t b/tests/py/ip6/icmpv6.t
index afbd451..a898fe3 100644
--- a/tests/py/ip6/icmpv6.t
+++ b/tests/py/ip6/icmpv6.t
@@ -11,7 +11,8 @@ icmpv6 type echo-request accept;ok
icmpv6 type echo-reply accept;ok
icmpv6 type mld-listener-query accept;ok
icmpv6 type mld-listener-report accept;ok
-icmpv6 type mld-listener-reduction accept;ok
+icmpv6 type mld-listener-done accept;ok
+icmpv6 type mld-listener-reduction accept;ok;icmpv6 type mld-listener-done accept
icmpv6 type nd-router-solicit accept;ok
icmpv6 type nd-router-advert accept;ok
icmpv6 type nd-neighbor-solicit accept;ok
@@ -19,8 +20,11 @@ icmpv6 type nd-neighbor-advert accept;ok
icmpv6 type nd-redirect accept;ok
icmpv6 type parameter-problem accept;ok
icmpv6 type router-renumbering accept;ok
+icmpv6 type ind-neighbor-solicit accept;ok
+icmpv6 type ind-neighbor-advert accept;ok
+icmpv6 type mld2-listener-report accept;ok
icmpv6 type {destination-unreachable, time-exceeded, nd-router-solicit} accept;ok
-icmpv6 type {router-renumbering, mld-listener-reduction, time-exceeded, nd-router-solicit} accept;ok
+icmpv6 type {router-renumbering, mld-listener-done, time-exceeded, nd-router-solicit} accept;ok
icmpv6 type {mld-listener-query, time-exceeded, nd-router-advert} accept;ok
icmpv6 type != {mld-listener-query, time-exceeded, nd-router-advert} accept;ok
diff --git a/tests/py/ip6/icmpv6.t.payload.ip6 b/tests/py/ip6/icmpv6.t.payload.ip6
index 9fe2496..30f58ca 100644
--- a/tests/py/ip6/icmpv6.t.payload.ip6
+++ b/tests/py/ip6/icmpv6.t.payload.ip6
@@ -54,6 +54,14 @@ ip6 test-ip6 input
[ cmp eq reg 1 0x00000083 ]
[ immediate reg 0 accept ]
+# icmpv6 type mld-listener-done accept
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000084 ]
+ [ immediate reg 0 accept ]
+
# icmpv6 type mld-listener-reduction accept
ip6 test-ip6 input
[ payload load 1b @ network header + 6 => reg 1 ]
@@ -118,6 +126,30 @@ ip6 test-ip6 input
[ cmp eq reg 1 0x0000008a ]
[ immediate reg 0 accept ]
+# icmpv6 type ind-neighbor-solicit accept
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000008d ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type ind-neighbor-advert accept
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000008e ]
+ [ immediate reg 0 accept ]
+
+# icmpv6 type mld2-listener-report accept
+ip6 test-ip6 input
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000008f ]
+ [ immediate reg 0 accept ]
+
# icmpv6 type {destination-unreachable, time-exceeded, nd-router-solicit} accept
__set%d test-ip6 3
__set%d test-ip6 0
@@ -129,7 +161,7 @@ ip6 test-ip6 input
[ lookup reg 1 set __set%d ]
[ immediate reg 0 accept ]
-# icmpv6 type {router-renumbering, mld-listener-reduction, time-exceeded, nd-router-solicit} accept
+# icmpv6 type {router-renumbering, mld-listener-done, time-exceeded, nd-router-solicit} accept
__set%d test-ip6 3
__set%d test-ip6 0
element 0000008a : 0 [end] element 00000084 : 0 [end] element 00000003 : 0 [end] element 00000085 : 0 [end]
--
2.11.0

View File

@ -0,0 +1,62 @@
From 8d8cfe5ad6ca460a5262fb15fdbef3601058c784 Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Thu, 18 May 2017 13:30:54 +0200
Subject: [PATCH 1/4] payload: split ll proto dependency into helper
will be re-used in folloup patch for icmp/icmpv6 depenency
handling.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
Upstream-Status: Backport
Signed-off-by: André Draszik <adraszik@tycoint.com>
src/payload.c | 29 ++++++++++++++++++-----------
1 file changed, 18 insertions(+), 11 deletions(-)
diff --git a/src/payload.c b/src/payload.c
index 55128fe..31e5a02 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -224,21 +224,28 @@ static int payload_add_dependency(struct eval_ctx *ctx,
}
static const struct proto_desc *
+payload_get_get_ll_hdr(const struct eval_ctx *ctx)
+{
+ switch (ctx->pctx.family) {
+ case NFPROTO_INET:
+ return &proto_inet;
+ case NFPROTO_BRIDGE:
+ return &proto_eth;
+ case NFPROTO_NETDEV:
+ return &proto_netdev;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static const struct proto_desc *
payload_gen_special_dependency(struct eval_ctx *ctx, const struct expr *expr)
{
switch (expr->payload.base) {
case PROTO_BASE_LL_HDR:
- switch (ctx->pctx.family) {
- case NFPROTO_INET:
- return &proto_inet;
- case NFPROTO_BRIDGE:
- return &proto_eth;
- case NFPROTO_NETDEV:
- return &proto_netdev;
- default:
- break;
- }
- break;
+ return payload_get_get_ll_hdr(ctx);
case PROTO_BASE_TRANSPORT_HDR:
if (expr->payload.desc == &proto_icmp)
return &proto_ip;
--
2.11.0

View File

@ -0,0 +1,65 @@
From 9a1f2bbf3cd2417e0c10d18578e224abe2071d68 Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Tue, 21 Mar 2017 19:47:22 +0100
Subject: [PATCH 2/4] src: allow update of net base w. meta l4proto icmpv6
nft add rule ip6 f i meta l4proto ipv6-icmp icmpv6 type nd-router-advert
<cmdline>:1:50-60: Error: conflicting protocols specified: unknown vs. icmpv6
add icmpv6 to nexthdr list so base gets updated correctly.
Reported-by: Thomas Woerner <twoerner@redhat.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
---
Upstream-Status: Backport
Signed-off-by: André Draszik <adraszik@tycoint.com>
src/proto.c | 1 +
tests/py/any/meta.t | 1 +
tests/py/any/meta.t.payload | 7 +++++++
3 files changed, 9 insertions(+)
diff --git a/src/proto.c b/src/proto.c
index 79e9dbf..fcdfbe7 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -779,6 +779,7 @@ const struct proto_desc proto_inet_service = {
PROTO_LINK(IPPROTO_TCP, &proto_tcp),
PROTO_LINK(IPPROTO_DCCP, &proto_dccp),
PROTO_LINK(IPPROTO_SCTP, &proto_sctp),
+ PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6),
},
.templates = {
[0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8),
diff --git a/tests/py/any/meta.t b/tests/py/any/meta.t
index c3ac0a4..2ff942f 100644
--- a/tests/py/any/meta.t
+++ b/tests/py/any/meta.t
@@ -38,6 +38,7 @@ meta l4proto { 33, 55, 67, 88};ok;meta l4proto { 33, 55, 67, 88}
meta l4proto != { 33, 55, 67, 88};ok
meta l4proto { 33-55};ok
meta l4proto != { 33-55};ok
+meta l4proto ipv6-icmp icmpv6 type nd-router-advert;ok;icmpv6 type nd-router-advert
meta priority root;ok
meta priority none;ok
diff --git a/tests/py/any/meta.t.payload b/tests/py/any/meta.t.payload
index e432656..871f1ad 100644
--- a/tests/py/any/meta.t.payload
+++ b/tests/py/any/meta.t.payload
@@ -187,6 +187,13 @@ ip test-ip4 input
[ byteorder reg 1 = hton(reg 1, 2, 1) ]
[ lookup reg 1 set __set%d 0x1 ]
+# meta l4proto ipv6-icmp icmpv6 type nd-router-advert
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000086 ]
+
# meta mark 0x4
ip test-ip4 input
[ meta load mark => reg 1 ]
--
2.11.0

View File

@ -0,0 +1,98 @@
From 2366ed9ffcb4f5f5341f10f0a1d1a4688d37ad87 Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Wed, 22 Mar 2017 15:08:48 +0100
Subject: [PATCH 3/4] src: ipv6: switch implicit dependencies to meta l4proto
when using rule like
ip6 filter input tcp dport 22
nft generates:
[ payload load 1b @ network header + 6 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x00001600 ]
which is: ip6 filter input ip6 nexthdr tcp dport 22
IOW, such a rule won't match if e.g. a fragment header is in place.
This changes ip6_proto to use 'meta l4proto' which is the protocol header
found by exthdr walk.
A side effect is that for bridge we get a shorter dependency chain as it
no longer needs to prepend 'ether proto ipv6' for old 'ip6 nexthdr' dep.
Only problem:
ip6 nexthdr tcp tcp dport 22
will now inject a (useless) meta l4 dependency as ip6 nexthdr is no
longer flagged as EXPR_F_PROTOCOL, to avoid this add a small helper
that skips the unneded meta dependency in that case.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
Upstream-Status: Backport
Signed-off-by: André Draszik <adraszik@tycoint.com>
src/payload.c | 19 ++++++++++++++++++-
src/proto.c | 2 +-
2 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/src/payload.c b/src/payload.c
index 31e5a02..38db15e 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -117,6 +117,23 @@ static const struct expr_ops payload_expr_ops = {
.pctx_update = payload_expr_pctx_update,
};
+/*
+ * ipv6 is special case, we normally use 'meta l4proto' to fetch the last
+ * l4 header of the ipv6 extension header chain so we will also match
+ * tcp after a fragmentation header, for instance.
+ *
+ * If user specifically asks for nexthdr x, treat is as a full
+ * dependency rather than injecting another (useless) meta l4 one.
+ */
+static bool proto_key_is_protocol(const struct proto_desc *desc, unsigned int type)
+{
+ if (type == desc->protocol_key ||
+ (desc == &proto_ip6 && type == IP6HDR_NEXTHDR))
+ return true;
+
+ return false;
+}
+
struct expr *payload_expr_alloc(const struct location *loc,
const struct proto_desc *desc,
unsigned int type)
@@ -129,7 +146,7 @@ struct expr *payload_expr_alloc(const struct location *loc,
if (desc != NULL) {
tmpl = &desc->templates[type];
base = desc->base;
- if (type == desc->protocol_key)
+ if (proto_key_is_protocol(desc, type))
flags = EXPR_F_PROTOCOL;
} else {
tmpl = &proto_unknown_template;
diff --git a/src/proto.c b/src/proto.c
index fcdfbe7..3b20a5f 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -707,7 +707,6 @@ const struct proto_desc proto_icmp6 = {
const struct proto_desc proto_ip6 = {
.name = "ip6",
.base = PROTO_BASE_NETWORK_HDR,
- .protocol_key = IP6HDR_NEXTHDR,
.protocols = {
PROTO_LINK(IPPROTO_ESP, &proto_esp),
PROTO_LINK(IPPROTO_AH, &proto_ah),
@@ -720,6 +719,7 @@ const struct proto_desc proto_ip6 = {
PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6),
},
.templates = {
+ [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8),
[IP6HDR_VERSION] = HDR_BITFIELD("version", &integer_type, 0, 4),
[IP6HDR_DSCP] = HDR_BITFIELD("dscp", &dscp_type, 4, 6),
[IP6HDR_ECN] = HDR_BITFIELD("ecn", &ecn_type, 10, 2),
--
2.11.0

View File

@ -0,0 +1,84 @@
From f21a7a4849b50c30341ec571813bd7fe37040ad3 Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Thu, 18 May 2017 13:30:54 +0200
Subject: [PATCH 4/4] payload: enforce ip/ip6 protocol depending on icmp or
icmpv6
After some discussion with Pablo we agreed to treat icmp/icmpv6 specially.
in the case of a rule like 'tcp dport 22' the inet, bridge and netdev
families only care about the lower layer protocol.
In the icmpv6 case however we'd like to also enforce an ipv6 protocol check
(and ipv4 check in icmp case).
This extends payload_gen_special_dependency() to consider this.
With this patch:
add rule $pf filter input meta l4proto icmpv6
add rule $pf filter input meta l4proto icmpv6 icmpv6 type echo-request
add rule $pf filter input icmpv6 type echo-request
will work in all tables and all families.
For inet/bridge/netdev, an ipv6 protocol dependency is added; this will
not match ipv4 packets with ip->protocol == icmpv6, EXCEPT in the case
of the ip family.
Its still possible to match icmpv6-in-ipv4 in inet/bridge/netdev with an
explicit dependency:
add rule inet f i ip protocol ipv6-icmp meta l4proto ipv6-icmp icmpv6 type ...
Implicit dependencies won't get removed at the moment, so
bridge ... icmp type echo-request
will be shown as
ether type ip meta l4proto 1 icmp type echo-request
Signed-off-by: Florian Westphal <fw@strlen.de>
---
Upstream-Status: Backport
Signed-off-by: André Draszik <adraszik@tycoint.com>
src/payload.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/src/payload.c b/src/payload.c
index 38db15e..8796ee5 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -264,10 +264,29 @@ payload_gen_special_dependency(struct eval_ctx *ctx, const struct expr *expr)
case PROTO_BASE_LL_HDR:
return payload_get_get_ll_hdr(ctx);
case PROTO_BASE_TRANSPORT_HDR:
- if (expr->payload.desc == &proto_icmp)
- return &proto_ip;
- if (expr->payload.desc == &proto_icmp6)
- return &proto_ip6;
+ if (expr->payload.desc == &proto_icmp ||
+ expr->payload.desc == &proto_icmp6) {
+ const struct proto_desc *desc, *desc_upper;
+ struct stmt *nstmt;
+
+ desc = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
+ if (!desc) {
+ desc = payload_get_get_ll_hdr(ctx);
+ if (!desc)
+ break;
+ }
+
+ desc_upper = &proto_ip6;
+ if (expr->payload.desc == &proto_icmp)
+ desc_upper = &proto_ip;
+
+ if (payload_add_dependency(ctx, desc, desc_upper,
+ expr, &nstmt) < 0)
+ return NULL;
+
+ list_add_tail(&nstmt->list, &ctx->stmt->list);
+ return desc_upper;
+ }
return &proto_inet_service;
default:
break;
--
2.11.0

View File

@ -0,0 +1,86 @@
From 0825c57d571bb7121e7048e198b9b023f7e7f358 Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Sun, 7 May 2017 03:53:30 +0200
Subject: [PATCH] src: ip: switch implicit dependencies to meta l4proto too
after ip6 nexthdr also switch ip to meta l4proto instead of ip protocol.
While its needed for ipv6 (due to extension headers) this isn't needed
for ip but it has the advantage that
tcp dport 22
produces same expressions for ip/ip6/inet families.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
Upstream-Status: Backport
Signed-off-by: André Draszik <adraszik@tycoint.com>
src/payload.c | 17 +++++++++++------
src/proto.c | 3 ++-
2 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/src/payload.c b/src/payload.c
index 8796ee5..11b6df3 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -118,17 +118,22 @@ static const struct expr_ops payload_expr_ops = {
};
/*
- * ipv6 is special case, we normally use 'meta l4proto' to fetch the last
- * l4 header of the ipv6 extension header chain so we will also match
+ * We normally use 'meta l4proto' to fetch the last l4 header of the
+ * ipv6 extension header chain so we will also match
* tcp after a fragmentation header, for instance.
+ * For consistency we also use meta l4proto for ipv4.
*
- * If user specifically asks for nexthdr x, treat is as a full
- * dependency rather than injecting another (useless) meta l4 one.
+ * If user specifically asks for nexthdr x, don't add another (useless)
+ * meta dependency.
*/
static bool proto_key_is_protocol(const struct proto_desc *desc, unsigned int type)
{
- if (type == desc->protocol_key ||
- (desc == &proto_ip6 && type == IP6HDR_NEXTHDR))
+ if (type == desc->protocol_key)
+ return true;
+
+ if (desc == &proto_ip6 && type == IP6HDR_NEXTHDR)
+ return true;
+ if (desc == &proto_ip && type == IPHDR_PROTOCOL)
return true;
return false;
diff --git a/src/proto.c b/src/proto.c
index 3b20a5f..2afedf7 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -587,7 +587,6 @@ const struct proto_desc proto_ip = {
.name = "ip",
.base = PROTO_BASE_NETWORK_HDR,
.checksum_key = IPHDR_CHECKSUM,
- .protocol_key = IPHDR_PROTOCOL,
.protocols = {
PROTO_LINK(IPPROTO_ICMP, &proto_icmp),
PROTO_LINK(IPPROTO_ESP, &proto_esp),
@@ -600,6 +599,7 @@ const struct proto_desc proto_ip = {
PROTO_LINK(IPPROTO_SCTP, &proto_sctp),
},
.templates = {
+ [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8),
[IPHDR_VERSION] = HDR_BITFIELD("version", &integer_type, 0, 4),
[IPHDR_HDRLENGTH] = HDR_BITFIELD("hdrlength", &integer_type, 4, 4),
[IPHDR_DSCP] = HDR_BITFIELD("dscp", &dscp_type, 8, 6),
@@ -779,6 +779,7 @@ const struct proto_desc proto_inet_service = {
PROTO_LINK(IPPROTO_TCP, &proto_tcp),
PROTO_LINK(IPPROTO_DCCP, &proto_dccp),
PROTO_LINK(IPPROTO_SCTP, &proto_sctp),
+ PROTO_LINK(IPPROTO_ICMP, &proto_icmp),
PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6),
},
.templates = {
--
2.11.0

View File

@ -9,6 +9,15 @@ RRECOMMENDS_${PN} += "kernel-module-nf-tables \
SRC_URI = "http://www.netfilter.org/projects/nftables/files/${BP}.tar.bz2 \
file://fix-to-generate-ntf.8.patch \
\
file://0001-payload-explicit-network-ctx-assignment-for-icmp-icm.patch \
file://0002-proto-Add-some-exotic-ICMPv6-types.patch \
\
file://0003-payload-split-ll-proto-dependency-into-helper.patch \
file://0004-src-allow-update-of-net-base-w.-meta-l4proto-icmpv6.patch \
file://0005-src-ipv6-switch-implicit-dependencies-to-meta-l4prot.patch \
file://0006-payload-enforce-ip-ip6-protocol-depending-on-icmp-or.patch \
file://0007-src-ip-switch-implicit-dependencies-to-meta-l4proto-.patch \
"
SRC_URI[md5sum] = "4c005e76a15a029afaba71d7db21d065"
SRC_URI[sha256sum] = "fe639239d801ce5890397f6f4391c58a934bfc27d8b7d5ef922692de5ec4ed43"