diff options
Diffstat (limited to 'src/libnftables.c')
-rw-r--r-- | src/libnftables.c | 149 |
1 files changed, 101 insertions, 48 deletions
diff --git a/src/libnftables.c b/src/libnftables.c index aac682b7..0dee1bac 100644 --- a/src/libnftables.c +++ b/src/libnftables.c @@ -2,10 +2,12 @@ * Copyright (c) 2017 Eric Leblond <eric@regit.org> * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * + * it under the terms of the GNU General Public License version 2 (or any + * later) as published by the Free Software Foundation. */ + +#include <nft.h> + #include <nftables/libnftables.h> #include <erec.h> #include <mnl.h> @@ -14,12 +16,10 @@ #include <iface.h> #include <cmd.h> #include <errno.h> -#include <stdlib.h> -#include <string.h> +#include <sys/stat.h> static int nft_netlink(struct nft_ctx *nft, - struct list_head *cmds, struct list_head *msgs, - struct mnl_socket *nf_sock) + struct list_head *cmds, struct list_head *msgs) { uint32_t batch_seqnum, seqnum = 0, last_seqnum = UINT32_MAX, num_cmds = 0; struct netlink_ctx ctx = { @@ -56,6 +56,13 @@ static int nft_netlink(struct nft_ctx *nft, ret = mnl_batch_talk(&ctx, &err_list, num_cmds); if (ret < 0) { + if (ctx.maybe_emsgsize && errno == EMSGSIZE) { + netlink_io_error(&ctx, NULL, + "Could not process rule: %s\n" + "Please, rise /proc/sys/net/core/wmem_max on the host namespace. Hint: %d bytes", + strerror(errno), round_pow_2(ctx.maybe_emsgsize)); + goto out; + } netlink_io_error(&ctx, NULL, "Could not process rule: %s", strerror(errno)); goto out; @@ -147,11 +154,11 @@ void nft_ctx_clear_vars(struct nft_ctx *ctx) unsigned int i; for (i = 0; i < ctx->num_vars; i++) { - xfree(ctx->vars[i].key); - xfree(ctx->vars[i].value); + free_const(ctx->vars[i].key); + free_const(ctx->vars[i].value); } ctx->num_vars = 0; - xfree(ctx->vars); + free(ctx->vars); } EXPORT_SYMBOL(nft_ctx_add_include_path); @@ -175,30 +182,20 @@ EXPORT_SYMBOL(nft_ctx_clear_include_paths); void nft_ctx_clear_include_paths(struct nft_ctx *ctx) { while (ctx->num_include_paths) - xfree(ctx->include_paths[--ctx->num_include_paths]); + free(ctx->include_paths[--ctx->num_include_paths]); - xfree(ctx->include_paths); + free(ctx->include_paths); ctx->include_paths = NULL; } -static void nft_ctx_netlink_init(struct nft_ctx *ctx) -{ - ctx->nf_sock = nft_mnl_socket_open(); -} - EXPORT_SYMBOL(nft_ctx_new); struct nft_ctx *nft_ctx_new(uint32_t flags) { - static bool init_once; struct nft_ctx *ctx; - if (!init_once) { - init_once = true; - gmp_init(); #ifdef HAVE_LIBXTABLES - xt_init(); + xt_init(); #endif - } ctx = xzalloc(sizeof(struct nft_ctx)); nft_init(ctx); @@ -213,8 +210,7 @@ struct nft_ctx *nft_ctx_new(uint32_t flags) ctx->output.error_fp = stderr; init_list_head(&ctx->vars_ctx.indesc_list); - if (flags == NFT_CTX_DEFAULT) - nft_ctx_netlink_init(ctx); + ctx->nf_sock = nft_mnl_socket_open(); return ctx; } @@ -338,8 +334,7 @@ const char *nft_ctx_get_error_buffer(struct nft_ctx *ctx) EXPORT_SYMBOL(nft_ctx_free); void nft_ctx_free(struct nft_ctx *ctx) { - if (ctx->nf_sock) - mnl_socket_close(ctx->nf_sock); + mnl_socket_close(ctx->nf_sock); exit_cookie(&ctx->output.output_cookie); exit_cookie(&ctx->output.error_cookie); @@ -348,9 +343,9 @@ void nft_ctx_free(struct nft_ctx *ctx) nft_ctx_clear_vars(ctx); nft_ctx_clear_include_paths(ctx); scope_free(ctx->top_scope); - xfree(ctx->state); + free(ctx->state); nft_exit(ctx); - xfree(ctx); + free(ctx); } EXPORT_SYMBOL(nft_ctx_set_output); @@ -403,6 +398,22 @@ void nft_ctx_set_optimize(struct nft_ctx *ctx, uint32_t flags) ctx->optimize_flags = flags; } +EXPORT_SYMBOL(nft_ctx_input_get_flags); +unsigned int nft_ctx_input_get_flags(struct nft_ctx *ctx) +{ + return ctx->input.flags; +} + +EXPORT_SYMBOL(nft_ctx_input_set_flags); +unsigned int nft_ctx_input_set_flags(struct nft_ctx *ctx, unsigned int flags) +{ + unsigned int old_flags; + + old_flags = ctx->input.flags; + ctx->input.flags = flags; + return old_flags; +} + EXPORT_SYMBOL(nft_ctx_output_get_flags); unsigned int nft_ctx_output_get_flags(struct nft_ctx *ctx) { @@ -506,7 +517,10 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs, int err = 0; filter = nft_cache_filter_init(); - flags = nft_cache_evaluate(nft, cmds, filter); + if (nft_cache_evaluate(nft, cmds, msgs, filter, &flags) < 0) { + nft_cache_filter_fini(filter); + return -1; + } if (nft_cache_update(nft, flags, msgs, filter) < 0) { nft_cache_filter_fini(filter); return -1; @@ -517,6 +531,14 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs, if (nft_cmd_collapse(cmds)) collapsed = true; + list_for_each_entry(cmd, cmds, list) { + if (cmd->op != CMD_ADD && + cmd->op != CMD_CREATE) + continue; + + nft_cmd_expand(cmd); + } + list_for_each_entry_safe(cmd, next, cmds, list) { struct eval_ctx ectx = { .nft = nft, @@ -536,13 +558,6 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs, if (err < 0 || nft->state->nerrs) return -1; - list_for_each_entry(cmd, cmds, list) { - if (cmd->op != CMD_ADD) - continue; - - nft_cmd_expand(cmd); - } - return 0; } @@ -558,7 +573,7 @@ int nft_run_cmd_from_buffer(struct nft_ctx *nft, const char *buf) nlbuf = xzalloc(strlen(buf) + 2); sprintf(nlbuf, "%s\n", buf); - if (nft_output_json(&nft->output)) + if (nft_output_json(&nft->output) || nft_input_json(&nft->input)) rc = nft_parse_json_buffer(nft, nlbuf, &msgs, &cmds); if (rc == -EINVAL) rc = nft_parse_bison_buffer(nft, nlbuf, &msgs, &cmds, @@ -580,7 +595,7 @@ int nft_run_cmd_from_buffer(struct nft_ctx *nft, const char *buf) goto err; } - if (nft_netlink(nft, &cmds, &msgs, nft->nf_sock) != 0) + if (nft_netlink(nft, &cmds, &msgs) != 0) rc = -1; err: erec_print_list(&nft->output, &msgs, nft->debug_mask); @@ -599,8 +614,10 @@ err: nft_output_json(&nft->output) && nft_output_echo(&nft->output)) json_print_echo(nft); - if (rc) + + if (rc || nft->check) nft_cache_release(&nft->cache); + return rc; } @@ -645,19 +662,52 @@ retry: return rc; } +/* need to use stat() to, fopen() will block for named fifos and + * libjansson makes no checks before or after open either. + */ +static struct error_record *filename_is_useable(struct nft_ctx *nft, const char *name) +{ + unsigned int type; + struct stat sb; + int err; + + err = stat(name, &sb); + if (err) + return error(&internal_location, "Could not open file \"%s\": %s\n", + name, strerror(errno)); + + type = sb.st_mode & S_IFMT; + + if (type == S_IFREG || type == S_IFIFO) + return NULL; + + if (type == S_IFCHR && 0 == strcmp(name, "/dev/stdin")) + return NULL; + + return error(&internal_location, "Not a regular file: \"%s\"\n", name); +} + static int __nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename) { + struct error_record *erec; struct cmd *cmd, *next; int rc, parser_rc; LIST_HEAD(msgs); LIST_HEAD(cmds); + erec = filename_is_useable(nft, filename); + if (erec) { + erec_print(&nft->output, erec, nft->debug_mask); + erec_destroy(erec); + return -1; + } + rc = load_cmdline_vars(nft, &msgs); if (rc < 0) goto err; rc = -EINVAL; - if (nft_output_json(&nft->output)) + if (nft_output_json(&nft->output) || nft_input_json(&nft->input)) rc = nft_parse_json_filename(nft, filename, &msgs, &cmds); if (rc == -EINVAL) rc = nft_parse_bison_filename(nft, filename, &msgs, &cmds); @@ -676,7 +726,7 @@ static int __nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename goto err; } - if (nft_netlink(nft, &cmds, &msgs, nft->nf_sock) != 0) + if (nft_netlink(nft, &cmds, &msgs) != 0) rc = -1; err: erec_print_list(&nft->output, &msgs, nft->debug_mask); @@ -694,20 +744,23 @@ err: list_for_each_entry_safe(indesc, next, &nft->vars_ctx.indesc_list, list) { if (indesc->name) - xfree(indesc->name); + free_const(indesc->name); - xfree(indesc); + free(indesc); } } - xfree(nft->vars_ctx.buf); + free_const(nft->vars_ctx.buf); if (!rc && nft_output_json(&nft->output) && nft_output_echo(&nft->output)) json_print_echo(nft); - if (rc) + + if (rc || nft->check) nft_cache_release(&nft->cache); + scope_release(nft->state->scopes[0]); + return rc; } @@ -747,12 +800,12 @@ int nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename) if (nft->optimize_flags) { ret = nft_run_optimized_file(nft, filename); - xfree(nft->stdin_buf); + free_const(nft->stdin_buf); return ret; } ret = __nft_run_cmd_from_filename(nft, filename); - xfree(nft->stdin_buf); + free_const(nft->stdin_buf); return ret; } |