From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Cc: kaber@trash.net
Subject: [PATCH nft] src: add tee statement
Date: Fri, 19 Jun 2015 12:26:34 +0200 [thread overview]
Message-ID: <1434709594-6460-1-git-send-email-pablo@netfilter.org> (raw)
This allows you to clone packets to some destination, eg.
... tee gateway 172.20.0.2
... tee oifname tap0 gateway ip saddr map { 192.168.0.2 : 172.20.0.2, ... }
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/statement.h | 9 +++++++++
src/evaluate.c | 21 +++++++++++++++++++--
src/netlink_delinearize.c | 39 +++++++++++++++++++++++++++++++++++++++
src/netlink_linearize.c | 21 +++++++++++++++++++++
src/parser_bison.y | 18 ++++++++++++++++++
src/scanner.l | 2 ++
src/statement.c | 29 +++++++++++++++++++++++++++++
7 files changed, 137 insertions(+), 2 deletions(-)
diff --git a/include/statement.h b/include/statement.h
index 48e6130..5c8e08d 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -103,6 +103,12 @@ struct ct_stmt {
extern struct stmt *ct_stmt_alloc(const struct location *loc,
enum nft_ct_keys key,
struct expr *expr);
+struct tee_stmt {
+ struct expr *gw;
+ const char *oifname;
+};
+
+struct stmt *tee_stmt_alloc(const struct location *loc);
struct set_stmt {
struct expr *set;
@@ -129,6 +135,7 @@ extern struct stmt *set_stmt_alloc(const struct location *loc);
* @STMT_QUEUE: QUEUE statement
* @STMT_CT: conntrack statement
* @STMT_SET: set statement
+ * @STMT_TEE: tee statement
*/
enum stmt_types {
STMT_INVALID,
@@ -145,6 +152,7 @@ enum stmt_types {
STMT_QUEUE,
STMT_CT,
STMT_SET,
+ STMT_TEE,
};
/**
@@ -195,6 +203,7 @@ struct stmt {
struct queue_stmt queue;
struct ct_stmt ct;
struct set_stmt set;
+ struct tee_stmt tee;
};
};
diff --git a/src/evaluate.c b/src/evaluate.c
index d99b38f..f29c716 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1557,7 +1557,7 @@ static int nat_evaluate_family(struct eval_ctx *ctx, struct stmt *stmt)
}
}
-static int nat_evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt,
+static int evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt,
struct expr **expr)
{
struct proto_ctx *pctx = &ctx->pctx;
@@ -1599,7 +1599,7 @@ static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt)
return err;
if (stmt->nat.addr != NULL) {
- err = nat_evaluate_addr(ctx, stmt, &stmt->nat.addr);
+ err = evaluate_addr(ctx, stmt, &stmt->nat.addr);
if (err < 0)
return err;
}
@@ -1643,6 +1643,21 @@ static int stmt_evaluate_redir(struct eval_ctx *ctx, struct stmt *stmt)
return 0;
}
+static int stmt_evaluate_tee(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ int err;
+
+ err = nat_evaluate_family(ctx, stmt);
+ if (err < 0)
+ return err;
+
+ err = evaluate_addr(ctx, stmt, &stmt->tee.gw);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
static int stmt_evaluate_queue(struct eval_ctx *ctx, struct stmt *stmt)
{
if (stmt->queue.queue != NULL) {
@@ -1726,6 +1741,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
return stmt_evaluate_redir(ctx, stmt);
case STMT_QUEUE:
return stmt_evaluate_queue(ctx, stmt);
+ case STMT_TEE:
+ return stmt_evaluate_tee(ctx, stmt);
case STMT_SET:
return stmt_evaluate_set(ctx, stmt);
default:
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 6d60be3..d0f9154 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -747,6 +747,40 @@ static void netlink_parse_redir(struct netlink_parse_ctx *ctx,
list_add_tail(&stmt->list, &ctx->rule->stmts);
}
+static void netlink_parse_tee(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nft_rule_expr *nle)
+{
+ struct stmt *stmt;
+ struct expr *addr;
+ enum nft_registers reg1;
+
+ stmt = tee_stmt_alloc(loc);
+
+ reg1 = netlink_parse_register(nle, NFT_EXPR_TEE_SREG_GW);
+ if (reg1) {
+ addr = netlink_get_register(ctx, loc, reg1);
+ if (addr == NULL)
+ return netlink_error(ctx, loc,
+ "TEE statement has no address "
+ "expression");
+
+ if (ctx->table->handle.family == NFPROTO_IPV4)
+ expr_set_type(addr, &ipaddr_type, BYTEORDER_BIG_ENDIAN);
+ else
+ expr_set_type(addr, &ip6addr_type,
+ BYTEORDER_BIG_ENDIAN);
+ stmt->tee.gw = addr;
+ }
+
+ if (nft_rule_expr_is_set(nle, NFT_EXPR_TEE_OIFNAME)) {
+ stmt->tee.oifname =
+ strdup(nft_rule_expr_get_str(nle, NFT_EXPR_TEE_OIFNAME));
+ }
+
+ list_add_tail(&stmt->list, &ctx->rule->stmts);
+}
+
static void netlink_parse_queue(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nft_rule_expr *nle)
@@ -835,6 +869,7 @@ static const struct {
{ .name = "nat", .parse = netlink_parse_nat },
{ .name = "masq", .parse = netlink_parse_masq },
{ .name = "redir", .parse = netlink_parse_redir },
+ { .name = "tee", .parse = netlink_parse_tee },
{ .name = "queue", .parse = netlink_parse_queue },
{ .name = "dynset", .parse = netlink_parse_dynset },
};
@@ -1365,6 +1400,10 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r
case STMT_SET:
expr_postprocess(&rctx, &stmt->set.key);
break;
+ case STMT_TEE:
+ if (stmt->tee.gw!= NULL)
+ expr_postprocess(&rctx, &stmt->tee.gw);
+ break;
default:
break;
}
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index bf1e56b..2a4f567 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -802,6 +802,25 @@ static void netlink_gen_redir_stmt(struct netlink_linearize_ctx *ctx,
nft_rule_add_expr(ctx->nlr, nle);
}
+static void netlink_gen_tee_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nft_rule_expr *nle;
+ const char *oifname = stmt->tee.oifname;
+ enum nft_registers sreg_gw;
+
+ nle = alloc_nft_expr("tee");
+
+ sreg_gw = get_register(ctx, stmt->tee.gw);
+ netlink_gen_expr(ctx, stmt->tee.gw, sreg_gw);
+ netlink_put_register(nle, NFT_EXPR_TEE_SREG_GW, sreg_gw);
+ release_register(ctx, stmt->tee.gw);
+
+ if (oifname != NULL)
+ nft_rule_expr_set_str(nle, NFT_EXPR_TEE_OIFNAME, oifname);
+ nft_rule_add_expr(ctx->nlr, nle);
+}
+
static void netlink_gen_queue_stmt(struct netlink_linearize_ctx *ctx,
const struct stmt *stmt)
{
@@ -892,6 +911,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
return netlink_gen_masq_stmt(ctx, stmt);
case STMT_REDIR:
return netlink_gen_redir_stmt(ctx, stmt);
+ case STMT_TEE:
+ return netlink_gen_tee_stmt(ctx, stmt);
case STMT_QUEUE:
return netlink_gen_queue_stmt(ctx, stmt);
case STMT_CT:
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 5c4e272..16c17e6 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -390,6 +390,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token BYPASS "bypass"
%token FANOUT "fanout"
+%token TEE "tee"
+
%token POSITION "position"
%token COMMENT "comment"
@@ -457,6 +459,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <stmt> queue_stmt queue_stmt_alloc
%destructor { stmt_free($$); } queue_stmt queue_stmt_alloc
%type <val> queue_stmt_flags queue_stmt_flag
+%type <stmt> tee_stmt
+%destructor { stmt_free($$); } tee_stmt
%type <stmt> set_stmt
%destructor { stmt_free($$); } set_stmt
%type <val> set_stmt_op
@@ -1275,6 +1279,7 @@ stmt : verdict_stmt
| ct_stmt
| masq_stmt
| redir_stmt
+ | tee_stmt
| set_stmt
;
@@ -1538,6 +1543,19 @@ redir_stmt_arg : TO expr
}
;
+tee_stmt : TEE GATEWAY expr
+ {
+ $$ = tee_stmt_alloc(&@$);
+ $$->tee.gw = $3;
+ }
+ | TEE OIFNAME string GATEWAY expr
+ {
+ $$ = tee_stmt_alloc(&@$);
+ $$->tee.oifname = strdup($3);
+ $$->tee.gw = $5;
+ }
+ ;
+
nf_nat_flags : nf_nat_flag
| nf_nat_flags COMMA nf_nat_flag
{
diff --git a/src/scanner.l b/src/scanner.l
index 985ea2a..d4f706f 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -454,6 +454,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"proto-dst" { return PROTO_DST; }
"label" { return LABEL; }
+"tee" { return TEE; }
+
"xml" { return XML; }
"json" { return JSON; }
diff --git a/src/statement.c b/src/statement.c
index 9ebc593..267be5e 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -408,3 +408,32 @@ struct stmt *set_stmt_alloc(const struct location *loc)
{
return stmt_alloc(loc, &set_stmt_ops);
}
+
+static void tee_stmt_print(const struct stmt *stmt)
+{
+ printf("tee");
+ if (stmt->tee.oifname != NULL)
+ printf(" oifname %s", stmt->tee.oifname);
+
+ printf(" gateway ");
+ expr_print(stmt->tee.gw);
+}
+
+static void tee_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->tee.gw);
+ if (stmt->tee.oifname != NULL)
+ xfree(stmt->tee.oifname);
+}
+
+static const struct stmt_ops tee_stmt_ops = {
+ .type = STMT_TEE,
+ .name = "tee",
+ .print = tee_stmt_print,
+ .destroy = tee_stmt_destroy,
+};
+
+struct stmt *tee_stmt_alloc(const struct location *loc)
+{
+ return stmt_alloc(loc, &tee_stmt_ops);
+}
--
1.7.10.4
next reply other threads:[~2015-06-19 10:21 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-06-19 10:26 Pablo Neira Ayuso [this message]
2015-06-19 12:57 ` [PATCH nft] src: add tee statement Patrick McHardy
2015-06-19 13:17 ` Patrick Schaaf
2015-06-19 13:24 ` Jan Engelhardt
2015-06-19 13:37 ` Patrick McHardy
2015-06-19 14:07 ` Jan Engelhardt
2015-06-26 11:47 ` Bjørnar Ness
2015-06-19 13:29 ` Patrick McHardy
2015-06-19 13:37 ` Pablo Neira Ayuso
2015-06-19 13:41 ` Patrick McHardy
2015-06-19 13:56 ` Pablo Neira Ayuso
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=1434709594-6460-1-git-send-email-pablo@netfilter.org \
--to=pablo@netfilter.org \
--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).