|
Packit |
c5a612 |
/*
|
|
Packit |
c5a612 |
* Copyright (c) 2017 Eric Leblond <eric@regit.org>
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
c5a612 |
* it under the terms of the GNU General Public License version 2 as
|
|
Packit |
c5a612 |
* published by the Free Software Foundation.
|
|
Packit |
c5a612 |
*
|
|
Packit |
c5a612 |
*/
|
|
Packit |
c5a612 |
#include <nftables/libnftables.h>
|
|
Packit |
c5a612 |
#include <erec.h>
|
|
Packit |
c5a612 |
#include <mnl.h>
|
|
Packit |
c5a612 |
#include <parser.h>
|
|
Packit |
c5a612 |
#include <utils.h>
|
|
Packit |
c5a612 |
#include <iface.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
#include <errno.h>
|
|
Packit |
c5a612 |
#include <stdlib.h>
|
|
Packit |
c5a612 |
#include <string.h>
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int nft_netlink(struct nft_ctx *nft,
|
|
Packit |
c5a612 |
struct list_head *cmds, struct list_head *msgs,
|
|
Packit |
c5a612 |
struct mnl_socket *nf_sock)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
uint32_t batch_seqnum, seqnum = 0, num_cmds = 0;
|
|
Packit |
c5a612 |
struct netlink_ctx ctx = {
|
|
Packit |
c5a612 |
.nft = nft,
|
|
Packit |
c5a612 |
.msgs = msgs,
|
|
Packit |
c5a612 |
.list = LIST_HEAD_INIT(ctx.list),
|
|
Packit |
c5a612 |
.batch = mnl_batch_init(),
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
struct cmd *cmd;
|
|
Packit |
c5a612 |
struct mnl_err *err, *tmp;
|
|
Packit |
c5a612 |
LIST_HEAD(err_list);
|
|
Packit |
c5a612 |
int ret = 0;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (list_empty(cmds))
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
batch_seqnum = mnl_batch_begin(ctx.batch, mnl_seqnum_alloc(&seqnum));
|
|
Packit |
c5a612 |
list_for_each_entry(cmd, cmds, list) {
|
|
Packit |
c5a612 |
ctx.seqnum = cmd->seqnum = mnl_seqnum_alloc(&seqnum);
|
|
Packit |
c5a612 |
ret = do_command(&ctx, cmd);
|
|
Packit |
c5a612 |
if (ret < 0) {
|
|
Packit |
c5a612 |
netlink_io_error(&ctx, &cmd->location,
|
|
Packit |
c5a612 |
"Could not process rule: %s",
|
|
Packit |
c5a612 |
strerror(errno));
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
num_cmds++;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
if (!nft->check)
|
|
Packit |
c5a612 |
mnl_batch_end(ctx.batch, mnl_seqnum_alloc(&seqnum));
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!mnl_batch_ready(ctx.batch))
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = mnl_batch_talk(&ctx, &err_list, num_cmds);
|
|
Packit |
c5a612 |
if (ret < 0) {
|
|
Packit |
c5a612 |
netlink_io_error(&ctx, NULL,
|
|
Packit |
c5a612 |
"Could not process rule: %s", strerror(errno));
|
|
Packit |
c5a612 |
goto out;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!list_empty(&err_list))
|
|
Packit |
c5a612 |
ret = -1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
list_for_each_entry_safe(err, tmp, &err_list, head) {
|
|
Packit |
c5a612 |
list_for_each_entry(cmd, cmds, list) {
|
|
Packit |
c5a612 |
if (err->seqnum == cmd->seqnum ||
|
|
Packit |
c5a612 |
err->seqnum == batch_seqnum) {
|
|
Packit |
c5a612 |
netlink_io_error(&ctx, &cmd->location,
|
|
Packit |
c5a612 |
"Could not process rule: %s",
|
|
Packit |
c5a612 |
strerror(err->err));
|
|
Packit |
c5a612 |
errno = err->err;
|
|
Packit |
c5a612 |
if (err->seqnum == cmd->seqnum) {
|
|
Packit |
c5a612 |
mnl_err_list_free(err);
|
|
Packit |
c5a612 |
break;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
out:
|
|
Packit |
c5a612 |
mnl_batch_reset(ctx.batch);
|
|
Packit |
c5a612 |
return ret;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void nft_init(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
mark_table_init(ctx);
|
|
Packit |
c5a612 |
realm_table_rt_init(ctx);
|
|
Packit |
c5a612 |
devgroup_table_init(ctx);
|
|
Packit |
c5a612 |
ct_label_table_init(ctx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void nft_exit(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
ct_label_table_exit(ctx);
|
|
Packit |
c5a612 |
realm_table_rt_exit(ctx);
|
|
Packit |
c5a612 |
devgroup_table_exit(ctx);
|
|
Packit |
c5a612 |
mark_table_exit(ctx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_add_include_path);
|
|
Packit |
c5a612 |
int nft_ctx_add_include_path(struct nft_ctx *ctx, const char *path)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
char **tmp;
|
|
Packit |
c5a612 |
int pcount = ctx->num_include_paths;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
tmp = realloc(ctx->include_paths, (pcount + 1) * sizeof(char *));
|
|
Packit |
c5a612 |
if (!tmp)
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ctx->include_paths = tmp;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (asprintf(&ctx->include_paths[pcount], "%s", path) < 0)
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ctx->num_include_paths++;
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_clear_include_paths);
|
|
Packit |
c5a612 |
void nft_ctx_clear_include_paths(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
while (ctx->num_include_paths)
|
|
Packit |
c5a612 |
xfree(ctx->include_paths[--ctx->num_include_paths]);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
xfree(ctx->include_paths);
|
|
Packit |
c5a612 |
ctx->include_paths = NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static void nft_ctx_netlink_init(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
ctx->nf_sock = nft_mnl_socket_open();
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_new);
|
|
Packit |
c5a612 |
struct nft_ctx *nft_ctx_new(uint32_t flags)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
static bool init_once;
|
|
Packit |
c5a612 |
struct nft_ctx *ctx;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!init_once) {
|
|
Packit |
c5a612 |
init_once = true;
|
|
Packit |
c5a612 |
gmp_init();
|
|
Packit |
c5a612 |
#ifdef HAVE_LIBXTABLES
|
|
Packit |
c5a612 |
xt_init();
|
|
Packit |
c5a612 |
#endif
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ctx = xzalloc(sizeof(struct nft_ctx));
|
|
Packit |
c5a612 |
nft_init(ctx);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ctx->state = xzalloc(sizeof(struct parser_state));
|
|
Packit |
c5a612 |
nft_ctx_add_include_path(ctx, DEFAULT_INCLUDE_PATH);
|
|
Packit |
c5a612 |
ctx->parser_max_errors = 10;
|
|
Packit |
c5a612 |
init_list_head(&ctx->cache.list);
|
|
Packit |
c5a612 |
ctx->top_scope = scope_alloc();
|
|
Packit |
c5a612 |
ctx->flags = flags;
|
|
Packit |
c5a612 |
ctx->output.output_fp = stdout;
|
|
Packit |
c5a612 |
ctx->output.error_fp = stderr;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (flags == NFT_CTX_DEFAULT)
|
|
Packit |
c5a612 |
nft_ctx_netlink_init(ctx);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return ctx;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static ssize_t cookie_write(void *cptr, const char *buf, size_t buflen)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct cookie *cookie = cptr;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!cookie->buflen) {
|
|
Packit |
c5a612 |
cookie->buflen = buflen + 1;
|
|
Packit |
c5a612 |
cookie->buf = xmalloc(cookie->buflen);
|
|
Packit |
c5a612 |
} else if (cookie->pos + buflen >= cookie->buflen) {
|
|
Packit |
c5a612 |
size_t newlen = cookie->buflen * 2;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
while (newlen <= cookie->pos + buflen)
|
|
Packit |
c5a612 |
newlen *= 2;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
cookie->buf = xrealloc(cookie->buf, newlen);
|
|
Packit |
c5a612 |
cookie->buflen = newlen;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
memcpy(cookie->buf + cookie->pos, buf, buflen);
|
|
Packit |
c5a612 |
cookie->pos += buflen;
|
|
Packit |
c5a612 |
cookie->buf[cookie->pos] = '\0';
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return buflen;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int init_cookie(struct cookie *cookie)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
cookie_io_functions_t cookie_fops = {
|
|
Packit |
c5a612 |
.write = cookie_write,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (cookie->orig_fp) { /* just rewind buffer */
|
|
Packit |
c5a612 |
if (cookie->buflen) {
|
|
Packit |
c5a612 |
cookie->pos = 0;
|
|
Packit |
c5a612 |
cookie->buf[0] = '\0';
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
cookie->orig_fp = cookie->fp;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
cookie->fp = fopencookie(cookie, "w", cookie_fops);
|
|
Packit |
c5a612 |
if (!cookie->fp) {
|
|
Packit |
c5a612 |
cookie->fp = cookie->orig_fp;
|
|
Packit |
c5a612 |
cookie->orig_fp = NULL;
|
|
Packit |
c5a612 |
return 1;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int exit_cookie(struct cookie *cookie)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (!cookie->orig_fp)
|
|
Packit |
c5a612 |
return 1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
fclose(cookie->fp);
|
|
Packit |
c5a612 |
cookie->fp = cookie->orig_fp;
|
|
Packit |
c5a612 |
cookie->orig_fp = NULL;
|
|
Packit |
c5a612 |
free(cookie->buf);
|
|
Packit |
c5a612 |
cookie->buf = NULL;
|
|
Packit |
c5a612 |
cookie->buflen = 0;
|
|
Packit |
c5a612 |
cookie->pos = 0;
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_buffer_output);
|
|
Packit |
c5a612 |
int nft_ctx_buffer_output(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return init_cookie(&ctx->output.output_cookie);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_unbuffer_output);
|
|
Packit |
c5a612 |
int nft_ctx_unbuffer_output(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return exit_cookie(&ctx->output.output_cookie);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_buffer_error);
|
|
Packit |
c5a612 |
int nft_ctx_buffer_error(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return init_cookie(&ctx->output.error_cookie);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_unbuffer_error);
|
|
Packit |
c5a612 |
int nft_ctx_unbuffer_error(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return exit_cookie(&ctx->output.error_cookie);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const char *get_cookie_buffer(struct cookie *cookie)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
fflush(cookie->fp);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
/* This is a bit tricky: Rewind the buffer for future use and return
|
|
Packit |
c5a612 |
* the old content at the same time. Therefore return an empty string
|
|
Packit |
c5a612 |
* if buffer position is zero, otherwise just rewind buffer position
|
|
Packit |
c5a612 |
* and return the unmodified buffer. */
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!cookie->pos)
|
|
Packit |
c5a612 |
return "";
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
cookie->pos = 0;
|
|
Packit |
c5a612 |
return cookie->buf;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_get_output_buffer);
|
|
Packit |
c5a612 |
const char *nft_ctx_get_output_buffer(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return get_cookie_buffer(&ctx->output.output_cookie);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_get_error_buffer);
|
|
Packit |
c5a612 |
const char *nft_ctx_get_error_buffer(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return get_cookie_buffer(&ctx->output.error_cookie);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_free);
|
|
Packit |
c5a612 |
void nft_ctx_free(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
if (ctx->nf_sock)
|
|
Packit |
c5a612 |
mnl_socket_close(ctx->nf_sock);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
exit_cookie(&ctx->output.output_cookie);
|
|
Packit |
c5a612 |
exit_cookie(&ctx->output.error_cookie);
|
|
Packit |
c5a612 |
iface_cache_release();
|
|
Packit |
c5a612 |
cache_release(&ctx->cache);
|
|
Packit |
c5a612 |
nft_ctx_clear_include_paths(ctx);
|
|
Packit |
c5a612 |
scope_free(ctx->top_scope);
|
|
Packit |
c5a612 |
xfree(ctx->state);
|
|
Packit |
c5a612 |
nft_exit(ctx);
|
|
Packit |
c5a612 |
xfree(ctx);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_set_output);
|
|
Packit |
c5a612 |
FILE *nft_ctx_set_output(struct nft_ctx *ctx, FILE *fp)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
FILE *old = ctx->output.output_fp;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!fp || ferror(fp))
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ctx->output.output_fp = fp;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return old;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_set_error);
|
|
Packit |
c5a612 |
FILE *nft_ctx_set_error(struct nft_ctx *ctx, FILE *fp)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
FILE *old = ctx->output.error_fp;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!fp || ferror(fp))
|
|
Packit |
c5a612 |
return NULL;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ctx->output.error_fp = fp;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return old;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_get_dry_run);
|
|
Packit |
c5a612 |
bool nft_ctx_get_dry_run(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return ctx->check;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_set_dry_run);
|
|
Packit |
c5a612 |
void nft_ctx_set_dry_run(struct nft_ctx *ctx, bool dry)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
ctx->check = dry;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_output_get_flags);
|
|
Packit |
c5a612 |
unsigned int nft_ctx_output_get_flags(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return ctx->output.flags;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_output_set_flags);
|
|
Packit |
c5a612 |
void nft_ctx_output_set_flags(struct nft_ctx *ctx, unsigned int flags)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
ctx->output.flags = flags;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_output_get_debug);
|
|
Packit |
c5a612 |
unsigned int nft_ctx_output_get_debug(struct nft_ctx *ctx)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
return ctx->debug_mask;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_ctx_output_set_debug);
|
|
Packit |
c5a612 |
void nft_ctx_output_set_debug(struct nft_ctx *ctx, unsigned int mask)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
ctx->debug_mask = mask;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static const struct input_descriptor indesc_cmdline = {
|
|
Packit |
c5a612 |
.type = INDESC_BUFFER,
|
|
Packit |
c5a612 |
.name = "<cmdline>",
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int nft_parse_bison_buffer(struct nft_ctx *nft, const char *buf,
|
|
Packit |
c5a612 |
struct list_head *msgs, struct list_head *cmds)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
int ret;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
parser_init(nft, nft->state, msgs, cmds, nft->top_scope);
|
|
Packit |
c5a612 |
nft->scanner = scanner_init(nft->state);
|
|
Packit |
c5a612 |
scanner_push_buffer(nft->scanner, &indesc_cmdline, buf);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = nft_parse(nft, nft->scanner, nft->state);
|
|
Packit |
c5a612 |
if (ret != 0 || nft->state->nerrs > 0)
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int nft_parse_bison_filename(struct nft_ctx *nft, const char *filename,
|
|
Packit |
c5a612 |
struct list_head *msgs, struct list_head *cmds)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
int ret;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
parser_init(nft, nft->state, msgs, cmds, nft->top_scope);
|
|
Packit |
c5a612 |
nft->scanner = scanner_init(nft->state);
|
|
Packit |
c5a612 |
if (scanner_read_file(nft, filename, &internal_location) < 0)
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
ret = nft_parse(nft, nft->scanner, nft->state);
|
|
Packit |
c5a612 |
if (ret != 0 || nft->state->nerrs > 0)
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
|
|
Packit |
c5a612 |
struct list_head *cmds)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
unsigned int flags;
|
|
Packit |
c5a612 |
struct cmd *cmd;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
flags = cache_evaluate(nft, cmds);
|
|
Packit |
c5a612 |
if (cache_update(nft, flags, msgs) < 0)
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
list_for_each_entry(cmd, cmds, list) {
|
|
Packit |
c5a612 |
struct eval_ctx ectx = {
|
|
Packit |
c5a612 |
.nft = nft,
|
|
Packit |
c5a612 |
.msgs = msgs,
|
|
Packit |
c5a612 |
};
|
|
Packit |
c5a612 |
if (cmd_evaluate(&ectx, cmd) < 0 &&
|
|
Packit |
c5a612 |
++nft->state->nerrs == nft->parser_max_errors)
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nft->state->nerrs)
|
|
Packit |
c5a612 |
return -1;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
list_for_each_entry(cmd, cmds, list)
|
|
Packit |
c5a612 |
nft_cmd_expand(cmd);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
return 0;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_run_cmd_from_buffer);
|
|
Packit |
c5a612 |
int nft_run_cmd_from_buffer(struct nft_ctx *nft, const char *buf)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
int rc = -EINVAL, parser_rc;
|
|
Packit |
c5a612 |
struct cmd *cmd, *next;
|
|
Packit |
c5a612 |
LIST_HEAD(msgs);
|
|
Packit |
c5a612 |
LIST_HEAD(cmds);
|
|
Packit |
c5a612 |
char *nlbuf;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
nlbuf = xzalloc(strlen(buf) + 2);
|
|
Packit |
c5a612 |
sprintf(nlbuf, "%s\n", buf);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nft_output_json(&nft->output))
|
|
Packit |
c5a612 |
rc = nft_parse_json_buffer(nft, nlbuf, &msgs, &cmds);
|
|
Packit |
c5a612 |
if (rc == -EINVAL)
|
|
Packit |
c5a612 |
rc = nft_parse_bison_buffer(nft, nlbuf, &msgs, &cmds);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
parser_rc = rc;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
rc = nft_evaluate(nft, &msgs, &cmds);
|
|
Packit |
c5a612 |
if (rc < 0)
|
|
Packit |
c5a612 |
goto err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (parser_rc) {
|
|
Packit |
c5a612 |
rc = parser_rc;
|
|
Packit |
c5a612 |
goto err;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nft_netlink(nft, &cmds, &msgs, nft->nf_sock) != 0)
|
|
Packit |
c5a612 |
rc = -1;
|
|
Packit |
c5a612 |
err:
|
|
Packit |
c5a612 |
erec_print_list(&nft->output, &msgs, nft->debug_mask);
|
|
Packit |
c5a612 |
list_for_each_entry_safe(cmd, next, &cmds, list) {
|
|
Packit |
c5a612 |
list_del(&cmd->list);
|
|
Packit |
c5a612 |
cmd_free(cmd);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
iface_cache_release();
|
|
Packit |
c5a612 |
if (nft->scanner) {
|
|
Packit |
c5a612 |
scanner_destroy(nft);
|
|
Packit |
c5a612 |
nft->scanner = NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
free(nlbuf);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!rc &&
|
|
Packit |
c5a612 |
nft_output_json(&nft->output) &&
|
|
Packit |
c5a612 |
nft_output_echo(&nft->output))
|
|
Packit |
c5a612 |
json_print_echo(nft);
|
|
Packit |
c5a612 |
if (rc)
|
|
Packit |
c5a612 |
cache_release(&nft->cache);
|
|
Packit |
c5a612 |
return rc;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
EXPORT_SYMBOL(nft_run_cmd_from_filename);
|
|
Packit |
c5a612 |
int nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename)
|
|
Packit |
c5a612 |
{
|
|
Packit |
c5a612 |
struct cmd *cmd, *next;
|
|
Packit |
c5a612 |
int rc, parser_rc;
|
|
Packit |
c5a612 |
LIST_HEAD(msgs);
|
|
Packit |
c5a612 |
LIST_HEAD(cmds);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!strcmp(filename, "-"))
|
|
Packit |
c5a612 |
filename = "/dev/stdin";
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
rc = -EINVAL;
|
|
Packit |
c5a612 |
if (nft_output_json(&nft->output))
|
|
Packit |
c5a612 |
rc = nft_parse_json_filename(nft, filename, &msgs, &cmds);
|
|
Packit |
c5a612 |
if (rc == -EINVAL)
|
|
Packit |
c5a612 |
rc = nft_parse_bison_filename(nft, filename, &msgs, &cmds);
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
parser_rc = rc;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
rc = nft_evaluate(nft, &msgs, &cmds);
|
|
Packit |
c5a612 |
if (rc < 0)
|
|
Packit |
c5a612 |
goto err;
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (parser_rc) {
|
|
Packit |
c5a612 |
rc = parser_rc;
|
|
Packit |
c5a612 |
goto err;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (nft_netlink(nft, &cmds, &msgs, nft->nf_sock) != 0)
|
|
Packit |
c5a612 |
rc = -1;
|
|
Packit |
c5a612 |
err:
|
|
Packit |
c5a612 |
erec_print_list(&nft->output, &msgs, nft->debug_mask);
|
|
Packit |
c5a612 |
list_for_each_entry_safe(cmd, next, &cmds, list) {
|
|
Packit |
c5a612 |
list_del(&cmd->list);
|
|
Packit |
c5a612 |
cmd_free(cmd);
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
iface_cache_release();
|
|
Packit |
c5a612 |
if (nft->scanner) {
|
|
Packit |
c5a612 |
scanner_destroy(nft);
|
|
Packit |
c5a612 |
nft->scanner = NULL;
|
|
Packit |
c5a612 |
}
|
|
Packit |
c5a612 |
|
|
Packit |
c5a612 |
if (!rc &&
|
|
Packit |
c5a612 |
nft_output_json(&nft->output) &&
|
|
Packit |
c5a612 |
nft_output_echo(&nft->output))
|
|
Packit |
c5a612 |
json_print_echo(nft);
|
|
Packit |
c5a612 |
if (rc)
|
|
Packit |
c5a612 |
cache_release(&nft->cache);
|
|
Packit |
c5a612 |
return rc;
|
|
Packit |
c5a612 |
}
|