From 0aad20f3979e3b6becd40e4ed5bba8d09d90706e Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 20 Jan 2013 22:32:43 +0100 Subject: xtables: purge out user-define chains from the kernel xtables-restore has to purge out user-defined chains that are not defined in the configuration file. Signed-off-by: Pablo Neira Ayuso --- iptables/nft.c | 63 +++++++++++++++++++++++++++++++++++++++------- iptables/nft.h | 3 +++ iptables/xtables-restore.c | 23 ++++++++++++++--- 3 files changed, 76 insertions(+), 13 deletions(-) diff --git a/iptables/nft.c b/iptables/nft.c index 43b13deb..fd19ff55 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1801,19 +1801,13 @@ err: return ret == 0 ? 1 : 0; } -static struct nft_chain * -nft_chain_find(struct nft_handle *h, const char *table, const char *chain) +struct nft_chain * +nft_chain_list_find(struct nft_handle *h, struct nft_chain_list *list, + const char *table, const char *chain) { - struct nft_chain_list *list; struct nft_chain_list_iter *iter; struct nft_chain *c; - list = nft_chain_list_get(h); - if (list == NULL) { - DEBUGP("cannot allocate chain list\n"); - return NULL; - } - iter = nft_chain_list_iter_create(list); if (iter == NULL) { DEBUGP("cannot allocate rule list iterator\n"); @@ -1833,13 +1827,29 @@ nft_chain_find(struct nft_handle *h, const char *table, const char *chain) if (strcmp(chain, chain_name) != 0) goto next; + nft_chain_list_iter_destroy(iter); return c; next: c = nft_chain_list_iter_next(iter); } + nft_chain_list_iter_destroy(iter); return NULL; } +static struct nft_chain * +nft_chain_find(struct nft_handle *h, const char *table, const char *chain) +{ + struct nft_chain_list *list; + + list = nft_chain_list_get(h); + if (list == NULL) { + DEBUGP("cannot allocate chain list\n"); + return NULL; + } + + return nft_chain_list_find(h, list, table, chain); +} + int nft_chain_user_rename(struct nft_handle *h,const char *chain, const char *table, const char *newname) { @@ -2006,6 +2016,41 @@ err: return ret == 0 ? 1 : 0; } +int nft_table_purge_chains(struct nft_handle *h, const char *this_table, + struct nft_chain_list *chain_list) +{ + struct nft_chain_list_iter *iter; + struct nft_chain *chain_obj; + + iter = nft_chain_list_iter_create(chain_list); + if (iter == NULL) { + DEBUGP("cannot allocate rule list iterator\n"); + return 0; + } + + chain_obj = nft_chain_list_iter_next(iter); + while (chain_obj != NULL) { + const char *table = + nft_chain_attr_get_str(chain_obj, NFT_CHAIN_ATTR_TABLE); + + if (strcmp(this_table, table) != 0) + goto next; + + if (nft_chain_builtin(chain_obj)) + goto next; + + if ( __nft_chain_del(h, chain_obj) < 0) { + if (errno != EBUSY) + return -1; + } +next: + chain_obj = nft_chain_list_iter_next(iter); + } + nft_chain_list_iter_destroy(iter); + + return 0; +} + static inline int match_different(const struct xt_entry_match *a, const unsigned char *a_elems, diff --git a/iptables/nft.h b/iptables/nft.h index 00216681..f7ed0a38 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -17,12 +17,14 @@ void nft_fini(struct nft_handle *h); * Operations with tables. */ struct nft_table; +struct nft_chain_list; int nft_table_add(struct nft_handle *h, const struct nft_table *t); int nft_for_each_table(struct nft_handle *h, int (*func)(struct nft_handle *h, const char *tablename, bool counters), bool counters); bool nft_table_find(struct nft_handle *h, const char *tablename); int nft_table_set_dormant(struct nft_handle *h, const char *table); int nft_table_wake_dormant(struct nft_handle *h, const char *table); +int nft_table_purge_chains(struct nft_handle *h, const char *table, struct nft_chain_list *list); /* * Operations with chains. @@ -32,6 +34,7 @@ struct nft_chain; int nft_chain_add(struct nft_handle *h, const struct nft_chain *c); int nft_chain_set(struct nft_handle *h, const char *table, const char *chain, const char *policy, const struct xt_counters *counters); struct nft_chain_list *nft_chain_dump(struct nft_handle *h); +struct nft_chain *nft_chain_list_find(struct nft_handle *h, struct nft_chain_list *list, const char *table, const char *chain); int nft_chain_save(struct nft_handle *h, struct nft_chain_list *list, const char *table); int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *table); int nft_chain_user_del(struct nft_handle *h, const char *chain, const char *table); diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c index f6009776..9778a9f7 100644 --- a/iptables/xtables-restore.c +++ b/iptables/xtables-restore.c @@ -16,6 +16,7 @@ #include "libiptc/libiptc.h" #include "xtables-multi.h" #include "nft.h" +#include #ifdef DEBUG #define DEBUGP(x, args...) fprintf(stderr, x, ## args) @@ -171,6 +172,8 @@ xtables_restore_main(int argc, char *argv[]) int in_table = 0, testing = 0; const char *tablename = NULL; const struct xtc_ops *ops = &iptc_ops; + struct nft_chain_list *chain_list; + struct nft_chain *chain_obj; line = 0; @@ -233,6 +236,10 @@ xtables_restore_main(int argc, char *argv[]) } else in = stdin; + chain_list = nft_chain_dump(&h); + if (chain_list == NULL) + xtables_error(OTHER_PROBLEM, "cannot retrieve chain list\n"); + /* Grab standard input. */ while (fgets(buffer, sizeof(buffer), in)) { int ret = 0; @@ -259,6 +266,10 @@ xtables_restore_main(int argc, char *argv[]) ret = 1; } in_table = 0; + + /* Purge out unused chains in this table */ + nft_table_purge_chains(&h, curtable, chain_list); + } else if ((buffer[0] == '*') && (!in_table)) { /* New table */ char *table; @@ -282,10 +293,6 @@ xtables_restore_main(int argc, char *argv[]) DEBUGP("Cleaning all chains of table '%s'\n", table); nft_rule_flush(&h, NULL, table); - - DEBUGP("Deleting all user-defined chains " - "of table '%s'\n", table); - nft_chain_user_del(&h, NULL, table); } ret = 1; @@ -305,6 +312,14 @@ xtables_restore_main(int argc, char *argv[]) exit(1); } + chain_obj = nft_chain_list_find(&h, chain_list, + curtable, chain); + /* This chain has been found, delete from list. Later + * on, unvisited chains will be purged out. + */ + if (chain_obj != NULL) + nft_chain_list_del(chain_obj); + if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN) xtables_error(PARAMETER_PROBLEM, "Invalid chain name `%s' " -- cgit v1.2.3