From: Alvaro Neira Ayuso <alvaroneay@gmail.com>
To: netfilter-devel@vger.kernel.org
Cc: kaber@trash.net
Subject: [nftables PATCH] proto: add icmp and icmpv6 in inet protocols
Date: Mon, 23 Jun 2014 13:18:17 +0200 [thread overview]
Message-ID: <1403522297-16661-1-git-send-email-alvaroneay@gmail.com> (raw)
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@gmail.com>
---
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
next reply other threads:[~2014-06-23 11:19 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-06-23 11:18 Alvaro Neira Ayuso [this message]
2014-06-23 11:55 ` [nftables PATCH] proto: add icmp and icmpv6 in inet protocols Patrick McHardy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1403522297-16661-1-git-send-email-alvaroneay@gmail.com \
--to=alvaroneay@gmail.com \
--cc=kaber@trash.net \
--cc=netfilter-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).