All of lore.kernel.org
 help / color / mirror / Atom feed
* [iptables PATCH 00/12] Eliminate dedicated arptables-nft parser
@ 2021-09-27 15:03 Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 01/12] nft: Introduce builtin_tables_lookup() Phil Sutter
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: Phil Sutter @ 2021-09-27 15:03 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Commandline parsing was widely identical with iptables and ip6tables.
This series adds the necessary code-changes to unify the parsers into a
common one.

Phil Sutter (12):
  nft: Introduce builtin_tables_lookup()
  xshared: Store optstring in xtables_globals
  nft-shared: Introduce init_cs family ops callback
  xtables: Simplify addr_mask freeing
  nft: Add family ops callbacks wrapping different nft_cmd_* functions
  xtables-standalone: Drop version number from init errors
  libxtables: Introduce xtables_globals print_help callback
  arptables: Use standard data structures when parsing
  nft-arp: Introduce post_parse callback
  nft-shared: Make nft_check_xt_legacy() family agnostic
  xtables: Derive xtables_globals from family
  nft: Merge xtables-arp-standalone.c into xtables-standalone.c

 include/xtables.h                 |   2 +
 iptables/Makefile.am              |   2 +-
 iptables/nft-arp.c                | 252 +++++++++-
 iptables/nft-ipv4.c               |  93 ++++
 iptables/nft-ipv6.c               | 104 +++++
 iptables/nft-shared.c             |   5 +
 iptables/nft-shared.h             |  24 +
 iptables/nft.c                    |  19 +-
 iptables/nft.h                    |   2 +-
 iptables/xshared.h                |   2 +
 iptables/xtables-arp-standalone.c |  65 ---
 iptables/xtables-arp.c            | 749 +-----------------------------
 iptables/xtables-eb-translate.c   |   1 -
 iptables/xtables-eb.c             |   7 +-
 iptables/xtables-monitor.c        |   2 +-
 iptables/xtables-multi.h          |   3 +
 iptables/xtables-restore.c        |   9 +-
 iptables/xtables-save.c           |   6 +-
 iptables/xtables-standalone.c     |  54 ++-
 iptables/xtables-translate.c      |   7 +-
 iptables/xtables.c                | 268 +++--------
 21 files changed, 642 insertions(+), 1034 deletions(-)
 delete mode 100644 iptables/xtables-arp-standalone.c

-- 
2.33.0


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

* [iptables PATCH 01/12] nft: Introduce builtin_tables_lookup()
  2021-09-27 15:03 [iptables PATCH 00/12] Eliminate dedicated arptables-nft parser Phil Sutter
@ 2021-09-27 15:03 ` Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 02/12] xshared: Store optstring in xtables_globals Phil Sutter
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Phil Sutter @ 2021-09-27 15:03 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

The set of builtin tables to use is fully determined by the given family
so just look it up instead of having callers pass it explicitly.

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 iptables/nft.c                | 19 +++++++++++++++++--
 iptables/nft.h                |  2 +-
 iptables/xtables-arp.c        |  2 +-
 iptables/xtables-eb.c         |  2 +-
 iptables/xtables-monitor.c    |  2 +-
 iptables/xtables-restore.c    |  7 +------
 iptables/xtables-save.c       |  6 +-----
 iptables/xtables-standalone.c |  2 +-
 iptables/xtables-translate.c  |  7 +------
 9 files changed, 25 insertions(+), 24 deletions(-)

diff --git a/iptables/nft.c b/iptables/nft.c
index dc1f5160eb983..1d3f3a3da1cbb 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -863,7 +863,22 @@ int nft_restart(struct nft_handle *h)
 	return 0;
 }
 
-int nft_init(struct nft_handle *h, int family, const struct builtin_table *t)
+static const struct builtin_table *builtin_tables_lookup(int family)
+{
+	switch (family) {
+	case AF_INET:
+	case AF_INET6:
+		return xtables_ipv4;
+	case NFPROTO_ARP:
+		return xtables_arp;
+	case NFPROTO_BRIDGE:
+		return xtables_bridge;
+	default:
+		return NULL;
+	}
+}
+
+int nft_init(struct nft_handle *h, int family)
 {
 	memset(h, 0, sizeof(*h));
 
@@ -881,7 +896,7 @@ int nft_init(struct nft_handle *h, int family, const struct builtin_table *t)
 		xtables_error(PARAMETER_PROBLEM, "Unknown family");
 
 	h->portid = mnl_socket_get_portid(h->nl);
-	h->tables = t;
+	h->tables = builtin_tables_lookup(family);
 	h->cache = &h->__cache[0];
 	h->family = family;
 
diff --git a/iptables/nft.h b/iptables/nft.h
index ef79b018f7836..f189b03fbc6b9 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -123,7 +123,7 @@ extern const struct builtin_table xtables_bridge[NFT_TABLE_MAX];
 int mnl_talk(struct nft_handle *h, struct nlmsghdr *nlh,
 	     int (*cb)(const struct nlmsghdr *nlh, void *data),
 	     void *data);
-int nft_init(struct nft_handle *h, int family, const struct builtin_table *t);
+int nft_init(struct nft_handle *h, int family);
 void nft_fini(struct nft_handle *h);
 int nft_restart(struct nft_handle *h);
 
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 9a079f06b948a..1d132bdf23546 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -397,7 +397,7 @@ int nft_init_arp(struct nft_handle *h, const char *pname)
 	init_extensionsa();
 #endif
 
-	if (nft_init(h, NFPROTO_ARP, xtables_arp) < 0)
+	if (nft_init(h, NFPROTO_ARP) < 0)
 		xtables_error(OTHER_PROBLEM,
 			      "Could not initialize nftables layer.");
 
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
index 23023ce13e4b8..1ed6bcd8a7877 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -672,7 +672,7 @@ int nft_init_eb(struct nft_handle *h, const char *pname)
 	init_extensionsb();
 #endif
 
-	if (nft_init(h, NFPROTO_BRIDGE, xtables_bridge) < 0)
+	if (nft_init(h, NFPROTO_BRIDGE) < 0)
 		xtables_error(OTHER_PROBLEM,
 			      "Could not initialize nftables layer.");
 
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index 21d4bec08fd9a..73dc80c24d722 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -631,7 +631,7 @@ int xtables_monitor_main(int argc, char *argv[])
 	init_extensions6();
 #endif
 
-	if (nft_init(&h, AF_INET, xtables_ipv4)) {
+	if (nft_init(&h, AF_INET)) {
 		fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
 			xtables_globals.program_name,
 			xtables_globals.program_version,
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index 72832103d6bc3..86dcede395e07 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -281,7 +281,6 @@ void xtables_restore_parse(struct nft_handle *h,
 static int
 xtables_restore_main(int family, const char *progname, int argc, char *argv[])
 {
-	const struct builtin_table *tables;
 	struct nft_xt_restore_parse p = {
 		.commit = true,
 		.cb = &restore_cb,
@@ -360,7 +359,6 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
 	switch (family) {
 	case NFPROTO_IPV4:
 	case NFPROTO_IPV6: /* fallthough, same table */
-		tables = xtables_ipv4;
 #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
 		init_extensions();
 		init_extensions4();
@@ -368,17 +366,14 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
 #endif
 		break;
 	case NFPROTO_ARP:
-		tables = xtables_arp;
-		break;
 	case NFPROTO_BRIDGE:
-		tables = xtables_bridge;
 		break;
 	default:
 		fprintf(stderr, "Unknown family %d\n", family);
 		return 1;
 	}
 
-	if (nft_init(&h, family, tables) < 0) {
+	if (nft_init(&h, family) < 0) {
 		fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
 				xtables_globals.program_name,
 				xtables_globals.program_version,
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index f794e3ff1e318..c6ebb0ec94c4f 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -131,7 +131,6 @@ static int
 xtables_save_main(int family, int argc, char *argv[],
 		  const char *optstring, const struct option *longopts)
 {
-	const struct builtin_table *tables;
 	const char *tablename = NULL;
 	struct do_output_data d = {
 		.format = FMT_NOCOUNTS,
@@ -208,11 +207,9 @@ xtables_save_main(int family, int argc, char *argv[],
 		init_extensions4();
 		init_extensions6();
 #endif
-		tables = xtables_ipv4;
 		d.commit = true;
 		break;
 	case NFPROTO_ARP:
-		tables = xtables_arp;
 		break;
 	case NFPROTO_BRIDGE: {
 		const char *ctr = getenv("EBTABLES_SAVE_COUNTER");
@@ -223,7 +220,6 @@ xtables_save_main(int family, int argc, char *argv[],
 			d.format &= ~FMT_NOCOUNTS;
 			d.format |= FMT_C_COUNTS | FMT_EBT_SAVE;
 		}
-		tables = xtables_bridge;
 		break;
 	}
 	default:
@@ -231,7 +227,7 @@ xtables_save_main(int family, int argc, char *argv[],
 		return 1;
 	}
 
-	if (nft_init(&h, family, tables) < 0) {
+	if (nft_init(&h, family) < 0) {
 		fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
 				xtables_globals.program_name,
 				xtables_globals.program_version,
diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c
index 1a6b7cf73a4bb..f4d40cda6ae43 100644
--- a/iptables/xtables-standalone.c
+++ b/iptables/xtables-standalone.c
@@ -60,7 +60,7 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
 	init_extensions6();
 #endif
 
-	if (nft_init(&h, family, xtables_ipv4) < 0) {
+	if (nft_init(&h, family) < 0) {
 		fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
 				xtables_globals.program_name,
 				xtables_globals.program_version,
diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c
index 2a00a85088e2c..086b85d2f9cef 100644
--- a/iptables/xtables-translate.c
+++ b/iptables/xtables-translate.c
@@ -465,7 +465,6 @@ static int xtables_xlate_main_common(struct nft_handle *h,
 				     int family,
 				     const char *progname)
 {
-	const struct builtin_table *tables;
 	int ret;
 
 	xtables_globals.program_name = progname;
@@ -485,20 +484,16 @@ static int xtables_xlate_main_common(struct nft_handle *h,
 	init_extensions4();
 	init_extensions6();
 #endif
-		tables = xtables_ipv4;
 		break;
 	case NFPROTO_ARP:
-		tables = xtables_arp;
-		break;
 	case NFPROTO_BRIDGE:
-		tables = xtables_bridge;
 		break;
 	default:
 		fprintf(stderr, "Unknown family %d\n", family);
 		return 1;
 	}
 
-	if (nft_init(h, family, tables) < 0) {
+	if (nft_init(h, family) < 0) {
 		fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
 				xtables_globals.program_name,
 				xtables_globals.program_version,
-- 
2.33.0


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

* [iptables PATCH 02/12] xshared: Store optstring in xtables_globals
  2021-09-27 15:03 [iptables PATCH 00/12] Eliminate dedicated arptables-nft parser Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 01/12] nft: Introduce builtin_tables_lookup() Phil Sutter
@ 2021-09-27 15:03 ` Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 03/12] nft-shared: Introduce init_cs family ops callback Phil Sutter
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Phil Sutter @ 2021-09-27 15:03 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Preparing for a common option parser, store the string of options for
each family inside the respective xtables_globals object. The
array of long option definitions sitting in there already indicates it's
the right place.

While being at it, drop '-m' support from arptables-nft.

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 include/xtables.h      | 1 +
 iptables/xshared.h     | 2 ++
 iptables/xtables-arp.c | 4 ++--
 iptables/xtables-eb.c  | 5 +++--
 iptables/xtables.c     | 4 ++--
 5 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/include/xtables.h b/include/xtables.h
index e51f4bfda318a..c872a04220867 100644
--- a/include/xtables.h
+++ b/include/xtables.h
@@ -420,6 +420,7 @@ struct xtables_globals
 {
 	unsigned int option_offset;
 	const char *program_name, *program_version;
+	const char *optstring;
 	struct option *orig_opts;
 	struct option *opts;
 	void (*exit_err)(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
diff --git a/iptables/xshared.h b/iptables/xshared.h
index 823894f94b841..b59116ac49747 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -68,6 +68,8 @@ struct xtables_globals;
 struct xtables_rule_match;
 struct xtables_target;
 
+#define OPTSTRING_COMMON "-:A:C:D:E:F::I:L::M:N:P:VX::Z::" "c:d:i:j:o:p:s:t:"
+
 /* define invflags which won't collide with IPT ones */
 #define IPT_INV_SRCDEVADDR	0x0080
 #define IPT_INV_TGTDEVADDR	0x0100
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 1d132bdf23546..a028ac340cba0 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -100,6 +100,7 @@ extern void xtables_exit_error(enum xtables_exittype status, const char *msg, ..
 struct xtables_globals arptables_globals = {
 	.option_offset		= 0,
 	.program_version	= PACKAGE_VERSION,
+	.optstring		= OPTSTRING_COMMON "R:S::" "h::l:nv" /* "m:" */,
 	.orig_opts		= original_opts,
 	.exit_err		= xtables_exit_error,
 	.compat_rev		= nft_compatible_revision,
@@ -444,8 +445,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 	opterr = 0;
 
 	opts = xt_params->orig_opts;
-	while ((c = getopt_long(argc, argv,
-	   "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:l:i:vnt:m:c:",
+	while ((c = getopt_long(argc, argv, xt_params->optstring,
 					   opts, NULL)) != -1) {
 		switch (c) {
 			/*
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
index 1ed6bcd8a7877..3f58754d14cee 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -220,6 +220,7 @@ extern void xtables_exit_error(enum xtables_exittype status, const char *msg, ..
 struct xtables_globals ebtables_globals = {
 	.option_offset 		= 0,
 	.program_version	= PACKAGE_VERSION,
+	.optstring		= OPTSTRING_COMMON "h",
 	.orig_opts		= ebt_original_options,
 	.exit_err		= xtables_exit_error,
 	.compat_rev		= nft_compatible_revision,
@@ -732,8 +733,8 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
 	opterr = false;
 
 	/* Getopt saves the day */
-	while ((c = getopt_long(argc, argv,
-	   "-A:D:C:I:N:E:X::L::Z::F::P:Vhi:o:j:c:p:s:d:t:M:", opts, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, xt_params->optstring,
+					opts, NULL)) != -1) {
 		cs.c = c;
 		switch (c) {
 
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 0a700e0847400..c17cf7aec6178 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -89,6 +89,7 @@ void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __at
 struct xtables_globals xtables_globals = {
 	.option_offset = 0,
 	.program_version = PACKAGE_VERSION,
+	.optstring = OPTSTRING_COMMON "R:S::W::" "46bfg:h::m:nvw::x",
 	.orig_opts = original_opts,
 	.exit_err = xtables_exit_error,
 	.compat_rev = nft_compatible_revision,
@@ -455,8 +456,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
 	opterr = 0;
 
 	opts = xt_params->orig_opts;
-	while ((cs->c = getopt_long(argc, argv,
-	   "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvw::W::nt:m:xc:g:46",
+	while ((cs->c = getopt_long(argc, argv, xt_params->optstring,
 					   opts, NULL)) != -1) {
 		switch (cs->c) {
 			/*
-- 
2.33.0


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

* [iptables PATCH 03/12] nft-shared: Introduce init_cs family ops callback
  2021-09-27 15:03 [iptables PATCH 00/12] Eliminate dedicated arptables-nft parser Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 01/12] nft: Introduce builtin_tables_lookup() Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 02/12] xshared: Store optstring in xtables_globals Phil Sutter
@ 2021-09-27 15:03 ` Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 04/12] xtables: Simplify addr_mask freeing Phil Sutter
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Phil Sutter @ 2021-09-27 15:03 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Arptables sets a few defaults in struct iptables_command_state upon
initialization. Introduce a callback to do that.

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 iptables/nft-arp.c    |  9 +++++++++
 iptables/nft-shared.h |  1 +
 iptables/xtables.c    | 12 +++++++-----
 3 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 2a9387a18dffe..fbaf1a6d52184 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -546,6 +546,14 @@ static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy)
 	printf(":%s %s\n", chain, policy ?: "-");
 }
 
+static void nft_arp_init_cs(struct iptables_command_state *cs)
+{
+	cs->arp.arp.arhln = 6;
+	cs->arp.arp.arhln_mask = 255;
+	cs->arp.arp.arhrd = htons(ARPHRD_ETHER);
+	cs->arp.arp.arhrd_mask = 65535;
+}
+
 struct nft_family_ops nft_family_ops_arp = {
 	.add			= nft_arp_add,
 	.is_same		= nft_arp_is_same,
@@ -559,6 +567,7 @@ struct nft_family_ops nft_family_ops_arp = {
 	.save_chain		= nft_arp_save_chain,
 	.post_parse		= NULL,
 	.rule_to_cs		= nft_rule_to_iptables_command_state,
+	.init_cs		= nft_arp_init_cs,
 	.clear_cs		= nft_clear_iptables_command_state,
 	.parse_target		= nft_ipv46_parse_target,
 };
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index cc8f3a79b369e..71094a28e73de 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -106,6 +106,7 @@ struct nft_family_ops {
 			   struct xtables_args *args);
 	void (*parse_match)(struct xtables_match *m, void *data);
 	void (*parse_target)(struct xtables_target *t, void *data);
+	void (*init_cs)(struct iptables_command_state *cs);
 	void (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r,
 			   struct iptables_command_state *cs);
 	void (*clear_cs)(struct iptables_command_state *cs);
diff --git a/iptables/xtables.c b/iptables/xtables.c
index c17cf7aec6178..092edaaf89224 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -433,10 +433,6 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
 	bool invert = false;
 	int wait = 0;
 
-	memset(cs, 0, sizeof(*cs));
-	cs->jumpto = "";
-	cs->argv = argv;
-
 	/* re-set optind to 0 in case do_command4 gets called
 	 * a second time */
 	optind = 0;
@@ -912,11 +908,17 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
 		.table		= *table,
 		.restore	= restore,
 	};
-	struct iptables_command_state cs;
+	struct iptables_command_state cs = {
+		.jumpto = "",
+		.argv = argv,
+	};
 	struct xtables_args args = {
 		.family = h->family,
 	};
 
+	if (h->ops->init_cs)
+		h->ops->init_cs(&cs);
+
 	do_parse(h, argc, argv, &p, &cs, &args);
 
 	switch (p.command) {
-- 
2.33.0


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

* [iptables PATCH 04/12] xtables: Simplify addr_mask freeing
  2021-09-27 15:03 [iptables PATCH 00/12] Eliminate dedicated arptables-nft parser Phil Sutter
                   ` (2 preceding siblings ...)
  2021-09-27 15:03 ` [iptables PATCH 03/12] nft-shared: Introduce init_cs family ops callback Phil Sutter
@ 2021-09-27 15:03 ` Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 05/12] nft: Add family ops callbacks wrapping different nft_cmd_* functions Phil Sutter
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Phil Sutter @ 2021-09-27 15:03 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Introduce a generic 'ptr' union field to pass to free().

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 iptables/nft-shared.h |  2 ++
 iptables/xtables.c    | 15 ++++-----------
 2 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index 71094a28e73de..44ad0811f4081 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -177,6 +177,7 @@ struct addr_mask {
 	union {
 		struct in_addr	*v4;
 		struct in6_addr *v6;
+		void *ptr;
 	} addr;
 
 	unsigned int naddrs;
@@ -184,6 +185,7 @@ struct addr_mask {
 	union {
 		struct in_addr	*v4;
 		struct in6_addr *v6;
+		void *ptr;
 	} mask;
 };
 
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 092edaaf89224..f45e36086dcb8 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -1021,17 +1021,10 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
 
 	nft_clear_iptables_command_state(&cs);
 
-	if (h->family == AF_INET) {
-		free(args.s.addr.v4);
-		free(args.s.mask.v4);
-		free(args.d.addr.v4);
-		free(args.d.mask.v4);
-	} else if (h->family == AF_INET6) {
-		free(args.s.addr.v6);
-		free(args.s.mask.v6);
-		free(args.d.addr.v6);
-		free(args.d.mask.v6);
-	}
+	free(args.s.addr.ptr);
+	free(args.s.mask.ptr);
+	free(args.d.addr.ptr);
+	free(args.d.mask.ptr);
 	xtables_free_opts(1);
 
 	return ret;
-- 
2.33.0


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

* [iptables PATCH 05/12] nft: Add family ops callbacks wrapping different nft_cmd_* functions
  2021-09-27 15:03 [iptables PATCH 00/12] Eliminate dedicated arptables-nft parser Phil Sutter
                   ` (3 preceding siblings ...)
  2021-09-27 15:03 ` [iptables PATCH 04/12] xtables: Simplify addr_mask freeing Phil Sutter
@ 2021-09-27 15:03 ` Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 06/12] xtables-standalone: Drop version number from init errors Phil Sutter
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Phil Sutter @ 2021-09-27 15:03 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Commands supporting multiple source/destination addresses need to
iterate over them and call the respective nft_cmd_* function multiple
times. These loops are family-specific though as each family uses a
different data structure within struct iptables_command_state to store
the addresses.

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 iptables/nft-ipv4.c   |  93 +++++++++++++++++++++
 iptables/nft-ipv6.c   | 104 +++++++++++++++++++++++
 iptables/nft-shared.h |  18 ++++
 iptables/xtables.c    | 190 +++---------------------------------------
 4 files changed, 228 insertions(+), 177 deletions(-)

diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index 34f94bd8cc24a..febd7673af4f8 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -468,6 +468,95 @@ static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl)
 	return ret;
 }
 
+static int
+nft_ipv4_add_entry(struct nft_handle *h,
+		   const char *chain, const char *table,
+		   struct iptables_command_state *cs,
+		   struct xtables_args *args, bool verbose,
+		   bool append, int rulenum)
+{
+	unsigned int i, j;
+	int ret = 1;
+
+	for (i = 0; i < args->s.naddrs; i++) {
+		cs->fw.ip.src.s_addr = args->s.addr.v4[i].s_addr;
+		cs->fw.ip.smsk.s_addr = args->s.mask.v4[i].s_addr;
+		for (j = 0; j < args->d.naddrs; j++) {
+			cs->fw.ip.dst.s_addr = args->d.addr.v4[j].s_addr;
+			cs->fw.ip.dmsk.s_addr = args->d.mask.v4[j].s_addr;
+
+			if (append) {
+				ret = nft_cmd_rule_append(h, chain, table,
+						      cs, NULL, verbose);
+			} else {
+				ret = nft_cmd_rule_insert(h, chain, table,
+						      cs, rulenum, verbose);
+			}
+		}
+	}
+
+	return ret;
+}
+
+static int
+nft_ipv4_delete_entry(struct nft_handle *h,
+		      const char *chain, const char *table,
+		      struct iptables_command_state *cs,
+		      struct xtables_args *args, bool verbose)
+{
+	unsigned int i, j;
+	int ret = 1;
+
+	for (i = 0; i < args->s.naddrs; i++) {
+		cs->fw.ip.src.s_addr = args->s.addr.v4[i].s_addr;
+		cs->fw.ip.smsk.s_addr = args->s.mask.v4[i].s_addr;
+		for (j = 0; j < args->d.naddrs; j++) {
+			cs->fw.ip.dst.s_addr = args->d.addr.v4[j].s_addr;
+			cs->fw.ip.dmsk.s_addr = args->d.mask.v4[j].s_addr;
+			ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
+		}
+	}
+
+	return ret;
+}
+
+static int
+nft_ipv4_check_entry(struct nft_handle *h,
+		     const char *chain, const char *table,
+		     struct iptables_command_state *cs,
+		     struct xtables_args *args, bool verbose)
+{
+	unsigned int i, j;
+	int ret = 1;
+
+	for (i = 0; i < args->s.naddrs; i++) {
+		cs->fw.ip.src.s_addr = args->s.addr.v4[i].s_addr;
+		cs->fw.ip.smsk.s_addr = args->s.mask.v4[i].s_addr;
+		for (j = 0; j < args->d.naddrs; j++) {
+			cs->fw.ip.dst.s_addr = args->d.addr.v4[j].s_addr;
+			cs->fw.ip.dmsk.s_addr = args->d.mask.v4[j].s_addr;
+			ret = nft_cmd_rule_check(h, chain, table, cs, verbose);
+		}
+	}
+
+	return ret;
+}
+
+static int
+nft_ipv4_replace_entry(struct nft_handle *h,
+		       const char *chain, const char *table,
+		       struct iptables_command_state *cs,
+		       struct xtables_args *args, bool verbose,
+		       int rulenum)
+{
+	cs->fw.ip.src.s_addr = args->s.addr.v4->s_addr;
+	cs->fw.ip.dst.s_addr = args->d.addr.v4->s_addr;
+	cs->fw.ip.smsk.s_addr = args->s.mask.v4->s_addr;
+	cs->fw.ip.dmsk.s_addr = args->d.mask.v4->s_addr;
+
+	return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
+}
+
 struct nft_family_ops nft_family_ops_ipv4 = {
 	.add			= nft_ipv4_add,
 	.is_same		= nft_ipv4_is_same,
@@ -484,4 +573,8 @@ struct nft_family_ops nft_family_ops_ipv4 = {
 	.rule_to_cs		= nft_rule_to_iptables_command_state,
 	.clear_cs		= nft_clear_iptables_command_state,
 	.xlate			= nft_ipv4_xlate,
+	.add_entry		= nft_ipv4_add_entry,
+	.delete_entry		= nft_ipv4_delete_entry,
+	.check_entry		= nft_ipv4_check_entry,
+	.replace_entry		= nft_ipv4_replace_entry,
 };
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index d9c9400ad7dc3..f0e64bbd4ab23 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -410,6 +410,106 @@ static int nft_ipv6_xlate(const void *data, struct xt_xlate *xl)
 	return ret;
 }
 
+static int
+nft_ipv6_add_entry(struct nft_handle *h,
+		   const char *chain, const char *table,
+		   struct iptables_command_state *cs,
+		   struct xtables_args *args, bool verbose,
+		   bool append, int rulenum)
+{
+	unsigned int i, j;
+	int ret = 1;
+
+	for (i = 0; i < args->s.naddrs; i++) {
+		memcpy(&cs->fw6.ipv6.src,
+		       &args->s.addr.v6[i], sizeof(struct in6_addr));
+		memcpy(&cs->fw6.ipv6.smsk,
+		       &args->s.mask.v6[i], sizeof(struct in6_addr));
+		for (j = 0; j < args->d.naddrs; j++) {
+			memcpy(&cs->fw6.ipv6.dst,
+			       &args->d.addr.v6[j], sizeof(struct in6_addr));
+			memcpy(&cs->fw6.ipv6.dmsk,
+			       &args->d.mask.v6[j], sizeof(struct in6_addr));
+			if (append) {
+				ret = nft_cmd_rule_append(h, chain, table,
+						      cs, NULL, verbose);
+			} else {
+				ret = nft_cmd_rule_insert(h, chain, table,
+						      cs, rulenum, verbose);
+			}
+		}
+	}
+
+	return ret;
+}
+
+static int
+nft_ipv6_delete_entry(struct nft_handle *h,
+		      const char *chain, const char *table,
+		      struct iptables_command_state *cs,
+		      struct xtables_args *args, bool verbose)
+{
+	unsigned int i, j;
+	int ret = 1;
+
+	for (i = 0; i < args->s.naddrs; i++) {
+		memcpy(&cs->fw6.ipv6.src,
+		       &args->s.addr.v6[i], sizeof(struct in6_addr));
+		memcpy(&cs->fw6.ipv6.smsk,
+		       &args->s.mask.v6[i], sizeof(struct in6_addr));
+		for (j = 0; j < args->d.naddrs; j++) {
+			memcpy(&cs->fw6.ipv6.dst,
+			       &args->d.addr.v6[j], sizeof(struct in6_addr));
+			memcpy(&cs->fw6.ipv6.dmsk,
+			       &args->d.mask.v6[j], sizeof(struct in6_addr));
+			ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
+		}
+	}
+
+	return ret;
+}
+
+static int
+nft_ipv6_check_entry(struct nft_handle *h,
+		     const char *chain, const char *table,
+		     struct iptables_command_state *cs,
+		     struct xtables_args *args, bool verbose)
+{
+	unsigned int i, j;
+	int ret = 1;
+
+	for (i = 0; i < args->s.naddrs; i++) {
+		memcpy(&cs->fw6.ipv6.src,
+		       &args->s.addr.v6[i], sizeof(struct in6_addr));
+		memcpy(&cs->fw6.ipv6.smsk,
+		       &args->s.mask.v6[i], sizeof(struct in6_addr));
+		for (j = 0; j < args->d.naddrs; j++) {
+			memcpy(&cs->fw6.ipv6.dst,
+			       &args->d.addr.v6[j], sizeof(struct in6_addr));
+			memcpy(&cs->fw6.ipv6.dmsk,
+			       &args->d.mask.v6[j], sizeof(struct in6_addr));
+			ret = nft_cmd_rule_check(h, chain, table, cs, verbose);
+		}
+	}
+
+	return ret;
+}
+
+static int
+nft_ipv6_replace_entry(struct nft_handle *h,
+		       const char *chain, const char *table,
+		       struct iptables_command_state *cs,
+		       struct xtables_args *args, bool verbose,
+		       int rulenum)
+{
+	memcpy(&cs->fw6.ipv6.src, args->s.addr.v6, sizeof(struct in6_addr));
+	memcpy(&cs->fw6.ipv6.dst, args->d.addr.v6, sizeof(struct in6_addr));
+	memcpy(&cs->fw6.ipv6.smsk, args->s.mask.v6, sizeof(struct in6_addr));
+	memcpy(&cs->fw6.ipv6.dmsk, args->d.mask.v6, sizeof(struct in6_addr));
+
+	return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
+}
+
 struct nft_family_ops nft_family_ops_ipv6 = {
 	.add			= nft_ipv6_add,
 	.is_same		= nft_ipv6_is_same,
@@ -426,4 +526,8 @@ struct nft_family_ops nft_family_ops_ipv6 = {
 	.rule_to_cs		= nft_rule_to_iptables_command_state,
 	.clear_cs		= nft_clear_iptables_command_state,
 	.xlate			= nft_ipv6_xlate,
+	.add_entry		= nft_ipv6_add_entry,
+	.delete_entry		= nft_ipv6_delete_entry,
+	.check_entry		= nft_ipv6_check_entry,
+	.replace_entry		= nft_ipv6_replace_entry,
 };
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index 44ad0811f4081..cb1c3fffe63b4 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -111,6 +111,24 @@ struct nft_family_ops {
 			   struct iptables_command_state *cs);
 	void (*clear_cs)(struct iptables_command_state *cs);
 	int (*xlate)(const void *data, struct xt_xlate *xl);
+	int (*add_entry)(struct nft_handle *h,
+			 const char *chain, const char *table,
+			 struct iptables_command_state *cs,
+			 struct xtables_args *args, bool verbose,
+			 bool append, int rulenum);
+	int (*delete_entry)(struct nft_handle *h,
+			    const char *chain, const char *table,
+			    struct iptables_command_state *cs,
+			    struct xtables_args *args, bool verbose);
+	int (*check_entry)(struct nft_handle *h,
+			   const char *chain, const char *table,
+			   struct iptables_command_state *cs,
+			   struct xtables_args *args, bool verbose);
+	int (*replace_entry)(struct nft_handle *h,
+			     const char *chain, const char *table,
+			     struct iptables_command_state *cs,
+			     struct xtables_args *args, bool verbose,
+			     int rulenum);
 };
 
 void add_meta(struct nftnl_rule *r, uint32_t key);
diff --git a/iptables/xtables.c b/iptables/xtables.c
index f45e36086dcb8..9abfc8f8d7f32 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -223,168 +223,6 @@ xtables_exit_error(enum xtables_exittype status, const char *msg, ...)
 
 /* Christophe Burki wants `-p 6' to imply `-m tcp'.  */
 
-static int
-add_entry(const char *chain,
-	  const char *table,
-	  struct iptables_command_state *cs,
-	  int rulenum, int family,
-	  const struct addr_mask s,
-	  const struct addr_mask d,
-	  bool verbose, struct nft_handle *h, bool append)
-{
-	unsigned int i, j;
-	int ret = 1;
-
-	for (i = 0; i < s.naddrs; i++) {
-		if (family == AF_INET) {
-			cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr;
-			cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr;
-			for (j = 0; j < d.naddrs; j++) {
-				cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
-				cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
-
-				if (append) {
-					ret = nft_cmd_rule_append(h, chain, table,
-							      cs, NULL,
-							      verbose);
-				} else {
-					ret = nft_cmd_rule_insert(h, chain, table,
-							      cs, rulenum,
-							      verbose);
-				}
-			}
-		} else if (family == AF_INET6) {
-			memcpy(&cs->fw6.ipv6.src,
-			       &s.addr.v6[i], sizeof(struct in6_addr));
-			memcpy(&cs->fw6.ipv6.smsk,
-			       &s.mask.v6[i], sizeof(struct in6_addr));
-			for (j = 0; j < d.naddrs; j++) {
-				memcpy(&cs->fw6.ipv6.dst,
-				       &d.addr.v6[j], sizeof(struct in6_addr));
-				memcpy(&cs->fw6.ipv6.dmsk,
-				       &d.mask.v6[j], sizeof(struct in6_addr));
-				if (append) {
-					ret = nft_cmd_rule_append(h, chain, table,
-							      cs, NULL,
-							      verbose);
-				} else {
-					ret = nft_cmd_rule_insert(h, chain, table,
-							      cs, rulenum,
-							      verbose);
-				}
-			}
-		}
-	}
-
-	return ret;
-}
-
-static int
-replace_entry(const char *chain, const char *table,
-	      struct iptables_command_state *cs,
-	      unsigned int rulenum,
-	      int family,
-	      const struct addr_mask s,
-	      const struct addr_mask d,
-	      bool verbose, struct nft_handle *h)
-{
-	if (family == AF_INET) {
-		cs->fw.ip.src.s_addr = s.addr.v4->s_addr;
-		cs->fw.ip.dst.s_addr = d.addr.v4->s_addr;
-		cs->fw.ip.smsk.s_addr = s.mask.v4->s_addr;
-		cs->fw.ip.dmsk.s_addr = d.mask.v4->s_addr;
-	} else if (family == AF_INET6) {
-		memcpy(&cs->fw6.ipv6.src, s.addr.v6, sizeof(struct in6_addr));
-		memcpy(&cs->fw6.ipv6.dst, d.addr.v6, sizeof(struct in6_addr));
-		memcpy(&cs->fw6.ipv6.smsk, s.mask.v6, sizeof(struct in6_addr));
-		memcpy(&cs->fw6.ipv6.dmsk, d.mask.v6, sizeof(struct in6_addr));
-	} else
-		return 1;
-
-	return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
-}
-
-static int
-delete_entry(const char *chain, const char *table,
-	     struct iptables_command_state *cs,
-	     int family,
-	     const struct addr_mask s,
-	     const struct addr_mask d,
-	     bool verbose,
-	     struct nft_handle *h)
-{
-	unsigned int i, j;
-	int ret = 1;
-
-	for (i = 0; i < s.naddrs; i++) {
-		if (family == AF_INET) {
-			cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr;
-			cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr;
-			for (j = 0; j < d.naddrs; j++) {
-				cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
-				cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
-				ret = nft_cmd_rule_delete(h, chain,
-						      table, cs, verbose);
-			}
-		} else if (family == AF_INET6) {
-			memcpy(&cs->fw6.ipv6.src,
-			       &s.addr.v6[i], sizeof(struct in6_addr));
-			memcpy(&cs->fw6.ipv6.smsk,
-			       &s.mask.v6[i], sizeof(struct in6_addr));
-			for (j = 0; j < d.naddrs; j++) {
-				memcpy(&cs->fw6.ipv6.dst,
-				       &d.addr.v6[j], sizeof(struct in6_addr));
-				memcpy(&cs->fw6.ipv6.dmsk,
-				       &d.mask.v6[j], sizeof(struct in6_addr));
-				ret = nft_cmd_rule_delete(h, chain,
-						      table, cs, verbose);
-			}
-		}
-	}
-
-	return ret;
-}
-
-static int
-check_entry(const char *chain, const char *table,
-	    struct iptables_command_state *cs,
-	    int family,
-	    const struct addr_mask s,
-	    const struct addr_mask d,
-	    bool verbose, struct nft_handle *h)
-{
-	unsigned int i, j;
-	int ret = 1;
-
-	for (i = 0; i < s.naddrs; i++) {
-		if (family == AF_INET) {
-			cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr;
-			cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr;
-			for (j = 0; j < d.naddrs; j++) {
-				cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
-				cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
-				ret = nft_cmd_rule_check(h, chain,
-						     table, cs, verbose);
-			}
-		} else if (family == AF_INET6) {
-			memcpy(&cs->fw6.ipv6.src,
-			       &s.addr.v6[i], sizeof(struct in6_addr));
-			memcpy(&cs->fw6.ipv6.smsk,
-			       &s.mask.v6[i], sizeof(struct in6_addr));
-			for (j = 0; j < d.naddrs; j++) {
-				memcpy(&cs->fw6.ipv6.dst,
-				       &d.addr.v6[j], sizeof(struct in6_addr));
-				memcpy(&cs->fw6.ipv6.dmsk,
-				       &d.mask.v6[j], sizeof(struct in6_addr));
-				ret = nft_cmd_rule_check(h, chain,
-						     table, cs, verbose);
-			}
-		}
-	}
-
-	return ret;
-}
-
 static int
 list_entries(struct nft_handle *h, const char *chain, const char *table,
 	     int rulenum, int verbose, int numeric, int expanded,
@@ -923,33 +761,31 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
 
 	switch (p.command) {
 	case CMD_APPEND:
-		ret = add_entry(p.chain, p.table, &cs, 0, h->family,
-				args.s, args.d,
-				cs.options & OPT_VERBOSE, h, true);
+		ret = h->ops->add_entry(h, p.chain, p.table, &cs, &args,
+					cs.options & OPT_VERBOSE, true,
+					p.rulenum - 1);
 		break;
 	case CMD_DELETE:
-		ret = delete_entry(p.chain, p.table, &cs, h->family,
-				   args.s, args.d,
-				   cs.options & OPT_VERBOSE, h);
+		ret = h->ops->delete_entry(h, p.chain, p.table, &cs, &args,
+					   cs.options & OPT_VERBOSE);
 		break;
 	case CMD_DELETE_NUM:
 		ret = nft_cmd_rule_delete_num(h, p.chain, p.table,
 					      p.rulenum - 1, p.verbose);
 		break;
 	case CMD_CHECK:
-		ret = check_entry(p.chain, p.table, &cs, h->family,
-				  args.s, args.d,
-				  cs.options & OPT_VERBOSE, h);
+		ret = h->ops->check_entry(h, p.chain, p.table, &cs, &args,
+					  cs.options & OPT_VERBOSE);
 		break;
 	case CMD_REPLACE:
-		ret = replace_entry(p.chain, p.table, &cs, p.rulenum - 1,
-				    h->family, args.s, args.d,
-				    cs.options & OPT_VERBOSE, h);
+		ret = h->ops->replace_entry(h, p.chain, p.table, &cs, &args,
+					    cs.options & OPT_VERBOSE,
+					    p.rulenum - 1);
 		break;
 	case CMD_INSERT:
-		ret = add_entry(p.chain, p.table, &cs, p.rulenum - 1,
-				h->family, args.s, args.d,
-				cs.options&OPT_VERBOSE, h, false);
+		ret = h->ops->add_entry(h, p.chain, p.table, &cs, &args,
+					cs.options & OPT_VERBOSE, false,
+					p.rulenum - 1);
 		break;
 	case CMD_FLUSH:
 		ret = nft_cmd_rule_flush(h, p.chain, p.table,
-- 
2.33.0


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

* [iptables PATCH 06/12] xtables-standalone: Drop version number from init errors
  2021-09-27 15:03 [iptables PATCH 00/12] Eliminate dedicated arptables-nft parser Phil Sutter
                   ` (4 preceding siblings ...)
  2021-09-27 15:03 ` [iptables PATCH 05/12] nft: Add family ops callbacks wrapping different nft_cmd_* functions Phil Sutter
@ 2021-09-27 15:03 ` Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 07/12] libxtables: Introduce xtables_globals print_help callback Phil Sutter
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Phil Sutter @ 2021-09-27 15:03 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Aside from the rather unconventional formatting, if those initialization
functions fail we've either released a completely broken iptables or
the wrong libraries are chosen by the loader. In both cases, the version
number is not really interesting.

While being at it, fix indenting of the first exit() call.

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 iptables/xtables-standalone.c | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c
index f4d40cda6ae43..54c70c5429766 100644
--- a/iptables/xtables-standalone.c
+++ b/iptables/xtables-standalone.c
@@ -49,10 +49,8 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
 	xtables_globals.program_name = progname;
 	ret = xtables_init_all(&xtables_globals, family);
 	if (ret < 0) {
-		fprintf(stderr, "%s/%s Failed to initialize xtables\n",
-				xtables_globals.program_name,
-				xtables_globals.program_version);
-				exit(1);
+		fprintf(stderr, "%s: Failed to initialize xtables\n", progname);
+		exit(1);
 	}
 #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
 	init_extensions();
@@ -61,10 +59,8 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
 #endif
 
 	if (nft_init(&h, family) < 0) {
-		fprintf(stderr, "%s/%s Failed to initialize nft: %s\n",
-				xtables_globals.program_name,
-				xtables_globals.program_version,
-				strerror(errno));
+		fprintf(stderr, "%s: Failed to initialize nft: %s\n",
+			xtables_globals.program_name, strerror(errno));
 		exit(EXIT_FAILURE);
 	}
 
-- 
2.33.0


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

* [iptables PATCH 07/12] libxtables: Introduce xtables_globals print_help callback
  2021-09-27 15:03 [iptables PATCH 00/12] Eliminate dedicated arptables-nft parser Phil Sutter
                   ` (5 preceding siblings ...)
  2021-09-27 15:03 ` [iptables PATCH 06/12] xtables-standalone: Drop version number from init errors Phil Sutter
@ 2021-09-27 15:03 ` Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 08/12] arptables: Use standard data structures when parsing Phil Sutter
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Phil Sutter @ 2021-09-27 15:03 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

With optstring being stored in struct xtables_globals as well, it is a
natural choice to store a pointer to a help printer also which matches
the supported options.

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 include/xtables.h      | 1 +
 iptables/xtables-arp.c | 6 ++++--
 iptables/xtables.c     | 4 +++-
 3 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/include/xtables.h b/include/xtables.h
index c872a04220867..ca674c2663eb4 100644
--- a/include/xtables.h
+++ b/include/xtables.h
@@ -425,6 +425,7 @@ struct xtables_globals
 	struct option *opts;
 	void (*exit_err)(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
 	int (*compat_rev)(const char *name, uint8_t rev, int opt);
+	void (*print_help)(const struct xtables_rule_match *m);
 };
 
 #define XT_GETOPT_TABLEEND {.name = NULL, .has_arg = false}
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index a028ac340cba0..2e4bb3f2313c8 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -97,6 +97,7 @@ static struct option original_opts[] = {
 #define opts xt_params->opts
 
 extern void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
+static void printhelp(const struct xtables_rule_match *m);
 struct xtables_globals arptables_globals = {
 	.option_offset		= 0,
 	.program_version	= PACKAGE_VERSION,
@@ -104,6 +105,7 @@ struct xtables_globals arptables_globals = {
 	.orig_opts		= original_opts,
 	.exit_err		= xtables_exit_error,
 	.compat_rev		= nft_compatible_revision,
+	.print_help		= printhelp,
 };
 
 /***********************************************/
@@ -164,7 +166,7 @@ exit_tryhelp(int status)
 }
 
 static void
-printhelp(void)
+printhelp(const struct xtables_rule_match *m)
 {
 	struct xtables_target *t = NULL;
 	int i;
@@ -563,7 +565,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 			if (!optarg)
 				optarg = argv[optind];
 
-			printhelp();
+			xt_params->print_help(NULL);
 			command = CMD_NONE;
 			break;
 		case 's':
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 9abfc8f8d7f32..2b3cc9301c455 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -85,6 +85,7 @@ static struct option original_opts[] = {
 };
 
 void xtables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3)));
+static void printhelp(const struct xtables_rule_match *m);
 
 struct xtables_globals xtables_globals = {
 	.option_offset = 0,
@@ -93,6 +94,7 @@ struct xtables_globals xtables_globals = {
 	.orig_opts = original_opts,
 	.exit_err = xtables_exit_error,
 	.compat_rev = nft_compatible_revision,
+	.print_help = printhelp,
 };
 
 #define opts xt_params->opts
@@ -435,7 +437,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
 				xtables_find_match(cs->protocol,
 					XTF_TRY_LOAD, &cs->matches);
 
-			printhelp(cs->matches);
+			xt_params->print_help(cs->matches);
 			p->command = CMD_NONE;
 			return;
 
-- 
2.33.0


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

* [iptables PATCH 08/12] arptables: Use standard data structures when parsing
  2021-09-27 15:03 [iptables PATCH 00/12] Eliminate dedicated arptables-nft parser Phil Sutter
                   ` (6 preceding siblings ...)
  2021-09-27 15:03 ` [iptables PATCH 07/12] libxtables: Introduce xtables_globals print_help callback Phil Sutter
@ 2021-09-27 15:03 ` Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 09/12] nft-arp: Introduce post_parse callback Phil Sutter
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Phil Sutter @ 2021-09-27 15:03 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Use the compound data structures introduced for dedicated parsing
routines in other families instead of the many local variables. This
allows to standardize code a bit for sharing a common parser later.

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 iptables/xtables-arp.c | 280 ++++++++++++++++++++---------------------
 1 file changed, 138 insertions(+), 142 deletions(-)

diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 2e4bb3f2313c8..1075b6be74e98 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -419,17 +419,13 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 			.arhrd_mask = 65535,
 		},
 	};
+	struct nft_xt_cmd_parse p = {
+		.table = *table,
+	};
+	struct xtables_args args = {
+		.family = h->family,
+	};
 	int invert = 0;
-	unsigned int nsaddrs = 0, ndaddrs = 0;
-	struct in_addr *saddrs = NULL, *smasks = NULL;
-	struct in_addr *daddrs = NULL, *dmasks = NULL;
-
-	int c, verbose = 0;
-	const char *chain = NULL;
-	const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
-	const char *policy = NULL, *newname = NULL;
-	unsigned int rulenum = 0, options = 0, command = 0;
-	const char *pcnt = NULL, *bcnt = NULL;
 	int ret = 1;
 	struct xtables_target *t;
 
@@ -447,34 +443,34 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 	opterr = 0;
 
 	opts = xt_params->orig_opts;
-	while ((c = getopt_long(argc, argv, xt_params->optstring,
+	while ((cs.c = getopt_long(argc, argv, xt_params->optstring,
 					   opts, NULL)) != -1) {
-		switch (c) {
+		switch (cs.c) {
 			/*
 			 * Command selection
 			 */
 		case 'A':
-			add_command(&command, CMD_APPEND, CMD_NONE,
+			add_command(&p.command, CMD_APPEND, CMD_NONE,
 				    invert);
-			chain = optarg;
+			p.chain = optarg;
 			break;
 
 		case 'D':
-			add_command(&command, CMD_DELETE, CMD_NONE,
+			add_command(&p.command, CMD_DELETE, CMD_NONE,
 				    invert);
-			chain = optarg;
+			p.chain = optarg;
 			if (xs_has_arg(argc, argv)) {
-				rulenum = parse_rulenumber(argv[optind++]);
-				command = CMD_DELETE_NUM;
+				p.rulenum = parse_rulenumber(argv[optind++]);
+				p.command = CMD_DELETE_NUM;
 			}
 			break;
 
 		case 'R':
-			add_command(&command, CMD_REPLACE, CMD_NONE,
+			add_command(&p.command, CMD_REPLACE, CMD_NONE,
 				    invert);
-			chain = optarg;
+			p.chain = optarg;
 			if (xs_has_arg(argc, argv))
-				rulenum = parse_rulenumber(argv[optind++]);
+				p.rulenum = parse_rulenumber(argv[optind++]);
 			else
 				xtables_error(PARAMETER_PROBLEM,
 					      "-%c requires a rule number",
@@ -482,36 +478,36 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 			break;
 
 		case 'I':
-			add_command(&command, CMD_INSERT, CMD_NONE,
+			add_command(&p.command, CMD_INSERT, CMD_NONE,
 				    invert);
-			chain = optarg;
+			p.chain = optarg;
 			if (xs_has_arg(argc, argv))
-				rulenum = parse_rulenumber(argv[optind++]);
-			else rulenum = 1;
+				p.rulenum = parse_rulenumber(argv[optind++]);
+			else p.rulenum = 1;
 			break;
 
 		case 'L':
-			add_command(&command, CMD_LIST, CMD_ZERO,
+			add_command(&p.command, CMD_LIST, CMD_ZERO,
 				    invert);
-			if (optarg) chain = optarg;
+			if (optarg) p.chain = optarg;
 			else if (xs_has_arg(argc, argv))
-				chain = argv[optind++];
+				p.chain = argv[optind++];
 			break;
 
 		case 'F':
-			add_command(&command, CMD_FLUSH, CMD_NONE,
+			add_command(&p.command, CMD_FLUSH, CMD_NONE,
 				    invert);
-			if (optarg) chain = optarg;
+			if (optarg) p.chain = optarg;
 			else if (xs_has_arg(argc, argv))
-				chain = argv[optind++];
+				p.chain = argv[optind++];
 			break;
 
 		case 'Z':
-			add_command(&command, CMD_ZERO, CMD_LIST,
+			add_command(&p.command, CMD_ZERO, CMD_LIST,
 				    invert);
-			if (optarg) chain = optarg;
+			if (optarg) p.chain = optarg;
 			else if (xs_has_arg(argc, argv))
-				chain = argv[optind++];
+				p.chain = argv[optind++];
 			break;
 
 		case 'N':
@@ -523,25 +519,25 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 				xtables_error(PARAMETER_PROBLEM,
 						"chain name may not clash "
 						"with target name\n");
-			add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
+			add_command(&p.command, CMD_NEW_CHAIN, CMD_NONE,
 				    invert);
-			chain = optarg;
+			p.chain = optarg;
 			break;
 
 		case 'X':
-			add_command(&command, CMD_DELETE_CHAIN, CMD_NONE,
+			add_command(&p.command, CMD_DELETE_CHAIN, CMD_NONE,
 				    invert);
-			if (optarg) chain = optarg;
+			if (optarg) p.chain = optarg;
 			else if (xs_has_arg(argc, argv))
-				chain = argv[optind++];
+				p.chain = argv[optind++];
 			break;
 
 		case 'E':
-			add_command(&command, CMD_RENAME_CHAIN, CMD_NONE,
+			add_command(&p.command, CMD_RENAME_CHAIN, CMD_NONE,
 				    invert);
-			chain = optarg;
+			p.chain = optarg;
 			if (xs_has_arg(argc, argv))
-				newname = argv[optind++];
+				p.newname = argv[optind++];
 			else
 				xtables_error(PARAMETER_PROBLEM,
 					      "-%c requires old-chain-name and "
@@ -550,11 +546,11 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 			break;
 
 		case 'P':
-			add_command(&command, CMD_SET_POLICY, CMD_NONE,
+			add_command(&p.command, CMD_SET_POLICY, CMD_NONE,
 				    invert);
-			chain = optarg;
+			p.chain = optarg;
 			if (xs_has_arg(argc, argv))
-				policy = argv[optind++];
+				p.policy = argv[optind++];
 			else
 				xtables_error(PARAMETER_PROBLEM,
 					      "-%c requires a chain and a policy",
@@ -566,25 +562,25 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 				optarg = argv[optind];
 
 			xt_params->print_help(NULL);
-			command = CMD_NONE;
+			p.command = CMD_NONE;
 			break;
 		case 's':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&options, OPT_SOURCE, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_SOURCE, &cs.arp.arp.invflags,
 				   invert);
-			shostnetworkmask = argv[optind-1];
+			args.shostnetworkmask = argv[optind-1];
 			break;
 
 		case 'd':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&options, OPT_DESTINATION, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_DESTINATION, &cs.arp.arp.invflags,
 				   invert);
-			dhostnetworkmask = argv[optind-1];
+			args.dhostnetworkmask = argv[optind-1];
 			break;
 
 		case 2:/* src-mac */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&options, OPT_S_MAC, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_S_MAC, &cs.arp.arp.invflags,
 				   invert);
 			if (xtables_parse_mac_and_mask(argv[optind - 1],
 			    cs.arp.arp.src_devaddr.addr, cs.arp.arp.src_devaddr.mask))
@@ -594,7 +590,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 
 		case 3:/* dst-mac */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&options, OPT_D_MAC, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_D_MAC, &cs.arp.arp.invflags,
 				   invert);
 
 			if (xtables_parse_mac_and_mask(argv[optind - 1],
@@ -605,7 +601,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 
 		case 'l':/* hardware length */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&options, OPT_H_LENGTH, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_H_LENGTH, &cs.arp.arp.invflags,
 				   invert);
 			getlength_and_mask(argv[optind - 1], &cs.arp.arp.arhln,
 					   &cs.arp.arp.arhln_mask);
@@ -622,7 +618,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 			xtables_error(PARAMETER_PROBLEM, "not supported");
 		case 4:/* opcode */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&options, OPT_OPCODE, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_OPCODE, &cs.arp.arp.invflags,
 				   invert);
 			if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpop,
 					   &cs.arp.arp.arpop_mask, 10)) {
@@ -639,7 +635,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 
 		case 5:/* h-type */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&options, OPT_H_TYPE, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_H_TYPE, &cs.arp.arp.invflags,
 				   invert);
 			if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arhrd,
 					   &cs.arp.arp.arhrd_mask, 16)) {
@@ -651,7 +647,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 
 		case 6:/* proto-type */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&options, OPT_P_TYPE, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_P_TYPE, &cs.arp.arp.invflags,
 				   invert);
 			if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpro,
 					   &cs.arp.arp.arpro_mask, 0)) {
@@ -662,14 +658,14 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 			break;
 
 		case 'j':
-			set_option(&options, OPT_JUMP, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_JUMP, &cs.arp.arp.invflags,
 				   invert);
 			command_jump(&cs, optarg);
 			break;
 
 		case 'i':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&options, OPT_VIANAMEIN, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_VIANAMEIN, &cs.arp.arp.invflags,
 				   invert);
 			xtables_parse_interface(argv[optind-1],
 						cs.arp.arp.iniface,
@@ -678,7 +674,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 
 		case 'o':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&options, OPT_VIANAMEOUT, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_VIANAMEOUT, &cs.arp.arp.invflags,
 				   invert);
 			xtables_parse_interface(argv[optind-1],
 						cs.arp.arp.outiface,
@@ -686,16 +682,16 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 			break;
 
 		case 'v':
-			if (!verbose)
-				set_option(&options, OPT_VERBOSE,
+			if (!p.verbose)
+				set_option(&cs.options, OPT_VERBOSE,
 					   &cs.arp.arp.invflags, invert);
-			verbose++;
+			p.verbose++;
 			break;
 
 		case 'm': /* ignored by arptables-legacy */
 			break;
 		case 'n':
-			set_option(&options, OPT_NUMERIC, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_NUMERIC, &cs.arp.arp.invflags,
 				   invert);
 			break;
 
@@ -719,7 +715,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 			exit(0);
 
 		case '0':
-			set_option(&options, OPT_LINENUMBERS, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_LINENUMBERS, &cs.arp.arp.invflags,
 				   invert);
 			break;
 
@@ -729,22 +725,22 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 
 		case 'c':
 
-			set_option(&options, OPT_COUNTERS, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_COUNTERS, &cs.arp.arp.invflags,
 				   invert);
-			pcnt = optarg;
+			args.pcnt = optarg;
 			if (xs_has_arg(argc, argv))
-				bcnt = argv[optind++];
+				args.bcnt = argv[optind++];
 			else
 				xtables_error(PARAMETER_PROBLEM,
 					      "-%c requires packet and byte counter",
 					      opt2char(OPT_COUNTERS));
 
-			if (sscanf(pcnt, "%llu", &cs.arp.counters.pcnt) != 1)
+			if (sscanf(args.pcnt, "%llu", &cs.arp.counters.pcnt) != 1)
 			xtables_error(PARAMETER_PROBLEM,
 				"-%c packet counter not numeric",
 				opt2char(OPT_COUNTERS));
 
-			if (sscanf(bcnt, "%llu", &cs.arp.counters.bcnt) != 1)
+			if (sscanf(args.bcnt, "%llu", &cs.arp.counters.bcnt) != 1)
 				xtables_error(PARAMETER_PROBLEM,
 					      "-%c byte counter not numeric",
 					      opt2char(OPT_COUNTERS));
@@ -767,7 +763,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 
 		default:
 			if (cs.target) {
-				xtables_option_tpcall(c, argv,
+				xtables_option_tpcall(cs.c, argv,
 						      invert, cs.target, &cs.arp);
 			}
 			break;
@@ -785,127 +781,127 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 		xtables_error(PARAMETER_PROBLEM,
 			      "nothing appropriate following !");
 
-	if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
-		if (!(options & OPT_DESTINATION))
-			dhostnetworkmask = "0.0.0.0/0";
-		if (!(options & OPT_SOURCE))
-			shostnetworkmask = "0.0.0.0/0";
+	if (p.command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
+		if (!(cs.options & OPT_DESTINATION))
+			args.dhostnetworkmask = "0.0.0.0/0";
+		if (!(cs.options & OPT_SOURCE))
+			args.shostnetworkmask = "0.0.0.0/0";
 	}
 
-	if (shostnetworkmask)
-		xtables_ipparse_multiple(shostnetworkmask, &saddrs,
-					 &smasks, &nsaddrs);
+	if (args.shostnetworkmask)
+		xtables_ipparse_multiple(args.shostnetworkmask, &args.s.addr.v4,
+					 &args.s.mask.v4, &args.s.naddrs);
 
-	if (dhostnetworkmask)
-		xtables_ipparse_multiple(dhostnetworkmask, &daddrs,
-					 &dmasks, &ndaddrs);
+	if (args.dhostnetworkmask)
+		xtables_ipparse_multiple(args.dhostnetworkmask, &args.d.addr.v4,
+					 &args.d.mask.v4, &args.d.naddrs);
 
-	if ((nsaddrs > 1 || ndaddrs > 1) &&
+	if ((args.s.naddrs > 1 || args.d.naddrs > 1) &&
 	    (cs.arp.arp.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
 		xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
 				" source or destination IP addresses");
 
-	if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
+	if (p.command == CMD_REPLACE && (args.s.naddrs != 1 || args.d.naddrs != 1))
 		xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
 						 "specify a unique address");
 
-	if (chain && strlen(chain) > ARPT_FUNCTION_MAXNAMELEN)
+	if (p.chain && strlen(p.chain) > ARPT_FUNCTION_MAXNAMELEN)
 		xtables_error(PARAMETER_PROBLEM,
 				"chain name `%s' too long (must be under %i chars)",
-				chain, ARPT_FUNCTION_MAXNAMELEN);
-
-	if (command == CMD_APPEND
-	    || command == CMD_DELETE
-	    || command == CMD_INSERT
-	    || command == CMD_REPLACE) {
-		if (strcmp(chain, "PREROUTING") == 0
-		    || strcmp(chain, "INPUT") == 0) {
+				p.chain, ARPT_FUNCTION_MAXNAMELEN);
+
+	if (p.command == CMD_APPEND
+	    || p.command == CMD_DELETE
+	    || p.command == CMD_INSERT
+	    || p.command == CMD_REPLACE) {
+		if (strcmp(p.chain, "PREROUTING") == 0
+		    || strcmp(p.chain, "INPUT") == 0) {
 			/* -o not valid with incoming packets. */
-			if (options & OPT_VIANAMEOUT)
+			if (cs.options & OPT_VIANAMEOUT)
 				xtables_error(PARAMETER_PROBLEM,
 					      "Can't use -%c with %s\n",
 					      opt2char(OPT_VIANAMEOUT),
-					      chain);
+					      p.chain);
 		}
 
-		if (strcmp(chain, "POSTROUTING") == 0
-		    || strcmp(chain, "OUTPUT") == 0) {
+		if (strcmp(p.chain, "POSTROUTING") == 0
+		    || strcmp(p.chain, "OUTPUT") == 0) {
 			/* -i not valid with outgoing packets */
-			if (options & OPT_VIANAMEIN)
+			if (cs.options & OPT_VIANAMEIN)
 				xtables_error(PARAMETER_PROBLEM,
 						"Can't use -%c with %s\n",
 						opt2char(OPT_VIANAMEIN),
-						chain);
+						p.chain);
 		}
 	}
 
-	switch (command) {
+	switch (p.command) {
 	case CMD_APPEND:
-		ret = append_entry(h, chain, *table, &cs, 0,
-				   nsaddrs, saddrs, smasks,
-				   ndaddrs, daddrs, dmasks,
-				   options&OPT_VERBOSE, true);
+		ret = append_entry(h, p.chain, p.table, &cs, 0,
+				   args.s.naddrs, args.s.addr.v4, args.s.mask.v4,
+				   args.d.naddrs, args.d.addr.v4, args.d.mask.v4,
+				   cs.options&OPT_VERBOSE, true);
 		break;
 	case CMD_DELETE:
-		ret = delete_entry(chain, *table, &cs,
-				   nsaddrs, saddrs, smasks,
-				   ndaddrs, daddrs, dmasks,
-				   options&OPT_VERBOSE, h);
+		ret = delete_entry(p.chain, p.table, &cs,
+				   args.s.naddrs, args.s.addr.v4, args.s.mask.v4,
+				   args.d.naddrs, args.d.addr.v4, args.d.mask.v4,
+				   cs.options&OPT_VERBOSE, h);
 		break;
 	case CMD_DELETE_NUM:
-		ret = nft_cmd_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
+		ret = nft_cmd_rule_delete_num(h, p.chain, p.table, p.rulenum - 1, p.verbose);
 		break;
 	case CMD_REPLACE:
-		ret = replace_entry(chain, *table, &cs, rulenum - 1,
-				    saddrs, smasks, daddrs, dmasks,
-				    options&OPT_VERBOSE, h);
+		ret = replace_entry(p.chain, p.table, &cs, p.rulenum - 1,
+				    args.s.addr.v4, args.s.mask.v4, args.d.addr.v4, args.d.mask.v4,
+				    cs.options&OPT_VERBOSE, h);
 		break;
 	case CMD_INSERT:
-		ret = append_entry(h, chain, *table, &cs, rulenum - 1,
-				   nsaddrs, saddrs, smasks,
-				   ndaddrs, daddrs, dmasks,
-				   options&OPT_VERBOSE, false);
+		ret = append_entry(h, p.chain, p.table, &cs, p.rulenum - 1,
+				   args.s.naddrs, args.s.addr.v4, args.s.mask.v4,
+				   args.d.naddrs, args.d.addr.v4, args.d.mask.v4,
+				   cs.options&OPT_VERBOSE, false);
 		break;
 	case CMD_LIST:
-		ret = list_entries(h, chain, *table,
-				   rulenum,
-				   options&OPT_VERBOSE,
-				   options&OPT_NUMERIC,
-				   /*options&OPT_EXPANDED*/0,
-				   options&OPT_LINENUMBERS);
+		ret = list_entries(h, p.chain, p.table,
+				   p.rulenum,
+				   cs.options&OPT_VERBOSE,
+				   cs.options&OPT_NUMERIC,
+				   /*cs.options&OPT_EXPANDED*/0,
+				   cs.options&OPT_LINENUMBERS);
 		break;
 	case CMD_FLUSH:
-		ret = nft_cmd_rule_flush(h, chain, *table, options & OPT_VERBOSE);
+		ret = nft_cmd_rule_flush(h, p.chain, p.table, cs.options & OPT_VERBOSE);
 		break;
 	case CMD_ZERO:
-		ret = nft_cmd_chain_zero_counters(h, chain, *table,
-					      options & OPT_VERBOSE);
+		ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
+					      cs.options & OPT_VERBOSE);
 		break;
 	case CMD_LIST|CMD_ZERO:
-		ret = list_entries(h, chain, *table, rulenum,
-				   options&OPT_VERBOSE,
-				   options&OPT_NUMERIC,
-				   /*options&OPT_EXPANDED*/0,
-				   options&OPT_LINENUMBERS);
+		ret = list_entries(h, p.chain, p.table, p.rulenum,
+				   cs.options&OPT_VERBOSE,
+				   cs.options&OPT_NUMERIC,
+				   /*cs.options&OPT_EXPANDED*/0,
+				   cs.options&OPT_LINENUMBERS);
 		if (ret)
-			ret = nft_cmd_chain_zero_counters(h, chain, *table,
-						      options & OPT_VERBOSE);
+			ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
+						      cs.options & OPT_VERBOSE);
 		break;
 	case CMD_NEW_CHAIN:
-		ret = nft_cmd_chain_user_add(h, chain, *table);
+		ret = nft_cmd_chain_user_add(h, p.chain, p.table);
 		break;
 	case CMD_DELETE_CHAIN:
-		ret = nft_cmd_chain_del(h, chain, *table,
-					options & OPT_VERBOSE);
+		ret = nft_cmd_chain_del(h, p.chain, p.table,
+					cs.options & OPT_VERBOSE);
 		break;
 	case CMD_RENAME_CHAIN:
-		ret = nft_cmd_chain_user_rename(h, chain, *table, newname);
+		ret = nft_cmd_chain_user_rename(h, p.chain, p.table, p.newname);
 		break;
 	case CMD_SET_POLICY:
-		ret = nft_cmd_chain_set(h, *table, chain, policy, NULL);
+		ret = nft_cmd_chain_set(h, p.table, p.chain, p.policy, NULL);
 		if (ret < 0)
 			xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n",
-				      policy);
+				      p.policy);
 		break;
 	case CMD_NONE:
 		break;
@@ -914,15 +910,15 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 		exit_tryhelp(2);
 	}
 
-	free(saddrs);
-	free(smasks);
-	free(daddrs);
-	free(dmasks);
+	free(args.s.addr.v4);
+	free(args.s.mask.v4);
+	free(args.d.addr.v4);
+	free(args.d.mask.v4);
 
 	nft_clear_iptables_command_state(&cs);
 	xtables_free_opts(1);
 
-/*	if (verbose > 1)
+/*	if (p.verbose > 1)
 		dump_entries(*handle);*/
 
 	return ret;
-- 
2.33.0


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

* [iptables PATCH 09/12] nft-arp: Introduce post_parse callback
  2021-09-27 15:03 [iptables PATCH 00/12] Eliminate dedicated arptables-nft parser Phil Sutter
                   ` (7 preceding siblings ...)
  2021-09-27 15:03 ` [iptables PATCH 08/12] arptables: Use standard data structures when parsing Phil Sutter
@ 2021-09-27 15:03 ` Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 10/12] nft-shared: Make nft_check_xt_legacy() family agnostic Phil Sutter
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Phil Sutter @ 2021-09-27 15:03 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

This accomplishes the same tasks as e.g. nft_ipv4_post_parse() plus some
arptables-specific bits.

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 iptables/nft-arp.c     | 150 +++++++++++++++++++++++++++++++++++++++-
 iptables/nft-shared.h  |   3 +
 iptables/xtables-arp.c | 153 +++++++----------------------------------
 3 files changed, 178 insertions(+), 128 deletions(-)

diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index fbaf1a6d52184..b37ffbb592023 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -546,6 +546,154 @@ static void nft_arp_save_chain(const struct nftnl_chain *c, const char *policy)
 	printf(":%s %s\n", chain, policy ?: "-");
 }
 
+static int getlength_and_mask(const char *from, uint8_t *to, uint8_t *mask)
+{
+	char *dup = strdup(from);
+	char *p, *buffer;
+	int i, ret = -1;
+
+	if (!dup)
+		return -1;
+
+	if ( (p = strrchr(dup, '/')) != NULL) {
+		*p = '\0';
+		i = strtol(p+1, &buffer, 10);
+		if (*buffer != '\0' || i < 0 || i > 255)
+			goto out_err;
+		*mask = (uint8_t)i;
+	} else
+		*mask = 255;
+	i = strtol(dup, &buffer, 10);
+	if (*buffer != '\0' || i < 0 || i > 255)
+		goto out_err;
+	*to = (uint8_t)i;
+	ret = 0;
+out_err:
+	free(dup);
+	return ret;
+
+}
+
+static int get16_and_mask(const char *from, uint16_t *to,
+			  uint16_t *mask, int base)
+{
+	char *dup = strdup(from);
+	char *p, *buffer;
+	int i, ret = -1;
+
+	if (!dup)
+		return -1;
+
+	if ( (p = strrchr(dup, '/')) != NULL) {
+		*p = '\0';
+		i = strtol(p+1, &buffer, base);
+		if (*buffer != '\0' || i < 0 || i > 65535)
+			goto out_err;
+		*mask = htons((uint16_t)i);
+	} else
+		*mask = 65535;
+	i = strtol(dup, &buffer, base);
+	if (*buffer != '\0' || i < 0 || i > 65535)
+		goto out_err;
+	*to = htons((uint16_t)i);
+	ret = 0;
+out_err:
+	free(dup);
+	return ret;
+}
+
+static void nft_arp_post_parse(int command,
+			       struct iptables_command_state *cs,
+			       struct xtables_args *args)
+{
+	cs->arp.arp.invflags = args->invflags;
+
+	memcpy(cs->arp.arp.iniface, args->iniface, IFNAMSIZ);
+	memcpy(cs->arp.arp.iniface_mask, args->iniface_mask, IFNAMSIZ);
+
+	memcpy(cs->arp.arp.outiface, args->outiface, IFNAMSIZ);
+	memcpy(cs->arp.arp.outiface_mask, args->outiface_mask, IFNAMSIZ);
+
+	cs->arp.counters.pcnt = args->pcnt_cnt;
+	cs->arp.counters.bcnt = args->bcnt_cnt;
+
+	if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
+		if (!(cs->options & OPT_DESTINATION))
+			args->dhostnetworkmask = "0.0.0.0/0";
+		if (!(cs->options & OPT_SOURCE))
+			args->shostnetworkmask = "0.0.0.0/0";
+	}
+
+	if (args->shostnetworkmask)
+		xtables_ipparse_multiple(args->shostnetworkmask,
+					 &args->s.addr.v4, &args->s.mask.v4,
+					 &args->s.naddrs);
+	if (args->dhostnetworkmask)
+		xtables_ipparse_multiple(args->dhostnetworkmask,
+					 &args->d.addr.v4, &args->d.mask.v4,
+					 &args->d.naddrs);
+
+	if ((args->s.naddrs > 1 || args->d.naddrs > 1) &&
+	    (cs->arp.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP)))
+		xtables_error(PARAMETER_PROBLEM,
+			      "! not allowed with multiple"
+			      " source or destination IP addresses");
+
+	if (args->src_mac &&
+	    xtables_parse_mac_and_mask(args->src_mac,
+				       cs->arp.arp.src_devaddr.addr,
+				       cs->arp.arp.src_devaddr.mask))
+		xtables_error(PARAMETER_PROBLEM,
+			      "Problem with specified source mac");
+	if (args->dst_mac &&
+	    xtables_parse_mac_and_mask(args->dst_mac,
+				       cs->arp.arp.tgt_devaddr.addr,
+				       cs->arp.arp.tgt_devaddr.mask))
+		xtables_error(PARAMETER_PROBLEM,
+			      "Problem with specified destination mac");
+	if (args->arp_hlen) {
+		getlength_and_mask(args->arp_hlen, &cs->arp.arp.arhln,
+				   &cs->arp.arp.arhln_mask);
+
+		if (cs->arp.arp.arhln != 6)
+			xtables_error(PARAMETER_PROBLEM,
+				      "Only harware address length of 6 is supported currently.");
+	}
+	if (args->arp_opcode) {
+		if (get16_and_mask(args->arp_opcode, &cs->arp.arp.arpop,
+				   &cs->arp.arp.arpop_mask, 10)) {
+			int i;
+
+			for (i = 0; i < NUMOPCODES; i++)
+				if (!strcasecmp(arp_opcodes[i],
+						args->arp_opcode))
+					break;
+			if (i == NUMOPCODES)
+				xtables_error(PARAMETER_PROBLEM,
+					      "Problem with specified opcode");
+			cs->arp.arp.arpop = htons(i+1);
+		}
+	}
+	if (args->arp_htype) {
+		if (get16_and_mask(args->arp_htype, &cs->arp.arp.arhrd,
+				   &cs->arp.arp.arhrd_mask, 16)) {
+			if (strcasecmp(args->arp_htype, "Ethernet"))
+				xtables_error(PARAMETER_PROBLEM,
+					      "Problem with specified hardware type");
+			cs->arp.arp.arhrd = htons(1);
+		}
+	}
+	if (args->arp_ptype) {
+		if (get16_and_mask(args->arp_ptype, &cs->arp.arp.arpro,
+				   &cs->arp.arp.arpro_mask, 0)) {
+			if (strcasecmp(args->arp_ptype, "ipv4"))
+				xtables_error(PARAMETER_PROBLEM,
+					      "Problem with specified protocol type");
+			cs->arp.arp.arpro = htons(0x800);
+		}
+	}
+}
+
 static void nft_arp_init_cs(struct iptables_command_state *cs)
 {
 	cs->arp.arp.arhln = 6;
@@ -565,7 +713,7 @@ struct nft_family_ops nft_family_ops_arp = {
 	.print_rule		= nft_arp_print_rule,
 	.save_rule		= nft_arp_save_rule,
 	.save_chain		= nft_arp_save_chain,
-	.post_parse		= NULL,
+	.post_parse		= nft_arp_post_parse,
 	.rule_to_cs		= nft_rule_to_iptables_command_state,
 	.init_cs		= nft_arp_init_cs,
 	.clear_cs		= nft_clear_iptables_command_state,
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index cb1c3fffe63b4..339c46e7f5b06 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -218,6 +218,9 @@ struct xtables_args {
 	const char	*shostnetworkmask, *dhostnetworkmask;
 	const char	*pcnt, *bcnt;
 	struct addr_mask s, d;
+	const char	*src_mac, *dst_mac;
+	const char	*arp_hlen, *arp_opcode;
+	const char	*arp_htype, *arp_ptype;
 	unsigned long long pcnt_cnt, bcnt_cnt;
 };
 
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 1075b6be74e98..de7c381788a37 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -108,54 +108,6 @@ struct xtables_globals arptables_globals = {
 	.print_help		= printhelp,
 };
 
-/***********************************************/
-/* ARPTABLES SPECIFIC NEW FUNCTIONS ADDED HERE */
-/***********************************************/
-
-static int getlength_and_mask(char *from, uint8_t *to, uint8_t *mask)
-{
-	char *p, *buffer;
-	int i;
-
-	if ( (p = strrchr(from, '/')) != NULL) {
-		*p = '\0';
-		i = strtol(p+1, &buffer, 10);
-		if (*buffer != '\0' || i < 0 || i > 255)
-			return -1;
-		*mask = (uint8_t)i;
-	} else
-		*mask = 255;
-	i = strtol(from, &buffer, 10);
-	if (*buffer != '\0' || i < 0 || i > 255)
-		return -1;
-	*to = (uint8_t)i;
-	return 0;
-}
-
-static int get16_and_mask(char *from, uint16_t *to, uint16_t *mask, int base)
-{
-	char *p, *buffer;
-	int i;
-
-	if ( (p = strrchr(from, '/')) != NULL) {
-		*p = '\0';
-		i = strtol(p+1, &buffer, base);
-		if (*buffer != '\0' || i < 0 || i > 65535)
-			return -1;
-		*mask = htons((uint16_t)i);
-	} else
-		*mask = 65535;
-	i = strtol(from, &buffer, base);
-	if (*buffer != '\0' || i < 0 || i > 65535)
-		return -1;
-	*to = htons((uint16_t)i);
-	return 0;
-}
-
-/*********************************************/
-/* ARPTABLES SPECIFIC NEW FUNCTIONS END HERE */
-/*********************************************/
-
 static void
 exit_tryhelp(int status)
 {
@@ -566,132 +518,97 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 			break;
 		case 's':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_SOURCE, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_SOURCE, &args.invflags,
 				   invert);
 			args.shostnetworkmask = argv[optind-1];
 			break;
 
 		case 'd':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_DESTINATION, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_DESTINATION, &args.invflags,
 				   invert);
 			args.dhostnetworkmask = argv[optind-1];
 			break;
 
 		case 2:/* src-mac */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_S_MAC, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_S_MAC, &args.invflags,
 				   invert);
-			if (xtables_parse_mac_and_mask(argv[optind - 1],
-			    cs.arp.arp.src_devaddr.addr, cs.arp.arp.src_devaddr.mask))
-				xtables_error(PARAMETER_PROBLEM, "Problem with specified "
-						"source mac");
+			args.src_mac = argv[optind - 1];
 			break;
 
 		case 3:/* dst-mac */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_D_MAC, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_D_MAC, &args.invflags,
 				   invert);
-
-			if (xtables_parse_mac_and_mask(argv[optind - 1],
-			    cs.arp.arp.tgt_devaddr.addr, cs.arp.arp.tgt_devaddr.mask))
-				xtables_error(PARAMETER_PROBLEM, "Problem with specified "
-						"destination mac");
+			args.dst_mac = argv[optind - 1];
 			break;
 
 		case 'l':/* hardware length */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_H_LENGTH, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_H_LENGTH, &args.invflags,
 				   invert);
-			getlength_and_mask(argv[optind - 1], &cs.arp.arp.arhln,
-					   &cs.arp.arp.arhln_mask);
-
-			if (cs.arp.arp.arhln != 6) {
-				xtables_error(PARAMETER_PROBLEM,
-					      "Only harware address length of"
-					      " 6 is supported currently.");
-			}
-
+			args.arp_hlen = argv[optind - 1];
 			break;
 
 		case 8: /* was never supported, not even in arptables-legacy */
 			xtables_error(PARAMETER_PROBLEM, "not supported");
 		case 4:/* opcode */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_OPCODE, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_OPCODE, &args.invflags,
 				   invert);
-			if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpop,
-					   &cs.arp.arp.arpop_mask, 10)) {
-				int i;
-
-				for (i = 0; i < NUMOPCODES; i++)
-					if (!strcasecmp(arp_opcodes[i], optarg))
-						break;
-				if (i == NUMOPCODES)
-					xtables_error(PARAMETER_PROBLEM, "Problem with specified opcode");
-				cs.arp.arp.arpop = htons(i+1);
-			}
+			args.arp_opcode = argv[optind - 1];
 			break;
 
 		case 5:/* h-type */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_H_TYPE, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_H_TYPE, &args.invflags,
 				   invert);
-			if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arhrd,
-					   &cs.arp.arp.arhrd_mask, 16)) {
-				if (strcasecmp(argv[optind-1], "Ethernet"))
-					xtables_error(PARAMETER_PROBLEM, "Problem with specified hardware type");
-				cs.arp.arp.arhrd = htons(1);
-			}
+			args.arp_htype = argv[optind - 1];
 			break;
 
 		case 6:/* proto-type */
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_P_TYPE, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_P_TYPE, &args.invflags,
 				   invert);
-			if (get16_and_mask(argv[optind - 1], &cs.arp.arp.arpro,
-					   &cs.arp.arp.arpro_mask, 0)) {
-				if (strcasecmp(argv[optind-1], "ipv4"))
-					xtables_error(PARAMETER_PROBLEM, "Problem with specified protocol type");
-				cs.arp.arp.arpro = htons(0x800);
-			}
+			args.arp_ptype = argv[optind - 1];
 			break;
 
 		case 'j':
-			set_option(&cs.options, OPT_JUMP, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_JUMP, &args.invflags,
 				   invert);
 			command_jump(&cs, optarg);
 			break;
 
 		case 'i':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_VIANAMEIN, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_VIANAMEIN, &args.invflags,
 				   invert);
 			xtables_parse_interface(argv[optind-1],
-						cs.arp.arp.iniface,
-						cs.arp.arp.iniface_mask);
+						args.iniface,
+						args.iniface_mask);
 			break;
 
 		case 'o':
 			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_VIANAMEOUT, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_VIANAMEOUT, &args.invflags,
 				   invert);
 			xtables_parse_interface(argv[optind-1],
-						cs.arp.arp.outiface,
-						cs.arp.arp.outiface_mask);
+						args.outiface,
+						args.outiface_mask);
 			break;
 
 		case 'v':
 			if (!p.verbose)
 				set_option(&cs.options, OPT_VERBOSE,
-					   &cs.arp.arp.invflags, invert);
+					   &args.invflags, invert);
 			p.verbose++;
 			break;
 
 		case 'm': /* ignored by arptables-legacy */
 			break;
 		case 'n':
-			set_option(&cs.options, OPT_NUMERIC, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_NUMERIC, &args.invflags,
 				   invert);
 			break;
 
@@ -715,7 +632,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 			exit(0);
 
 		case '0':
-			set_option(&cs.options, OPT_LINENUMBERS, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_LINENUMBERS, &args.invflags,
 				   invert);
 			break;
 
@@ -725,7 +642,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 
 		case 'c':
 
-			set_option(&cs.options, OPT_COUNTERS, &cs.arp.arp.invflags,
+			set_option(&cs.options, OPT_COUNTERS, &args.invflags,
 				   invert);
 			args.pcnt = optarg;
 			if (xs_has_arg(argc, argv))
@@ -781,25 +698,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
 		xtables_error(PARAMETER_PROBLEM,
 			      "nothing appropriate following !");
 
-	if (p.command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
-		if (!(cs.options & OPT_DESTINATION))
-			args.dhostnetworkmask = "0.0.0.0/0";
-		if (!(cs.options & OPT_SOURCE))
-			args.shostnetworkmask = "0.0.0.0/0";
-	}
-
-	if (args.shostnetworkmask)
-		xtables_ipparse_multiple(args.shostnetworkmask, &args.s.addr.v4,
-					 &args.s.mask.v4, &args.s.naddrs);
-
-	if (args.dhostnetworkmask)
-		xtables_ipparse_multiple(args.dhostnetworkmask, &args.d.addr.v4,
-					 &args.d.mask.v4, &args.d.naddrs);
-
-	if ((args.s.naddrs > 1 || args.d.naddrs > 1) &&
-	    (cs.arp.arp.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
-		xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
-				" source or destination IP addresses");
+	h->ops->post_parse(p.command, &cs, &args);
 
 	if (p.command == CMD_REPLACE && (args.s.naddrs != 1 || args.d.naddrs != 1))
 		xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
-- 
2.33.0


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

* [iptables PATCH 10/12] nft-shared: Make nft_check_xt_legacy() family agnostic
  2021-09-27 15:03 [iptables PATCH 00/12] Eliminate dedicated arptables-nft parser Phil Sutter
                   ` (8 preceding siblings ...)
  2021-09-27 15:03 ` [iptables PATCH 09/12] nft-arp: Introduce post_parse callback Phil Sutter
@ 2021-09-27 15:03 ` Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 11/12] xtables: Derive xtables_globals from family Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 12/12] nft: Merge xtables-arp-standalone.c into xtables-standalone.c Phil Sutter
  11 siblings, 0 replies; 13+ messages in thread
From: Phil Sutter @ 2021-09-27 15:03 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Of course there is no such thing as *_tables_names for ebtables, so no
legacy tables checking for ebtables-nft.

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 iptables/nft-shared.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 4253b08196d29..72727270026ee 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -992,6 +992,7 @@ void nft_check_xt_legacy(int family, bool is_ipt_save)
 {
 	static const char tables6[] = "/proc/net/ip6_tables_names";
 	static const char tables4[] = "/proc/net/ip_tables_names";
+	static const char tablesa[] = "/proc/net/arp_tables_names";
 	const char *prefix = "ip";
 	FILE *fp = NULL;
 	char buf[1024];
@@ -1004,6 +1005,10 @@ void nft_check_xt_legacy(int family, bool is_ipt_save)
 		fp = fopen(tables6, "r");
 		prefix = "ip6";
 		break;
+	case NFPROTO_ARP:
+		fp = fopen(tablesa, "r");
+		prefix = "arp";
+		break;
 	default:
 		break;
 	}
-- 
2.33.0


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

* [iptables PATCH 11/12] xtables: Derive xtables_globals from family
  2021-09-27 15:03 [iptables PATCH 00/12] Eliminate dedicated arptables-nft parser Phil Sutter
                   ` (9 preceding siblings ...)
  2021-09-27 15:03 ` [iptables PATCH 10/12] nft-shared: Make nft_check_xt_legacy() family agnostic Phil Sutter
@ 2021-09-27 15:03 ` Phil Sutter
  2021-09-27 15:03 ` [iptables PATCH 12/12] nft: Merge xtables-arp-standalone.c into xtables-standalone.c Phil Sutter
  11 siblings, 0 replies; 13+ messages in thread
From: Phil Sutter @ 2021-09-27 15:03 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Prepare xtables_main() for use with other families than IPV4 or IPV6
which both use the same xtables_globals object. Therefore introduce a
function to map from family value to xtables_globals object pointer.

In do_parse(), use xt_params pointer as well instead of direct
reference.

While being at it, Declare arptables_globals and ebtables_globals in
xtables_multi.h which seems to be the proper place for that.

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 iptables/xtables-arp-standalone.c |  2 --
 iptables/xtables-eb-translate.c   |  1 -
 iptables/xtables-multi.h          |  3 +++
 iptables/xtables-standalone.c     | 23 +++++++++++++++++++----
 iptables/xtables.c                |  2 +-
 5 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/iptables/xtables-arp-standalone.c b/iptables/xtables-arp-standalone.c
index 04cf7dccc8206..82db3f3801c10 100644
--- a/iptables/xtables-arp-standalone.c
+++ b/iptables/xtables-arp-standalone.c
@@ -41,8 +41,6 @@
 
 #include "xtables-multi.h"
 
-extern struct xtables_globals arptables_globals;
-
 int xtables_arp_main(int argc, char *argv[])
 {
 	int ret;
diff --git a/iptables/xtables-eb-translate.c b/iptables/xtables-eb-translate.c
index 0539a829d3ff8..a6c86b6531e3f 100644
--- a/iptables/xtables-eb-translate.c
+++ b/iptables/xtables-eb-translate.c
@@ -87,7 +87,6 @@ static int parse_rule_number(const char *rule)
 /* Default command line options. Do not mess around with the already
  * assigned numbers unless you know what you are doing */
 extern struct option ebt_original_options[];
-extern struct xtables_globals ebtables_globals;
 #define opts ebtables_globals.opts
 #define prog_name ebtables_globals.program_name
 #define prog_vers ebtables_globals.program_version
diff --git a/iptables/xtables-multi.h b/iptables/xtables-multi.h
index 0fedb430e1a28..94c24d5a22c7e 100644
--- a/iptables/xtables-multi.h
+++ b/iptables/xtables-multi.h
@@ -22,6 +22,9 @@ extern int xtables_eb_restore_main(int, char **);
 extern int xtables_eb_save_main(int, char **);
 extern int xtables_config_main(int, char **);
 extern int xtables_monitor_main(int, char **);
+
+extern struct xtables_globals arptables_globals;
+extern struct xtables_globals ebtables_globals;
 #endif
 
 #endif /* _XTABLES_MULTI_H */
diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c
index 54c70c5429766..19d663b02348c 100644
--- a/iptables/xtables-standalone.c
+++ b/iptables/xtables-standalone.c
@@ -39,19 +39,34 @@
 #include "xtables-multi.h"
 #include "nft.h"
 
+static struct xtables_globals *xtables_globals_lookup(int family)
+{
+	switch (family) {
+	case AF_INET:
+	case AF_INET6:
+		return &xtables_globals;
+	case NFPROTO_ARP:
+		return &arptables_globals;
+	case NFPROTO_BRIDGE:
+		return &ebtables_globals;
+	default:
+		xtables_error(OTHER_PROBLEM, "Unknown family value %d", family);
+	}
+}
+
 static int
 xtables_main(int family, const char *progname, int argc, char *argv[])
 {
-	int ret;
 	char *table = "filter";
 	struct nft_handle h;
+	int ret;
 
-	xtables_globals.program_name = progname;
-	ret = xtables_init_all(&xtables_globals, family);
+	ret = xtables_init_all(xtables_globals_lookup(family), family);
 	if (ret < 0) {
 		fprintf(stderr, "%s: Failed to initialize xtables\n", progname);
 		exit(1);
 	}
+	xt_params->program_name = progname;
 #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
 	init_extensions();
 	init_extensions4();
@@ -60,7 +75,7 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
 
 	if (nft_init(&h, family) < 0) {
 		fprintf(stderr, "%s: Failed to initialize nft: %s\n",
-			xtables_globals.program_name, strerror(errno));
+			xt_params->program_name, strerror(errno));
 		exit(EXIT_FAILURE);
 	}
 
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 2b3cc9301c455..dc67affc19dbe 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -659,7 +659,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
 			exit_tryhelp(2);
 
 		default:
-			if (command_default(cs, &xtables_globals, invert))
+			if (command_default(cs, xt_params, invert))
 				/* cf. ip6tables.c */
 				continue;
 			break;
-- 
2.33.0


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

* [iptables PATCH 12/12] nft: Merge xtables-arp-standalone.c into xtables-standalone.c
  2021-09-27 15:03 [iptables PATCH 00/12] Eliminate dedicated arptables-nft parser Phil Sutter
                   ` (10 preceding siblings ...)
  2021-09-27 15:03 ` [iptables PATCH 11/12] xtables: Derive xtables_globals from family Phil Sutter
@ 2021-09-27 15:03 ` Phil Sutter
  11 siblings, 0 replies; 13+ messages in thread
From: Phil Sutter @ 2021-09-27 15:03 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

By declaring the relevant family_ops callbacks for arptables, the code
becomes ready to just use do_commandx() instead of a dedicated parser.

As a side-effect, this enables a bunch of new features in arptables-nft:

* Support '-C' command
* Support '-S' command
* Support rule indexes just like xtables, e.g. in '-I' or '-R' commands
* Reject chain names starting with '!'
* Support '-c N,M' counter syntax

Signed-off-by: Phil Sutter <phil@nwl.cc>
---
 iptables/Makefile.am              |   2 +-
 iptables/nft-arp.c                |  95 ++++-
 iptables/xtables-arp-standalone.c |  63 ---
 iptables/xtables-arp.c            | 638 +-----------------------------
 iptables/xtables-restore.c        |   2 +-
 iptables/xtables-standalone.c     |  19 +-
 iptables/xtables.c                |  41 +-
 7 files changed, 169 insertions(+), 691 deletions(-)
 delete mode 100644 iptables/xtables-arp-standalone.c

diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index f789521042f87..0258264c4c705 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -37,7 +37,7 @@ xtables_nft_multi_SOURCES += xtables-save.c xtables-restore.c \
 				xtables-standalone.c xtables.c nft.c \
 				nft-shared.c nft-ipv4.c nft-ipv6.c nft-arp.c \
 				xtables-monitor.c nft-cache.c \
-				xtables-arp-standalone.c xtables-arp.c \
+				xtables-arp.c \
 				nft-bridge.c nft-cmd.c nft-chain.c \
 				xtables-eb-standalone.c xtables-eb.c \
 				xtables-eb-translate.c \
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index b37ffbb592023..32eb91add4f1e 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -617,7 +617,8 @@ static void nft_arp_post_parse(int command,
 	cs->arp.counters.pcnt = args->pcnt_cnt;
 	cs->arp.counters.bcnt = args->bcnt_cnt;
 
-	if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
+	if (command & (CMD_REPLACE | CMD_INSERT |
+			CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
 		if (!(cs->options & OPT_DESTINATION))
 			args->dhostnetworkmask = "0.0.0.0/0";
 		if (!(cs->options & OPT_SOURCE))
@@ -702,6 +703,94 @@ static void nft_arp_init_cs(struct iptables_command_state *cs)
 	cs->arp.arp.arhrd_mask = 65535;
 }
 
+static int
+nft_arp_add_entry(struct nft_handle *h,
+		  const char *chain, const char *table,
+		  struct iptables_command_state *cs,
+		  struct xtables_args *args, bool verbose,
+		  bool append, int rulenum)
+{
+	unsigned int i, j;
+	int ret = 1;
+
+	for (i = 0; i < args->s.naddrs; i++) {
+		cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
+		cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
+		for (j = 0; j < args->d.naddrs; j++) {
+			cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
+			cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
+			if (append) {
+				ret = nft_cmd_rule_append(h, chain, table, cs, NULL,
+						          verbose);
+			} else {
+				ret = nft_cmd_rule_insert(h, chain, table, cs,
+						          rulenum, verbose);
+			}
+		}
+	}
+
+	return ret;
+}
+
+static int
+nft_arp_delete_entry(struct nft_handle *h,
+		     const char *chain, const char *table,
+		     struct iptables_command_state *cs,
+		     struct xtables_args *args, bool verbose)
+{
+	unsigned int i, j;
+	int ret = 1;
+
+	for (i = 0; i < args->s.naddrs; i++) {
+		cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
+		cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
+		for (j = 0; j < args->d.naddrs; j++) {
+			cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
+			cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
+			ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
+		}
+	}
+
+	return ret;
+}
+
+static int
+nft_arp_check_entry(struct nft_handle *h,
+		    const char *chain, const char *table,
+		    struct iptables_command_state *cs,
+		    struct xtables_args *args, bool verbose)
+{
+	unsigned int i, j;
+	int ret = 1;
+
+	for (i = 0; i < args->s.naddrs; i++) {
+		cs->arp.arp.src.s_addr = args->s.addr.v4[i].s_addr;
+		cs->arp.arp.smsk.s_addr = args->s.mask.v4[i].s_addr;
+		for (j = 0; j < args->d.naddrs; j++) {
+			cs->arp.arp.tgt.s_addr = args->d.addr.v4[j].s_addr;
+			cs->arp.arp.tmsk.s_addr = args->d.mask.v4[j].s_addr;
+			ret = nft_cmd_rule_check(h, chain, table, cs, verbose);
+		}
+	}
+
+	return ret;
+}
+
+static int
+nft_arp_replace_entry(struct nft_handle *h,
+		      const char *chain, const char *table,
+		      struct iptables_command_state *cs,
+		      struct xtables_args *args, bool verbose,
+		      int rulenum)
+{
+	cs->arp.arp.src.s_addr = args->s.addr.v4->s_addr;
+	cs->arp.arp.tgt.s_addr = args->d.addr.v4->s_addr;
+	cs->arp.arp.smsk.s_addr = args->s.mask.v4->s_addr;
+	cs->arp.arp.tmsk.s_addr = args->d.mask.v4->s_addr;
+
+	return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
+}
+
 struct nft_family_ops nft_family_ops_arp = {
 	.add			= nft_arp_add,
 	.is_same		= nft_arp_is_same,
@@ -718,4 +807,8 @@ struct nft_family_ops nft_family_ops_arp = {
 	.init_cs		= nft_arp_init_cs,
 	.clear_cs		= nft_clear_iptables_command_state,
 	.parse_target		= nft_ipv46_parse_target,
+	.add_entry		= nft_arp_add_entry,
+	.delete_entry		= nft_arp_delete_entry,
+	.check_entry		= nft_arp_check_entry,
+	.replace_entry		= nft_arp_replace_entry,
 };
diff --git a/iptables/xtables-arp-standalone.c b/iptables/xtables-arp-standalone.c
deleted file mode 100644
index 82db3f3801c10..0000000000000
--- a/iptables/xtables-arp-standalone.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au
- *
- * Based on the ipchains code by Paul Russell and Michael Neuling
- *
- * (C) 2000-2002 by the netfilter coreteam <coreteam@netfilter.org>:
- * 		    Paul 'Rusty' Russell <rusty@rustcorp.com.au>
- * 		    Marc Boucher <marc+nf@mbsi.ca>
- * 		    James Morris <jmorris@intercode.com.au>
- * 		    Harald Welte <laforge@gnumonks.org>
- * 		    Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- *
- *	arptables -- IP firewall administration for kernels with
- *	firewall table (aimed for the 2.3 kernels)
- *
- *	See the accompanying manual page arptables(8) for information
- *	about proper usage of this program.
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- *	You should have received a copy of the GNU General Public License
- *	along with this program; if not, write to the Free Software
- *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <xtables.h>
-#include "nft.h"
-#include <linux/netfilter_arp/arp_tables.h>
-
-#include "xtables-multi.h"
-
-int xtables_arp_main(int argc, char *argv[])
-{
-	int ret;
-	char *table = "filter";
-	struct nft_handle h;
-
-	nft_init_arp(&h, "arptables");
-
-	ret = do_commandarp(&h, argc, argv, &table, false);
-	if (ret)
-		ret = nft_commit(&h);
-
-	nft_fini(&h);
-	xtables_fini();
-
-	if (!ret)
-		fprintf(stderr, "arptables: %s\n", nft_strerror(errno));
-
-	exit(!ret);
-}
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index de7c381788a37..cca19438a877e 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -30,35 +30,23 @@
 #include "config.h"
 #include <getopt.h>
 #include <string.h>
-#include <netdb.h>
-#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <inttypes.h>
-#include <dlfcn.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <limits.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/wait.h>
-#include <net/if.h>
-#include <netinet/ether.h>
-#include <iptables.h>
 #include <xtables.h>
 
 #include "xshared.h"
 
 #include "nft.h"
 #include "nft-arp.h"
-#include <linux/netfilter_arp/arp_tables.h>
 
 static struct option original_opts[] = {
 	{ "append", 1, 0, 'A' },
 	{ "delete", 1, 0,  'D' },
+	{ "check", 1, 0,  'C'},
 	{ "insert", 1, 0,  'I' },
 	{ "replace", 1, 0,  'R' },
 	{ "list", 2, 0,  'L' },
+	{ "list-rules", 2, 0,  'S'},
 	{ "flush", 2, 0,  'F' },
 	{ "zero", 2, 0,  'Z' },
 	{ "new-chain", 1, 0,  'N' },
@@ -101,22 +89,13 @@ static void printhelp(const struct xtables_rule_match *m);
 struct xtables_globals arptables_globals = {
 	.option_offset		= 0,
 	.program_version	= PACKAGE_VERSION,
-	.optstring		= OPTSTRING_COMMON "R:S::" "h::l:nv" /* "m:" */,
+	.optstring		= OPTSTRING_COMMON "C:R:S::" "h::l:nv" /* "m:" */,
 	.orig_opts		= original_opts,
 	.exit_err		= xtables_exit_error,
 	.compat_rev		= nft_compatible_revision,
 	.print_help		= printhelp,
 };
 
-static void
-exit_tryhelp(int status)
-{
-	fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n",
-		arptables_globals.program_name,
-		arptables_globals.program_version);
-	exit(status);
-}
-
 static void
 printhelp(const struct xtables_rule_match *m)
 {
@@ -124,10 +103,12 @@ printhelp(const struct xtables_rule_match *m)
 	int i;
 
 	printf("%s v%s\n\n"
-"Usage: %s -[AD] chain rule-specification [options]\n"
-"       %s -[RI] chain rulenum rule-specification [options]\n"
+"Usage: %s -[ACD] chain rule-specification [options]\n"
+"       %s -I chain [rulenum] rule-specification [options]\n"
+"       %s -R chain rulenum rule-specification [options]\n"
 "       %s -D chain rulenum [options]\n"
-"       %s -[LFZ] [chain] [options]\n"
+"       %s -[LS] [chain [rulenum]] [options]\n"
+"       %s -[FZ] [chain] [options]\n"
 "       %s -[NX] chain\n"
 "       %s -E old-chain-name new-chain-name\n"
 "       %s -P chain target [options]\n"
@@ -141,11 +122,14 @@ printhelp(const struct xtables_rule_match *m)
 	       arptables_globals.program_name,
 	       arptables_globals.program_name,
 	       arptables_globals.program_name,
+	       arptables_globals.program_name,
+	       arptables_globals.program_name,
 	       arptables_globals.program_name);
 	printf(
 "Commands:\n"
 "Either long or short options are allowed.\n"
 "  --append  -A chain		Append to chain\n"
+"  --check   -C chain		Check for the existence of a rule\n"
 "  --delete  -D chain		Delete matching rule from chain\n"
 "  --delete  -D chain rulenum\n"
 "				Delete rule rulenum (1 = first) from chain\n"
@@ -153,9 +137,13 @@ printhelp(const struct xtables_rule_match *m)
 "				Insert in chain as rulenum (default 1=first)\n"
 "  --replace -R chain rulenum\n"
 "				Replace rule rulenum (1 = first) in chain\n"
-"  --list    -L [chain]		List the rules in a chain or all chains\n"
+"  --list    -L [chain [rulenum]]\n"
+"				List the rules in a chain or all chains\n"
+"  --list-rules -S [chain [rulenum]]\n"
+"				Print the rules in a chain or all chains\n"
 "  --flush   -F [chain]		Delete all rules in  chain or all chains\n"
-"  --zero    -Z [chain]		Zero counters in chain or all chains\n"
+"  --zero    -Z [chain [rulenum]]\n"
+"				Zero counters in chain or all chains\n"
 "  --new     -N chain		Create a new user-defined chain\n"
 "  --delete-chain\n"
 "            -X [chain]		Delete a user-defined chain\n"
@@ -210,134 +198,6 @@ printhelp(const struct xtables_rule_match *m)
 	}
 }
 
-static int
-check_inverse(const char option[], int *invert, int *optidx, int argc)
-{
-	if (option && strcmp(option, "!") == 0) {
-		if (*invert)
-			xtables_error(PARAMETER_PROBLEM,
-				      "Multiple `!' flags not allowed");
-		*invert = true;
-		if (optidx) {
-			*optidx = *optidx+1;
-			if (argc && *optidx > argc)
-				xtables_error(PARAMETER_PROBLEM,
-					      "no argument following `!'");
-		}
-
-		return true;
-	}
-	return false;
-}
-
-static int
-list_entries(struct nft_handle *h, const char *chain, const char *table,
-	     int rulenum, int verbose, int numeric, int expanded,
-	     int linenumbers)
-{
-	unsigned int format;
-
-	format = FMT_OPTIONS;
-	if (!verbose)
-		format |= FMT_NOCOUNTS;
-	else
-		format |= FMT_VIA;
-
-	if (numeric)
-		format |= FMT_NUMERIC;
-
-	if (!expanded)
-		format |= FMT_KILOMEGAGIGA;
-
-	if (linenumbers)
-		format |= FMT_LINENUMBERS;
-
-	return nft_cmd_rule_list(h, chain, table, rulenum, format);
-}
-
-static int
-append_entry(struct nft_handle *h,
-	     const char *chain,
-	     const char *table,
-	     struct iptables_command_state *cs,
-	     int rulenum,
-	     unsigned int nsaddrs,
-	     const struct in_addr saddrs[],
-	     const struct in_addr smasks[],
-	     unsigned int ndaddrs,
-	     const struct in_addr daddrs[],
-	     const struct in_addr dmasks[],
-	     bool verbose, bool append)
-{
-	unsigned int i, j;
-	int ret = 1;
-
-	for (i = 0; i < nsaddrs; i++) {
-		cs->arp.arp.src.s_addr = saddrs[i].s_addr;
-		cs->arp.arp.smsk.s_addr = smasks[i].s_addr;
-		for (j = 0; j < ndaddrs; j++) {
-			cs->arp.arp.tgt.s_addr = daddrs[j].s_addr;
-			cs->arp.arp.tmsk.s_addr = dmasks[j].s_addr;
-			if (append) {
-				ret = nft_cmd_rule_append(h, chain, table, cs, NULL,
-						      verbose);
-			} else {
-				ret = nft_cmd_rule_insert(h, chain, table, cs,
-						      rulenum, verbose);
-			}
-		}
-	}
-
-	return ret;
-}
-
-static int
-replace_entry(const char *chain,
-	      const char *table,
-	      struct iptables_command_state *cs,
-	      unsigned int rulenum,
-	      const struct in_addr *saddr,
-	      const struct in_addr *smask,
-	      const struct in_addr *daddr,
-	      const struct in_addr *dmask,
-	      bool verbose, struct nft_handle *h)
-{
-	cs->arp.arp.src.s_addr = saddr->s_addr;
-	cs->arp.arp.tgt.s_addr = daddr->s_addr;
-	cs->arp.arp.smsk.s_addr = smask->s_addr;
-	cs->arp.arp.tmsk.s_addr = dmask->s_addr;
-
-	return nft_cmd_rule_replace(h, chain, table, cs, rulenum, verbose);
-}
-
-static int
-delete_entry(const char *chain,
-	     const char *table,
-	     struct iptables_command_state *cs,
-	     unsigned int nsaddrs,
-	     const struct in_addr saddrs[],
-	     const struct in_addr smasks[],
-	     unsigned int ndaddrs,
-	     const struct in_addr daddrs[],
-	     const struct in_addr dmasks[],
-	     bool verbose, struct nft_handle *h)
-{
-	unsigned int i, j;
-	int ret = 1;
-
-	for (i = 0; i < nsaddrs; i++) {
-		cs->arp.arp.src.s_addr = saddrs[i].s_addr;
-		cs->arp.arp.smsk.s_addr = smasks[i].s_addr;
-		for (j = 0; j < ndaddrs; j++) {
-			cs->arp.arp.tgt.s_addr = daddrs[j].s_addr;
-			cs->arp.arp.tmsk.s_addr = dmasks[j].s_addr;
-			ret = nft_cmd_rule_delete(h, chain, table, cs, verbose);
-		}
-	}
-
-	return ret;
-}
-
 int nft_init_arp(struct nft_handle *h, const char *pname)
 {
 	arptables_globals.program_name = pname;
@@ -358,467 +218,3 @@ int nft_init_arp(struct nft_handle *h, const char *pname)
 
 	return 0;
 }
-
-int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
-		  bool restore)
-{
-	struct iptables_command_state cs = {
-		.jumpto = "",
-		.arp.arp = {
-			.arhln = 6,
-			.arhln_mask = 255,
-			.arhrd = htons(ARPHRD_ETHER),
-			.arhrd_mask = 65535,
-		},
-	};
-	struct nft_xt_cmd_parse p = {
-		.table = *table,
-	};
-	struct xtables_args args = {
-		.family = h->family,
-	};
-	int invert = 0;
-	int ret = 1;
-	struct xtables_target *t;
-
-	/* re-set optind to 0 in case do_command gets called
-	 * a second time */
-	optind = 0;
-
-	for (t = xtables_targets; t; t = t->next) {
-		t->tflags = 0;
-		t->used = 0;
-	}
-
-	/* Suppress error messages: we may add new options if we
-	    demand-load a protocol. */
-	opterr = 0;
-
-	opts = xt_params->orig_opts;
-	while ((cs.c = getopt_long(argc, argv, xt_params->optstring,
-					   opts, NULL)) != -1) {
-		switch (cs.c) {
-			/*
-			 * Command selection
-			 */
-		case 'A':
-			add_command(&p.command, CMD_APPEND, CMD_NONE,
-				    invert);
-			p.chain = optarg;
-			break;
-
-		case 'D':
-			add_command(&p.command, CMD_DELETE, CMD_NONE,
-				    invert);
-			p.chain = optarg;
-			if (xs_has_arg(argc, argv)) {
-				p.rulenum = parse_rulenumber(argv[optind++]);
-				p.command = CMD_DELETE_NUM;
-			}
-			break;
-
-		case 'R':
-			add_command(&p.command, CMD_REPLACE, CMD_NONE,
-				    invert);
-			p.chain = optarg;
-			if (xs_has_arg(argc, argv))
-				p.rulenum = parse_rulenumber(argv[optind++]);
-			else
-				xtables_error(PARAMETER_PROBLEM,
-					      "-%c requires a rule number",
-					      cmd2char(CMD_REPLACE));
-			break;
-
-		case 'I':
-			add_command(&p.command, CMD_INSERT, CMD_NONE,
-				    invert);
-			p.chain = optarg;
-			if (xs_has_arg(argc, argv))
-				p.rulenum = parse_rulenumber(argv[optind++]);
-			else p.rulenum = 1;
-			break;
-
-		case 'L':
-			add_command(&p.command, CMD_LIST, CMD_ZERO,
-				    invert);
-			if (optarg) p.chain = optarg;
-			else if (xs_has_arg(argc, argv))
-				p.chain = argv[optind++];
-			break;
-
-		case 'F':
-			add_command(&p.command, CMD_FLUSH, CMD_NONE,
-				    invert);
-			if (optarg) p.chain = optarg;
-			else if (xs_has_arg(argc, argv))
-				p.chain = argv[optind++];
-			break;
-
-		case 'Z':
-			add_command(&p.command, CMD_ZERO, CMD_LIST,
-				    invert);
-			if (optarg) p.chain = optarg;
-			else if (xs_has_arg(argc, argv))
-				p.chain = argv[optind++];
-			break;
-
-		case 'N':
-			if (optarg && *optarg == '-')
-				xtables_error(PARAMETER_PROBLEM,
-					      "chain name not allowed to start "
-					      "with `-'\n");
-			if (xtables_find_target(optarg, XTF_TRY_LOAD))
-				xtables_error(PARAMETER_PROBLEM,
-						"chain name may not clash "
-						"with target name\n");
-			add_command(&p.command, CMD_NEW_CHAIN, CMD_NONE,
-				    invert);
-			p.chain = optarg;
-			break;
-
-		case 'X':
-			add_command(&p.command, CMD_DELETE_CHAIN, CMD_NONE,
-				    invert);
-			if (optarg) p.chain = optarg;
-			else if (xs_has_arg(argc, argv))
-				p.chain = argv[optind++];
-			break;
-
-		case 'E':
-			add_command(&p.command, CMD_RENAME_CHAIN, CMD_NONE,
-				    invert);
-			p.chain = optarg;
-			if (xs_has_arg(argc, argv))
-				p.newname = argv[optind++];
-			else
-				xtables_error(PARAMETER_PROBLEM,
-					      "-%c requires old-chain-name and "
-					      "new-chain-name",
-					      cmd2char(CMD_RENAME_CHAIN));
-			break;
-
-		case 'P':
-			add_command(&p.command, CMD_SET_POLICY, CMD_NONE,
-				    invert);
-			p.chain = optarg;
-			if (xs_has_arg(argc, argv))
-				p.policy = argv[optind++];
-			else
-				xtables_error(PARAMETER_PROBLEM,
-					      "-%c requires a chain and a policy",
-					      cmd2char(CMD_SET_POLICY));
-			break;
-
-		case 'h':
-			if (!optarg)
-				optarg = argv[optind];
-
-			xt_params->print_help(NULL);
-			p.command = CMD_NONE;
-			break;
-		case 's':
-			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_SOURCE, &args.invflags,
-				   invert);
-			args.shostnetworkmask = argv[optind-1];
-			break;
-
-		case 'd':
-			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_DESTINATION, &args.invflags,
-				   invert);
-			args.dhostnetworkmask = argv[optind-1];
-			break;
-
-		case 2:/* src-mac */
-			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_S_MAC, &args.invflags,
-				   invert);
-			args.src_mac = argv[optind - 1];
-			break;
-
-		case 3:/* dst-mac */
-			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_D_MAC, &args.invflags,
-				   invert);
-			args.dst_mac = argv[optind - 1];
-			break;
-
-		case 'l':/* hardware length */
-			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_H_LENGTH, &args.invflags,
-				   invert);
-			args.arp_hlen = argv[optind - 1];
-			break;
-
-		case 8: /* was never supported, not even in arptables-legacy */
-			xtables_error(PARAMETER_PROBLEM, "not supported");
-		case 4:/* opcode */
-			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_OPCODE, &args.invflags,
-				   invert);
-			args.arp_opcode = argv[optind - 1];
-			break;
-
-		case 5:/* h-type */
-			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_H_TYPE, &args.invflags,
-				   invert);
-			args.arp_htype = argv[optind - 1];
-			break;
-
-		case 6:/* proto-type */
-			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_P_TYPE, &args.invflags,
-				   invert);
-			args.arp_ptype = argv[optind - 1];
-			break;
-
-		case 'j':
-			set_option(&cs.options, OPT_JUMP, &args.invflags,
-				   invert);
-			command_jump(&cs, optarg);
-			break;
-
-		case 'i':
-			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_VIANAMEIN, &args.invflags,
-				   invert);
-			xtables_parse_interface(argv[optind-1],
-						args.iniface,
-						args.iniface_mask);
-			break;
-
-		case 'o':
-			check_inverse(optarg, &invert, &optind, argc);
-			set_option(&cs.options, OPT_VIANAMEOUT, &args.invflags,
-				   invert);
-			xtables_parse_interface(argv[optind-1],
-						args.outiface,
-						args.outiface_mask);
-			break;
-
-		case 'v':
-			if (!p.verbose)
-				set_option(&cs.options, OPT_VERBOSE,
-					   &args.invflags, invert);
-			p.verbose++;
-			break;
-
-		case 'm': /* ignored by arptables-legacy */
-			break;
-		case 'n':
-			set_option(&cs.options, OPT_NUMERIC, &args.invflags,
-				   invert);
-			break;
-
-		case 't':
-			if (invert)
-				xtables_error(PARAMETER_PROBLEM,
-					      "unexpected ! flag before --table");
-			/* ignore this option.
-			 * arptables-legacy parses it, but libarptc doesn't use it.
-			 * arptables only has a 'filter' table anyway.
-			 */
-			break;
-
-		case 'V':
-			if (invert)
-				printf("Not %s ;-)\n", arptables_globals.program_version);
-			else
-				printf("%s v%s (nf_tables)\n",
-				       arptables_globals.program_name,
-				       arptables_globals.program_version);
-			exit(0);
-
-		case '0':
-			set_option(&cs.options, OPT_LINENUMBERS, &args.invflags,
-				   invert);
-			break;
-
-		case 'M':
-			//modprobe = optarg;
-			break;
-
-		case 'c':
-
-			set_option(&cs.options, OPT_COUNTERS, &args.invflags,
-				   invert);
-			args.pcnt = optarg;
-			if (xs_has_arg(argc, argv))
-				args.bcnt = argv[optind++];
-			else
-				xtables_error(PARAMETER_PROBLEM,
-					      "-%c requires packet and byte counter",
-					      opt2char(OPT_COUNTERS));
-
-			if (sscanf(args.pcnt, "%llu", &cs.arp.counters.pcnt) != 1)
-			xtables_error(PARAMETER_PROBLEM,
-				"-%c packet counter not numeric",
-				opt2char(OPT_COUNTERS));
-
-			if (sscanf(args.bcnt, "%llu", &cs.arp.counters.bcnt) != 1)
-				xtables_error(PARAMETER_PROBLEM,
-					      "-%c byte counter not numeric",
-					      opt2char(OPT_COUNTERS));
-
-			break;
-
-
-		case 1: /* non option */
-			if (optarg[0] == '!' && optarg[1] == '\0') {
-				if (invert)
-					xtables_error(PARAMETER_PROBLEM,
-						      "multiple consecutive ! not"
-						      " allowed");
-				invert = true;
-				optarg[0] = '\0';
-				continue;
-			}
-			printf("Bad argument `%s'\n", optarg);
-			exit_tryhelp(2);
-
-		default:
-			if (cs.target) {
-				xtables_option_tpcall(cs.c, argv,
-						      invert, cs.target, &cs.arp);
-			}
-			break;
-		}
-		invert = false;
-	}
-
-	if (cs.target)
-		xtables_option_tfcall(cs.target);
-
-	if (optind < argc)
-		xtables_error(PARAMETER_PROBLEM,
-			      "unknown arguments found on commandline");
-	if (invert)
-		xtables_error(PARAMETER_PROBLEM,
-			      "nothing appropriate following !");
-
-	h->ops->post_parse(p.command, &cs, &args);
-
-	if (p.command == CMD_REPLACE && (args.s.naddrs != 1 || args.d.naddrs != 1))
-		xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
-						 "specify a unique address");
-
-	if (p.chain && strlen(p.chain) > ARPT_FUNCTION_MAXNAMELEN)
-		xtables_error(PARAMETER_PROBLEM,
-				"chain name `%s' too long (must be under %i chars)",
-				p.chain, ARPT_FUNCTION_MAXNAMELEN);
-
-	if (p.command == CMD_APPEND
-	    || p.command == CMD_DELETE
-	    || p.command == CMD_INSERT
-	    || p.command == CMD_REPLACE) {
-		if (strcmp(p.chain, "PREROUTING") == 0
-		    || strcmp(p.chain, "INPUT") == 0) {
-			/* -o not valid with incoming packets. */
-			if (cs.options & OPT_VIANAMEOUT)
-				xtables_error(PARAMETER_PROBLEM,
-					      "Can't use -%c with %s\n",
-					      opt2char(OPT_VIANAMEOUT),
-					      p.chain);
-		}
-
-		if (strcmp(p.chain, "POSTROUTING") == 0
-		    || strcmp(p.chain, "OUTPUT") == 0) {
-			/* -i not valid with outgoing packets */
-			if (cs.options & OPT_VIANAMEIN)
-				xtables_error(PARAMETER_PROBLEM,
-						"Can't use -%c with %s\n",
-						opt2char(OPT_VIANAMEIN),
-						p.chain);
-		}
-	}
-
-	switch (p.command) {
-	case CMD_APPEND:
-		ret = append_entry(h, p.chain, p.table, &cs, 0,
-				   args.s.naddrs, args.s.addr.v4, args.s.mask.v4,
-				   args.d.naddrs, args.d.addr.v4, args.d.mask.v4,
-				   cs.options&OPT_VERBOSE, true);
-		break;
-	case CMD_DELETE:
-		ret = delete_entry(p.chain, p.table, &cs,
-				   args.s.naddrs, args.s.addr.v4, args.s.mask.v4,
-				   args.d.naddrs, args.d.addr.v4, args.d.mask.v4,
-				   cs.options&OPT_VERBOSE, h);
-		break;
-	case CMD_DELETE_NUM:
-		ret = nft_cmd_rule_delete_num(h, p.chain, p.table, p.rulenum - 1, p.verbose);
-		break;
-	case CMD_REPLACE:
-		ret = replace_entry(p.chain, p.table, &cs, p.rulenum - 1,
-				    args.s.addr.v4, args.s.mask.v4, args.d.addr.v4, args.d.mask.v4,
-				    cs.options&OPT_VERBOSE, h);
-		break;
-	case CMD_INSERT:
-		ret = append_entry(h, p.chain, p.table, &cs, p.rulenum - 1,
-				   args.s.naddrs, args.s.addr.v4, args.s.mask.v4,
-				   args.d.naddrs, args.d.addr.v4, args.d.mask.v4,
-				   cs.options&OPT_VERBOSE, false);
-		break;
-	case CMD_LIST:
-		ret = list_entries(h, p.chain, p.table,
-				   p.rulenum,
-				   cs.options&OPT_VERBOSE,
-				   cs.options&OPT_NUMERIC,
-				   /*cs.options&OPT_EXPANDED*/0,
-				   cs.options&OPT_LINENUMBERS);
-		break;
-	case CMD_FLUSH:
-		ret = nft_cmd_rule_flush(h, p.chain, p.table, cs.options & OPT_VERBOSE);
-		break;
-	case CMD_ZERO:
-		ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
-					      cs.options & OPT_VERBOSE);
-		break;
-	case CMD_LIST|CMD_ZERO:
-		ret = list_entries(h, p.chain, p.table, p.rulenum,
-				   cs.options&OPT_VERBOSE,
-				   cs.options&OPT_NUMERIC,
-				   /*cs.options&OPT_EXPANDED*/0,
-				   cs.options&OPT_LINENUMBERS);
-		if (ret)
-			ret = nft_cmd_chain_zero_counters(h, p.chain, p.table,
-						      cs.options & OPT_VERBOSE);
-		break;
-	case CMD_NEW_CHAIN:
-		ret = nft_cmd_chain_user_add(h, p.chain, p.table);
-		break;
-	case CMD_DELETE_CHAIN:
-		ret = nft_cmd_chain_del(h, p.chain, p.table,
-					cs.options & OPT_VERBOSE);
-		break;
-	case CMD_RENAME_CHAIN:
-		ret = nft_cmd_chain_user_rename(h, p.chain, p.table, p.newname);
-		break;
-	case CMD_SET_POLICY:
-		ret = nft_cmd_chain_set(h, p.table, p.chain, p.policy, NULL);
-		if (ret < 0)
-			xtables_error(PARAMETER_PROBLEM, "Wrong policy `%s'\n",
-				      p.policy);
-		break;
-	case CMD_NONE:
-		break;
-	default:
-		/* We should never reach this... */
-		exit_tryhelp(2);
-	}
-
-	free(args.s.addr.v4);
-	free(args.s.mask.v4);
-	free(args.d.addr.v4);
-	free(args.d.mask.v4);
-
-	nft_clear_iptables_command_state(&cs);
-	xtables_free_opts(1);
-
-/*	if (p.verbose > 1)
-		dump_entries(*handle);*/
-
-	return ret;
-}
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index 86dcede395e07..aa8b397f29ac7 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -451,7 +451,7 @@ int xtables_eb_restore_main(int argc, char *argv[])
 static const struct nft_xt_restore_cb arp_restore_cb = {
 	.commit		= nft_commit,
 	.table_flush	= nft_cmd_table_flush,
-	.do_command	= do_commandarp,
+	.do_command	= do_commandx,
 	.chain_set	= nft_cmd_chain_set,
 	.chain_restore  = nft_cmd_chain_restore,
 };
diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c
index 19d663b02348c..5482a85689d79 100644
--- a/iptables/xtables-standalone.c
+++ b/iptables/xtables-standalone.c
@@ -68,9 +68,17 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
 	}
 	xt_params->program_name = progname;
 #if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS)
-	init_extensions();
-	init_extensions4();
-	init_extensions6();
+	switch (family) {
+	case NFPROTO_IPV4:
+	case NFPROTO_IPV6:
+		init_extensions();
+		init_extensions4();
+		init_extensions6();
+		break;
+	case NFPROTO_ARP:
+		init_extensionsa();
+		break;
+	}
 #endif
 
 	if (nft_init(&h, family) < 0) {
@@ -107,3 +115,8 @@ int xtables_ip6_main(int argc, char *argv[])
 {
 	return xtables_main(NFPROTO_IPV6, "ip6tables", argc, argv);
 }
+
+int xtables_arp_main(int argc, char *argv[])
+{
+	return xtables_main(NFPROTO_ARP, "arptables", argc, argv);
+}
diff --git a/iptables/xtables.c b/iptables/xtables.c
index dc67affc19dbe..64590b4329ec6 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -36,11 +36,13 @@
 #include <stdarg.h>
 #include <limits.h>
 #include <unistd.h>
+#include <netinet/ether.h>
 #include <iptables.h>
 #include <xtables.h>
 #include <fcntl.h>
 #include "xshared.h"
 #include "nft-shared.h"
+#include "nft-arp.h"
 #include "nft.h"
 
 static struct option original_opts[] = {
@@ -485,13 +487,50 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
 			break;
 #endif
 
+		case 2:/* src-mac */
+			set_option(&cs->options, OPT_S_MAC, &args->invflags,
+				   invert);
+			args->src_mac = optarg;
+			break;
+
+		case 3:/* dst-mac */
+			set_option(&cs->options, OPT_D_MAC, &args->invflags,
+				   invert);
+			args->dst_mac = optarg;
+			break;
+
+		case 'l':/* hardware length */
+			set_option(&cs->options, OPT_H_LENGTH, &args->invflags,
+				   invert);
+			args->arp_hlen = optarg;
+			break;
+
+		case 8: /* was never supported, not even in arptables-legacy */
+			xtables_error(PARAMETER_PROBLEM, "not supported");
+		case 4:/* opcode */
+			set_option(&cs->options, OPT_OPCODE, &args->invflags,
+				   invert);
+			args->arp_opcode = optarg;
+			break;
+
+		case 5:/* h-type */
+			set_option(&cs->options, OPT_H_TYPE, &args->invflags,
+				   invert);
+			args->arp_htype = optarg;
+			break;
+
+		case 6:/* proto-type */
+			set_option(&cs->options, OPT_P_TYPE, &args->invflags,
+				   invert);
+			args->arp_ptype = optarg;
+			break;
+
 		case 'j':
 			set_option(&cs->options, OPT_JUMP, &args->invflags,
 				   invert);
 			command_jump(cs, optarg);
 			break;
 
-
 		case 'i':
 			if (*optarg == '\0')
 				xtables_error(PARAMETER_PROBLEM,
-- 
2.33.0


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

end of thread, other threads:[~2021-09-27 15:04 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-27 15:03 [iptables PATCH 00/12] Eliminate dedicated arptables-nft parser Phil Sutter
2021-09-27 15:03 ` [iptables PATCH 01/12] nft: Introduce builtin_tables_lookup() Phil Sutter
2021-09-27 15:03 ` [iptables PATCH 02/12] xshared: Store optstring in xtables_globals Phil Sutter
2021-09-27 15:03 ` [iptables PATCH 03/12] nft-shared: Introduce init_cs family ops callback Phil Sutter
2021-09-27 15:03 ` [iptables PATCH 04/12] xtables: Simplify addr_mask freeing Phil Sutter
2021-09-27 15:03 ` [iptables PATCH 05/12] nft: Add family ops callbacks wrapping different nft_cmd_* functions Phil Sutter
2021-09-27 15:03 ` [iptables PATCH 06/12] xtables-standalone: Drop version number from init errors Phil Sutter
2021-09-27 15:03 ` [iptables PATCH 07/12] libxtables: Introduce xtables_globals print_help callback Phil Sutter
2021-09-27 15:03 ` [iptables PATCH 08/12] arptables: Use standard data structures when parsing Phil Sutter
2021-09-27 15:03 ` [iptables PATCH 09/12] nft-arp: Introduce post_parse callback Phil Sutter
2021-09-27 15:03 ` [iptables PATCH 10/12] nft-shared: Make nft_check_xt_legacy() family agnostic Phil Sutter
2021-09-27 15:03 ` [iptables PATCH 11/12] xtables: Derive xtables_globals from family Phil Sutter
2021-09-27 15:03 ` [iptables PATCH 12/12] nft: Merge xtables-arp-standalone.c into xtables-standalone.c Phil Sutter

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.