[nftables PATCH] proto: add icmp and icmpv6 in inet protocols

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If we try to add a rule with icmp or icmpv6 in a inet table like this:

nft add rule inet filter input icmp type echo-request counter
or
nft add rule inet filter input icmpv6 type echo-request counter

we have this error:

<cmdline>:1:28-38: Error: conflicting protocols specified: inet-service vs. icmpv6
add rule inet filter input icmpv6 type echo-request counter accept
                           ^^^^^^^^^^^

This patch solve it adding icmp and icmpv6 in the inet protocols that we can use.
Also, I have added a statement meta for restricting that the rules for icmp is only
for ipv4 traffic and the rules for icmpv6 is for ipv6 traffic.

Signed-off-by: Alvaro Neira Ayuso <alvaroneay@xxxxxxxxx>
---
I have tested this patch with the rules:

nft add rule inet filter input tcp dport 22 counter
nft add rule inet filter input icmp type echo-request counter
nft add rule inet filter input icmpv6 type echo-request counter

I have created traffic and I have seen that it works for me.

 include/payload.h         |    4 +--
 include/statement.h       |    1 +
 src/evaluate.c            |   11 ++----
 src/netlink_delinearize.c |   43 +++++++++++++++--------
 src/payload.c             |   84 ++++++++++++++++++++++++++++++++++-----------
 src/proto.c               |    2 ++
 6 files changed, 100 insertions(+), 45 deletions(-)

diff --git a/include/payload.h b/include/payload.h
index d47e564..db2184e 100644
--- a/include/payload.h
+++ b/include/payload.h
@@ -11,8 +11,8 @@ extern void payload_init_raw(struct expr *expr, enum proto_bases base,
 			     unsigned int offset, unsigned int len);
 
 struct eval_ctx;
-extern int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
-				  struct expr **res);
+extern int payload_gen_dependency(struct eval_ctx *ctx,
+				  const struct expr *expr);
 
 extern bool payload_is_adjacent(const struct expr *e1, const struct expr *e2);
 extern struct expr *payload_expr_join(const struct expr *e1,
diff --git a/include/statement.h b/include/statement.h
index 28f9a35..b0ce377 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -162,4 +162,5 @@ extern void stmt_free(struct stmt *stmt);
 extern void stmt_list_free(struct list_head *list);
 extern void stmt_print(const struct stmt *stmt);
 
+int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt);
 #endif /* NFTABLES_STATEMENT_H */
diff --git a/src/evaluate.c b/src/evaluate.c
index 216194f..9b307b5 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -27,7 +27,6 @@
 #include <utils.h>
 
 static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr);
-static int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt);
 
 static const char *byteorder_names[] = {
 	[BYTEORDER_INVALID]		= "invalid",
@@ -271,16 +270,10 @@ static int expr_evaluate_payload(struct eval_ctx *ctx, struct expr **expr)
 {
 	struct expr *payload = *expr;
 	enum proto_bases base = payload->payload.base;
-	struct stmt *nstmt;
-	struct expr *nexpr;
 
 	if (ctx->pctx.protocol[base].desc == NULL) {
-		if (payload_gen_dependency(ctx, payload, &nexpr) < 0)
+		if (payload_gen_dependency(ctx, payload) < 0)
 			return -1;
-		nstmt = expr_stmt_alloc(&nexpr->location, nexpr);
-		if (stmt_evaluate(ctx, nstmt) < 0)
-			return -1;
-		list_add_tail(&nstmt->list, &ctx->stmt->list);
 	} else if (ctx->pctx.protocol[base].desc != payload->payload.desc)
 		return expr_error(ctx->msgs, payload,
 				  "conflicting protocols specified: %s vs. %s",
@@ -1196,7 +1189,7 @@ static int stmt_evaluate_ct(struct eval_ctx *ctx, struct stmt *stmt)
 	return 0;
 }
 
-static int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
+int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
 {
 #ifdef DEBUG
 	if (debug_level & DEBUG_EVALUATION) {
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 8d30b2d..81cd3f3 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -14,6 +14,8 @@
 #include <string.h>
 #include <limits.h>
 #include <linux/netfilter/nf_tables.h>
+#include <netinet/in.h>
+#include <linux/netfilter.h>
 #include <netlink.h>
 #include <rule.h>
 #include <statement.h>
@@ -603,8 +605,9 @@ static int netlink_parse_expr(struct nft_rule_expr *nle, void *arg)
 
 struct rule_pp_ctx {
 	struct proto_ctx	pctx;
-	enum proto_bases	pbase;
-	struct stmt		*pdep;
+	struct {
+		struct stmt		*pdep;
+	} protocol[PROTO_BASE_MAX + 1];
 };
 
 /*
@@ -612,13 +615,27 @@ struct rule_pp_ctx {
  */
 static void payload_dependency_kill(struct rule_pp_ctx *ctx, struct expr *expr)
 {
-	if (ctx->pbase != PROTO_BASE_INVALID &&
-	    ctx->pbase == expr->payload.base - 1 &&
-	    ctx->pdep != NULL) {
-		list_del(&ctx->pdep->list);
-		stmt_free(ctx->pdep);
-		ctx->pbase = PROTO_BASE_INVALID;
-		ctx->pdep = NULL;
+	int base = expr->payload.base - 1;
+
+	if (base < 0)
+		return;
+
+	if (ctx->protocol[base].pdep != NULL) {
+		list_del(&ctx->protocol[base].pdep->list);
+		stmt_free(ctx->protocol[base].pdep);
+		ctx->protocol[base].pdep = NULL;
+	}
+
+	if (ctx->pctx.family == NFPROTO_INET) {
+		base--;
+		if (base < 0)
+			return;
+
+		if (ctx->protocol[base].pdep != NULL) {
+			list_del(&ctx->protocol[base].pdep->list);
+			stmt_free(ctx->protocol[base].pdep);
+			ctx->protocol[base].pdep = NULL;
+		}
 	}
 }
 
@@ -626,8 +643,7 @@ static void payload_dependency_store(struct rule_pp_ctx *ctx,
 				     struct stmt *stmt,
 				     enum proto_bases base)
 {
-	ctx->pbase = base;
-	ctx->pdep  = stmt;
+	ctx->protocol[base].pdep = stmt;
 }
 
 static void payload_match_postprocess(struct rule_pp_ctx *ctx,
@@ -660,7 +676,7 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx,
 			 * kill it later on if made redundant by a higher layer
 			 * payload expression.
 			 */
-			if (ctx->pbase == PROTO_BASE_INVALID &&
+			if (ctx->protocol[left->payload.base-1].pdep == NULL &&
 			    left->flags & EXPR_F_PROTOCOL)
 				payload_dependency_store(ctx, nstmt,
 							 left->payload.base);
@@ -689,8 +705,7 @@ static void meta_match_postprocess(struct rule_pp_ctx *ctx,
 	case OP_EQ:
 		expr->left->ops->pctx_update(&ctx->pctx, expr);
 
-		if (ctx->pbase == PROTO_BASE_INVALID &&
-		    left->flags & EXPR_F_PROTOCOL)
+		if (left->flags & EXPR_F_PROTOCOL)
 			payload_dependency_store(ctx, stmt, left->meta.base);
 		break;
 	default:
diff --git a/src/payload.c b/src/payload.c
index a1785a5..757e6c2 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -24,6 +24,7 @@
 #include <payload.h>
 #include <gmputil.h>
 #include <utils.h>
+#include <statement.h>
 
 static void payload_expr_print(const struct expr *expr)
 {
@@ -128,6 +129,45 @@ void payload_init_raw(struct expr *expr, enum proto_bases base,
 	expr->len		= len;
 }
 
+static struct expr *payload_gen_dependency_node(const struct proto_desc *desc,
+						const struct expr *expr,
+						int protocol,
+						struct eval_ctx *ctx)
+{
+	struct expr *dep, *left, *right;
+	const struct proto_hdr_template *tmpl;
+
+	tmpl = &desc->templates[desc->protocol_key];
+	if (tmpl->meta_key)
+		left = meta_expr_alloc(&expr->location, tmpl->meta_key);
+	else
+		left = payload_expr_alloc(&expr->location, desc,
+					  desc->protocol_key);
+
+	right = constant_expr_alloc(&expr->location, tmpl->dtype,
+				    BYTEORDER_HOST_ENDIAN,
+				    tmpl->len,
+				    constant_data_ptr(protocol, tmpl->len));
+
+	dep = relational_expr_alloc(&expr->location, OP_EQ, left, right);
+	left->ops->pctx_update(&ctx->pctx, dep);
+
+	return dep;
+}
+
+static int expr_stmt_create_evaluate(const struct expr *expr,
+				     struct expr *dep,
+				     struct eval_ctx *ctx)
+{
+	struct stmt *nstmt;
+
+	nstmt = expr_stmt_alloc(&expr->location, dep);
+	if (stmt_evaluate(ctx, nstmt) < 0)
+		return -1;
+
+	list_add_tail(&nstmt->list, &ctx->stmt->list);
+	return 0;
+}
 /**
  * payload_gen_dependency - generate match expression on payload dependency
  *
@@ -151,14 +191,12 @@ void payload_init_raw(struct expr *expr, enum proto_bases base,
  *   it is not explicitly verified. The NFT_META_IIFTYPE match will only match
  *   in the input path though.
  */
-int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
-			   struct expr **res)
+int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr)
 {
 	const struct hook_proto_desc *h = &hook_proto_desc[ctx->pctx.family];
 	const struct proto_desc *desc;
-	const struct proto_hdr_template *tmpl;
 	struct expr *dep, *left, *right;
-	int protocol;
+	int protocol, ret = 0;
 	uint16_t type;
 
 	if (expr->payload.base < h->base) {
@@ -178,8 +216,7 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
 					    2 * BITS_PER_BYTE, &type);
 
 		dep = relational_expr_alloc(&expr->location, OP_EQ, left, right);
-		*res = dep;
-		return 0;
+		return expr_stmt_create_evaluate(expr, dep, ctx);
 	}
 
 	desc = ctx->pctx.protocol[expr->payload.base - 1].desc;
@@ -201,21 +238,28 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
 				  "conflicting protocols specified: %s vs. %s",
 				  desc->name, expr->payload.desc->name);
 
-	tmpl = &desc->templates[desc->protocol_key];
-	if (tmpl->meta_key)
-		left = meta_expr_alloc(&expr->location, tmpl->meta_key);
-	else
-		left = payload_expr_alloc(&expr->location, desc, desc->protocol_key);
-
-	right = constant_expr_alloc(&expr->location, tmpl->dtype,
-				    BYTEORDER_HOST_ENDIAN,
-				    tmpl->len,
-				    constant_data_ptr(protocol, tmpl->len));
+	if (ctx->pctx.family == NFPROTO_INET) {
+		switch (protocol) {
+		case IPPROTO_ICMP:
+			dep = payload_gen_dependency_node(&proto_inet, expr,
+							  NFPROTO_IPV4, ctx);
+			ret = expr_stmt_create_evaluate(expr, dep, ctx);
+			break;
+		case IPPROTO_ICMPV6:
+			dep = payload_gen_dependency_node(&proto_inet, expr,
+							  NFPROTO_IPV6, ctx);
+			ret = expr_stmt_create_evaluate(expr, dep, ctx);
+			break;
+		default:
+			break;
+		}
+	}
+	if (ret < 0)
+		return -1;
 
-	dep = relational_expr_alloc(&expr->location, OP_EQ, left, right);
-	left->ops->pctx_update(&ctx->pctx, dep);
-	*res = dep;
-	return 0;
+	dep = payload_gen_dependency_node(desc, expr, protocol, ctx);
+	ret = expr_stmt_create_evaluate(expr, dep, ctx);
+	return ret;
 }
 
 /**
diff --git a/src/proto.c b/src/proto.c
index 0a37a65..a3bf387 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -644,6 +644,8 @@ 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),
+		PROTO_LINK(IPPROTO_ICMP,	&proto_icmp),
 	},
 	.templates	= {
 		[0]	= PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8),
-- 
1.7.10.4

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




[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux