Re: tproxy with nftables

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

 



Hi Pablo,

----- On 8 Jan, 2015, at 11:56, Pablo Neira Ayuso pablo@xxxxxxxxxxxxx wrote:

> On Mon, Jan 05, 2015 at 02:05:43PM +0000, Andreas Schultz wrote:
>> Hi,
>> 
>> Is it possible to use tproxy with nftables?
> 
> No native tproxy support yet and noone is scheduled to work on that
> anytime soon, sorry.
> 
>> It seem that nft has no support for the tproxy table. It might
>> be possible to use a mix of nft and xtable-compat to get tproxy
>> to work on nft.
> 
> I posted a patch time ago to:
> 
> http://patchwork.ozlabs.org/patch/255896/
> 
> the main problem was that getopt() gets confused when this is used
> from the command-line (so it works fine with nft -f). The internal
> state of getopt() needs to be reset before calling libxtables to parse
> the options.

That patch does not apply to the nftable 0.4. I've forward ported it
(patch attached) and 'nft list' does work fine. However, attempting
to restore that output using 'nft -f' fails. It tried to debug it, but
my grasp of the nft structures is not good enough to understand what
exactly is wrong.

As simple chain like:

table mangle {
	chain test {
		tcp dport 80 counter packets 0 bytes 0 xt TPROXY [ --on-port 3128 --on-ip 0.0.0.0 --tproxy-mark 0x80000000/0x80000000 ]
	}
}

results in:

# nft -f rule
requesting `TPROXY' rev=1 type=1 via nft_compat
1:1:1-2: Error: Could not process rule: Invalid argument

> 
>> But I would like to use a map to lookup a match and then use tproxy
>> as action. I there a way to get this working?
> 
> I would need to know more on your use-case to be sure that the patch
> above will help you to achieve this, otherwise wait for the native
> tproxy support :-(.

Andreas
Index: nftables-0.4/configure.ac
===================================================================
--- nftables-0.4.orig/configure.ac
+++ nftables-0.4/configure.ac
@@ -73,6 +73,9 @@ AM_CONDITIONAL([BUILD_PDF], [test "$DBLA
 PKG_CHECK_MODULES([LIBMNL], [libmnl >= 1.0.3])
 PKG_CHECK_MODULES([LIBNFTNL], [libnftnl >= 1.0.2])
 
+AC_CHECK_LIB([xtables], [xtables_find_target], ,
+	     AC_MSG_ERROR([No suitable version of libxtables found]))
+
 AC_CHECK_LIB([gmp], [__gmpz_init], ,
 	     AC_MSG_ERROR([No suitable version of libgmp found]))
 
Index: nftables-0.4/include/expression.h
===================================================================
--- nftables-0.4.orig/include/expression.h
+++ nftables-0.4/include/expression.h
@@ -32,6 +32,7 @@
  * @EXPR_UNARY:		byteorder conversion, generated during evaluation
  * @EXPR_BINOP:		binary operations (bitwise, shifts)
  * @EXPR_RELATIONAL:	equality and relational expressions
+ * @EXPR_OPTION:	--option value expression
  */
 enum expr_types {
 	EXPR_INVALID,
@@ -53,6 +54,7 @@ enum expr_types {
 	EXPR_UNARY,
 	EXPR_BINOP,
 	EXPR_RELATIONAL,
+	EXPR_OPTION,
 };
 
 enum ops {
@@ -265,6 +267,11 @@ struct expr {
 			/* EXPR_CT */
 			enum nft_ct_keys	key;
 		} ct;
+		struct {
+			/* EXPR_OPTION */
+			const char		*id;
+			struct expr		*val;
+		};
 	};
 };
 
@@ -367,4 +374,7 @@ extern struct expr *set_ref_expr_alloc(c
 extern void range_expr_value_low(mpz_t rop, const struct expr *expr);
 extern void range_expr_value_high(mpz_t rop, const struct expr *expr);
 
+struct expr *option_expr_alloc(const struct location *loc, const char *id,
+			       struct expr *value);
+
 #endif /* NFTABLES_EXPRESSION_H */
Index: nftables-0.4/include/linux/netfilter/nf_tables_compat.h
===================================================================
--- /dev/null
+++ nftables-0.4/include/linux/netfilter/nf_tables_compat.h
@@ -0,0 +1,20 @@
+#ifndef _NFT_COMPAT_NFNETLINK_H_
+#define _NFT_COMPAT_NFNETLINK_H_
+
+#define NFT_COMPAT_NAME_MAX	32
+
+enum {
+	NFNL_MSG_COMPAT_GET,
+	NFNL_MSG_COMPAT_MAX
+};
+
+enum {
+	NFTA_COMPAT_UNSPEC = 0,
+	NFTA_COMPAT_NAME,
+	NFTA_COMPAT_REV,
+	NFTA_COMPAT_TYPE,
+	__NFTA_COMPAT_MAX,
+};
+#define NFTA_COMPAT_MAX (__NFTA_COMPAT_MAX - 1)
+
+#endif
Index: nftables-0.4/include/statement.h
===================================================================
--- nftables-0.4.orig/include/statement.h
+++ nftables-0.4/include/statement.h
@@ -3,6 +3,7 @@
 
 #include <list.h>
 #include <expression.h>
+#include <xt.h>
 
 extern struct stmt *expr_stmt_alloc(const struct location *loc,
 				    struct expr *expr);
@@ -104,6 +105,16 @@ extern struct stmt *ct_stmt_alloc(const
 				  enum nft_ct_keys key,
 				  struct expr *expr);
 
+struct xt_stmt {
+	const char		*name;
+	struct xtables_target	*target;
+	struct xtables_match	*match;
+	void			*entry;
+	struct expr		*list;
+};
+
+extern struct stmt *xt_stmt_alloc(const struct location *loc);
+
 /**
  * enum stmt_types - statement types
  *
@@ -120,6 +131,7 @@ extern struct stmt *ct_stmt_alloc(const
  * @STMT_REDIR:		redirect statement
  * @STMT_QUEUE:		QUEUE statement
  * @STMT_CT:		conntrack statement
+ * @STMT_XT:		XT statement
  */
 enum stmt_types {
 	STMT_INVALID,
@@ -135,6 +147,7 @@ enum stmt_types {
 	STMT_REDIR,
 	STMT_QUEUE,
 	STMT_CT,
+	STMT_XT,
 };
 
 /**
@@ -184,6 +197,7 @@ struct stmt {
 		struct redir_stmt	redir;
 		struct queue_stmt	queue;
 		struct ct_stmt		ct;
+		struct xt_stmt		xt;
 	};
 };
 
Index: nftables-0.4/include/xt.h
===================================================================
--- /dev/null
+++ nftables-0.4/include/xt.h
@@ -0,0 +1,23 @@
+#ifndef _NFT_XT_H_
+#define _NFT_XT_H_
+
+#include <xtables.h>
+
+enum nft_xt_ext_type {
+	NFT_XT_MATCH = 0,
+	NFT_XT_TARGET,
+};
+
+struct nft_xt_ext {
+	enum nft_xt_ext_type	type;
+	union {
+		struct xtables_target *tg;
+		struct xtables_match *mt;
+	};
+	void			*info;
+};
+
+int xt_argv_to_binary(const char *name, int argc, char *argv[],
+		      struct nft_xt_ext *ext);
+
+#endif
Index: nftables-0.4/src/evaluate.c
===================================================================
--- nftables-0.4.orig/src/evaluate.c
+++ nftables-0.4/src/evaluate.c
@@ -1633,6 +1633,7 @@ int stmt_evaluate(struct eval_ctx *ctx,
 	switch (stmt->ops->type) {
 	case STMT_COUNTER:
 	case STMT_LIMIT:
+	case STMT_XT:
 		return 0;
 	case STMT_EXPRESSION:
 		return stmt_evaluate_expr(ctx, stmt);
Index: nftables-0.4/src/expression.c
===================================================================
--- nftables-0.4.orig/src/expression.c
+++ nftables-0.4/src/expression.c
@@ -917,3 +917,27 @@ void range_expr_value_high(mpz_t rop, co
 		BUG("invalid range expression type %s\n", expr->ops->name);
 	}
 }
+
+static void option_expr_destroy(struct expr *expr)
+{
+	xfree(expr->id);
+	expr_free(expr->val);
+}
+
+static const struct expr_ops option_expr_ops = {
+	.type		= EXPR_OPTION,
+	.name		= "option",
+	.destroy	= option_expr_destroy,
+};
+
+struct expr *option_expr_alloc(const struct location *loc, const char *id,
+			       struct expr *value)
+{
+	struct expr *expr;
+
+	expr = expr_alloc(loc, &option_expr_ops, &invalid_type,
+			  BYTEORDER_INVALID, 0);
+	expr->id = id;
+	expr->val = value;
+	return expr;
+}
Index: nftables-0.4/src/netlink_delinearize.c
===================================================================
--- nftables-0.4.orig/src/netlink_delinearize.c
+++ nftables-0.4/src/netlink_delinearize.c
@@ -24,6 +24,7 @@
 #include <gmputil.h>
 #include <utils.h>
 #include <erec.h>
+#include <xtables.h>
 #include <sys/socket.h>
 
 struct netlink_parse_ctx {
@@ -666,6 +667,74 @@ static void netlink_parse_queue(struct n
 	list_add_tail(&stmt->list, &ctx->rule->stmts);
 }
 
+static void netlink_parse_match(struct netlink_parse_ctx *ctx,
+				const struct location *loc,
+				const struct nft_rule_expr *nle)
+{
+	struct stmt *stmt;
+	const char *name;
+	struct xtables_match *mt;
+	const void *tginfo;
+	struct xt_entry_target *entry;
+	uint32_t len;
+
+	xtables_set_nfproto(ctx->table->handle.family);
+
+	name = nft_rule_expr_get_str(nle, NFT_EXPR_MT_NAME);
+	mt = xtables_find_match(name, XTF_TRY_LOAD, NULL);
+	if (!mt)
+		BUG("XT match %s not found\n", name);
+
+	tginfo = nft_rule_expr_get(nle, NFT_EXPR_MT_INFO, &len);
+
+	entry = xzalloc(sizeof(struct xt_entry_match) + len);
+	if (!entry)
+		return;
+
+	memcpy(entry->data, tginfo, len);
+
+	stmt = xt_stmt_alloc(loc);
+	stmt->xt.name = strdup(name);
+	stmt->xt.match = mt;
+	stmt->xt.entry = entry;
+
+	list_add_tail(&stmt->list, &ctx->rule->stmts);
+}
+
+static void netlink_parse_target(struct netlink_parse_ctx *ctx,
+				 const struct location *loc,
+				 const struct nft_rule_expr *nle)
+{
+	struct stmt *stmt;
+	const char *name;
+	struct xtables_target *tg;
+	const void *tginfo;
+	struct xt_entry_target *entry;
+	uint32_t len;
+
+	xtables_set_nfproto(ctx->table->handle.family);
+
+	name = nft_rule_expr_get_str(nle, NFT_EXPR_TG_NAME);
+	tg = xtables_find_target(name, XTF_TRY_LOAD);
+	if (!tg)
+		BUG("XT target %s not found\n", name);
+
+	tginfo = nft_rule_expr_get(nle, NFT_EXPR_TG_INFO, &len);
+
+	entry = xzalloc(sizeof(struct xt_entry_match) + len);
+	if (!entry)
+		return;
+
+	memcpy(entry->data, tginfo, len);
+
+	stmt = xt_stmt_alloc(loc);
+	stmt->xt.name = strdup(name);
+	stmt->xt.target = tg;
+	stmt->xt.entry = entry;
+
+	list_add_tail(&stmt->list, &ctx->rule->stmts);
+}
+
 static const struct {
 	const char	*name;
 	void		(*parse)(struct netlink_parse_ctx *ctx,
@@ -689,6 +758,9 @@ static const struct {
 	{ .name = "masq",	.parse = netlink_parse_masq },
 	{ .name = "redir",	.parse = netlink_parse_redir },
 	{ .name = "queue",	.parse = netlink_parse_queue },
+	{ .name = "target",	.parse = netlink_parse_target },
+	{ .name = "match",	.parse = netlink_parse_match },
+
 };
 
 static int netlink_parse_expr(struct nft_rule_expr *nle, void *arg)
Index: nftables-0.4/src/netlink_linearize.c
===================================================================
--- nftables-0.4.orig/src/netlink_linearize.c
+++ nftables-0.4/src/netlink_linearize.c
@@ -18,6 +18,7 @@
 #include <netlink.h>
 #include <gmputil.h>
 #include <utils.h>
+#include <xt.h>
 
 struct netlink_linearize_ctx {
 	struct nft_rule		*nlr;
@@ -792,6 +793,115 @@ static void netlink_gen_ct_stmt(struct n
 	nft_rule_add_expr(ctx->nlr, nle);
 }
 
+#define MAX_ARG		128	/* Should be sufficient */
+
+static void netlink_gen_xt_stmt(struct netlink_linearize_ctx *ctx,
+				const struct stmt *stmt)
+{
+	struct nft_xt_ext ext;
+	struct nft_rule_expr *nle;
+	const struct expr *expr;
+	char *argv[MAX_ARG];
+	int family;
+	int i = 3, k, ret;
+
+	/* Makes getopt_long happy */
+	argv[0] = strdup("nft");
+	argv[1] = strdup("add");
+	argv[2] = strdup("rule");
+
+	list_for_each_entry(expr, &stmt->xt.list->expressions, list) {
+		if (i >= MAX_ARG)
+			return;
+
+		switch (expr->ops->type) {
+		case EXPR_OPTION:
+			argv[i++] = strdup(expr->id);
+
+			/* This is an option with no value */
+			if (expr->val == NULL)
+				continue;
+
+			switch(expr->val->ops->type) {
+			case EXPR_SYMBOL:
+				argv[i++] = strdup(expr->val->identifier);
+				break;
+			case EXPR_RANGE: {
+				int len = strlen(expr->val->left->identifier) +
+					  strlen(expr->val->right->identifier) + 3;
+				char buf[len];
+
+				snprintf(buf, len, "%s-%s",
+					 expr->val->left->identifier,
+					 expr->val->right->identifier);
+				buf[len-1] = '\0';
+				argv[i++] = strdup(buf);
+				break;
+			}
+			case EXPR_PREFIX:
+				switch (expr->val->prefix->ops->type) {
+				case EXPR_SYMBOL:
+					asprintf(&argv[i++], "%s/0x%x", expr->val->prefix->identifier, expr->val->prefix_len);
+					break;
+				default:
+					BUG("unknown statement type %s\n",
+					    expr->val->prefix->ops->name);
+				}
+				break;
+
+			default:
+				BUG("unknown statement type %s\n",
+				    expr->val->ops->name);
+			}
+			break;
+		default:
+			BUG("unknown statement type %s\n", expr->ops->name);
+		}
+	}
+
+	family = nft_rule_attr_get_u32(ctx->nlr, NFT_RULE_ATTR_FAMILY);
+	xtables_set_nfproto(family);
+
+	ret = xt_argv_to_binary(stmt->xt.name, i, argv, &ext);
+
+	for (k=0; k<i; k++)
+		xfree(argv[k]);
+
+	if (ret < 0)
+		return;
+
+	switch(ext.type) {
+	case NFT_XT_MATCH:
+		nle = nft_rule_expr_alloc("match");
+		if (nle == NULL)
+			return;
+
+		nft_rule_expr_set_str(nle, NFT_EXPR_MT_NAME, ext.mt->name);
+		nft_rule_expr_set_u32(nle, NFT_EXPR_MT_REV, ext.mt->revision);
+		nft_rule_expr_set(nle, NFT_EXPR_MT_INFO, ext.info,
+				  ext.mt->userspacesize);
+		nft_rule_add_expr(ctx->nlr, nle);
+
+		xfree(ext.mt->m);
+		break;
+	case NFT_XT_TARGET:
+		nle = nft_rule_expr_alloc("target");
+		if (nle == NULL)
+			return;
+
+		nft_rule_expr_set_str(nle, NFT_EXPR_TG_NAME, ext.tg->name);
+		nft_rule_expr_set_u32(nle, NFT_EXPR_TG_REV, ext.tg->revision);
+		nft_rule_expr_set(nle, NFT_EXPR_TG_INFO, ext.info,
+				  ext.tg->userspacesize);
+		nft_rule_add_expr(ctx->nlr, nle);
+
+		xfree(ext.tg->t);
+		break;
+	default:
+		return;
+	}
+}
+
 static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
 			     const struct stmt *stmt)
 {
@@ -820,6 +930,8 @@ static void netlink_gen_stmt(struct netl
 		return netlink_gen_queue_stmt(ctx, stmt);
 	case STMT_CT:
 		return netlink_gen_ct_stmt(ctx, stmt);
+	case STMT_XT:
+		return netlink_gen_xt_stmt(ctx, stmt);
 	default:
 		BUG("unknown statement type %s\n", stmt->ops->name);
 	}
Index: nftables-0.4/src/scanner.l
===================================================================
--- nftables-0.4.orig/src/scanner.l
+++ nftables-0.4/src/scanner.l
@@ -113,6 +113,7 @@ hexstring	0[xX]{hexdigit}+
 range		({decstring}?:{decstring}?)
 letter		[a-zA-Z]
 string		({letter})({letter}|{digit}|[/\-_\.])*
+option		\-\-({letter}|{digit}|\-)*
 quotedstring	\"[^"]*\"
 comment		#.*$
 slash		\/
@@ -325,6 +326,8 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr
 "fully-random"		{ return FULLY_RANDOM; }
 "persistent"		{ return PERSISTENT; }
 
+"xt"			{ return XT; }
+
 "ll"			{ return LL_HDR; }
 "nh"			{ return NETWORK_HDR; }
 "th"			{ return TRANSPORT_HDR; }
@@ -488,6 +491,11 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr
 				return STRING;
 			}
 
+{option}		{
+				yylval->string = xstrdup(yytext);
+				return OPTION;
+			}
+
 \\{newline}		{
 				reset_pos(yyget_extra(yyscanner), yylloc);
 			}
Index: nftables-0.4/src/statement.c
===================================================================
--- nftables-0.4.orig/src/statement.c
+++ nftables-0.4/src/statement.c
@@ -377,3 +377,70 @@ struct stmt *redir_stmt_alloc(const stru
 {
 	return stmt_alloc(loc, &redir_stmt_ops);
 }
+
+static void xt_stmt_print(const struct stmt *stmt)
+{
+	struct expr *expr;
+
+	/* The XT statement is special since we obtain a binary layout from
+	 * the kernel that we cannot interpret. So we have two different
+	 * representations, one for the delinearize path (in binary layout)
+	 * and one for the linearize path (as a list of option expressions).
+	 */
+	printf("xt %s [", stmt->xt.name);
+
+	if (stmt->xt.match && stmt->xt.match->save)
+		stmt->xt.match->save(NULL, stmt->xt.entry);
+	else if (stmt->xt.target && stmt->xt.target->save)
+		stmt->xt.target->save(NULL, stmt->xt.entry);
+
+	if (stmt->xt.list == NULL)
+		goto out;
+
+        list_for_each_entry(expr, &stmt->xt.list->expressions, list) {
+		switch (expr->ops->type) {
+                case EXPR_OPTION:
+			printf("%s ", strdup(expr->id));
+
+			/* This is an option with no value */
+			if (expr->val == NULL)
+				continue;
+
+                        switch(expr->val->ops->type) {
+                        case EXPR_SYMBOL:
+				printf("%s ", expr->val->identifier);
+				break;
+			case EXPR_RANGE:
+				printf("%s-%s", expr->val->left->identifier,
+				       expr->val->right->identifier);
+				break;
+			default:
+				BUG("unknown statement type %s\n",
+				    expr->val->ops->name);
+			break;
+			}
+		default:
+			BUG("unknown statement type %s\n", expr->ops->name);
+		}
+	}
+out:
+	printf(" ]");
+}
+
+static void xt_stmt_destroy(struct stmt *stmt)
+{
+	if (stmt->xt.list)
+		expr_free(stmt->xt.list);
+}
+
+static const struct stmt_ops xt_stmt_ops = {
+	.type		= STMT_XT,
+	.name		= "xt",
+	.print		= xt_stmt_print,
+	.destroy	= xt_stmt_destroy,
+};
+
+struct stmt *xt_stmt_alloc(const struct location *loc)
+{
+	return stmt_alloc(loc, &xt_stmt_ops);
+}
Index: nftables-0.4/src/xt.c
===================================================================
--- /dev/null
+++ nftables-0.4/src/xt.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2013 Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Development of this code funded by Astaro AG (http://www.astaro.com/)
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <xtables.h>
+#include <utils.h>
+#include <getopt.h>
+#include <statement.h>
+#include <ctype.h> /* isupper */
+#include <xt.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nf_tables_compat.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+static struct option original_opts[] = {
+	{ NULL },
+};
+
+static int xt_target_to_binary(const char *name, int argc, char *argv[],
+			       struct nft_xt_ext *ext)
+{
+	struct option *opt;
+	unsigned int offset;
+	uint8_t *entry;
+	int c;
+	struct xtables_target *tg;
+
+	tg = xtables_find_target(name, XTF_TRY_LOAD);
+	if (!tg) {
+		printf("target not found\n");
+		return -1;
+	}
+
+	/* No leak, this is attached to the nft_rule_expr object */
+	entry = xzalloc(sizeof(struct xt_entry_target) + tg->size);
+	if (entry == NULL)
+		memory_allocation_error();
+
+	tg->t = (void *)entry;
+
+	/* TODO: support non x6_options */
+	opt = xtables_options_xfrm(original_opts, NULL, tg->x6_options,
+				   &offset);
+
+	/* Reset internal state of getopt_long */
+	optind = 0;
+	while ((c = getopt_long(argc, argv, "j:", opt, NULL)) != -1) {
+		c -= offset;
+
+		/* TODO: invert */
+		xtables_option_tpcall(tg->option_offset + c, argv,
+				      false, tg, entry);
+	}
+
+	/* Reset parsing flags */
+	tg->tflags = 0;
+	xfree(opt);
+
+	ext->type = NFT_XT_TARGET;
+	ext->tg = tg;
+	ext->info = xmalloc(tg->userspacesize);
+	memcpy(ext->info, entry + sizeof(struct xt_entry_target), tg->userspacesize);
+
+	return 0;
+}
+
+static int xt_match_to_binary(const char *name, int argc, char *argv[],
+			      struct nft_xt_ext *ext)
+{
+	struct option *opt;
+	unsigned int offset;
+	uint8_t *entry;
+	int c;
+	struct xtables_match *mt;
+
+	mt = xtables_find_match(name, XTF_TRY_LOAD, NULL);
+	if (!mt) {
+		printf("match not found\n");
+		return -1;
+	}
+
+	/* No leak, this is attached to the nft_rule_expr object */
+	entry = xzalloc(sizeof(struct xt_entry_match) + mt->size);
+	if (entry == NULL)
+		memory_allocation_error();
+
+	mt->m = (void *)entry;
+
+	/* TODO: support non x6_options */
+	opt = xtables_options_xfrm(original_opts, NULL, mt->x6_options,
+				   &offset);
+
+	/* Reset internal state of getopt_long */
+	optind = 0;
+	while ((c = getopt_long(argc, argv, "m:", opt, NULL)) != -1) {
+		c -= offset;
+
+		/* TODO: invert */
+		xtables_option_mpcall(mt->option_offset + c, argv,
+				      false, mt, entry);
+	}
+
+	/* Reset parsing flags */
+	mt->mflags = 0;
+	xfree(opt);
+
+	ext->type = NFT_XT_MATCH;
+	ext->mt = mt;
+	ext->info = xmalloc(mt->userspacesize);
+	memcpy(ext->info, entry + sizeof(struct xt_entry_match), mt->userspacesize);
+
+
+	return 0;
+}
+
+int xt_argv_to_binary(const char *name, int argc, char *argv[],
+		      struct nft_xt_ext *ext)
+{
+	int ret;
+
+	/* Assume upper case is a target, fine for {ip,ip6}tables. */
+	if (isupper(name[0]))
+		ret = xt_target_to_binary(name, argc, argv, ext);
+	else
+		ret = xt_match_to_binary(name, argc, argv, ext);
+
+	return ret;
+}
+
+static int nft_xt_compatible_revision(const char *name, uint8_t rev, int opt)
+{
+	struct mnl_socket *nl;
+	char buf[MNL_SOCKET_BUFFER_SIZE];
+	struct nlmsghdr *nlh;
+	uint32_t portid, seq, type;
+	struct nfgenmsg *nfg;
+	int ret = 0;
+
+	if (opt == IPT_SO_GET_REVISION_MATCH)
+		type = 0;
+	else
+		type = 1;
+
+	nlh = mnl_nlmsg_put_header(buf);
+	nlh->nlmsg_type = (NFNL_SUBSYS_NFT_COMPAT << 8) | NFNL_MSG_COMPAT_GET;
+	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+	nlh->nlmsg_seq = seq = time(NULL);
+
+	nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+	nfg->nfgen_family = AF_INET;
+	nfg->version = NFNETLINK_V0;
+	nfg->res_id = 0;
+
+	mnl_attr_put_strz(nlh, NFTA_COMPAT_NAME, name);
+	mnl_attr_put_u32(nlh, NFTA_COMPAT_REV, htonl(rev));
+	mnl_attr_put_u32(nlh, NFTA_COMPAT_TYPE, htonl(type));
+
+	pr_debug("requesting `%s' rev=%d type=%d via nft_compat\n",
+		 name, rev, type);
+
+	nl = mnl_socket_open(NETLINK_NETFILTER);
+	if (nl == NULL)
+		return 0;
+
+	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
+		goto err;
+
+	portid = mnl_socket_get_portid(nl);
+
+	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
+		goto err;
+
+	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+	if (ret == -1)
+		goto err;
+
+	ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
+	if (ret == -1)
+		goto err;
+
+err:
+	mnl_socket_close(nl);
+
+	return ret < 0 ? 0 : 1;
+}
+
+static struct xtables_globals xt_nft_globals = {
+	.program_name		= "nft",
+	.program_version	= PACKAGE_VERSION,
+	.orig_opts		= original_opts,
+	.compat_rev		= nft_xt_compatible_revision,
+};
+
+static void __init xt_init(void)
+{
+	/* Default to IPv4, but this changes in runtime */
+	xtables_init_all(&xt_nft_globals, NFPROTO_IPV4);
+}
Index: nftables-0.4/src/Makefile.am
===================================================================
--- nftables-0.4.orig/src/Makefile.am
+++ nftables-0.4/src/Makefile.am
@@ -44,6 +44,7 @@ nft_SOURCES =	main.c				\
 		utils.c				\
 		erec.c				\
 		mnl.c				\
+		xt.c				\
 		scanner.l			\
 		parser_bison.y
 
Index: nftables-0.4/src/parser_bison.y
===================================================================
--- nftables-0.4.orig/src/parser_bison.y
+++ nftables-0.4/src/parser_bison.y
@@ -208,10 +208,11 @@ static void location_update(struct locat
 %token SIZE			"size"
 
 %token <val> NUM		"number"
+%token <string> OPTION		"option"
 %token <string> STRING		"string"
 %token <string> QUOTED_STRING
 %token <string> ERROR		"error"
-%destructor { xfree($$); }	STRING QUOTED_STRING ERROR
+%destructor { xfree($$); }	OPTION STRING QUOTED_STRING ERROR
 
 %token LL_HDR			"ll"
 %token NETWORK_HDR		"nh"
@@ -381,6 +382,7 @@ static void location_update(struct locat
 %token RANDOM			"random"
 %token FULLY_RANDOM		"fully-random"
 %token PERSISTENT		"persistent"
+%token XT			"xt"
 
 %token QUEUE			"queue"
 %token QUEUENUM			"num"
@@ -450,6 +452,15 @@ static void location_update(struct locat
 %destructor { stmt_free($$); }	queue_stmt queue_stmt_alloc
 %type <val>			queue_stmt_flags queue_stmt_flag
 
+%type <stmt>			xt_stmt
+%destructor { stmt_free($$); }	xt_stmt
+
+%type <expr>			xt_list_expr xt_list_member_expr
+%destructor { expr_free($$); }	xt_list_expr xt_list_member_expr
+
+%type <expr>			xt_stmt_args
+%destructor { expr_free($$); }	xt_stmt_args
+
 %type <expr>			symbol_expr verdict_expr integer_expr
 %destructor { expr_free($$); }	symbol_expr verdict_expr integer_expr
 %type <expr>			primary_expr shift_expr and_expr
@@ -1192,6 +1203,7 @@ stmt			:	verdict_stmt
 			|	ct_stmt
 			|	masq_stmt
 			|	redir_stmt
+			|	xt_stmt
 			;
 
 verdict_stmt		:	verdict_expr
@@ -1505,6 +1517,50 @@ queue_stmt_flag		:	BYPASS	{ $$ = NFT_QUE
 			|	FANOUT	{ $$ = NFT_QUEUE_FLAG_CPU_FANOUT; }
 			;
 
+xt_stmt			:	XT string xt_stmt_args
+			{
+				$$ = xt_stmt_alloc(&@$);
+				$$->xt.name = $2;
+				$$->xt.list = $3;
+			}
+
+xt_stmt_args		:	'['	xt_list_expr	']'
+			{
+				$2->location = @$;
+				$$ = $2;
+			}
+			;
+
+xt_list_expr		:	xt_list_member_expr
+			{
+				$$ = list_expr_alloc(&@$);
+				compound_expr_add($$, $1);
+			}
+			|	xt_list_expr OPTION expr
+			{
+				$$ = option_expr_alloc(&@$, $2, $3);
+				compound_expr_add($1, $$);
+				$$ = $1;
+			}
+			|	xt_list_expr OPTION
+			{
+				$$ = option_expr_alloc(&@$, $2, NULL);
+				compound_expr_add($1, $$);
+				$$ = $1;
+			}
+			;
+
+xt_list_member_expr	:	OPTION expr
+			{
+				$$ = option_expr_alloc(&@$, $1, $2);
+			}
+			|	OPTION
+			{
+				$$ = option_expr_alloc(&@$, $1, NULL);
+			}
+			;
+
+
 match_stmt		:	relational_expr
 			{
 				$$ = expr_stmt_alloc(&@$, $1);

[Index of Archives]     [Linux Netfilter Development]     [Linux Kernel Networking Development]     [Netem]     [Berkeley Packet Filter]     [Linux Kernel Development]     [Advanced Routing & Traffice Control]     [Bugtraq]

  Powered by Linux