Discussion:
[nft PATCH 1/4 v2] evaluate: refactor function to check the reject family in inet and bridge
Alvaro Neira Ayuso
2014-10-21 14:15:43 UTC
Permalink
This patch make a refactorization of the code to check the reject family in inet
and bridge. These changes will be used in follow up patches.

Signed-off-by: Alvaro Neira Ayuso <***@gmail.com>
---
[changes in v2]
* Refactor the functions in two functions more, to check the reject family in
inet and bridge tables.

src/evaluate.c | 134 ++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 86 insertions(+), 48 deletions(-)

diff --git a/src/evaluate.c b/src/evaluate.c
index ff46fda..e26e2f8 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1202,12 +1202,94 @@ static int stmt_reject_gen_dependency(struct eval_ctx *ctx, struct stmt *stmt,
return 0;
}

-static int stmt_evaluate_reject_family(struct eval_ctx *ctx, struct stmt *stmt,
+static int stmt_evaluate_reject_inet_family(struct eval_ctx *ctx,
+ struct stmt *stmt,
+ const struct proto_desc *desc)
+{
+ const struct proto_desc *base;
+ int protocol;
+
+ base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
+ protocol = proto_find_num(base, desc);
+ switch (protocol) {
+ case NFPROTO_IPV4:
+ if (stmt->reject.family == NFPROTO_IPV4)
+ break;
+ return stmt_error(ctx, stmt,
+ "conflicting protocols specified: ip vs ip6");
+ case NFPROTO_IPV6:
+ if (stmt->reject.family == NFPROTO_IPV6)
+ break;
+ return stmt_error(ctx, stmt,
+ "conflicting protocols specified: ip vs ip6");
+ default:
+ BUG("unsupported family");
+ }
+
+ return 0;
+}
+
+static int stmt_evaluate_reject_inet(struct eval_ctx *ctx, struct stmt *stmt,
struct expr *expr)
{
- const struct proto_desc *desc, *base;
+ const struct proto_desc *desc;
+
+ desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+ if (desc != NULL &&
+ stmt_evaluate_reject_inet_family(ctx, stmt, desc) < 0)
+ return -1;
+ if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH)
+ return 0;
+ if (stmt_reject_gen_dependency(ctx, stmt, expr) < 0)
+ return -1;
+ return 0;
+}
+
+static int stmt_evaluate_reject_bridge_family(struct eval_ctx *ctx,
+ struct stmt *stmt,
+ const struct proto_desc *desc)
+{
+ const struct proto_desc *base;
int protocol;

+ base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
+ protocol = proto_find_num(base, desc);
+ switch (protocol) {
+ case __constant_htons(ETH_P_IP):
+ if (NFPROTO_IPV4 == stmt->reject.family)
+ break;
+ case __constant_htons(ETH_P_IPV6):
+ if (NFPROTO_IPV6 == stmt->reject.family)
+ break;
+ return stmt_error(ctx, stmt,
+ "conflicting protocols specified: ip vs ip6");
+ default:
+ return stmt_error(ctx, stmt,
+ "cannot reject this ether type");
+ }
+
+ return 0;
+}
+
+static int stmt_evaluate_reject_bridge(struct eval_ctx *ctx, struct stmt *stmt,
+ struct expr *expr)
+{
+ const struct proto_desc *desc;
+
+ desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+ if (desc != NULL &&
+ stmt_evaluate_reject_bridge_family(ctx, stmt, desc) < 0)
+ return -1;
+ if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH)
+ return 0;
+ if (stmt_reject_gen_dependency(ctx, stmt, expr) < 0)
+ return -1;
+ return 0;
+}
+
+static int stmt_evaluate_reject_family(struct eval_ctx *ctx, struct stmt *stmt,
+ struct expr *expr)
+{
switch (ctx->pctx.family) {
case NFPROTO_ARP:
return stmt_error(ctx, stmt, "cannot use reject with arp");
@@ -1229,55 +1311,11 @@ static int stmt_evaluate_reject_family(struct eval_ctx *ctx, struct stmt *stmt,
}
break;
case NFPROTO_BRIDGE:
- base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
- desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
- if (desc != NULL) {
- protocol = proto_find_num(base, desc);
- switch (protocol) {
- case __constant_htons(ETH_P_IP):
- if (NFPROTO_IPV4 == stmt->reject.family)
- break;
- case __constant_htons(ETH_P_IPV6):
- if (NFPROTO_IPV6 == stmt->reject.family)
- break;
- return stmt_error(ctx, stmt,
- "conflicting protocols specified: ip vs ip6");
- default:
- return stmt_error(ctx, stmt,
- "cannot reject this ether type");
- }
- break;
- }
- if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH)
- break;
- if (stmt_reject_gen_dependency(ctx, stmt, expr) < 0)
+ if (stmt_evaluate_reject_bridge(ctx, stmt, expr) < 0)
return -1;
break;
case NFPROTO_INET:
- base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
- desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
- if (desc != NULL) {
- protocol = proto_find_num(base, desc);
- switch (protocol) {
- case NFPROTO_IPV4:
- if (stmt->reject.family == NFPROTO_IPV4)
- break;
- return stmt_error(ctx, stmt,
- "conflicting protocols specified: ip vs ip6");
- break;
- case NFPROTO_IPV6:
- if (stmt->reject.family == NFPROTO_IPV6)
- break;
- return stmt_error(ctx, stmt,
- "conflicting protocols specified: ip vs ip6");
- default:
- BUG("unsupported family");
- }
- break;
- }
- if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH)
- break;
- if (stmt_reject_gen_dependency(ctx, stmt, expr) < 0)
+ if (stmt_evaluate_reject_inet(ctx, stmt, expr) < 0)
return -1;
break;
}
--
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Alvaro Neira Ayuso
2014-10-21 14:15:45 UTC
Permalink
In Inet tables, we have to check the network context in rules that we use
icmp or icmpv6 reason in reject. To be sure that the context is the correct.
However, for icmpx and tcp reject, we don't need to check it.

In Bridge tables, we have vlan and arp traffic and they are not supported.
For this things, we have to check the network context. For example:

nft add rule bridge test-bridge input \
ether type arp reject with icmp type host-unreachable
or
nft add rule bridge test-bridge input \
ether type vlan reject with tcp reset

In that cases, we have to throw an error. Moreover, we have to accept rules
that the network context is Ipv4 and Ipv6. For example:

nft add rule -nnn bridge test-bridge input \
ip protocol tcp reject with tcp reset

Signed-off-by: Alvaro Neira Ayuso <***@gmail.com>
---
[changes in v2]
* Check the network context is correct only in bridge tables, if we use
icmpx or tcp reset.

src/evaluate.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/src/evaluate.c b/src/evaluate.c
index 017d9b0..79576c1 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1234,12 +1234,18 @@ static int stmt_evaluate_reject_inet(struct eval_ctx *ctx, struct stmt *stmt,
{
const struct proto_desc *desc;

- desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
- if (desc != NULL &&
- stmt_evaluate_reject_inet_family(ctx, stmt, desc) < 0)
- return -1;
- if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH)
+ switch (stmt->reject.type) {
+ case NFT_REJECT_TCP_RST:
+ break;
+ case NFT_REJECT_ICMPX_UNREACH:
return 0;
+ case NFT_REJECT_ICMP_UNREACH:
+ desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+ if (desc != NULL &&
+ stmt_evaluate_reject_inet_family(ctx, stmt, desc) < 0)
+ return -1;
+ break;
+ }
if (stmt_reject_gen_dependency(ctx, stmt, expr) < 0)
return -1;
return 0;
@@ -1256,11 +1262,15 @@ static int stmt_evaluate_reject_bridge_family(struct eval_ctx *ctx,
protocol = proto_find_num(base, desc);
switch (protocol) {
case __constant_htons(ETH_P_IP):
+ if (stmt->reject.type != NFT_REJECT_ICMP_UNREACH)
+ break;
if (NFPROTO_IPV4 == stmt->reject.family)
break;
return stmt_error(ctx, stmt,
"conflicting protocols specified: ip vs ip6");
case __constant_htons(ETH_P_IPV6):
+ if (stmt->reject.type != NFT_REJECT_ICMP_UNREACH)
+ break;
if (NFPROTO_IPV6 == stmt->reject.family)
break;
return stmt_error(ctx, stmt,
--
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Alvaro Neira Ayuso
2014-10-21 14:15:44 UTC
Permalink
nft add rule bridge test-bridge input ether type ip \
reject with icmpv6 type no-route

This rule pass the evaluation step but the network context is incompatible with
the reject reason. In that cases, we have to throw an error like "conflicting
protocols specified: ip vs ip6"

Signed-off-by: Alvaro Neira Ayuso <***@gmail.com>
---
[no changes in v2]

src/evaluate.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/src/evaluate.c b/src/evaluate.c
index e26e2f8..017d9b0 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1258,6 +1258,8 @@ static int stmt_evaluate_reject_bridge_family(struct eval_ctx *ctx,
case __constant_htons(ETH_P_IP):
if (NFPROTO_IPV4 == stmt->reject.family)
break;
+ return stmt_error(ctx, stmt,
+ "conflicting protocols specified: ip vs ip6");
case __constant_htons(ETH_P_IPV6):
if (NFPROTO_IPV6 == stmt->reject.family)
break;
--
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Alvaro Neira Ayuso
2014-10-21 14:15:46 UTC
Permalink
Signed-off-by: Alvaro Neira Ayuso <***@gmail.com>
---
[changes in v4]
* Add rules that we have to check the network context in inet and bridge tables

tests/regression/bridge/reject.t | 35 +++++++++++++++++++++++++++++++++++
tests/regression/inet/reject.t | 32 ++++++++++++++++++++++++++++++++
tests/regression/ip/reject.t | 11 ++++++++++-
tests/regression/ip6/reject.t | 9 ++++++++-
4 files changed, 85 insertions(+), 2 deletions(-)
create mode 100644 tests/regression/bridge/reject.t
create mode 100644 tests/regression/inet/reject.t

diff --git a/tests/regression/bridge/reject.t b/tests/regression/bridge/reject.t
new file mode 100644
index 0000000..11a0f1c
--- /dev/null
+++ b/tests/regression/bridge/reject.t
@@ -0,0 +1,35 @@
+*bridge;test-bridge
+:input;type filter hook input priority 0
+
+# The output is specific for bridge family
+reject with icmp type host-unreachable;ok;ether type ip reject with icmp type host-unreachable
+reject with icmp type net-unreachable;ok;ether type ip reject with icmp type net-unreachable
+reject with icmp type prot-unreachable;ok;ether type ip reject with icmp type prot-unreachable
+reject with icmp type port-unreachable;ok;ether type ip reject
+reject with icmp type net-prohibited;ok;ether type ip reject with icmp type net-prohibited
+reject with icmp type host-prohibited;ok;ether type ip reject with icmp type host-prohibited
+reject with icmp type admin-prohibited;ok;ether type ip reject with icmp type admin-prohibited
+
+reject with icmpv6 type no-route;ok;ether type ip6 reject with icmpv6 type no-route
+reject with icmpv6 type admin-prohibited;ok;ether type ip6 reject with icmpv6 type admin-prohibited
+reject with icmpv6 type addr-unreachable;ok;ether type ip6 reject with icmpv6 type addr-unreachable
+reject with icmpv6 type port-unreachable;ok;ether type ip6 reject
+
+ip protocol tcp reject with tcp reset;ok;ip protocol 6 reject with tcp reset
+
+reject;ok
+reject with icmpx type host-unreachable;ok
+reject with icmpx type no-route;ok
+reject with icmpx type admin-prohibited;ok
+reject with icmpx type port-unreachable;ok;reject
+
+ether type ipv6 reject with icmp type host-unreachable;fail
+ether type ip6 reject with icmp type host-unreachable;fail
+ether type ip reject with icmpv6 type no-route;fail
+ether type vlan reject;fail
+ether type arp reject;fail
+ether type vlan reject;fail
+ether type arp reject;fail
+ether type vlan reject with tcp reset;fail
+ether type arp reject with tcp reset;fail
+ip protocol udp reject with tcp reset;fail
diff --git a/tests/regression/inet/reject.t b/tests/regression/inet/reject.t
new file mode 100644
index 0000000..2f5aef3
--- /dev/null
+++ b/tests/regression/inet/reject.t
@@ -0,0 +1,32 @@
+*inet;test-inet
+:input;type filter hook input priority 0
+
+# The output is specific for inet family
+reject with icmp type host-unreachable;ok;meta nfproto ipv4 reject with icmp type host-unreachable
+reject with icmp type net-unreachable;ok;meta nfproto ipv4 reject with icmp type net-unreachable
+reject with icmp type prot-unreachable;ok;meta nfproto ipv4 reject with icmp type prot-unreachable
+reject with icmp type port-unreachable;ok;meta nfproto ipv4 reject
+reject with icmp type net-prohibited;ok;meta nfproto ipv4 reject with icmp type net-prohibited
+reject with icmp type host-prohibited;ok;meta nfproto ipv4 reject with icmp type host-prohibited
+reject with icmp type admin-prohibited;ok;meta nfproto ipv4 reject with icmp type admin-prohibited
+
+reject with icmpv6 type no-route;ok;meta nfproto ipv6 reject with icmpv6 type no-route
+reject with icmpv6 type admin-prohibited;ok;meta nfproto ipv6 reject with icmpv6 type admin-prohibited
+reject with icmpv6 type addr-unreachable;ok;meta nfproto ipv6 reject with icmpv6 type addr-unreachable
+reject with icmpv6 type port-unreachable;ok;meta nfproto ipv6 reject
+
+reject with tcp reset;ok;meta l4proto 6 reject with tcp reset
+
+reject;ok
+reject with icmpx type host-unreachable;ok
+reject with icmpx type no-route;ok
+reject with icmpx type admin-prohibited;ok
+reject with icmpx type port-unreachable;ok;reject
+
+meta nfproto ipv4 reject with icmp type host-unreachable;ok
+meta nfproto ipv6 reject with icmpv6 type no-route;ok
+
+meta nfproto ipv6 reject with icmp type host-unreachable;fail
+meta nfproto ipv4 ip protocol icmp reject with icmpv6 type no-route;fail
+meta nfproto ipv6 ip protocol icmp reject with icmp type host-unreachable;fail
+meta l4proto udp reject with tcp reset;fail
diff --git a/tests/regression/ip/reject.t b/tests/regression/ip/reject.t
index e7fb15b..70a63a0 100644
--- a/tests/regression/ip/reject.t
+++ b/tests/regression/ip/reject.t
@@ -1,5 +1,14 @@
*ip;test-ip4
-*ip;test-inet
:output;type filter hook output priority 0

reject;ok
+reject with icmp type host-unreachable;ok
+reject with icmp type net-unreachable;ok
+reject with icmp type prot-unreachable;ok
+reject with icmp type port-unreachable;ok;reject
+reject with icmp type net-prohibited;ok
+reject with icmp type host-prohibited;ok
+reject with icmp type admin-prohibited;ok
+
+reject with icmp type no-route;fail
+reject with icmpv6 type no-route;fail
diff --git a/tests/regression/ip6/reject.t b/tests/regression/ip6/reject.t
index b49c50b..60dec90 100644
--- a/tests/regression/ip6/reject.t
+++ b/tests/regression/ip6/reject.t
@@ -1,5 +1,12 @@
*ip6;test-ip6
-*inet;test-inet
:output;type filter hook output priority 0

reject;ok
+reject with icmpv6 type no-route;ok
+reject with icmpv6 type admin-prohibited;ok
+reject with icmpv6 type addr-unreachable;ok
+reject with icmpv6 type port-unreachable;ok;reject
+reject with tcp reset;ok;ip6 nexthdr 6 reject with tcp reset
+
+reject with icmpv6 type host-unreachable;fail
+reject with icmp type host-unreachable;fail
--
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Loading...