summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2014-07-04 12:24:46 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2014-07-14 12:30:43 +0200
commit09f81768090ffea1dbb0362950b0d5414c609436 (patch)
tree05f388c6ebbbccab960bdb6e93ca8a03c299b860 /src
parent654b51ab84cf10591eba1c443e6d65bf2de35c37 (diff)
mnl: check for NLM_F_DUMP_INTR when dumping object lists
This flag allows to detect that an update has ocurred while dumping any of the object lists. In case of interference, nft cancels the netlink socket to skip processing the remaining stale entries and it retries to obtain fresh list of objects. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r--src/main.c8
-rw-r--r--src/netlink.c42
-rw-r--r--src/rule.c64
3 files changed, 81 insertions, 33 deletions
diff --git a/src/main.c b/src/main.c
index a446bc68..30ea2c6c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -223,8 +223,14 @@ int nft_run(void *scanner, struct parser_state *state, struct list_head *msgs)
ret = nft_parse(scanner, state);
if (ret != 0 || state->nerrs > 0)
return -1;
+retry:
+ ret = nft_netlink(state, msgs);
+ if (ret < 0 && errno == EINTR) {
+ netlink_restart();
+ goto retry;
+ }
- return nft_netlink(state, msgs);
+ return ret;
}
int main(int argc, char * const *argv)
diff --git a/src/netlink.c b/src/netlink.c
index 987dd63e..afad5a46 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -70,6 +70,12 @@ static void __exit netlink_close_sock(void)
mnl_socket_close(nf_mon_sock);
}
+void netlink_restart(void)
+{
+ netlink_close_sock();
+ netlink_open_sock();
+}
+
static void netlink_open_mon_sock(void)
{
nf_mon_sock = nfsock_open();
@@ -443,10 +449,14 @@ static int netlink_list_rules(struct netlink_ctx *ctx, const struct handle *h,
struct nft_rule_list *rule_cache;
rule_cache = mnl_nft_rule_dump(nf_sock, h->family);
- if (rule_cache == NULL)
+ if (rule_cache == NULL) {
+ if (errno == EINTR)
+ return -1;
+
return netlink_io_error(ctx, loc,
"Could not receive rules from kernel: %s",
strerror(errno));
+ }
ctx->data = h;
nft_rule_list_foreach(rule_cache, list_rule_cb, ctx);
@@ -704,10 +714,14 @@ int netlink_list_chains(struct netlink_ctx *ctx, const struct handle *h,
struct chain *chain;
chain_cache = mnl_nft_chain_dump(nf_sock, h->family);
- if (chain_cache == NULL)
+ if (chain_cache == NULL) {
+ if (errno == EINTR)
+ return -1;
+
return netlink_io_error(ctx, loc,
"Could not receive chains from kernel: %s",
strerror(errno));
+ }
ctx->data = h;
nft_chain_list_foreach(chain_cache, list_chain_cb, ctx);
@@ -907,10 +921,14 @@ int netlink_list_tables(struct netlink_ctx *ctx, const struct handle *h,
struct nft_table_list *table_cache;
table_cache = mnl_nft_table_dump(nf_sock, h->family);
- if (table_cache == NULL)
+ if (table_cache == NULL) {
+ if (errno == EINTR)
+ return -1;
+
return netlink_io_error(ctx, loc,
"Could not receive tables from kernel: %s",
strerror(errno));
+ }
nft_table_list_foreach(table_cache, list_table_cb, ctx);
nft_table_list_free(table_cache);
@@ -1177,10 +1195,14 @@ int netlink_list_sets(struct netlink_ctx *ctx, const struct handle *h,
int err;
set_cache = mnl_nft_set_dump(nf_sock, h->family, h->table);
- if (set_cache == NULL)
+ if (set_cache == NULL) {
+ if (errno == EINTR)
+ return -1;
+
return netlink_io_error(ctx, loc,
"Could not receive sets from kernel: %s",
strerror(errno));
+ }
err = nft_set_list_foreach(set_cache, list_set_cb, ctx);
nft_set_list_free(set_cache);
@@ -1393,8 +1415,12 @@ int netlink_get_setelems(struct netlink_ctx *ctx, const struct handle *h,
netlink_dump_set(nls);
err = mnl_nft_setelem_get(nf_sock, nls);
- if (err < 0)
+ if (err < 0) {
+ if (errno == EINTR)
+ return -1;
+
goto out;
+ }
ctx->set = set;
set->init = set_expr_alloc(loc);
@@ -1423,9 +1449,13 @@ struct nft_ruleset *netlink_dump_ruleset(struct netlink_ctx *ctx,
struct nft_ruleset *rs;
rs = mnl_nft_ruleset_dump(nf_sock, h->family);
- if (rs == NULL)
+ if (rs == NULL) {
+ if (errno == EINTR)
+ return NULL;
+
netlink_io_error(ctx, loc, "Could not receive ruleset: %s",
strerror(errno));
+ }
return rs;
}
diff --git a/src/rule.c b/src/rule.c
index a7bc6f44..1e545260 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -14,6 +14,7 @@
#include <stdint.h>
#include <string.h>
#include <inttypes.h>
+#include <errno.h>
#include <statement.h>
#include <rule.h>
@@ -701,12 +702,28 @@ static int do_command_export(struct netlink_ctx *ctx, struct cmd *cmd)
return 0;
}
+static void do_command_list_cleanup(struct table *table)
+{
+ struct chain *chain, *nchain;
+ struct set *set, *nset;
+
+ list_for_each_entry_safe(chain, nchain, &table->chains, list) {
+ list_del(&chain->list);
+ chain_free(chain);
+ }
+
+ list_for_each_entry_safe(set, nset, &table->sets, list) {
+ list_del(&set->list);
+ set_free(set);
+ }
+}
+
static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
{
struct table *table = NULL;
- struct chain *chain, *nchain;
+ struct chain *chain;
struct rule *rule, *nrule;
- struct set *set, *nset;
+ struct set *set;
/* No need to allocate the table object when listing all tables */
if (cmd->handle.table != NULL) {
@@ -726,7 +743,7 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
if (netlink_list_tables(ctx, &cmd->handle,
&cmd->location) < 0)
- return -1;
+ goto err;
list_for_each_entry(table, &ctx->list, list) {
printf("table %s\n", table->handle.table);
@@ -735,39 +752,41 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
}
/* List content of this table */
if (do_list_sets(ctx, &cmd->location, table) < 0)
- return -1;
+ goto err;
if (netlink_list_chains(ctx, &cmd->handle, &cmd->location) < 0)
- return -1;
+ goto err;
list_splice_tail_init(&ctx->list, &table->chains);
if (netlink_list_table(ctx, &cmd->handle, &cmd->location) < 0)
- return -1;
+ goto err;
break;
case CMD_OBJ_CHAIN:
if (do_list_sets(ctx, &cmd->location, table) < 0)
- return -1;
+ goto err;
if (netlink_list_chains(ctx, &cmd->handle, &cmd->location) < 0)
- return -1;
+ goto err;
list_splice_tail_init(&ctx->list, &table->chains);
if (netlink_list_table(ctx, &cmd->handle, &cmd->location) < 0)
- return -1;
+ goto err;
break;
case CMD_OBJ_SETS:
if (netlink_list_sets(ctx, &cmd->handle, &cmd->location) < 0)
- return -1;
+ goto err;
list_for_each_entry(set, &ctx->list, list){
if (netlink_get_setelems(ctx, &set->handle,
- &cmd->location, set) < 0)
- return -1;
+ &cmd->location, set) < 0) {
+ goto err;
+ }
set_print(set);
}
return 0;
case CMD_OBJ_SET:
if (netlink_get_set(ctx, &cmd->handle, &cmd->location) < 0)
- return -1;
+ goto err;
list_for_each_entry(set, &ctx->list, list) {
if (netlink_get_setelems(ctx, &cmd->handle,
- &cmd->location, set) < 0)
- return -1;
+ &cmd->location, set) < 0) {
+ goto err;
+ }
set_print(set);
}
return 0;
@@ -787,18 +806,11 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
}
table_print(table);
-
- list_for_each_entry_safe(chain, nchain, &table->chains, list) {
- list_del(&chain->list);
- chain_free(chain);
- }
-
- list_for_each_entry_safe(set, nset, &table->sets, list) {
- list_del(&set->list);
- set_free(set);
- }
-
+ do_command_list_cleanup(table);
return 0;
+err:
+ do_command_list_cleanup(table);
+ return -1;
}
static int do_command_flush(struct netlink_ctx *ctx, struct cmd *cmd)