From 49900d448ac95ecabd038a9936d467d6e37aacec Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 23 Oct 2017 17:33:16 +0200 Subject: libnftables: Move library stuff out of main.c This creates src/libnftables.c and include/nftables/nftables.h which will become the central elements of libnftables. Signed-off-by: Phil Sutter Signed-off-by: Pablo Neira Ayuso --- src/Makefile.am | 3 +- src/libnftables.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 252 +-------------------------------------------------- 3 files changed, 265 insertions(+), 252 deletions(-) create mode 100644 src/libnftables.c (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 99eef7bb..4d613a73 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -56,7 +56,8 @@ nft_SOURCES = main.c \ mergesort.c \ scanner.l \ tcpopt.c \ - parser_bison.y + parser_bison.y \ + libnftables.c if BUILD_CLI nft_SOURCES += cli.c diff --git a/src/libnftables.c b/src/libnftables.c new file mode 100644 index 00000000..9bc51dd8 --- /dev/null +++ b/src/libnftables.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2017 Eric Leblond + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include + +#include +#include + +static int nft_netlink(struct nft_ctx *nft, + struct parser_state *state, struct list_head *msgs, + struct mnl_socket *nf_sock) +{ + uint32_t batch_seqnum, seqnum = 0; + struct nftnl_batch *batch; + struct netlink_ctx ctx; + struct cmd *cmd; + struct mnl_err *err, *tmp; + LIST_HEAD(err_list); + bool batch_supported = netlink_batch_supported(nf_sock, &seqnum); + int ret = 0; + + batch = mnl_batch_init(); + + batch_seqnum = mnl_batch_begin(batch, mnl_seqnum_alloc(&seqnum)); + list_for_each_entry(cmd, &state->cmds, list) { + memset(&ctx, 0, sizeof(ctx)); + ctx.msgs = msgs; + ctx.seqnum = cmd->seqnum = mnl_seqnum_alloc(&seqnum); + ctx.batch = batch; + ctx.batch_supported = batch_supported; + ctx.octx = &nft->output; + ctx.nf_sock = nf_sock; + ctx.cache = &nft->cache; + ctx.debug_mask = nft->debug_mask; + init_list_head(&ctx.list); + ret = do_command(&ctx, cmd); + if (ret < 0) + goto out; + } + if (!nft->check) + mnl_batch_end(batch, mnl_seqnum_alloc(&seqnum)); + + if (!mnl_batch_ready(batch)) + goto out; + + ret = netlink_batch_send(&ctx, &err_list); + + list_for_each_entry_safe(err, tmp, &err_list, head) { + list_for_each_entry(cmd, &state->cmds, list) { + if (err->seqnum == cmd->seqnum || + err->seqnum == batch_seqnum) { + netlink_io_error(&ctx, &cmd->location, + "Could not process rule: %s", + strerror(err->err)); + errno = err->err; + if (err->seqnum == cmd->seqnum) { + mnl_err_list_free(err); + break; + } + } + } + } +out: + mnl_batch_reset(batch); + return ret; +} + +int nft_run(struct nft_ctx *nft, struct mnl_socket *nf_sock, + void *scanner, struct parser_state *state, + struct list_head *msgs) +{ + struct cmd *cmd, *next; + int ret; + + ret = nft_parse(nft, scanner, state); + if (ret != 0 || state->nerrs > 0) { + ret = -1; + goto err1; + } + + list_for_each_entry(cmd, &state->cmds, list) + nft_cmd_expand(cmd); + + ret = nft_netlink(nft, state, msgs, nf_sock); +err1: + list_for_each_entry_safe(cmd, next, &state->cmds, list) { + list_del(&cmd->list); + cmd_free(cmd); + } + + return ret; +} + +static void nft_init(void) +{ + mark_table_init(); + realm_table_rt_init(); + devgroup_table_init(); + realm_table_meta_init(); + ct_label_table_init(); + gmp_init(); +#ifdef HAVE_LIBXTABLES + xt_init(); +#endif +} + +static void nft_exit(void) +{ + ct_label_table_exit(); + realm_table_rt_exit(); + devgroup_table_exit(); + realm_table_meta_exit(); + mark_table_exit(); +} + +static void nft_ctx_netlink_init(struct nft_ctx *ctx) +{ + ctx->nf_sock = netlink_open_sock(); +} + +struct nft_ctx *nft_ctx_new(uint32_t flags) +{ + struct nft_ctx *ctx; + + nft_init(); + ctx = xzalloc(sizeof(struct nft_ctx)); + + ctx->include_paths[0] = DEFAULT_INCLUDE_PATH; + ctx->num_include_paths = 1; + ctx->parser_max_errors = 10; + init_list_head(&ctx->cache.list); + ctx->flags = flags; + + if (flags == NFT_CTX_DEFAULT) + nft_ctx_netlink_init(ctx); + + return ctx; +} + +void nft_ctx_free(struct nft_ctx *ctx) +{ + if (ctx->nf_sock) + netlink_close_sock(ctx->nf_sock); + + iface_cache_release(); + cache_release(&ctx->cache); + xfree(ctx); + nft_exit(); +} + +FILE *nft_ctx_set_output(struct nft_ctx *ctx, FILE *fp) +{ + FILE *old = ctx->output.output_fp; + + ctx->output.output_fp = fp; + + return old; +} + +static const struct input_descriptor indesc_cmdline = { + .type = INDESC_BUFFER, + .name = "", +}; + +int nft_run_cmd_from_buffer(struct nft_ctx *nft, char *buf, size_t buflen) +{ + int rc = NFT_EXIT_SUCCESS; + struct parser_state state; + LIST_HEAD(msgs); + void *scanner; + FILE *fp; + + parser_init(nft->nf_sock, &nft->cache, &state, + &msgs, nft->debug_mask, &nft->output); + scanner = scanner_init(&state); + scanner_push_buffer(scanner, &indesc_cmdline, buf); + + if (nft_run(nft, nft->nf_sock, scanner, &state, &msgs) != 0) + rc = NFT_EXIT_FAILURE; + + fp = nft_ctx_set_output(nft, stderr); + erec_print_list(&nft->output, &msgs, nft->debug_mask); + nft_ctx_set_output(nft, fp); + scanner_destroy(scanner); + + return rc; +} + +int nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename) +{ + struct parser_state state; + LIST_HEAD(msgs); + void *scanner; + int rc; + FILE *fp; + + rc = cache_update(nft->nf_sock, &nft->cache, CMD_INVALID, &msgs, + nft->debug_mask, &nft->output); + if (rc < 0) + return NFT_EXIT_FAILURE; + + parser_init(nft->nf_sock, &nft->cache, &state, + &msgs, nft->debug_mask, &nft->output); + scanner = scanner_init(&state); + if (scanner_read_file(scanner, filename, &internal_location) < 0) { + rc = NFT_EXIT_FAILURE; + goto err; + } + + if (nft_run(nft, nft->nf_sock, scanner, &state, &msgs) != 0) + rc = NFT_EXIT_FAILURE; +err: + fp = nft_ctx_set_output(nft, stderr); + erec_print_list(&nft->output, &msgs, nft->debug_mask); + nft_ctx_set_output(nft, fp); + scanner_destroy(scanner); + + return rc; +} + +int nft_print(struct output_ctx *octx, const char *fmt, ...) +{ + int ret; + va_list arg; + + if (!octx->output_fp) + return -1; + + va_start(arg, fmt); + ret = vfprintf(octx->output_fp, fmt, arg); + va_end(arg); + fflush(octx->output_fp); + + return ret; +} + +int nft_gmp_print(struct output_ctx *octx, const char *fmt, ...) +{ + int ret; + va_list arg; + + if (!octx->output_fp) + return -1; + + va_start(arg, fmt); + ret = gmp_vfprintf(octx->output_fp, fmt, arg); + va_end(arg); + fflush(octx->output_fp); + + return ret; +} + diff --git a/src/main.c b/src/main.c index 1b268380..b9938c9c 100644 --- a/src/main.c +++ b/src/main.c @@ -18,14 +18,9 @@ #include #include -#include +#include #include #include -#include -#include -#include -#include -#include #include static struct nft_ctx *nft; @@ -169,251 +164,6 @@ static const struct { }, }; -static const struct input_descriptor indesc_cmdline = { - .type = INDESC_BUFFER, - .name = "", -}; - -static int nft_netlink(struct nft_ctx *nft, - struct parser_state *state, struct list_head *msgs, - struct mnl_socket *nf_sock) -{ - uint32_t batch_seqnum, seqnum = 0; - struct nftnl_batch *batch; - struct netlink_ctx ctx; - struct cmd *cmd; - struct mnl_err *err, *tmp; - LIST_HEAD(err_list); - bool batch_supported = netlink_batch_supported(nf_sock, &seqnum); - int ret = 0; - - batch = mnl_batch_init(); - - batch_seqnum = mnl_batch_begin(batch, mnl_seqnum_alloc(&seqnum)); - list_for_each_entry(cmd, &state->cmds, list) { - memset(&ctx, 0, sizeof(ctx)); - ctx.msgs = msgs; - ctx.seqnum = cmd->seqnum = mnl_seqnum_alloc(&seqnum); - ctx.batch = batch; - ctx.batch_supported = batch_supported; - ctx.octx = &nft->output; - ctx.nf_sock = nf_sock; - ctx.cache = &nft->cache; - ctx.debug_mask = nft->debug_mask; - init_list_head(&ctx.list); - ret = do_command(&ctx, cmd); - if (ret < 0) - goto out; - } - if (!nft->check) - mnl_batch_end(batch, mnl_seqnum_alloc(&seqnum)); - - if (!mnl_batch_ready(batch)) - goto out; - - ret = netlink_batch_send(&ctx, &err_list); - - list_for_each_entry_safe(err, tmp, &err_list, head) { - list_for_each_entry(cmd, &state->cmds, list) { - if (err->seqnum == cmd->seqnum || - err->seqnum == batch_seqnum) { - netlink_io_error(&ctx, &cmd->location, - "Could not process rule: %s", - strerror(err->err)); - errno = err->err; - if (err->seqnum == cmd->seqnum) { - mnl_err_list_free(err); - break; - } - } - } - } -out: - mnl_batch_reset(batch); - return ret; -} - -int nft_run(struct nft_ctx *nft, struct mnl_socket *nf_sock, - void *scanner, struct parser_state *state, - struct list_head *msgs) -{ - struct cmd *cmd, *next; - int ret; - - ret = nft_parse(nft, scanner, state); - if (ret != 0 || state->nerrs > 0) { - ret = -1; - goto err1; - } - - list_for_each_entry(cmd, &state->cmds, list) - nft_cmd_expand(cmd); - - ret = nft_netlink(nft, state, msgs, nf_sock); -err1: - list_for_each_entry_safe(cmd, next, &state->cmds, list) { - list_del(&cmd->list); - cmd_free(cmd); - } - - return ret; -} - -static void nft_init(void) -{ - mark_table_init(); - realm_table_rt_init(); - devgroup_table_init(); - realm_table_meta_init(); - ct_label_table_init(); - gmp_init(); -#ifdef HAVE_LIBXTABLES - xt_init(); -#endif -} - -static void nft_exit(void) -{ - ct_label_table_exit(); - realm_table_rt_exit(); - devgroup_table_exit(); - realm_table_meta_exit(); - mark_table_exit(); -} - -static void nft_ctx_netlink_init(struct nft_ctx *ctx) -{ - ctx->nf_sock = netlink_open_sock(); -} - -static struct nft_ctx *nft_ctx_new(uint32_t flags) -{ - struct nft_ctx *ctx; - - nft_init(); - ctx = xzalloc(sizeof(struct nft_ctx)); - - ctx->include_paths[0] = DEFAULT_INCLUDE_PATH; - ctx->num_include_paths = 1; - ctx->parser_max_errors = 10; - init_list_head(&ctx->cache.list); - ctx->flags = flags; - - if (flags == NFT_CTX_DEFAULT) - nft_ctx_netlink_init(ctx); - - return ctx; -} - -static void nft_ctx_free(struct nft_ctx *ctx) -{ - if (ctx->nf_sock) - netlink_close_sock(ctx->nf_sock); - - iface_cache_release(); - cache_release(&ctx->cache); - xfree(ctx); - nft_exit(); -} - -static FILE *nft_ctx_set_output(struct nft_ctx *ctx, FILE *fp) -{ - FILE *old = ctx->output.output_fp; - - ctx->output.output_fp = fp; - - return old; -} - -static int nft_run_cmd_from_buffer(struct nft_ctx *nft, - char *buf, size_t buflen) -{ - int rc = NFT_EXIT_SUCCESS; - struct parser_state state; - LIST_HEAD(msgs); - void *scanner; - FILE *fp; - - parser_init(nft->nf_sock, &nft->cache, &state, - &msgs, nft->debug_mask, &nft->output); - scanner = scanner_init(&state); - scanner_push_buffer(scanner, &indesc_cmdline, buf); - - if (nft_run(nft, nft->nf_sock, scanner, &state, &msgs) != 0) - rc = NFT_EXIT_FAILURE; - - fp = nft_ctx_set_output(nft, stderr); - erec_print_list(&nft->output, &msgs, nft->debug_mask); - nft_ctx_set_output(nft, fp); - scanner_destroy(scanner); - - return rc; -} - -static int nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename) -{ - struct parser_state state; - LIST_HEAD(msgs); - void *scanner; - int rc; - FILE *fp; - - rc = cache_update(nft->nf_sock, &nft->cache, CMD_INVALID, &msgs, - nft->debug_mask, &nft->output); - if (rc < 0) - return NFT_EXIT_FAILURE; - - parser_init(nft->nf_sock, &nft->cache, &state, - &msgs, nft->debug_mask, &nft->output); - scanner = scanner_init(&state); - if (scanner_read_file(scanner, filename, &internal_location) < 0) { - rc = NFT_EXIT_FAILURE; - goto err; - } - - if (nft_run(nft, nft->nf_sock, scanner, &state, &msgs) != 0) - rc = NFT_EXIT_FAILURE; -err: - fp = nft_ctx_set_output(nft, stderr); - erec_print_list(&nft->output, &msgs, nft->debug_mask); - nft_ctx_set_output(nft, fp); - scanner_destroy(scanner); - - return rc; -} - -int nft_print(struct output_ctx *octx, const char *fmt, ...) -{ - int ret; - va_list arg; - - if (!octx->output_fp) - return -1; - - va_start(arg, fmt); - ret = vfprintf(octx->output_fp, fmt, arg); - va_end(arg); - fflush(octx->output_fp); - - return ret; -} - -int nft_gmp_print(struct output_ctx *octx, const char *fmt, ...) -{ - int ret; - va_list arg; - - if (!octx->output_fp) - return -1; - - va_start(arg, fmt); - ret = gmp_vfprintf(octx->output_fp, fmt, arg); - va_end(arg); - fflush(octx->output_fp); - - return ret; -} - int main(int argc, char * const *argv) { char *buf = NULL, *filename = NULL; -- cgit v1.2.3