All of lore.kernel.org
 help / color / mirror / Atom feed
* [nft PATCH 1/3] src: expose delinearize/linearize structures and stmt_error()
@ 2015-03-25 19:15 Arturo Borrero Gonzalez
  2015-03-25 19:16 ` [nft PATCH 2/3] src: add xt compat support Arturo Borrero Gonzalez
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Arturo Borrero Gonzalez @ 2015-03-25 19:15 UTC (permalink / raw)
  To: netfilter-devel; +Cc: kaber, pablo

From: Pablo Neira Ayuso <pablo@netfilter.org>

Needed by the follow up xt compatibility layer patch.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
---
 include/netlink.h         |   41 ++++++++++++++++++++++++++++++++++++++++-
 include/statement.h       |   10 ++++++++++
 src/evaluate.c            |   12 ++++--------
 src/netlink_delinearize.c |   13 -------------
 src/netlink_linearize.c   |    5 -----
 5 files changed, 54 insertions(+), 27 deletions(-)

diff --git a/include/netlink.h b/include/netlink.h
index c1ff9c6..57f7a7b 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -12,10 +12,49 @@
 
 #include <rule.h>
 
+/** struct netlink_linearize_ctx
+ *
+ * @nlr:	nftnl rule object
+ * @reg_low:	next spare register
+ */
+struct netlink_linearize_ctx {
+	struct nft_rule		*nlr;
+	unsigned int		reg_low;
+};
+
+/**
+ * struct netlink_parse_ctx
+ *
+ * @msgs:	message queue
+ * @table:	current table
+ * @rule:	pointer to current rule that is being delinearized
+ * @expr:	registers
+ */
+struct netlink_parse_ctx {
+	struct list_head	*msgs;
+	struct table		*table;
+	struct rule		*rule;
+	struct expr		*registers[NFT_REG_MAX + 1];
+};
+
+/**
+ * struct rule_pp_ctx
+ *
+ * @pctx:	protocol context
+ * @pbase:	protocol base
+ * @pdep:	dependency statement
+ */
+struct rule_pp_ctx {
+	struct proto_ctx	pctx;
+	enum proto_bases	pbase;
+	struct stmt		*pdep;
+};
+
+
 extern const struct input_descriptor indesc_netlink;
 extern const struct location netlink_location;
 
-/** 
+/**
  * struct netlink_ctx
  *
  * @msgs:	message queue
diff --git a/include/statement.h b/include/statement.h
index d143121..23d2d84 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -194,4 +194,14 @@ 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 __fmtstring(4, 5) __stmt_binary_error(struct eval_ctx *ctx,
+					  const struct location *l1,
+					  const struct location *l2,
+					  const char *fmt, ...);
+
+#define stmt_error(ctx, s1, fmt, args...) \
+	__stmt_binary_error(ctx, &(s1)->location, NULL, fmt, ## args)
+#define stmt_binary_error(ctx, s1, s2, fmt, args...) \
+	__stmt_binary_error(ctx, &(s1)->location, &(s2)->location, fmt, ## args)
+
 #endif /* NFTABLES_STATEMENT_H */
diff --git a/src/evaluate.c b/src/evaluate.c
index 7ecb793..c420cd4 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -36,10 +36,10 @@ static const char *byteorder_names[] = {
 	[BYTEORDER_BIG_ENDIAN]		= "big endian",
 };
 
-static int __fmtstring(4, 5) __stmt_binary_error(struct eval_ctx *ctx,
-						 const struct location *l1,
-						 const struct location *l2,
-						 const char *fmt, ...)
+int __fmtstring(4, 5) __stmt_binary_error(struct eval_ctx *ctx,
+					  const struct location *l1,
+					  const struct location *l2,
+					  const char *fmt, ...)
 {
 	struct error_record *erec;
 	va_list ap;
@@ -54,10 +54,6 @@ static int __fmtstring(4, 5) __stmt_binary_error(struct eval_ctx *ctx,
 
 }
 
-#define stmt_error(ctx, s1, fmt, args...) \
-	__stmt_binary_error(ctx, &(s1)->location, NULL, fmt, ## args)
-#define stmt_binary_error(ctx, s1, s2, fmt, args...) \
-	__stmt_binary_error(ctx, &(s1)->location, &(s2)->location, fmt, ## args)
 #define chain_error(ctx, s1, fmt, args...) \
 	__stmt_binary_error(ctx, &(s1)->location, NULL, fmt, ## args)
 #define monitor_error(ctx, s1, fmt, args...) \
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 387bb67..3bae7d6 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -26,13 +26,6 @@
 #include <erec.h>
 #include <sys/socket.h>
 
-struct netlink_parse_ctx {
-	struct list_head	*msgs;
-	struct table		*table;
-	struct rule		*rule;
-	struct expr		*registers[NFT_REG_MAX + 1];
-};
-
 static void __fmtstring(3, 4) netlink_error(struct netlink_parse_ctx *ctx,
 					    const struct location *loc,
 					    const char *fmt, ...)
@@ -741,12 +734,6 @@ static int netlink_parse_expr(struct nft_rule_expr *nle, void *arg)
 	return 0;
 }
 
-struct rule_pp_ctx {
-	struct proto_ctx	pctx;
-	enum proto_bases	pbase;
-	struct stmt		*pdep;
-};
-
 /*
  * Kill a redundant payload dependecy that is implied by a higher layer payload expression.
  */
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 9bef67b..6a637a4 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -19,11 +19,6 @@
 #include <gmputil.h>
 #include <utils.h>
 
-struct netlink_linearize_ctx {
-	struct nft_rule		*nlr;
-	unsigned int		reg_low;
-};
-
 static void netlink_put_register(struct nft_rule_expr *nle,
 				 uint32_t attr, uint32_t reg)
 {


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [nft PATCH 2/3] src: add xt compat support
  2015-03-25 19:15 [nft PATCH 1/3] src: expose delinearize/linearize structures and stmt_error() Arturo Borrero Gonzalez
@ 2015-03-25 19:16 ` Arturo Borrero Gonzalez
  2015-03-25 19:44   ` Pablo Neira Ayuso
  2015-03-25 19:16 ` [nft PATCH 3/3] tests: regression: add xt compat tests Arturo Borrero Gonzalez
  2015-03-25 19:23 ` [nft PATCH 1/3] src: expose delinearize/linearize structures and stmt_error() Patrick McHardy
  2 siblings, 1 reply; 12+ messages in thread
From: Arturo Borrero Gonzalez @ 2015-03-25 19:16 UTC (permalink / raw)
  To: netfilter-devel; +Cc: kaber, pablo

From: Pablo Neira Ayuso <pablo@netfilter.org>

At compilation time, you have to pass this option.

  # ./configure --with-xtables

And libxtables needs to be installed in your system.

This patch allows you to use xt extensions from nft, eg.

  # nft add rule filter output \
	tcp flags syn xt target TCPMSS [ --clamp-mss-to-pmtu ]

This provides access to all existing xt modules from nft. Users can
meanwhile use xt extension until we can provide native expressions.

You can build this optionally, if disabled it displays an error:

  # nft add rule filter output tcp flags syn xt target TCPMSS [ --clamp-mss-to-pmtu ]
  <cmdline>:1:38-77: Error: this build does not support xtables
  add rule filter output tcp flags syn xt target TCPMSS [ --clamp-mss-to-pmtu ]
                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

so you know your build doesn't support this.

Limitations:

* Beware of clashes with keywords, eg. state, from bison parser.
* Better xt parsing errors for unknown options.

This is joint work with Arturo Borrero Gonzalez.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
---
 configure.ac              |   13 +
 include/statement.h       |   36 ++
 include/xt.h              |  100 ++++++
 src/Makefile.am           |    8 +
 src/evaluate.c            |    3 
 src/main.c                |   12 +
 src/netlink_delinearize.c |    6 
 src/netlink_linearize.c   |    3 
 src/parser_bison.y        |   59 ++++
 src/rule.c                |    1 
 src/scanner.l             |   12 +
 src/statement.c           |   42 +++
 src/xt.c                  |  701 +++++++++++++++++++++++++++++++++++++++++++++
 13 files changed, 993 insertions(+), 3 deletions(-)
 create mode 100644 include/xt.h
 create mode 100644 src/xt.c

diff --git a/configure.ac b/configure.ac
index d8f949a..f51acb9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -92,6 +92,16 @@ AC_DEFINE([HAVE_LIBREADLINE], [1], [])
 AC_SUBST(with_cli)
 AM_CONDITIONAL([BUILD_CLI], [test "x$with_cli" != xno])
 
+AC_ARG_WITH([xtables], [AS_HELP_STRING([--with-xtables],
+            [Use libxtables for iptables interaction)])],
+	    [with_libxtables=yes], [with_libxtables=no])
+AS_IF([test "x$with_libxtables" != xno], [
+PKG_CHECK_MODULES([XTABLES], [xtables >= 1.4.21])
+AC_DEFINE([HAVE_LIBXTABLES], [1], [0])
+])
+AC_SUBST(with_libxtables)
+AM_CONDITIONAL([BUILD_XTABLES], [test "x$with_libxtables" == xyes])
+
 # Checks for header files.
 AC_HEADER_STDC
 AC_HEADER_ASSERT
@@ -136,4 +146,5 @@ echo "
 nft configuration:
   cli support:			${with_cli}
   enable debugging:		${with_debug}
-  use mini-gmp:			${with_mini_gmp}"
+  use mini-gmp:			${with_mini_gmp}
+  libxtables support:		${with_libxtables}"
diff --git a/include/statement.h b/include/statement.h
index 23d2d84..3a9f95a 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -105,6 +105,39 @@ extern struct stmt *ct_stmt_alloc(const struct location *loc,
 				  struct expr *expr);
 
 /**
+ * enum nft_xt_type - xtables statement types
+ *
+ * @NFT_XT_MATCH:	match
+ * @NFT_XT_TARGET:	target
+ * @NFT_XT_WATCHER:	watcher (only for the bridge family)
+ */
+enum nft_xt_type {
+	NFT_XT_MATCH = 0,
+	NFT_XT_TARGET,
+	NFT_XT_WATCHER,
+	NFT_XT_MAX
+};
+
+struct xtables_match;
+struct xtables_target;
+
+#include <xt.h>
+
+struct xt_stmt {
+	const char			*name;
+	enum nft_xt_type		type;
+	uint32_t			proto;
+	union {
+		struct xtables_match	*match;
+		struct xtables_target	*target;
+	};
+	const char			*opts;
+	union nft_entry			entry;
+};
+
+extern struct stmt *xt_stmt_alloc(const struct location *loc);
+
+/**
  * enum stmt_types - statement types
  *
  * @STMT_INVALID:	uninitialised
@@ -120,6 +153,7 @@ extern struct stmt *ct_stmt_alloc(const struct location *loc,
  * @STMT_REDIR:		redirect statement
  * @STMT_QUEUE:		QUEUE statement
  * @STMT_CT:		conntrack statement
+ * @STMT_XT:		XT statement
  */
 enum stmt_types {
 	STMT_INVALID,
@@ -135,6 +169,7 @@ enum stmt_types {
 	STMT_REDIR,
 	STMT_QUEUE,
 	STMT_CT,
+	STMT_XT,
 };
 
 /**
@@ -184,6 +219,7 @@ struct stmt {
 		struct redir_stmt	redir;
 		struct queue_stmt	queue;
 		struct ct_stmt		ct;
+		struct xt_stmt		xt;
 	};
 };
 
diff --git a/include/xt.h b/include/xt.h
new file mode 100644
index 0000000..414f3d1
--- /dev/null
+++ b/include/xt.h
@@ -0,0 +1,100 @@
+#ifndef _NFT_XT_H_
+#define _NFT_XT_H_
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <limits.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+
+struct netlink_linearize_ctx;
+struct netlink_parse_ctx;
+struct nft_rule_expr;
+struct rule_pp_ctx;
+struct rule;
+
+#ifdef HAVE_LIBXTABLES
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_arp/arp_tables.h>
+
+/* Fake ebt_entry */
+struct ebt_entry {
+	/* this needs to be the first field */
+	unsigned int bitmask;
+	unsigned int invflags;
+	uint16_t ethproto;
+	/* the physical in-dev */
+	char in[IFNAMSIZ];
+	/* the logical in-dev */
+	char logical_in[IFNAMSIZ];
+	/* the physical out-dev */
+	char out[IFNAMSIZ];
+	/* the logical out-dev */
+	char logical_out[IFNAMSIZ];
+	unsigned char sourcemac[ETH_ALEN];
+	unsigned char sourcemsk[ETH_ALEN];
+	unsigned char destmac[ETH_ALEN];
+	unsigned char destmsk[ETH_ALEN];
+
+	unsigned char in_mask[IFNAMSIZ];
+	unsigned char out_mask[IFNAMSIZ];
+};
+
+union nft_entry {
+	struct ipt_entry	e4;
+	struct ip6t_entry	e6;
+	struct ebt_entry	ebt;
+	struct arpt_entry	arp;
+};
+void xt_stmt_destroy_internals(const struct stmt *stmt);
+const char *xt_stmt_name(const struct stmt *stmt);
+void xt_stmt_save(const struct stmt *stmt);
+
+int stmt_evaluate_xt(struct eval_ctx *ctx, struct stmt *stmt);
+
+void netlink_gen_xt_stmt(struct netlink_linearize_ctx *ctx,
+			 const struct stmt *stmt);
+
+void netlink_parse_target(struct netlink_parse_ctx *ctx,
+			  const struct location *loc,
+			  const struct nft_rule_expr *nle);
+void netlink_parse_match(struct netlink_parse_ctx *ctx,
+			 const struct location *loc,
+			 const struct nft_rule_expr *nle);
+void stmt_xt_postprocess(struct rule_pp_ctx *rctx, struct stmt *stmt,
+			 struct rule *rule);
+#else /* HAVE_LIBXTABLES */
+union nft_entry {
+	uint32_t	*nothing;
+};
+
+static inline void xt_stmt_destroy_internals(const struct stmt *stmt) {}
+
+static inline const char *xt_stmt_name(const struct stmt *stmt)
+{
+	return "unknown";
+}
+static inline void xt_stmt_save(const struct stmt *stmt) {}
+
+static inline int stmt_evaluate_xt(struct eval_ctx *ctx, struct stmt *stmt)
+{
+	return stmt_error(ctx, stmt, "this build does not support xtables");
+}
+
+static inline void netlink_gen_xt_stmt(struct netlink_linearize_ctx *ctx,
+				       const struct stmt *stmt) {}
+
+static inline void netlink_parse_target(struct netlink_parse_ctx *ctx,
+                                 const struct location *loc,
+                                 const struct nft_rule_expr *nle) {}
+static inline void netlink_parse_match(struct netlink_parse_ctx *ctx,
+                                 const struct location *loc,
+                                 const struct nft_rule_expr *nle) {}
+static inline void stmt_xt_postprocess(struct rule_pp_ctx rctx,
+				       struct stmt *stmt, struct rule *rule) {}
+
+#endif /* HAVE_LIBXTABLES */
+
+#endif /* _NFT_XT_H_ */
diff --git a/src/Makefile.am b/src/Makefile.am
index 2410fd3..1b48d9d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -8,6 +8,9 @@ AM_CPPFLAGS += -DDEFAULT_INCLUDE_PATH="\"${sysconfdir}\"" \
 if BUILD_DEBUG
 AM_CPPFLAGS += -g -DDEBUG
 endif
+if BUILD_XTABLES
+AM_CPPFLAGS += ${XTABLES_CFLAGS}
+endif
 
 AM_CFLAGS = -Wall								\
 	    -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations	\
@@ -58,3 +61,8 @@ nft_SOURCES +=	mini-gmp.c
 endif
 
 nft_LDADD	= ${LIBMNL_LIBS} ${LIBNFTNL_LIBS}
+
+if BUILD_XTABLES
+nft_SOURCES +=	xt.c
+nft_LDADD   +=  ${XTABLES_LIBS}
+endif
diff --git a/src/evaluate.c b/src/evaluate.c
index c420cd4..7905149 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -27,6 +27,7 @@
 #include <erec.h>
 #include <gmputil.h>
 #include <utils.h>
+#include <xt.h>
 
 static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr);
 
@@ -1676,6 +1677,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_XT:
+		return stmt_evaluate_xt(ctx, stmt);
 	default:
 		BUG("unknown statement type %s\n", stmt->ops->name);
 	}
diff --git a/src/main.c b/src/main.c
index 4590c30..c560d49 100644
--- a/src/main.c
+++ b/src/main.c
@@ -254,10 +254,18 @@ int main(int argc, char * const *argv)
 	char *buf = NULL, *filename = NULL;
 	unsigned int len;
 	bool interactive = false;
-	int i, val, rc = NFT_EXIT_SUCCESS;
+	int i, val, rc = NFT_EXIT_SUCCESS, fake_argc = argc;
+
+	/* This avoids a clash with libxtables getopt_long parser */
+	for (i = 0; i < argc; i++) {
+		if (argv[i][0] == '[') {
+			fake_argc = i;
+			break;
+		}
+	}
 
 	while (1) {
-		val = getopt_long(argc, argv, OPTSTRING, options, NULL);
+		val = getopt_long(fake_argc, argv, OPTSTRING, options, NULL);
 		if (val == -1)
 			break;
 
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 3bae7d6..6a33293 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -25,6 +25,7 @@
 #include <utils.h>
 #include <erec.h>
 #include <sys/socket.h>
+#include <xt.h>
 
 static void __fmtstring(3, 4) netlink_error(struct netlink_parse_ctx *ctx,
 					    const struct location *loc,
@@ -710,6 +711,8 @@ 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)
@@ -1124,6 +1127,9 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r
 		case STMT_REJECT:
 			stmt_reject_postprocess(rctx, stmt);
 			break;
+		case STMT_XT:
+			stmt_xt_postprocess(&rctx, stmt, rule);
+			break;
 		default:
 			break;
 		}
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 6a637a4..0c84d54 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -18,6 +18,7 @@
 #include <netlink.h>
 #include <gmputil.h>
 #include <utils.h>
+#include <xt.h>
 
 static void netlink_put_register(struct nft_rule_expr *nle,
 				 uint32_t attr, uint32_t reg)
@@ -821,6 +822,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
 		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);
 	}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index ea3ff52..7a5657d 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -382,6 +382,14 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %token FULLY_RANDOM		"fully-random"
 %token PERSISTENT		"persistent"
 
+%token XT			"xt"
+%token MATCH			"match"
+%token TARGET			"target"
+%token WATCHER			"watcher"
+%token <string> XTOPTS		"xtoptions"
+%destructor { xfree($$); }	XTOPTS
+%token _802_3			"802_3"
+
 %token QUEUE			"queue"
 %token QUEUENUM			"num"
 %token BYPASS			"bypass"
@@ -449,6 +457,12 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %type <stmt>			nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc
 %destructor { stmt_free($$); }	nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc
 %type <val>			nf_nat_flags nf_nat_flag
+
+%type <stmt>			xt_stmt
+%destructor { stmt_free($$); }	xt_stmt
+%type <string>			xt_name xt_opts
+%destructor { xfree($$); }	xt_name xt_opts
+
 %type <stmt>			queue_stmt queue_stmt_alloc
 %destructor { stmt_free($$); }	queue_stmt queue_stmt_alloc
 %type <val>			queue_stmt_flags queue_stmt_flag
@@ -1241,6 +1255,7 @@ stmt			:	verdict_stmt
 			|	ct_stmt
 			|	masq_stmt
 			|	redir_stmt
+			|	xt_stmt
 			;
 
 verdict_stmt		:	verdict_expr
@@ -1504,6 +1519,50 @@ redir_stmt_arg		:	TO	expr
 			}
 			;
 
+xt_stmt			:       XT	MATCH	xt_name xt_opts
+			{
+				$$ = xt_stmt_alloc(&@$);
+				$$->xt.name = $3;
+				$$->xt.type = NFT_XT_MATCH;
+				$$->xt.opts = $4;
+			}
+			|	XT	TARGET	xt_name	xt_opts
+			{
+				$$ = xt_stmt_alloc(&@$);
+				$$->xt.name = $3;
+				$$->xt.type = NFT_XT_TARGET;
+				$$->xt.opts = $4;
+			}
+			|	XT	WATCHER	xt_name	xt_opts
+			{
+				$$ = xt_stmt_alloc(&@$);
+				$$->xt.name = $3;
+				$$->xt.type = NFT_XT_WATCHER;
+				$$->xt.opts = $4;
+			}
+			;
+
+xt_opts			:	/* empty */	{ $$ = NULL; }
+			|	XTOPTS		{ $$ = $1; }
+			;
+
+xt_name			:	STRING		{ $$ = $1; }
+			|	STATE		{ $$ = xstrdup("state"); }
+			|	COMMENT		{ $$ = xstrdup("comment"); }
+			|	AH		{ $$ = xstrdup("ah"); }
+			|	ESP		{ $$ = xstrdup("esp"); }
+			|	TCP		{ $$ = xstrdup("tcp"); }
+			|	UDP		{ $$ = xstrdup("udp"); }
+			|	UDPLITE		{ $$ = xstrdup("udplite"); }
+			|	SCTP		{ $$ = xstrdup("sctp"); }
+			|	ICMP		{ $$ = xstrdup("icmp"); }
+			|	IP		{ $$ = xstrdup("ip"); }
+			|	VLAN		{ $$ = xstrdup("vlan"); }
+			|	LOG		{ $$ = xstrdup("log"); }
+			|	_802_3		{ $$ = xstrdup("802_3"); }
+			|	MARK		{ $$ = xstrdup("mark"); }
+			;
+
 nf_nat_flags		:	nf_nat_flag
 			|	nf_nat_flags	COMMA	nf_nat_flag
 			{
diff --git a/src/rule.c b/src/rule.c
index 7114380..c7c5e20 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -820,6 +820,7 @@ static void table_cleanup(struct table *table)
 	}
 }
 
+#include <xt.h>
 static int do_list_table(struct netlink_ctx *ctx, struct cmd *cmd,
 			 struct table *table)
 {
diff --git a/src/scanner.l b/src/scanner.l
index 73c4f8b..33f0699 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -113,6 +113,7 @@ hexstring	0[xX]{hexdigit}+
 range		({decstring}?:{decstring}?)
 letter		[a-zA-Z]
 string		({letter})({letter}|{digit}|[/\-_\.])*
+xtopts		\[({letter}|{digit}|[!/\-_\.\"\:\, ])*\]
 quotedstring	\"[^"]*\"
 comment		#.*$
 slash		\/
@@ -449,6 +450,12 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "proto-dst"		{ return PROTO_DST; }
 "label"			{ return LABEL; }
 
+"xt"			{ return XT; }
+"match"			{ return MATCH; }
+"target"		{ return TARGET; }
+"watcher"		{ return WATCHER; }
+"802_3"			{ return _802_3; }
+
 "xml"			{ return XML; }
 "json"			{ return JSON; }
 
@@ -488,6 +495,11 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 				return STRING;
 			}
 
+{xtopts}		{
+				yylval->string = xstrdup(yytext);
+				return XTOPTS;
+			}
+
 \\{newline}		{
 				reset_pos(yyget_extra(yyscanner), yylloc);
 			}
diff --git a/src/statement.c b/src/statement.c
index d72c6e9..5092ea8 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -23,6 +23,7 @@
 #include <statement.h>
 #include <utils.h>
 #include <list.h>
+#include <xt.h>
 
 #include <netinet/in.h>
 #include <linux/netfilter/nf_nat.h>
@@ -377,3 +378,44 @@ struct stmt *redir_stmt_alloc(const struct location *loc)
 {
 	return stmt_alloc(loc, &redir_stmt_ops);
 }
+
+static const char *xt_type_name[NFT_XT_MAX] = {
+	[NFT_XT_MATCH]	= "match",
+	[NFT_XT_TARGET]	= "target",
+	[NFT_XT_WATCHER]= "watcher",
+};
+
+static const char *xt_stmt_to_type(enum nft_xt_type type)
+{
+	if (type > NFT_XT_MAX)
+		return "unknown";
+
+	return xt_type_name[type];
+}
+
+static void xt_stmt_print(const struct stmt *stmt)
+{
+	printf("xt %s %s ", xt_stmt_to_type(stmt->xt.type),
+			    xt_stmt_name(stmt));
+	xt_stmt_save(stmt);
+}
+
+static void xt_stmt_destroy(struct stmt *stmt)
+{
+	xfree(stmt->xt.name);
+	xfree(stmt->xt.opts);
+
+	xt_stmt_destroy_internals(stmt);
+}
+
+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);
+}
diff --git a/src/xt.c b/src/xt.c
new file mode 100644
index 0000000..dcb461b
--- /dev/null
+++ b/src/xt.c
@@ -0,0 +1,701 @@
+/*
+ * Copyright (c) 2013-2015 Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modifyi
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <xtables.h>
+#include <utils.h>
+#include <getopt.h>
+#include <ctype.h>	/* for isspace */
+#include <statement.h>
+#include <rule.h>
+#include <netlink.h>
+#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>
+
+#include <libnftnl/rule.h>
+#include <libnftnl/expr.h>
+
+void xt_stmt_destroy_internals(const struct stmt *stmt)
+{
+	switch (stmt->xt.type) {
+	case NFT_XT_MATCH:
+		if (!stmt->xt.match)
+			break;
+		if (stmt->xt.match->m)
+			xfree(stmt->xt.match->m);
+		/* this has been cloned */
+		xfree(stmt->xt.match);
+		break;
+	case NFT_XT_WATCHER:
+	case NFT_XT_TARGET:
+		if (!stmt->xt.target)
+			break;
+		if (stmt->xt.target->t)
+			xfree(stmt->xt.target->t);
+		/* this has been cloned */
+		xfree(stmt->xt.target);
+		break;
+	default:
+		break;
+	}
+}
+
+const char *xt_stmt_name(const struct stmt *stmt)
+{
+	switch (stmt->xt.type) {
+	case NFT_XT_MATCH:
+		if (stmt->xt.match == NULL)
+			break;
+		if (stmt->xt.match->alias)
+			return stmt->xt.match->alias(stmt->xt.match->m);
+		break;
+	case NFT_XT_TARGET:
+	case NFT_XT_WATCHER:
+		if (stmt->xt.target == NULL)
+			break;
+		if (stmt->xt.target->alias)
+			return stmt->xt.target->alias(stmt->xt.target->t);
+		break;
+	default:
+		return "unknown";
+	}
+
+	return stmt->xt.name;
+}
+
+void xt_stmt_save(const struct stmt *stmt)
+{
+#ifdef DEBUG
+	switch (stmt->xt.type) {
+	case NFT_XT_MATCH:
+		if (stmt->xt.match)
+			break;
+		if (stmt->xt.opts)
+			fprintf(stdout, "%s", stmt->xt.opts);
+		return;
+	case NFT_XT_WATCHER:
+	case NFT_XT_TARGET:
+		if (stmt->xt.target)
+			break;
+		if (stmt->xt.opts)
+			fprintf(stdout, "%s", stmt->xt.opts);
+		return;
+	default:
+		break;
+	}
+#endif /* DEBUG */
+
+	printf("[");
+
+	switch (stmt->xt.type) {
+	case NFT_XT_MATCH:
+		if (stmt->xt.match->save) {
+			stmt->xt.match->save(&stmt->xt.entry,
+					     stmt->xt.match->m);
+		} else if (stmt->xt.match->print) {
+			stmt->xt.match->print(&stmt->xt.entry,
+					      stmt->xt.match->m, 0);
+		}
+		break;
+	case NFT_XT_WATCHER:
+	case NFT_XT_TARGET:
+		if (stmt->xt.target->save)
+			stmt->xt.target->save(NULL, stmt->xt.target->t);
+		else if (stmt->xt.target->print)
+			stmt->xt.target->print(NULL, stmt->xt.target->t, 0);
+		break;
+	default:
+		break;
+	}
+
+	printf(" ]");
+}
+
+static void *xt_entry_x_alloc(struct xt_stmt *xt)
+{
+
+	uint32_t size = 0;
+
+	switch (xt->type) {
+	case NFT_XT_MATCH:
+		size = XT_ALIGN(sizeof(struct xt_entry_match)) +
+		       xt->match->size;
+		break;
+	case NFT_XT_WATCHER:
+	case NFT_XT_TARGET:
+		size = XT_ALIGN(sizeof(struct xt_entry_target)) +
+		       xt->target->size;
+		break;
+	default:
+		break;
+	}
+
+	return xzalloc(size);
+}
+
+static void nft_entry_setup(struct xt_stmt *xt, uint32_t af)
+{
+	switch (af) {
+	case NFPROTO_IPV4:
+		xt->entry.e4.ip.proto = xt->proto;
+		break;
+	case NFPROTO_IPV6:
+		xt->entry.e6.ipv6.proto = xt->proto;
+		break;
+	case NFPROTO_BRIDGE:
+		xt->entry.ebt.ethproto = xt->proto;
+		break;
+	case NFPROTO_ARP:
+		/* XXX hardcoded, these are the only values accepted by arpt */
+		xt->entry.arp.arp.arhln_mask = 0xff;
+		xt->entry.arp.arp.arhln = 6;
+		break;
+	default:
+		break;
+	}
+}
+
+static uint32_t xt_proto(const struct proto_ctx *pctx)
+{
+	const struct proto_desc *desc = NULL;
+
+	if (pctx->family == NFPROTO_BRIDGE) {
+		desc = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
+		if (desc == NULL)
+			goto noproto;
+		if (strcmp(desc->name, "ip") == 0)
+			return __constant_htons(ETH_P_IP);
+		if (strcmp(desc->name, "ip6") == 0)
+			return __constant_htons(ETH_P_IPV6);
+		goto noproto;
+	}
+
+	desc = pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc;
+	if (desc == NULL)
+		goto noproto;
+	if (strcmp(desc->name, "tcp") == 0)
+		return IPPROTO_TCP;
+	else if (strcmp(desc->name, "udp") == 0)
+		return IPPROTO_UDP;
+	else if (strcmp(desc->name, "udplite") == 0)
+		return IPPROTO_UDPLITE;
+	else if (strcmp(desc->name, "sctp") == 0)
+		return IPPROTO_SCTP;
+	else if (strcmp(desc->name, "dccp") == 0)
+		return IPPROTO_DCCP;
+	else if (strcmp(desc->name, "esp") == 0)
+		return IPPROTO_ESP;
+	else
+		BUG("xt with unknown protocol\n");
+
+noproto:
+	return 0;
+}
+
+static struct xtables_target *clone_target(struct xtables_target *t)
+{
+	struct xtables_target *clone;
+
+	clone = xzalloc(sizeof(struct xtables_target));
+	memcpy(clone, t, sizeof(struct xtables_target));
+	return clone;
+}
+
+static struct xtables_match *clone_match(struct xtables_match *m)
+{
+	struct xtables_match *clone;
+
+	clone = xzalloc(sizeof(struct xtables_match));
+	memcpy(clone, m, sizeof(struct xtables_match));
+	return clone;
+}
+
+/*
+ * Evaluation
+ */
+
+static struct option original_opts[] = {
+	{ NULL },
+};
+
+static int xt_target_to_binary(struct xt_stmt *xt, int argc, char *argv[],
+			       uint32_t af)
+{
+	struct option *opt;
+	unsigned int offset;
+	int c;
+
+	xt->target->t = xt_entry_x_alloc(xt);
+	nft_entry_setup(xt, af);
+
+	if (xt->target->x6_options != NULL)
+		opt = xtables_options_xfrm(original_opts, NULL,
+					   xt->target->x6_options,
+					   &offset);
+	else
+		opt = xtables_merge_options(original_opts, NULL,
+					    xt->target->extra_opts,
+					    &offset);
+
+	if (xt->target->init != NULL)
+		xt->target->init(xt->target->t);
+
+	/* Reset internal state of getopt_long. */
+	optind = 0;
+	/* Suppress error messages. */
+	opterr = 0;
+
+	while ((c = getopt_long(argc, argv, "-:", opt, NULL)) != -1) {
+
+		c -= offset;
+		xtables_option_tpcall(xt->target->option_offset + c,
+				      argv, 0, xt->target, &xt->entry);
+	}
+
+	/* Reset parsing flags */
+	xt->target->tflags = 0;
+	xfree(opt);
+
+	return 0;
+}
+
+static int xt_match_to_binary(struct xt_stmt *xt, int argc, char *argv[],
+			      uint32_t af)
+{
+	struct option *opt;
+	unsigned int offset;
+	bool invert = false;
+	int c;
+
+	xt->match->m = xt_entry_x_alloc(xt);
+	nft_entry_setup(xt, af);
+
+	if (xt->match->x6_options != NULL)
+		opt = xtables_options_xfrm(original_opts, NULL,
+					   xt->match->x6_options,
+					   &offset);
+	else
+		opt = xtables_merge_options(original_opts, NULL,
+					    xt->match->extra_opts,
+					    &offset);
+
+	if (xt->match->init != NULL)
+		xt->match->init(xt->match->m);
+
+	/* Reset internal state of getopt_long. */
+	optind = 0;
+	/* Suppress error messages. */
+	opterr = 0;
+
+	while ((c = getopt_long(argc, argv, "-:", opt, NULL)) != -1) {
+		switch (c) {
+		case 1:
+			invert = true;
+			continue;
+		default:
+			break;
+		}
+
+		if (optarg != NULL && optarg[0] == '!' && optarg[1] == '\0') {
+			invert = true;
+			optarg = argv[optind];
+		}
+
+		c -= offset;
+		xtables_option_mpcall(xt->match->option_offset + c,
+				      argv, invert, xt->match,
+				      &xt->entry);
+		if (invert)
+			invert = false;
+	}
+
+	/* Reset parsing flags */
+	xt->match->mflags = 0;
+	xfree(opt);
+
+	return 0;
+}
+
+/* An xt extension doesn't have more than arguments. */
+#define MAX_ARG			64
+
+static int string_to_argv(const char *str, char *argv[], uint32_t argc_max)
+{
+	uint32_t i, k = 1, len = 0;
+	bool atquote = false, dupquote = false;
+
+	if (str == NULL)
+		return 0;
+
+	/* skip first/last char, are '[' and ']' */
+	for (i = 1; i < strlen(str)-1; i++) {
+		if (k == argc_max)
+			goto err;
+
+		if (isspace(str[i]) && !atquote) {
+			if (len <= 0)
+				continue;
+
+			if (dupquote) {
+				argv[k] = strndup(&str[i - len + 1], len - 2);
+				dupquote = false;
+			} else {
+				argv[k] = strndup(&str[i - len], len);
+			}
+
+			k++;
+			len = 0;
+		} else {
+			len++;
+		}
+
+		if (str[i] == '"') {
+			if (!atquote)
+				dupquote = true;
+			atquote = !atquote;
+		}
+	}
+	return k;
+err:
+	for (i = 0; i < k; i++)
+		free(argv[i]);
+	return -1;
+}
+
+int stmt_evaluate_xt(struct eval_ctx *ctx, struct stmt *stmt)
+{
+	char *argv[MAX_ARG] = { "iptables" };
+	struct xtables_match *mt;
+	struct xtables_target *tg;
+	int argc, i, err;
+
+	argc = string_to_argv(stmt->xt.opts, argv, MAX_ARG);
+	if (argc < 0)
+		return stmt_error(ctx, stmt, "too many xt options");
+
+	xtables_set_nfproto(ctx->pctx.family);
+	stmt->xt.proto = xt_proto(&ctx->pctx);
+
+	if (stmt->xt.type == NFT_XT_WATCHER &&
+	    ctx->pctx.family != NFPROTO_BRIDGE)
+		return stmt_error(ctx, stmt,
+				  "watcher only available from bridge family");
+
+	switch (stmt->xt.type) {
+	case NFT_XT_MATCH:
+		mt = xtables_find_match(stmt->xt.name, XTF_TRY_LOAD, NULL);
+		if (!mt)
+			return stmt_error(ctx, stmt, "unknown match %s",
+					  stmt->xt.name);
+
+		stmt->xt.match = clone_match(mt);
+		err = xt_match_to_binary(&stmt->xt, argc, argv,
+					 ctx->pctx.family);
+		break;
+	case NFT_XT_TARGET:
+	case NFT_XT_WATCHER:
+		tg = xtables_find_target(stmt->xt.name, XTF_TRY_LOAD);
+		if (!tg)
+			return stmt_error(ctx, stmt, "unknown target %s",
+					  stmt->xt.name);
+
+		stmt->xt.target = clone_target(tg);
+		err = xt_target_to_binary(&stmt->xt, argc, argv,
+					 ctx->pctx.family);
+		break;
+	default:
+		BUG("Unknown xt type %d\n", stmt->xt.type);
+	}
+
+	if (stmt->xt.type == NFT_XT_TARGET)
+		stmt->flags |= STMT_F_TERMINAL;
+
+	for (i = 1; i < argc; i++)
+		xfree(argv[i]);
+
+	if (err < 0)
+		return stmt_error(ctx, stmt, "failed to parse");
+
+	return 0;
+}
+
+/*
+ * Delinearization
+ */
+
+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 char *mtinfo;
+	struct xt_entry_match *m;
+	uint32_t mt_len;
+
+	xtables_set_nfproto(ctx->table->handle.family);
+
+	name = nft_rule_expr_get_str(nle, NFT_EXPR_MT_NAME);
+
+	/* XXXX mem leak. When is this memory freed?
+	 * - can't call xtables_rule_matches_free()
+	 * - the same match could be in use by the next rule
+	 * - use a wrapper struct with a refcount? lot of code overhead
+	 */
+	mt = xtables_find_match(name, XTF_TRY_LOAD, NULL);
+	if (!mt)
+		BUG("XT match %s not found\n", name);
+
+	mtinfo = nft_rule_expr_get(nle, NFT_EXPR_MT_INFO, &mt_len);
+
+	m = xzalloc(sizeof(struct xt_entry_match) + mt_len);
+	memcpy(&m->data, mtinfo, mt_len);
+
+	m->u.match_size = mt_len + XT_ALIGN(sizeof(struct xt_entry_match));
+	m->u.user.revision = nft_rule_expr_get_u32(nle, NFT_EXPR_MT_REV);
+
+	stmt = xt_stmt_alloc(loc);
+	stmt->xt.name = strdup(name);
+	stmt->xt.type = NFT_XT_MATCH;
+	stmt->xt.match = clone_match(mt);
+	stmt->xt.match->m = m;
+
+	list_add_tail(&stmt->list, &ctx->rule->stmts);
+}
+
+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 *t;
+	size_t size;
+	uint32_t tg_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, &tg_len);
+
+	size = XT_ALIGN(sizeof(struct xt_entry_target)) + tg_len;
+	t = xzalloc(size);
+	memcpy(&t->data, tginfo, tg_len);
+	t->u.target_size = size;
+	t->u.user.revision = nft_rule_expr_get_u32(nle, NFT_EXPR_TG_REV);
+	strcpy(t->u.user.name, tg->name);
+
+	stmt = xt_stmt_alloc(loc);
+	stmt->xt.name = strdup(name);
+	stmt->xt.type = NFT_XT_TARGET;
+	stmt->xt.target = clone_target(tg);
+	stmt->xt.target->t = t;
+
+	list_add_tail(&stmt->list, &ctx->rule->stmts);
+}
+
+static bool is_watcher(uint32_t family, struct stmt *stmt)
+{
+	if (family != NFPROTO_BRIDGE)
+		return false;
+
+	if (stmt->xt.type != NFT_XT_TARGET)
+		return false;
+
+	/* this has to be hardcoded :-( */
+	if (strcmp(stmt->xt.name, "log") == 0)
+		return true;
+	if (strcmp(stmt->xt.name, "nflog") == 0)
+		return true;
+	if (strcmp(stmt->xt.name, "uflog") == 0)
+		return true;
+
+	return false;
+}
+
+void stmt_xt_postprocess(struct rule_pp_ctx *rctx, struct stmt *stmt,
+			 struct rule *rule)
+{
+	if (is_watcher(rctx->pctx.family, stmt))
+		stmt->xt.type = NFT_XT_WATCHER;
+
+	stmt->xt.proto = xt_proto(&rctx->pctx);
+	nft_entry_setup(&stmt->xt, rctx->pctx.family);
+}
+
+/*
+ * Linearization
+ */
+
+static const char *xt_stmt_real_name(const struct stmt *stmt)
+{
+	switch (stmt->xt.type) {
+	case NFT_XT_MATCH:
+		if (stmt->xt.match->real_name)
+			return stmt->xt.match->real_name;
+		break;
+	case NFT_XT_TARGET:
+	case NFT_XT_WATCHER:
+		if (stmt->xt.target->real_name)
+			return stmt->xt.target->real_name;
+		break;
+	default:
+		return "unknown";
+	}
+
+	return stmt->xt.name;
+}
+
+static void *xt_match_info(const void *entry)
+{
+	return (char *)entry + XT_ALIGN(sizeof(struct xt_entry_match));
+}
+
+static void *xt_target_info(const void *entry)
+{
+	return (char *)entry + XT_ALIGN(sizeof(struct xt_entry_target));
+}
+
+void netlink_gen_xt_stmt(struct netlink_linearize_ctx *ctx,
+			 const struct stmt *stmt)
+{
+	struct nft_rule_expr *nle;
+	void *info;
+
+	switch (stmt->xt.type) {
+	case NFT_XT_MATCH:
+		info = xzalloc(stmt->xt.match->size);
+		if (info == NULL)
+			memory_allocation_error();
+
+		memcpy(info, xt_match_info(stmt->xt.match->m),
+		       stmt->xt.match->size);
+
+		nle = nft_rule_expr_alloc("match");
+		if (nle == NULL)
+			memory_allocation_error();
+
+		nft_rule_expr_set_str(nle, NFT_EXPR_MT_NAME,
+				      xt_stmt_real_name(stmt));
+		nft_rule_expr_set_u32(nle, NFT_EXPR_MT_REV,
+				      stmt->xt.match->revision);
+		nft_rule_expr_set(nle, NFT_EXPR_MT_INFO, info,
+				  stmt->xt.match->userspacesize);
+		nft_rule_add_expr(ctx->nlr, nle);
+		break;
+	case NFT_XT_TARGET:
+	case NFT_XT_WATCHER:
+		info = xzalloc(stmt->xt.target->size);
+		if (info == NULL)
+			memory_allocation_error();
+
+		memcpy(info, xt_target_info(stmt->xt.target->t),
+		       stmt->xt.target->size);
+
+		nle = nft_rule_expr_alloc("target");
+		if (nle == NULL)
+			memory_allocation_error();
+
+		nft_rule_expr_set_str(nle, NFT_EXPR_TG_NAME,
+				      xt_stmt_real_name(stmt));
+		nft_rule_expr_set_u32(nle, NFT_EXPR_TG_REV,
+				      stmt->xt.target->revision);
+		nft_rule_expr_set(nle, NFT_EXPR_TG_INFO, info,
+				  stmt->xt.target->userspacesize);
+		nft_rule_add_expr(ctx->nlr, nle);
+		break;
+	default:
+		BUG("Unknown xt type %d\n", stmt->xt.type);
+	}
+
+	if (stmt->xt.proto) {
+		nft_rule_attr_set_u32(ctx->nlr, NFT_RULE_ATTR_COMPAT_PROTO,
+				      stmt->xt.proto);
+		nft_rule_attr_set_u32(ctx->nlr, NFT_RULE_ATTR_COMPAT_FLAGS, 0);
+	}
+}
+
+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));
+
+	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);
+}


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [nft PATCH 3/3] tests: regression: add xt compat tests
  2015-03-25 19:15 [nft PATCH 1/3] src: expose delinearize/linearize structures and stmt_error() Arturo Borrero Gonzalez
  2015-03-25 19:16 ` [nft PATCH 2/3] src: add xt compat support Arturo Borrero Gonzalez
@ 2015-03-25 19:16 ` Arturo Borrero Gonzalez
  2015-03-25 19:23 ` [nft PATCH 1/3] src: expose delinearize/linearize structures and stmt_error() Patrick McHardy
  2 siblings, 0 replies; 12+ messages in thread
From: Arturo Borrero Gonzalez @ 2015-03-25 19:16 UTC (permalink / raw)
  To: netfilter-devel; +Cc: kaber, pablo

This patch adds several regression test for the xt compat stuff.

Note the current output is:
 ip/xt.t: 25 unit tests, 0 error, 0 warning
 ip6/xt.t: 25 unit tests, 0 error, 0 warning
 bridge/xt.t: 26 unit tests, 0 error, 0 warning
 arp/xt.t: 12 unit tests, 0 error, 0 warning

Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
---
 tests/regression/bridge/xt.t |   44 +++++++++++++++++++++++++++++++++++++++++
 tests/regression/ip/xt.t     |   45 ++++++++++++++++++++++++++++++++++++++++++
 tests/regression/ip6/xt.t    |   45 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 134 insertions(+)
 create mode 100644 tests/regression/bridge/xt.t
 create mode 100644 tests/regression/ip/xt.t
 create mode 100644 tests/regression/ip6/xt.t

diff --git a/tests/regression/bridge/xt.t b/tests/regression/bridge/xt.t
new file mode 100644
index 0000000..8b8d214
--- /dev/null
+++ b/tests/regression/bridge/xt.t
@@ -0,0 +1,44 @@
+*bridge;test-bridge
+:test-forward;type filter hook forward priority 0
+
+# standard load of match, target, watcher
+xt match 802_3 [ --802_3-sap 0x1 ];ok;xt match 802_3 [--802_3-sap 0x01  ]
+xt target mark [ --mark-set 0x1 ];ok;xt target mark [--mark-set 0x1 --mark-target ACCEPT ]
+xt watcher log [ ];ok;xt watcher log [--log-level notice --log-prefix ""  ]
+xt watcher log;ok;xt watcher log [--log-level notice --log-prefix ""  ]
+
+# more than one argument in a single statement
+xt match 802_3 [ --802_3-sap 0x1 --802_3-type 0x2 ];ok;xt match 802_3 [--802_3-sap 0x01 --802_3-type 0x0002  ]
+xt target mark [ --mark-set 0x1 --mark-target CONTINUE ];ok;xt target mark [--mark-set 0x1 --mark-target CONTINUE ]
+xt watcher log [ --log-level notice --log-prefix "test" ];ok;xt watcher log [--log-level notice --log-prefix "test"  ]
+
+# repeated statement with different argument (also testing final statement flag)
+xt match 802_3 [ --802_3-sap 0x1 --802_3-type 0x2 ] xt match 802_3 [ --802_3-type 0x3 --802_3-sap 0x4 ];ok;xt match 802_3 [--802_3-sap 0x01 --802_3-type 0x0002  ] xt match 802_3 [--802_3-sap 0x04 --802_3-type 0x0003  ]
+xt target mark [ --mark-set 0x1 --mark-target CONTINUE ] xt target mark [ --mark-set 0x1 ];fail
+xt watcher log [ --log-level notice ] xt watcher log [ --log-level notice --log-prefix "test" ];ok;xt watcher log [--log-level notice --log-prefix ""  ] xt watcher log [--log-level notice --log-prefix "test"  ]
+
+# statement with weird/invalid options
+xt match mark_m [ --test ];fail
+xt target mark [];ok;xt target mark [--mark-set 0x0 --mark-target ACCEPT ]
+xt target mark;ok;xt target mark [--mark-set 0x0 --mark-target ACCEPT ]
+xt watcher log [];ok;xt watcher log [--log-level notice --log-prefix ""  ]
+xt watcher log [--test];ok;xt watcher log [--log-level notice --log-prefix ""  ]
+
+# statement with invalid argument
+xt match 802_3 [ --802_3-sap -1 ];fail
+xt target mark [ --mark-target TEST ];fail
+xt watcher log [ --log-level test ];fail
+
+# inversions
+xt match 802_3 [ ! --802_3-sap 0x1 ];ok;xt match 802_3 [--802_3-sap ! 0x01  ]
+xt match 802_3 [ --802_3-sap ! 0x1 ];ok;xt match 802_3 [--802_3-sap ! 0x01  ]
+ether type ip xt match ip [ --ip-src ! 1.1.1.1 ];ok;ether type ip xt match ip [--ip-src ! 1.1.1.1  ]
+
+# protocol context games
+xt match ip [ --ip-src 1.1.1.1 ];fail
+ether type ip xt match ip [ --ip-src 1.1.1.1 ];ok;ether type ip xt match ip [--ip-src 1.1.1.1  ]
+ether type ip6 xt match ip [ --ip-src 1.1.1.1 ];fail
+ether type ip xt match ip [ --ip-proto tcp --ip-sport 123 ];ok;ether type ip xt match ip [--ip-proto tcp --ip-sport 123  ]
+
+# quoted strings
+xt watcher log [ --log-prefix \"test test\" ];ok;xt watcher log [--log-level notice --log-prefix "test test"  ]
diff --git a/tests/regression/ip/xt.t b/tests/regression/ip/xt.t
new file mode 100644
index 0000000..0ee3a21
--- /dev/null
+++ b/tests/regression/ip/xt.t
@@ -0,0 +1,45 @@
+*ip;nat
+:test-postrouting;type nat hook postrouting priority 0
+
+# standard load of match, target, watcher
+ip protocol 6 xt match multiport [ --dports 123,234,345 ];ok
+xt target MASQUERADE;ok;xt target MASQUERADE [ ]
+xt target LOG;ok;xt target LOG [ ]
+xt target LOG [];ok;xt target LOG [ ]
+xt target LOG [ ];ok;xt target LOG [ ]
+xt watcher log;fail
+
+# foreing extensions
+xt match 802_3 [ --802_3-sap 0x1 ];fail
+xt target mark [ --mark-set 0x1 ];fail
+
+# more than one argument in a single statement
+xt match conntrack [ --ctstate NEW --ctdir ORIGINAL ];ok
+xt target SNAT [ --to-source 10.0.0.10 --persistent ];ok
+
+# repeated statement with different argument (also testing final statement flag)
+xt match conntrack [ --ctstate NEW ] xt match conntrack [ --ctstate ESTABLISHED ] xt match conntrack [ --ctstate NEW,ESTABLISHED ];ok
+xt target SNAT [ --to-source 10.0.0.10 ] xt target SNAT [ --to-source 10.0.0.10 ];fail
+
+# statement with weird/invalid options
+xt match conntrack [ --asdasd --asdasd ];fail
+xt match multiport;fail
+xt match multiport [];fail
+xt match multiport [ ];fail
+xt target SNAT [ --asdasd --asdasd ];fail
+
+# statement with invalid argument
+xt match conntrack [ --ctstate TEST ];fail
+xt target SNAT [ --to-source asd ];fail
+
+# inversions
+xt match conntrack [ ! --ctstate NEW ! --ctstatus CONFIRMED --ctdir REPLY ];ok
+
+# protocol context games
+ip protocol 6 xt match multiport [ --dports 1,2,3 ]; ok
+ip protocol 17 xt match multiport [ --dports 1,2,3 ]; ok
+xt match multiport [ --dports 1,2,3 ]; fail
+
+# quoted strings
+xt match comment [ --comment \"test test\" ];ok;xt match comment [ --comment "test test" ]
+xt target LOG [ --log-prefix \"test test\" ];ok;xt target LOG [ --log-prefix "test test" ]
diff --git a/tests/regression/ip6/xt.t b/tests/regression/ip6/xt.t
new file mode 100644
index 0000000..0ee3a21
--- /dev/null
+++ b/tests/regression/ip6/xt.t
@@ -0,0 +1,45 @@
+*ip;nat
+:test-postrouting;type nat hook postrouting priority 0
+
+# standard load of match, target, watcher
+ip protocol 6 xt match multiport [ --dports 123,234,345 ];ok
+xt target MASQUERADE;ok;xt target MASQUERADE [ ]
+xt target LOG;ok;xt target LOG [ ]
+xt target LOG [];ok;xt target LOG [ ]
+xt target LOG [ ];ok;xt target LOG [ ]
+xt watcher log;fail
+
+# foreing extensions
+xt match 802_3 [ --802_3-sap 0x1 ];fail
+xt target mark [ --mark-set 0x1 ];fail
+
+# more than one argument in a single statement
+xt match conntrack [ --ctstate NEW --ctdir ORIGINAL ];ok
+xt target SNAT [ --to-source 10.0.0.10 --persistent ];ok
+
+# repeated statement with different argument (also testing final statement flag)
+xt match conntrack [ --ctstate NEW ] xt match conntrack [ --ctstate ESTABLISHED ] xt match conntrack [ --ctstate NEW,ESTABLISHED ];ok
+xt target SNAT [ --to-source 10.0.0.10 ] xt target SNAT [ --to-source 10.0.0.10 ];fail
+
+# statement with weird/invalid options
+xt match conntrack [ --asdasd --asdasd ];fail
+xt match multiport;fail
+xt match multiport [];fail
+xt match multiport [ ];fail
+xt target SNAT [ --asdasd --asdasd ];fail
+
+# statement with invalid argument
+xt match conntrack [ --ctstate TEST ];fail
+xt target SNAT [ --to-source asd ];fail
+
+# inversions
+xt match conntrack [ ! --ctstate NEW ! --ctstatus CONFIRMED --ctdir REPLY ];ok
+
+# protocol context games
+ip protocol 6 xt match multiport [ --dports 1,2,3 ]; ok
+ip protocol 17 xt match multiport [ --dports 1,2,3 ]; ok
+xt match multiport [ --dports 1,2,3 ]; fail
+
+# quoted strings
+xt match comment [ --comment \"test test\" ];ok;xt match comment [ --comment "test test" ]
+xt target LOG [ --log-prefix \"test test\" ];ok;xt target LOG [ --log-prefix "test test" ]


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [nft PATCH 1/3] src: expose delinearize/linearize structures and stmt_error()
  2015-03-25 19:15 [nft PATCH 1/3] src: expose delinearize/linearize structures and stmt_error() Arturo Borrero Gonzalez
  2015-03-25 19:16 ` [nft PATCH 2/3] src: add xt compat support Arturo Borrero Gonzalez
  2015-03-25 19:16 ` [nft PATCH 3/3] tests: regression: add xt compat tests Arturo Borrero Gonzalez
@ 2015-03-25 19:23 ` Patrick McHardy
  2 siblings, 0 replies; 12+ messages in thread
From: Patrick McHardy @ 2015-03-25 19:23 UTC (permalink / raw)
  To: Arturo Borrero Gonzalez; +Cc: netfilter-devel, pablo

> diff --git a/src/evaluate.c b/src/evaluate.c
> index 7ecb793..c420cd4 100644
> --- a/src/evaluate.c
> +++ b/src/evaluate.c
> @@ -36,10 +36,10 @@ static const char *byteorder_names[] = {
>  	[BYTEORDER_BIG_ENDIAN]		= "big endian",
>  };
>  
> -static int __fmtstring(4, 5) __stmt_binary_error(struct eval_ctx *ctx,
> -						 const struct location *l1,
> -						 const struct location *l2,
> -						 const char *fmt, ...)
> +int __fmtstring(4, 5) __stmt_binary_error(struct eval_ctx *ctx,
> +					  const struct location *l1,
> +					  const struct location *l2,
> +					  const char *fmt, ...)
>  {
>  	struct error_record *erec;
>  	va_list ap;

Lets move this to erec.c and rename it to __binary_error. Its only
in evaluate.c because it didn't use to have other users.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [nft PATCH 2/3] src: add xt compat support
  2015-03-25 19:16 ` [nft PATCH 2/3] src: add xt compat support Arturo Borrero Gonzalez
@ 2015-03-25 19:44   ` Pablo Neira Ayuso
  2015-03-27 12:00     ` Arturo Borrero Gonzalez
  0 siblings, 1 reply; 12+ messages in thread
From: Pablo Neira Ayuso @ 2015-03-25 19:44 UTC (permalink / raw)
  To: Arturo Borrero Gonzalez; +Cc: netfilter-devel, kaber

On Wed, Mar 25, 2015 at 08:16:02PM +0100, Arturo Borrero Gonzalez wrote:
> diff --git a/include/xt.h b/include/xt.h
> new file mode 100644
> index 0000000..414f3d1
> --- /dev/null
> +++ b/include/xt.h
> @@ -0,0 +1,100 @@
> +#ifndef _NFT_XT_H_
> +#define _NFT_XT_H_
> +
> +#include <arpa/inet.h>
> +#include <netinet/in.h>
> +#include <limits.h>
> +#include <net/if.h>
> +#include <net/ethernet.h>
> +
> +struct netlink_linearize_ctx;
> +struct netlink_parse_ctx;
> +struct nft_rule_expr;
> +struct rule_pp_ctx;
> +struct rule;
> +
> +#ifdef HAVE_LIBXTABLES
> +
> +#include <linux/netfilter_ipv4/ip_tables.h>
> +#include <linux/netfilter_ipv6/ip6_tables.h>
> +#include <linux/netfilter_arp/arp_tables.h>
> +
> +/* Fake ebt_entry */
> +struct ebt_entry {

I think you can avoid this if you:

#include <linux/netfilter_bridge/ebtables.h>

[...]
> +#else /* HAVE_LIBXTABLES */
> +union nft_entry {
> +	uint32_t	*nothing;
> +};

I'd suggest:

        #define nft_entry void

> +static inline void stmt_xt_postprocess(struct rule_pp_ctx rctx,
                                                             ^^^^

I think this needs to be *rctx.

Please, retest without libxtables support.

> +				       struct stmt *stmt, struct rule *rule) {}
> +
> +#endif /* HAVE_LIBXTABLES */
> +
> +#endif /* _NFT_XT_H_ */
> +xt_opts			:	/* empty */	{ $$ = NULL; }
> +			|	XTOPTS		{ $$ = $1; }
> +			;
> +
> +xt_name			:	STRING		{ $$ = $1; }
> +			|	STATE		{ $$ = xstrdup("state"); }
> +			|	COMMENT		{ $$ = xstrdup("comment"); }
> +			|	AH		{ $$ = xstrdup("ah"); }
> +			|	ESP		{ $$ = xstrdup("esp"); }
> +			|	TCP		{ $$ = xstrdup("tcp"); }
> +			|	UDP		{ $$ = xstrdup("udp"); }
> +			|	UDPLITE		{ $$ = xstrdup("udplite"); }
> +			|	SCTP		{ $$ = xstrdup("sctp"); }
> +			|	ICMP		{ $$ = xstrdup("icmp"); }
> +			|	IP		{ $$ = xstrdup("ip"); }
> +			|	VLAN		{ $$ = xstrdup("vlan"); }
> +			|	LOG		{ $$ = xstrdup("log"); }
> +			|	_802_3		{ $$ = xstrdup("802_3"); }

This _802_3 should not be clashing with anything else, the problem is
somewhere else.

> +			|	MARK		{ $$ = xstrdup("mark"); }
> +			;
> +
>  nf_nat_flags		:	nf_nat_flag
>  			|	nf_nat_flags	COMMA	nf_nat_flag
>  			{
> diff --git a/src/rule.c b/src/rule.c
> index 7114380..c7c5e20 100644
> --- a/src/rule.c
> +++ b/src/rule.c
> @@ -820,6 +820,7 @@ static void table_cleanup(struct table *table)
>  	}
>  }
>  
> +#include <xt.h>
>  static int do_list_table(struct netlink_ctx *ctx, struct cmd *cmd,
>  			 struct table *table)
>  {
> diff --git a/src/scanner.l b/src/scanner.l
> index 73c4f8b..33f0699 100644
> --- a/src/scanner.l
> +++ b/src/scanner.l
> @@ -113,6 +113,7 @@ hexstring	0[xX]{hexdigit}+
>  range		({decstring}?:{decstring}?)
>  letter		[a-zA-Z]
>  string		({letter})({letter}|{digit}|[/\-_\.])*
> +xtopts		\[({letter}|{digit}|[!/\-_\.\"\:\, ])*\]
>  quotedstring	\"[^"]*\"
>  comment		#.*$
>  slash		\/
> @@ -449,6 +450,12 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
>  "proto-dst"		{ return PROTO_DST; }
>  "label"			{ return LABEL; }
>  
> +"xt"			{ return XT; }
> +"match"			{ return MATCH; }
> +"target"		{ return TARGET; }
> +"watcher"		{ return WATCHER; }
> +"802_3"			{ return _802_3; }
> +
>  "xml"			{ return XML; }
>  "json"			{ return JSON; }
>  
> @@ -488,6 +495,11 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
>  				return STRING;
>  			}
>  
> +{xtopts}		{
> +				yylval->string = xstrdup(yytext);
> +				return XTOPTS;
> +			}
> +
>  \\{newline}		{
>  				reset_pos(yyget_extra(yyscanner), yylloc);
>  			}
> diff --git a/src/statement.c b/src/statement.c
> index d72c6e9..5092ea8 100644
> --- a/src/statement.c
> +++ b/src/statement.c
> @@ -23,6 +23,7 @@
>  #include <statement.h>
>  #include <utils.h>
>  #include <list.h>
> +#include <xt.h>
>  
>  #include <netinet/in.h>
>  #include <linux/netfilter/nf_nat.h>
> @@ -377,3 +378,44 @@ struct stmt *redir_stmt_alloc(const struct location *loc)
>  {
>  	return stmt_alloc(loc, &redir_stmt_ops);
>  }
> +
> +static const char *xt_type_name[NFT_XT_MAX] = {
> +	[NFT_XT_MATCH]	= "match",
> +	[NFT_XT_TARGET]	= "target",
> +	[NFT_XT_WATCHER]= "watcher",
> +};
> +
> +static const char *xt_stmt_to_type(enum nft_xt_type type)
> +{
> +	if (type > NFT_XT_MAX)
> +		return "unknown";
> +
> +	return xt_type_name[type];
> +}
> +
> +static void xt_stmt_print(const struct stmt *stmt)
> +{
> +	printf("xt %s %s ", xt_stmt_to_type(stmt->xt.type),
> +			    xt_stmt_name(stmt));
> +	xt_stmt_save(stmt);
> +}
> +
> +static void xt_stmt_destroy(struct stmt *stmt)
> +{
> +	xfree(stmt->xt.name);
> +	xfree(stmt->xt.opts);
> +
> +	xt_stmt_destroy_internals(stmt);
> +}
> +
> +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);
> +}
> diff --git a/src/xt.c b/src/xt.c
> new file mode 100644
> index 0000000..dcb461b
> --- /dev/null
> +++ b/src/xt.c
> @@ -0,0 +1,701 @@
> +/*
> + * Copyright (c) 2013-2015 Pablo Neira Ayuso <pablo@netfilter.org>
> + *
> + * This program is free software; you can redistribute it and/or modifyi
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <stdlib.h>
> +#include <time.h>
> +#include <string.h>
> +#include <xtables.h>
> +#include <utils.h>
> +#include <getopt.h>
> +#include <ctype.h>	/* for isspace */
> +#include <statement.h>
> +#include <rule.h>
> +#include <netlink.h>
> +#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>
> +
> +#include <libnftnl/rule.h>
> +#include <libnftnl/expr.h>
> +
> +void xt_stmt_destroy_internals(const struct stmt *stmt)

xt_stmt_release ?

> +{
> +	switch (stmt->xt.type) {
> +	case NFT_XT_MATCH:
> +		if (!stmt->xt.match)
> +			break;
> +		if (stmt->xt.match->m)
> +			xfree(stmt->xt.match->m);
> +		/* this has been cloned */

I think you can remove this comment.

> +		xfree(stmt->xt.match);
> +		break;
> +	case NFT_XT_WATCHER:
> +	case NFT_XT_TARGET:
> +		if (!stmt->xt.target)
> +			break;
> +		if (stmt->xt.target->t)
> +			xfree(stmt->xt.target->t);
> +		/* this has been cloned */

Same here.

> +		xfree(stmt->xt.target);
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +const char *xt_stmt_name(const struct stmt *stmt)
> +{
> +	switch (stmt->xt.type) {
> +	case NFT_XT_MATCH:
> +		if (stmt->xt.match == NULL)
> +			break;
> +		if (stmt->xt.match->alias)
> +			return stmt->xt.match->alias(stmt->xt.match->m);
> +		break;
> +	case NFT_XT_TARGET:
> +	case NFT_XT_WATCHER:
> +		if (stmt->xt.target == NULL)
> +			break;
> +		if (stmt->xt.target->alias)
> +			return stmt->xt.target->alias(stmt->xt.target->t);
> +		break;
> +	default:
> +		return "unknown";
> +	}
> +
> +	return stmt->xt.name;
> +}
> +
> +void xt_stmt_save(const struct stmt *stmt)
> +{
> +#ifdef DEBUG
> +	switch (stmt->xt.type) {
> +	case NFT_XT_MATCH:
> +		if (stmt->xt.match)
> +			break;
> +		if (stmt->xt.opts)
> +			fprintf(stdout, "%s", stmt->xt.opts);
> +		return;
> +	case NFT_XT_WATCHER:
> +	case NFT_XT_TARGET:
> +		if (stmt->xt.target)
> +			break;
> +		if (stmt->xt.opts)
> +			fprintf(stdout, "%s", stmt->xt.opts);
> +		return;
> +	default:
> +		break;
> +	}
> +#endif /* DEBUG */

I think you can merge this.

> +
> +	printf("[");
> +
> +	switch (stmt->xt.type) {
> +	case NFT_XT_MATCH:

I think the DEBUG case needs this:

                if (stmt->xt.match == NULL && stmt->xt.opts)
                        fprintf(stdout, "%s", stmt->xt.opts);

> +		if (stmt->xt.match->save) {
> +			stmt->xt.match->save(&stmt->xt.entry,
> +					     stmt->xt.match->m);
> +		} else if (stmt->xt.match->print) {
> +			stmt->xt.match->print(&stmt->xt.entry,
> +					      stmt->xt.match->m, 0);
> +		}
> +		break;
> +	case NFT_XT_WATCHER:
> +	case NFT_XT_TARGET:
> +		if (stmt->xt.target->save)
> +			stmt->xt.target->save(NULL, stmt->xt.target->t);
> +		else if (stmt->xt.target->print)
> +			stmt->xt.target->print(NULL, stmt->xt.target->t, 0);
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	printf(" ]");
> +}
> +
> +static void *xt_entry_x_alloc(struct xt_stmt *xt)

xt_entry_data_alloc() ?

> +{
> +
> +	uint32_t size = 0;
> +
> +	switch (xt->type) {
> +	case NFT_XT_MATCH:
> +		size = XT_ALIGN(sizeof(struct xt_entry_match)) +
> +		       xt->match->size;
> +		break;
> +	case NFT_XT_WATCHER:
> +	case NFT_XT_TARGET:
> +		size = XT_ALIGN(sizeof(struct xt_entry_target)) +
> +		       xt->target->size;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return xzalloc(size);
> +}
> +
> +static void nft_entry_setup(struct xt_stmt *xt, uint32_t af)
> +{
> +	switch (af) {
> +	case NFPROTO_IPV4:
> +		xt->entry.e4.ip.proto = xt->proto;
> +		break;
> +	case NFPROTO_IPV6:
> +		xt->entry.e6.ipv6.proto = xt->proto;
> +		break;
> +	case NFPROTO_BRIDGE:
> +		xt->entry.ebt.ethproto = xt->proto;
> +		break;
> +	case NFPROTO_ARP:
> +		/* XXX hardcoded, these are the only values accepted by arpt */
> +		xt->entry.arp.arp.arhln_mask = 0xff;
> +		xt->entry.arp.arp.arhln = 6;

If this is good for all extensions, then you can probably remove the
comment.

> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +static uint32_t xt_proto(const struct proto_ctx *pctx)
> +{
> +	const struct proto_desc *desc = NULL;
> +
> +	if (pctx->family == NFPROTO_BRIDGE) {
> +		desc = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
> +		if (desc == NULL)
> +			goto noproto;
> +		if (strcmp(desc->name, "ip") == 0)
> +			return __constant_htons(ETH_P_IP);
> +		if (strcmp(desc->name, "ip6") == 0)
> +			return __constant_htons(ETH_P_IPV6);
> +		goto noproto;

                return 0; instead ?

> +	}
> +
> +	desc = pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc;
> +	if (desc == NULL)
> +		goto noproto;
> +	if (strcmp(desc->name, "tcp") == 0)
> +		return IPPROTO_TCP;
> +	else if (strcmp(desc->name, "udp") == 0)
> +		return IPPROTO_UDP;
> +	else if (strcmp(desc->name, "udplite") == 0)
> +		return IPPROTO_UDPLITE;
> +	else if (strcmp(desc->name, "sctp") == 0)
> +		return IPPROTO_SCTP;
> +	else if (strcmp(desc->name, "dccp") == 0)
> +		return IPPROTO_DCCP;
> +	else if (strcmp(desc->name, "esp") == 0)
> +		return IPPROTO_ESP;
> +	else
> +		BUG("xt with unknown protocol\n");
> +
> +noproto:
> +	return 0;
> +}
> +
> +static struct xtables_target *clone_target(struct xtables_target *t)

xt_target_clone() ?

> +{
> +	struct xtables_target *clone;
> +
> +	clone = xzalloc(sizeof(struct xtables_target));
> +	memcpy(clone, t, sizeof(struct xtables_target));
> +	return clone;
> +}
> +
> +static struct xtables_match *clone_match(struct xtables_match *m)

xt_match_clone() ?

> +{
> +	struct xtables_match *clone;
> +
> +	clone = xzalloc(sizeof(struct xtables_match));
> +	memcpy(clone, m, sizeof(struct xtables_match));
> +	return clone;
> +}
> +
> +/*
> + * Evaluation
> + */
> +
> +static struct option original_opts[] = {
> +	{ NULL },
> +};
> +
> +static int xt_target_to_binary(struct xt_stmt *xt, int argc, char *argv[],
> +			       uint32_t af)
> +{
> +	struct option *opt;
> +	unsigned int offset;
> +	int c;
> +
> +	xt->target->t = xt_entry_x_alloc(xt);
> +	nft_entry_setup(xt, af);
> +
> +	if (xt->target->x6_options != NULL)
> +		opt = xtables_options_xfrm(original_opts, NULL,
> +					   xt->target->x6_options,
> +					   &offset);
> +	else
> +		opt = xtables_merge_options(original_opts, NULL,
> +					    xt->target->extra_opts,
> +					    &offset);
> +
> +	if (xt->target->init != NULL)
> +		xt->target->init(xt->target->t);
> +
> +	/* Reset internal state of getopt_long. */
> +	optind = 0;
> +	/* Suppress error messages. */
> +	opterr = 0;
> +
> +	while ((c = getopt_long(argc, argv, "-:", opt, NULL)) != -1) {
> +
> +		c -= offset;
> +		xtables_option_tpcall(xt->target->option_offset + c,
> +				      argv, 0, xt->target, &xt->entry);
> +	}
> +
> +	/* Reset parsing flags */
> +	xt->target->tflags = 0;
> +	xfree(opt);
> +
> +	return 0;
> +}
> +
> +static int xt_match_to_binary(struct xt_stmt *xt, int argc, char *argv[],
> +			      uint32_t af)
> +{
> +	struct option *opt;
> +	unsigned int offset;
> +	bool invert = false;
> +	int c;
> +
> +	xt->match->m = xt_entry_x_alloc(xt);
> +	nft_entry_setup(xt, af);
> +
> +	if (xt->match->x6_options != NULL)
> +		opt = xtables_options_xfrm(original_opts, NULL,
> +					   xt->match->x6_options,
> +					   &offset);
> +	else
> +		opt = xtables_merge_options(original_opts, NULL,
> +					    xt->match->extra_opts,
> +					    &offset);
> +
> +	if (xt->match->init != NULL)
> +		xt->match->init(xt->match->m);
> +
> +	/* Reset internal state of getopt_long. */
> +	optind = 0;
> +	/* Suppress error messages. */
> +	opterr = 0;
> +
> +	while ((c = getopt_long(argc, argv, "-:", opt, NULL)) != -1) {
> +		switch (c) {
> +		case 1:
> +			invert = true;
> +			continue;
> +		default:
> +			break;
> +		}
> +
> +		if (optarg != NULL && optarg[0] == '!' && optarg[1] == '\0') {
> +			invert = true;
> +			optarg = argv[optind];
> +		}
> +
> +		c -= offset;
> +		xtables_option_mpcall(xt->match->option_offset + c,
> +				      argv, invert, xt->match,
> +				      &xt->entry);
> +		if (invert)
> +			invert = false;
> +	}
> +
> +	/* Reset parsing flags */
> +	xt->match->mflags = 0;
> +	xfree(opt);
> +
> +	return 0;
> +}
> +
> +/* An xt extension doesn't have more than arguments. */
> +#define MAX_ARG			64
> +
> +static int string_to_argv(const char *str, char *argv[], uint32_t argc_max)
> +{
> +	uint32_t i, k = 1, len = 0;
> +	bool atquote = false, dupquote = false;
> +
> +	if (str == NULL)
> +		return 0;
> +
> +	/* skip first/last char, are '[' and ']' */
> +	for (i = 1; i < strlen(str)-1; i++) {

                        strlen(str) - 1

> +		if (k == argc_max)
> +			goto err;
> +
> +		if (isspace(str[i]) && !atquote) {
> +			if (len <= 0)
> +				continue;
> +
> +			if (dupquote) {
> +				argv[k] = strndup(&str[i - len + 1], len - 2);
> +				dupquote = false;
> +			} else {
> +				argv[k] = strndup(&str[i - len], len);
> +			}
> +
> +			k++;
> +			len = 0;
> +		} else {
> +			len++;
> +		}
> +
> +		if (str[i] == '"') {
> +			if (!atquote)
> +				dupquote = true;
> +			atquote = !atquote;
> +		}
> +	}
> +	return k;
> +err:
> +	for (i = 0; i < k; i++)
> +		free(argv[i]);
> +	return -1;
> +}
> +
> +int stmt_evaluate_xt(struct eval_ctx *ctx, struct stmt *stmt)
> +{
> +	char *argv[MAX_ARG] = { "iptables" };
> +	struct xtables_match *mt;
> +	struct xtables_target *tg;
> +	int argc, i, err;
> +
> +	argc = string_to_argv(stmt->xt.opts, argv, MAX_ARG);
> +	if (argc < 0)
> +		return stmt_error(ctx, stmt, "too many xt options");
> +
> +	xtables_set_nfproto(ctx->pctx.family);
> +	stmt->xt.proto = xt_proto(&ctx->pctx);
> +
> +	if (stmt->xt.type == NFT_XT_WATCHER &&
> +	    ctx->pctx.family != NFPROTO_BRIDGE)
> +		return stmt_error(ctx, stmt,
> +				  "watcher only available from bridge family");
> +
> +	switch (stmt->xt.type) {
> +	case NFT_XT_MATCH:
> +		mt = xtables_find_match(stmt->xt.name, XTF_TRY_LOAD, NULL);
> +		if (!mt)
> +			return stmt_error(ctx, stmt, "unknown match %s",
> +					  stmt->xt.name);
> +
> +		stmt->xt.match = clone_match(mt);
> +		err = xt_match_to_binary(&stmt->xt, argc, argv,
> +					 ctx->pctx.family);
> +		break;
> +	case NFT_XT_TARGET:
> +	case NFT_XT_WATCHER:
> +		tg = xtables_find_target(stmt->xt.name, XTF_TRY_LOAD);
> +		if (!tg)
> +			return stmt_error(ctx, stmt, "unknown target %s",
> +					  stmt->xt.name);
> +
> +		stmt->xt.target = clone_target(tg);
> +		err = xt_target_to_binary(&stmt->xt, argc, argv,
> +					 ctx->pctx.family);
> +		break;
> +	default:
> +		BUG("Unknown xt type %d\n", stmt->xt.type);
> +	}
> +
> +	if (stmt->xt.type == NFT_XT_TARGET)
> +		stmt->flags |= STMT_F_TERMINAL;
> +
> +	for (i = 1; i < argc; i++)
> +		xfree(argv[i]);
> +
> +	if (err < 0)
> +		return stmt_error(ctx, stmt, "failed to parse");
> +
> +	return 0;
> +}
> +
> +/*
> + * Delinearization
> + */
> +
> +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 char *mtinfo;
> +	struct xt_entry_match *m;
> +	uint32_t mt_len;
> +
> +	xtables_set_nfproto(ctx->table->handle.family);
> +
> +	name = nft_rule_expr_get_str(nle, NFT_EXPR_MT_NAME);
> +
> +	/* XXXX mem leak. When is this memory freed?
> +	 * - can't call xtables_rule_matches_free()
> +	 * - the same match could be in use by the next rule
> +	 * - use a wrapper struct with a refcount? lot of code overhead
> +	 */

This comment ?

> +	mt = xtables_find_match(name, XTF_TRY_LOAD, NULL);
> +	if (!mt)
> +		BUG("XT match %s not found\n", name);
> +
> +	mtinfo = nft_rule_expr_get(nle, NFT_EXPR_MT_INFO, &mt_len);
> +
> +	m = xzalloc(sizeof(struct xt_entry_match) + mt_len);
> +	memcpy(&m->data, mtinfo, mt_len);
> +
> +	m->u.match_size = mt_len + XT_ALIGN(sizeof(struct xt_entry_match));
> +	m->u.user.revision = nft_rule_expr_get_u32(nle, NFT_EXPR_MT_REV);
> +
> +	stmt = xt_stmt_alloc(loc);
> +	stmt->xt.name = strdup(name);
> +	stmt->xt.type = NFT_XT_MATCH;
> +	stmt->xt.match = clone_match(mt);
> +	stmt->xt.match->m = m;
> +
> +	list_add_tail(&stmt->list, &ctx->rule->stmts);
> +}
> +
> +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 *t;
> +	size_t size;
> +	uint32_t tg_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, &tg_len);
> +
> +	size = XT_ALIGN(sizeof(struct xt_entry_target)) + tg_len;
> +	t = xzalloc(size);
> +	memcpy(&t->data, tginfo, tg_len);
> +	t->u.target_size = size;
> +	t->u.user.revision = nft_rule_expr_get_u32(nle, NFT_EXPR_TG_REV);
> +	strcpy(t->u.user.name, tg->name);
> +
> +	stmt = xt_stmt_alloc(loc);
> +	stmt->xt.name = strdup(name);
> +	stmt->xt.type = NFT_XT_TARGET;
> +	stmt->xt.target = clone_target(tg);
> +	stmt->xt.target->t = t;
> +
> +	list_add_tail(&stmt->list, &ctx->rule->stmts);
> +}
> +
> +static bool is_watcher(uint32_t family, struct stmt *stmt)
> +{
> +	if (family != NFPROTO_BRIDGE)
> +		return false;
> +
> +	if (stmt->xt.type != NFT_XT_TARGET)
> +		return false;
> +
> +	/* this has to be hardcoded :-( */
> +	if (strcmp(stmt->xt.name, "log") == 0)
> +		return true;
> +	if (strcmp(stmt->xt.name, "nflog") == 0)
> +		return true;
> +	if (strcmp(stmt->xt.name, "uflog") == 0)

ulog ?

> +		return true;
> +
> +	return false;
> +}

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [nft PATCH 2/3] src: add xt compat support
  2015-03-25 19:44   ` Pablo Neira Ayuso
@ 2015-03-27 12:00     ` Arturo Borrero Gonzalez
  2015-03-27 12:31       ` Pablo Neira Ayuso
  0 siblings, 1 reply; 12+ messages in thread
From: Arturo Borrero Gonzalez @ 2015-03-27 12:00 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: Netfilter Development Mailing list, Patrick McHardy

On 25 March 2015 at 20:44, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Wed, Mar 25, 2015 at 08:16:02PM +0100, Arturo Borrero Gonzalez wrote:
>> diff --git a/include/xt.h b/include/xt.h
>> new file mode 100644
>> index 0000000..414f3d1
>> --- /dev/null
>> +++ b/include/xt.h
>> @@ -0,0 +1,100 @@
>> +#ifndef _NFT_XT_H_
>> +#define _NFT_XT_H_
>> +
>> +#include <arpa/inet.h>
>> +#include <netinet/in.h>
>> +#include <limits.h>
>> +#include <net/if.h>
>> +#include <net/ethernet.h>
>> +
>> +struct netlink_linearize_ctx;
>> +struct netlink_parse_ctx;
>> +struct nft_rule_expr;
>> +struct rule_pp_ctx;
>> +struct rule;
>> +
>> +#ifdef HAVE_LIBXTABLES
>> +
>> +#include <linux/netfilter_ipv4/ip_tables.h>
>> +#include <linux/netfilter_ipv6/ip6_tables.h>
>> +#include <linux/netfilter_arp/arp_tables.h>
>> +
>> +/* Fake ebt_entry */
>> +struct ebt_entry {
>
> I think you can avoid this if you:
>
> #include <linux/netfilter_bridge/ebtables.h>
>

Can't include <linux/netfilter_bridge/ebtables.h> because it includes
<linux/if.h> and clash with <net/if.h>

I will put a comment in the code.

>
>> +                                    struct stmt *stmt, struct rule *rule) {}
>> +
>> +#endif /* HAVE_LIBXTABLES */
>> +
>> +#endif /* _NFT_XT_H_ */
>> +xt_opts                      :       /* empty */     { $$ = NULL; }
>> +                     |       XTOPTS          { $$ = $1; }
>> +                     ;
>> +
>> +xt_name                      :       STRING          { $$ = $1; }
>> +                     |       STATE           { $$ = xstrdup("state"); }
>> +                     |       COMMENT         { $$ = xstrdup("comment"); }
>> +                     |       AH              { $$ = xstrdup("ah"); }
>> +                     |       ESP             { $$ = xstrdup("esp"); }
>> +                     |       TCP             { $$ = xstrdup("tcp"); }
>> +                     |       UDP             { $$ = xstrdup("udp"); }
>> +                     |       UDPLITE         { $$ = xstrdup("udplite"); }
>> +                     |       SCTP            { $$ = xstrdup("sctp"); }
>> +                     |       ICMP            { $$ = xstrdup("icmp"); }
>> +                     |       IP              { $$ = xstrdup("ip"); }
>> +                     |       VLAN            { $$ = xstrdup("vlan"); }
>> +                     |       LOG             { $$ = xstrdup("log"); }
>> +                     |       _802_3          { $$ = xstrdup("802_3"); }
>
> This _802_3 should not be clashing with anything else, the problem is
> somewhere else.
>

% sudo nft add rule bridge filter FORWARD xt match 802_3 [--802_3-sap 0x01  ]
<cmdline>:1:41-43: Error: syntax error, unexpected number
add rule bridge filter FORWARD xt match 802_3 [--802_3-sap 0x01 ]
                                        ^^^

I have to admit I don't know where to look. Do you have any hint?
-- 
Arturo Borrero González
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [nft PATCH 2/3] src: add xt compat support
  2015-03-27 12:31       ` Pablo Neira Ayuso
@ 2015-03-27 12:31         ` Patrick McHardy
  2015-03-27 12:59         ` Arturo Borrero Gonzalez
  1 sibling, 0 replies; 12+ messages in thread
From: Patrick McHardy @ 2015-03-27 12:31 UTC (permalink / raw)
  To: Pablo Neira Ayuso
  Cc: Arturo Borrero Gonzalez, Netfilter Development Mailing list

On 27.03, Pablo Neira Ayuso wrote:
> On Fri, Mar 27, 2015 at 01:00:37PM +0100, Arturo Borrero Gonzalez wrote:
> > On 25 March 2015 at 20:44, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > 
> > % sudo nft add rule bridge filter FORWARD xt match 802_3 [--802_3-sap 0x01  ]
> > <cmdline>:1:41-43: Error: syntax error, unexpected number
> > add rule bridge filter FORWARD xt match 802_3 [--802_3-sap 0x01 ]
> >                                         ^^^
> > 
> > I have to admit I don't know where to look. Do you have any hint?
> 
> I know see the problem, the scanner doesn't consider that a string can
> start by a number, we have a similar problem with the expiration time.
> Well, I would keep it there until we find a better solution. Please,
> check if we have more extensions with this pattern.

For this specifc case what might work is add a token

"match [^ ]+"

and return XT_MATCH as token type and the name as value. This will of
course not allow to use "match" for anything else, including identifiers.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [nft PATCH 2/3] src: add xt compat support
  2015-03-27 12:00     ` Arturo Borrero Gonzalez
@ 2015-03-27 12:31       ` Pablo Neira Ayuso
  2015-03-27 12:31         ` Patrick McHardy
  2015-03-27 12:59         ` Arturo Borrero Gonzalez
  0 siblings, 2 replies; 12+ messages in thread
From: Pablo Neira Ayuso @ 2015-03-27 12:31 UTC (permalink / raw)
  To: Arturo Borrero Gonzalez
  Cc: Netfilter Development Mailing list, Patrick McHardy

On Fri, Mar 27, 2015 at 01:00:37PM +0100, Arturo Borrero Gonzalez wrote:
> On 25 March 2015 at 20:44, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > On Wed, Mar 25, 2015 at 08:16:02PM +0100, Arturo Borrero Gonzalez wrote:
> >> diff --git a/include/xt.h b/include/xt.h
> >> new file mode 100644
> >> index 0000000..414f3d1
> >> --- /dev/null
> >> +++ b/include/xt.h
> >> @@ -0,0 +1,100 @@
> >> +#ifndef _NFT_XT_H_
> >> +#define _NFT_XT_H_
> >> +
> >> +#include <arpa/inet.h>
> >> +#include <netinet/in.h>
> >> +#include <limits.h>
> >> +#include <net/if.h>
> >> +#include <net/ethernet.h>
> >> +
> >> +struct netlink_linearize_ctx;
> >> +struct netlink_parse_ctx;
> >> +struct nft_rule_expr;
> >> +struct rule_pp_ctx;
> >> +struct rule;
> >> +
> >> +#ifdef HAVE_LIBXTABLES
> >> +
> >> +#include <linux/netfilter_ipv4/ip_tables.h>
> >> +#include <linux/netfilter_ipv6/ip6_tables.h>
> >> +#include <linux/netfilter_arp/arp_tables.h>
> >> +
> >> +/* Fake ebt_entry */
> >> +struct ebt_entry {
> >
> > I think you can avoid this if you:
> >
> > #include <linux/netfilter_bridge/ebtables.h>
> >
> 
> Can't include <linux/netfilter_bridge/ebtables.h> because it includes
> <linux/if.h> and clash with <net/if.h>

There must be a clean way to fix this without embedding the ebt_entry
structure.

> I will put a comment in the code.
> 
> >
> >> +                                    struct stmt *stmt, struct rule *rule) {}
> >> +
> >> +#endif /* HAVE_LIBXTABLES */
> >> +
> >> +#endif /* _NFT_XT_H_ */
> >> +xt_opts                      :       /* empty */     { $$ = NULL; }
> >> +                     |       XTOPTS          { $$ = $1; }
> >> +                     ;
> >> +
> >> +xt_name                      :       STRING          { $$ = $1; }
> >> +                     |       STATE           { $$ = xstrdup("state"); }
> >> +                     |       COMMENT         { $$ = xstrdup("comment"); }
> >> +                     |       AH              { $$ = xstrdup("ah"); }
> >> +                     |       ESP             { $$ = xstrdup("esp"); }
> >> +                     |       TCP             { $$ = xstrdup("tcp"); }
> >> +                     |       UDP             { $$ = xstrdup("udp"); }
> >> +                     |       UDPLITE         { $$ = xstrdup("udplite"); }
> >> +                     |       SCTP            { $$ = xstrdup("sctp"); }
> >> +                     |       ICMP            { $$ = xstrdup("icmp"); }
> >> +                     |       IP              { $$ = xstrdup("ip"); }
> >> +                     |       VLAN            { $$ = xstrdup("vlan"); }
> >> +                     |       LOG             { $$ = xstrdup("log"); }
> >> +                     |       _802_3          { $$ = xstrdup("802_3"); }
> >
> > This _802_3 should not be clashing with anything else, the problem is
> > somewhere else.
> >
> 
> % sudo nft add rule bridge filter FORWARD xt match 802_3 [--802_3-sap 0x01  ]
> <cmdline>:1:41-43: Error: syntax error, unexpected number
> add rule bridge filter FORWARD xt match 802_3 [--802_3-sap 0x01 ]
>                                         ^^^
> 
> I have to admit I don't know where to look. Do you have any hint?

I know see the problem, the scanner doesn't consider that a string can
start by a number, we have a similar problem with the expiration time.
Well, I would keep it there until we find a better solution. Please,
check if we have more extensions with this pattern.

Thanks Arturo.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [nft PATCH 2/3] src: add xt compat support
  2015-03-27 12:31       ` Pablo Neira Ayuso
  2015-03-27 12:31         ` Patrick McHardy
@ 2015-03-27 12:59         ` Arturo Borrero Gonzalez
  2015-03-27 13:13           ` Pablo Neira Ayuso
  1 sibling, 1 reply; 12+ messages in thread
From: Arturo Borrero Gonzalez @ 2015-03-27 12:59 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: Netfilter Development Mailing list, Patrick McHardy

On 27 March 2015 at 13:31, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Fri, Mar 27, 2015 at 01:00:37PM +0100, Arturo Borrero Gonzalez wrote:
>> On 25 March 2015 at 20:44, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
>> > On Wed, Mar 25, 2015 at 08:16:02PM +0100, Arturo Borrero Gonzalez wrote:
>> >> diff --git a/include/xt.h b/include/xt.h
>> >> new file mode 100644
>> >> index 0000000..414f3d1
>> >> --- /dev/null
>> >> +++ b/include/xt.h
>> >> @@ -0,0 +1,100 @@
>> >> +#ifndef _NFT_XT_H_
>> >> +#define _NFT_XT_H_
>> >> +
>> >> +#include <arpa/inet.h>
>> >> +#include <netinet/in.h>
>> >> +#include <limits.h>
>> >> +#include <net/if.h>
>> >> +#include <net/ethernet.h>
>> >> +
>> >> +struct netlink_linearize_ctx;
>> >> +struct netlink_parse_ctx;
>> >> +struct nft_rule_expr;
>> >> +struct rule_pp_ctx;
>> >> +struct rule;
>> >> +
>> >> +#ifdef HAVE_LIBXTABLES
>> >> +
>> >> +#include <linux/netfilter_ipv4/ip_tables.h>
>> >> +#include <linux/netfilter_ipv6/ip6_tables.h>
>> >> +#include <linux/netfilter_arp/arp_tables.h>
>> >> +
>> >> +/* Fake ebt_entry */
>> >> +struct ebt_entry {
>> >
>> > I think you can avoid this if you:
>> >
>> > #include <linux/netfilter_bridge/ebtables.h>
>> >
>>
>> Can't include <linux/netfilter_bridge/ebtables.h> because it includes
>> <linux/if.h> and clash with <net/if.h>
>
> There must be a clean way to fix this without embedding the ebt_entry
> structure.
>

We seem to have the same problem in ebtables-compat:

http://git.netfilter.org/iptables/tree/iptables/nft-bridge.h#n32
-- 
Arturo Borrero González
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [nft PATCH 2/3] src: add xt compat support
  2015-03-27 12:59         ` Arturo Borrero Gonzalez
@ 2015-03-27 13:13           ` Pablo Neira Ayuso
  2015-03-27 13:14             ` Patrick McHardy
  0 siblings, 1 reply; 12+ messages in thread
From: Pablo Neira Ayuso @ 2015-03-27 13:13 UTC (permalink / raw)
  To: Arturo Borrero Gonzalez
  Cc: Netfilter Development Mailing list, Patrick McHardy

On Fri, Mar 27, 2015 at 01:59:31PM +0100, Arturo Borrero Gonzalez wrote:
> On 27 March 2015 at 13:31, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > On Fri, Mar 27, 2015 at 01:00:37PM +0100, Arturo Borrero Gonzalez wrote:
> >> On 25 March 2015 at 20:44, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> >> > On Wed, Mar 25, 2015 at 08:16:02PM +0100, Arturo Borrero Gonzalez wrote:
> >> >> diff --git a/include/xt.h b/include/xt.h
> >> >> new file mode 100644
> >> >> index 0000000..414f3d1
> >> >> --- /dev/null
> >> >> +++ b/include/xt.h
> >> >> @@ -0,0 +1,100 @@
> >> >> +#ifndef _NFT_XT_H_
> >> >> +#define _NFT_XT_H_
> >> >> +
> >> >> +#include <arpa/inet.h>
> >> >> +#include <netinet/in.h>
> >> >> +#include <limits.h>
> >> >> +#include <net/if.h>
> >> >> +#include <net/ethernet.h>
> >> >> +
> >> >> +struct netlink_linearize_ctx;
> >> >> +struct netlink_parse_ctx;
> >> >> +struct nft_rule_expr;
> >> >> +struct rule_pp_ctx;
> >> >> +struct rule;
> >> >> +
> >> >> +#ifdef HAVE_LIBXTABLES
> >> >> +
> >> >> +#include <linux/netfilter_ipv4/ip_tables.h>
> >> >> +#include <linux/netfilter_ipv6/ip6_tables.h>
> >> >> +#include <linux/netfilter_arp/arp_tables.h>
> >> >> +
> >> >> +/* Fake ebt_entry */
> >> >> +struct ebt_entry {
> >> >
> >> > I think you can avoid this if you:
> >> >
> >> > #include <linux/netfilter_bridge/ebtables.h>
> >> >
> >>
> >> Can't include <linux/netfilter_bridge/ebtables.h> because it includes
> >> <linux/if.h> and clash with <net/if.h>
> >
> > There must be a clean way to fix this without embedding the ebt_entry
> > structure.
> >
> 
> We seem to have the same problem in ebtables-compat:
> 
> http://git.netfilter.org/iptables/tree/iptables/nft-bridge.h#n32

Try to find a way to fix it there too ;-)

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [nft PATCH 2/3] src: add xt compat support
  2015-03-27 13:13           ` Pablo Neira Ayuso
@ 2015-03-27 13:14             ` Patrick McHardy
  2015-03-30 10:19               ` Arturo Borrero Gonzalez
  0 siblings, 1 reply; 12+ messages in thread
From: Patrick McHardy @ 2015-03-27 13:14 UTC (permalink / raw)
  To: Pablo Neira Ayuso
  Cc: Arturo Borrero Gonzalez, Netfilter Development Mailing list

On 27.03, Pablo Neira Ayuso wrote:
> On Fri, Mar 27, 2015 at 01:59:31PM +0100, Arturo Borrero Gonzalez wrote:
> > >> >> index 0000000..414f3d1
> > >> >> --- /dev/null
> > >> >> +++ b/include/xt.h
> > >> >> @@ -0,0 +1,100 @@
> > >> >> +#ifndef _NFT_XT_H_
> > >> >> +#define _NFT_XT_H_
> > >> >> +
> > >> >> +#include <net/if.h>
> > >> >> +
> > >> >> +/* Fake ebt_entry */
> > >> >> +struct ebt_entry {
> > >> >
> > >> > I think you can avoid this if you:
> > >> >
> > >> > #include <linux/netfilter_bridge/ebtables.h>
> > >>
> > >> Can't include <linux/netfilter_bridge/ebtables.h> because it includes
> > >> <linux/if.h> and clash with <net/if.h>
> > >
> > > There must be a clean way to fix this without embedding the ebt_entry
> > > structure.
> > 
> > We seem to have the same problem in ebtables-compat:
> > 
> > http://git.netfilter.org/iptables/tree/iptables/nft-bridge.h#n32
> 
> Try to find a way to fix it there too ;-)

Can't we switch to the linux includes? We're Linux only anyways :)

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [nft PATCH 2/3] src: add xt compat support
  2015-03-27 13:14             ` Patrick McHardy
@ 2015-03-30 10:19               ` Arturo Borrero Gonzalez
  0 siblings, 0 replies; 12+ messages in thread
From: Arturo Borrero Gonzalez @ 2015-03-30 10:19 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Netfilter Development Mailing list, Pablo Neira Ayuso

On 27 March 2015 at 14:14, Patrick McHardy <kaber@trash.net> wrote:
> On 27.03, Pablo Neira Ayuso wrote:
>> On Fri, Mar 27, 2015 at 01:59:31PM +0100, Arturo Borrero Gonzalez wrote:
>> > >> >> index 0000000..414f3d1
>> > >> >> --- /dev/null
>> > >> >> +++ b/include/xt.h
>> > >> >> @@ -0,0 +1,100 @@
>> > >> >> +#ifndef _NFT_XT_H_
>> > >> >> +#define _NFT_XT_H_
>> > >> >> +
>> > >> >> +#include <net/if.h>
>> > >> >> +
>> > >> >> +/* Fake ebt_entry */
>> > >> >> +struct ebt_entry {
>> > >> >
>> > >> > I think you can avoid this if you:
>> > >> >
>> > >> > #include <linux/netfilter_bridge/ebtables.h>
>> > >>
>> > >> Can't include <linux/netfilter_bridge/ebtables.h> because it includes
>> > >> <linux/if.h> and clash with <net/if.h>
>> > >
>> > > There must be a clean way to fix this without embedding the ebt_entry
>> > > structure.
>> >
>> > We seem to have the same problem in ebtables-compat:
>> >
>> > http://git.netfilter.org/iptables/tree/iptables/nft-bridge.h#n32
>>
>> Try to find a way to fix it there too ;-)
>
> Can't we switch to the linux includes? We're Linux only anyways :)

It doesn't seem to be that simple:
 * src/meta.c uses if_nametoindex() and if_indextoname() which are
defined in <net/if.h> and not in <linux/if.h>.
 * <xtables.h> uses <net/if.h> and replacing it leads to also touch
<include/libiptc/ipt_kernel_headers.h>

Should I workaround these two?

Could you please suggest any replacement for if_nametoindex() and
if_indextoname()?

regards

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

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2015-03-30 10:19 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-25 19:15 [nft PATCH 1/3] src: expose delinearize/linearize structures and stmt_error() Arturo Borrero Gonzalez
2015-03-25 19:16 ` [nft PATCH 2/3] src: add xt compat support Arturo Borrero Gonzalez
2015-03-25 19:44   ` Pablo Neira Ayuso
2015-03-27 12:00     ` Arturo Borrero Gonzalez
2015-03-27 12:31       ` Pablo Neira Ayuso
2015-03-27 12:31         ` Patrick McHardy
2015-03-27 12:59         ` Arturo Borrero Gonzalez
2015-03-27 13:13           ` Pablo Neira Ayuso
2015-03-27 13:14             ` Patrick McHardy
2015-03-30 10:19               ` Arturo Borrero Gonzalez
2015-03-25 19:16 ` [nft PATCH 3/3] tests: regression: add xt compat tests Arturo Borrero Gonzalez
2015-03-25 19:23 ` [nft PATCH 1/3] src: expose delinearize/linearize structures and stmt_error() Patrick McHardy

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.