nft: load tables and chains based on /etc/xtables.conf

If /etc/xtables.conf is available, use the configuration there to
autoload the xtables built-in table and chain so you can define custom
configurations. Otherwise, rely on default common table/chain
configuration.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
diff --git a/iptables/nft.c b/iptables/nft.c
index 88fd84b..f39f407 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -17,6 +17,7 @@
 #include <errno.h>
 #include <netdb.h>	/* getprotobynumber */
 #include <time.h>
+#include <stdarg.h>
 
 #include <xtables.h>
 #include <libiptc/libxtc.h>
@@ -47,6 +48,7 @@
 #include "nft.h"
 #include "xshared.h" /* proto_to_name */
 #include "nft-shared.h"
+#include "xtables-config-parser.h"
 
 static void *nft_fn;
 
@@ -683,7 +685,8 @@
 	int ip_flags = 0;
 
 	/* If built-in chains don't exist for this table, create them */
-	nft_chain_builtin_init(h, table, chain, NF_ACCEPT);
+	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
+		nft_chain_builtin_init(h, table, chain, NF_ACCEPT);
 
 	nft_fn = nft_rule_add;
 
@@ -1302,7 +1305,8 @@
 	int ret;
 
 	/* If built-in chains don't exist for this table, create them */
-	nft_chain_builtin_init(h, table, NULL, NF_ACCEPT);
+	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
+		nft_chain_builtin_init(h, table, NULL, NF_ACCEPT);
 
 	c = nft_chain_alloc();
 	if (c == NULL) {
@@ -1469,7 +1473,8 @@
 	int ret;
 
 	/* If built-in chains don't exist for this table, create them */
-	nft_chain_builtin_init(h, table, NULL, NF_ACCEPT);
+	if (nft_xtables_config_load(h, XTABLES_CONFIG_DEFAULT, 0) < 0)
+		nft_chain_builtin_init(h, table, NULL, NF_ACCEPT);
 
 	/* Find the old chain to be renamed */
 	c = nft_chain_find(h, table, chain);
@@ -2760,3 +2765,88 @@
 
 	return strerror(err);
 }
+
+static void xtables_config_perror(uint32_t flags, const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+
+	if (flags & NFT_LOAD_VERBOSE)
+		vfprintf(stderr, fmt, args);
+
+	va_end(args);
+}
+
+int nft_xtables_config_load(struct nft_handle *h, const char *filename,
+			    uint32_t flags)
+{
+	struct nft_table_list *table_list = nft_table_list_alloc();
+	struct nft_chain_list *chain_list = nft_chain_list_alloc();
+	struct nft_table_list_iter *titer;
+	struct nft_chain_list_iter *citer;
+	struct nft_table *table;
+	struct nft_chain *chain;
+
+	if (xtables_config_parse(filename, table_list, chain_list) < 0) {
+		if (errno == ENOENT) {
+			xtables_config_perror(flags,
+				"configuration file `%s' does not exists\n",
+				filename);
+		} else {
+			xtables_config_perror(flags,
+				"Fatal error parsing config file: %s\n",
+				 strerror(errno));
+		}
+		return -1;
+	}
+
+	nft_init(h);
+
+	/* Stage 1) create tables */
+	titer = nft_table_list_iter_create(table_list);
+	while ((table = nft_table_list_iter_next(titer)) != NULL) {
+		if (nft_table_add(h, table) < 0) {
+			if (errno == EEXIST) {
+				xtables_config_perror(flags,
+					"table `%s' already exists, skipping\n",
+					(char *)nft_table_attr_get(table, NFT_TABLE_ATTR_NAME));
+			} else {
+				xtables_config_perror(flags,
+					"table `%s' cannot be create, reason `%s'. Exitting\n",
+					(char *)nft_table_attr_get(table, NFT_TABLE_ATTR_NAME),
+					strerror(errno));
+				return -1;
+			}
+			continue;
+		}
+		xtables_config_perror(flags, "table `%s' has been created\n",
+			(char *)nft_table_attr_get(table, NFT_TABLE_ATTR_NAME));
+	}
+
+	/* Stage 2) create chains */
+	citer = nft_chain_list_iter_create(chain_list);
+	while ((chain = nft_chain_list_iter_next(citer)) != NULL) {
+		if (nft_chain_add(h, chain) < 0) {
+			if (errno == EEXIST) {
+				xtables_config_perror(flags,
+					"chain `%s' already exists in table `%s', skipping\n",
+					(char *)nft_chain_attr_get(chain, NFT_CHAIN_ATTR_NAME),
+					(char *)nft_chain_attr_get(chain, NFT_CHAIN_ATTR_TABLE));
+			} else {
+				xtables_config_perror(flags,
+					"chain `%s' cannot be create, reason `%s'. Exitting\n",
+					(char *)nft_chain_attr_get(chain, NFT_CHAIN_ATTR_NAME),
+					strerror(errno));
+				return -1;
+			}
+			continue;
+		}
+
+		xtables_config_perror(flags,
+			"chain `%s' in table `%s' has been created\n",
+			(char *)nft_chain_attr_get(chain, NFT_CHAIN_ATTR_NAME),
+			(char *)nft_chain_attr_get(chain, NFT_CHAIN_ATTR_TABLE));
+	}
+	return 0;
+}
diff --git a/iptables/nft.h b/iptables/nft.h
index d2a9b92..8d5881d 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -84,4 +84,20 @@
 /* For xtables.c */
 int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table);
 
+/*
+ * Parse config for tables and chain helper functions
+ */
+#define XTABLES_CONFIG_DEFAULT  "/etc/xtables.conf"
+
+struct nft_table_list;
+struct nft_chain_list;
+
+extern int xtables_config_parse(const char *filename, struct nft_table_list *table_list, struct nft_chain_list *chain_list);
+
+enum {
+	NFT_LOAD_VERBOSE = (1 << 0),
+};
+
+int nft_xtables_config_load(struct nft_handle *h, const char *filename, uint32_t flags);
+
 #endif
diff --git a/iptables/xtables-config.c b/iptables/xtables-config.c
index fce03a1..3ad46e8 100644
--- a/iptables/xtables-config.c
+++ b/iptables/xtables-config.c
@@ -16,32 +16,15 @@
 #include <string.h>
 #include <errno.h>
 
-#include <libnftables/table.h>
-#include <libnftables/chain.h>
-
 #include "xtables-multi.h"
-#include "xtables-config-parser.h"
-
 #include "nft.h"
 
-extern int xtables_config_parse(const char *filename,
-				struct nft_table_list *table_list,
-				struct nft_chain_list *chain_list);
-
-#define XTABLES_CONFIG_DEFAULT	"/etc/xtables.conf"
-
 int xtables_config_main(int argc, char *argv[])
 {
-	struct nft_table_list *table_list = nft_table_list_alloc();
-	struct nft_chain_list *chain_list = nft_chain_list_alloc();
-	struct nft_table_list_iter *titer;
-	struct nft_chain_list_iter *citer;
-	struct nft_table *table;
-	struct nft_chain *chain;
-	const char *filename = NULL;
 	struct nft_handle h = {
 		.family = AF_INET,
 	};
+	const char *filename = NULL;
 
 	if (argc > 2) {
 		fprintf(stderr, "Usage: %s [<config_file>]\n", argv[0]);
@@ -52,58 +35,6 @@
 	else
 		filename = argv[1];
 
-	if (xtables_config_parse(filename, table_list, chain_list) < 0) {
-		if (errno == ENOENT) {
-			fprintf(stderr, "configuration file `%s' does not "
-					"exists\n", filename);
-		} else {
-			fprintf(stderr, "Fatal error: %s\n", strerror(errno));
-		}
-		return EXIT_FAILURE;
-	}
-
-	nft_init(&h);
-
-	/* Stage 1) create tables */
-	titer = nft_table_list_iter_create(table_list);
-	while ((table = nft_table_list_iter_next(titer)) != NULL) {
-		if (nft_table_add(&h, table) < 0) {
-			if (errno == EEXIST) {
-				printf("table `%s' already exists, skipping\n",
-					(char *)nft_table_attr_get(table, NFT_TABLE_ATTR_NAME));
-			} else {
-				printf("table `%s' cannot be create, reason `%s'. Exitting\n",
-					(char *)nft_table_attr_get(table, NFT_TABLE_ATTR_NAME),
-					strerror(errno));
-				return EXIT_FAILURE;
-			}
-			continue;
-		}
-		printf("table `%s' has been created\n",
-			(char *)nft_table_attr_get(table, NFT_TABLE_ATTR_NAME));
-	}
-
-	/* Stage 2) create chains */
-	citer = nft_chain_list_iter_create(chain_list);
-	while ((chain = nft_chain_list_iter_next(citer)) != NULL) {
-		if (nft_chain_add(&h, chain) < 0) {
-			if (errno == EEXIST) {
-				printf("chain `%s' already exists in table `%s', skipping\n",
-					(char *)nft_chain_attr_get(chain, NFT_CHAIN_ATTR_NAME),
-					(char *)nft_chain_attr_get(chain, NFT_CHAIN_ATTR_TABLE));
-			} else {
-				printf("chain `%s' cannot be create, reason `%s'. Exitting\n",
-					(char *)nft_chain_attr_get(chain, NFT_CHAIN_ATTR_NAME),
-					strerror(errno));
-				return EXIT_FAILURE;
-			}
-			continue;
-		}
-
-		printf("chain `%s' in table `%s' has been created\n",
-			(char *)nft_chain_attr_get(chain, NFT_CHAIN_ATTR_NAME),
-			(char *)nft_chain_attr_get(chain, NFT_CHAIN_ATTR_TABLE));
-	}
-
-	return EXIT_SUCCESS;
+	return nft_xtables_config_load(&h, filename, NFT_LOAD_VERBOSE) == 0 ?
+						    EXIT_SUCCESS : EXIT_FAILURE;
 }