#include <libnftnl/object.h>
#include <libnftnl/set.h>
#include <libnftnl/udata.h>
+#include <libnftnl/ruleset.h>
#include <libnftnl/common.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nf_tables.h>
monhandler);
}
+static int netlink_markup_setelems(const struct nftnl_parse_ctx *ctx)
+{
+ const struct ruleset_parse *rp;
+ struct nftnl_set *set;
+ uint32_t cmd;
+ int ret = -1;
+
+ set = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_SET);
+ rp = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_DATA);
+
+ cmd = nftnl_ruleset_ctx_get_u32(ctx, NFTNL_RULESET_CTX_CMD);
+ switch (cmd) {
+ case NFTNL_CMD_ADD:
+ ret = mnl_nft_setelem_batch_add(set, rp->nl_ctx->batch,
+ 0, rp->nl_ctx->seqnum);
+ break;
+ case NFTNL_CMD_DELETE:
+ ret = mnl_nft_setelem_batch_del(set, rp->nl_ctx->batch,
+ 0, rp->nl_ctx->seqnum);
+ break;
+ default:
+ errno = EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static int netlink_markup_set(const struct nftnl_parse_ctx *ctx)
+{
+ const struct ruleset_parse *rp;
+ struct nftnl_set *set;
+ uint32_t cmd;
+ int ret = -1;
+
+ set = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_SET);
+ rp = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_DATA);
+
+ cmd = nftnl_ruleset_ctx_get_u32(ctx, NFTNL_RULESET_CTX_CMD);
+ switch (cmd) {
+ case NFTNL_CMD_ADD:
+ ret = mnl_nft_set_batch_add(set, rp->nl_ctx->batch, NLM_F_EXCL,
+ rp->nl_ctx->seqnum);
+ break;
+ case NFTNL_CMD_DELETE:
+ ret = mnl_nft_set_batch_del(set, rp->nl_ctx->batch,
+ 0, rp->nl_ctx->seqnum);
+ break;
+ default:
+ errno = EOPNOTSUPP;
+ break;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ return netlink_markup_setelems(ctx);
+}
+
+static int netlink_markup_build_rule(const struct nftnl_parse_ctx *ctx,
+ uint32_t cmd, struct nftnl_rule *rule)
+{
+ const struct ruleset_parse *rp;
+ uint32_t nl_flags;
+ int ret = -1;
+
+ rp = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_DATA);
+
+ switch (cmd) {
+ case NFTNL_CMD_ADD:
+ nl_flags = NLM_F_APPEND | NLM_F_CREATE;
+ nftnl_rule_unset(rule, NFTNL_RULE_HANDLE);
+ ret = mnl_nft_rule_batch_add(rule, rp->nl_ctx->batch, nl_flags,
+ rp->nl_ctx->seqnum);
+ break;
+ case NFTNL_CMD_DELETE:
+ ret = mnl_nft_rule_batch_del(rule, rp->nl_ctx->batch,
+ 0, rp->nl_ctx->seqnum);
+ break;
+ case NFTNL_CMD_REPLACE:
+ nl_flags = NLM_F_REPLACE;
+ ret = mnl_nft_rule_batch_add(rule, rp->nl_ctx->batch, nl_flags,
+ rp->nl_ctx->seqnum);
+ break;
+ case NFTNL_CMD_INSERT:
+ nl_flags = NLM_F_CREATE;
+ nftnl_rule_unset(rule, NFTNL_RULE_HANDLE);
+ ret = mnl_nft_rule_batch_add(rule, rp->nl_ctx->batch, nl_flags,
+ rp->nl_ctx->seqnum);
+ break;
+ default:
+ errno = EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+
+}
+
+static int netlink_markup_rule(const struct nftnl_parse_ctx *ctx)
+{
+ struct nftnl_rule *rule;
+ uint32_t cmd;
+
+ cmd = nftnl_ruleset_ctx_get_u32(ctx, NFTNL_RULESET_CTX_CMD);
+ rule = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_RULE);
+
+ return netlink_markup_build_rule(ctx, cmd, rule);
+}
+
+static int netlink_markup_build_flush(const struct nftnl_parse_ctx *ctx)
+{
+ struct nftnl_rule *rule;
+ struct nftnl_table *table;
+ struct nftnl_chain *chain;
+ const char *table_get_name, *table_get_family;
+ const char *chain_get_table, *chain_get_name, *chain_get_family;
+ uint32_t type;
+ int ret = -1;
+
+ rule = nftnl_rule_alloc();
+ if (rule == NULL)
+ return -1;
+
+ type = nftnl_ruleset_ctx_get_u32(ctx, NFTNL_RULESET_CTX_TYPE);
+ switch (type) {
+ case NFTNL_RULESET_TABLE:
+ table = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_TABLE);
+ table_get_name = nftnl_table_get(table, NFTNL_TABLE_NAME);
+ table_get_family = nftnl_table_get(table, NFTNL_TABLE_FAMILY);
+
+ nftnl_rule_set(rule, NFTNL_RULE_TABLE, table_get_name);
+ nftnl_rule_set(rule, NFTNL_RULE_FAMILY, table_get_family);
+ break;
+ case NFTNL_RULESET_CHAIN:
+ chain = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_CHAIN);
+ chain_get_table = nftnl_chain_get(chain, NFTNL_CHAIN_TABLE);
+ chain_get_name = nftnl_chain_get(chain, NFTNL_CHAIN_NAME);
+ chain_get_family = nftnl_chain_get(chain, NFTNL_TABLE_FAMILY);
+
+ nftnl_rule_set(rule, NFTNL_RULE_TABLE, chain_get_table);
+ nftnl_rule_set(rule, NFTNL_RULE_CHAIN, chain_get_name);
+ nftnl_rule_set(rule, NFTNL_RULE_FAMILY, chain_get_family);
+ break;
+ default:
+ errno = EOPNOTSUPP;
+ goto err;
+ }
+
+ ret = netlink_markup_build_rule(ctx, NFTNL_CMD_DELETE, rule);
+err:
+ nftnl_rule_free(rule);
+ return ret;
+}
+
+static int netlink_markup_chain(const struct nftnl_parse_ctx *ctx)
+{
+ const struct ruleset_parse *rp;
+ struct nftnl_chain *chain;
+ uint32_t cmd;
+ int ret = -1;
+
+ chain = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_CHAIN);
+ rp = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_DATA);
+
+ nftnl_chain_unset(chain, NFTNL_CHAIN_HANDLE);
+
+ cmd = nftnl_ruleset_ctx_get_u32(ctx, NFTNL_RULESET_CTX_CMD);
+ switch (cmd) {
+ case NFTNL_CMD_ADD:
+ ret = mnl_nft_chain_batch_add(chain, rp->nl_ctx->batch,
+ 0, rp->nl_ctx->seqnum);
+ break;
+ case NFTNL_CMD_DELETE:
+ ret = mnl_nft_chain_batch_del(chain, rp->nl_ctx->batch,
+ 0, rp->nl_ctx->seqnum);
+ break;
+ case NFTNL_CMD_FLUSH:
+ ret = netlink_markup_build_flush(ctx);
+ break;
+ default:
+ errno = EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+
+static int netlink_markup_build_table(const struct nftnl_parse_ctx *ctx,
+ uint32_t cmd, struct nftnl_table *table)
+{
+ struct ruleset_parse *rp;
+ int ret = -1;
+
+ rp = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_DATA);
+
+ switch (cmd) {
+ case NFTNL_CMD_ADD:
+ ret = mnl_nft_table_batch_add(table, rp->nl_ctx->batch,
+ 0, rp->nl_ctx->seqnum);
+ break;
+ case NFTNL_CMD_DELETE:
+ ret = mnl_nft_table_batch_del(table, rp->nl_ctx->batch,
+ 0, rp->nl_ctx->seqnum);
+ break;
+ case NFTNL_CMD_FLUSH:
+ ret = netlink_markup_build_flush(ctx);
+ break;
+ default:
+ errno = EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static int netlink_markup_table(const struct nftnl_parse_ctx *ctx)
+{
+ struct nftnl_table *table;
+ uint32_t cmd;
+
+ cmd = nftnl_ruleset_ctx_get_u32(ctx, NFTNL_RULESET_CTX_CMD);
+ table = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_TABLE);
+
+ return netlink_markup_build_table(ctx, cmd, table);
+}
+
+static int netlink_markup_flush(const struct nftnl_parse_ctx *ctx)
+{
+ struct nftnl_table *table;
+ int ret;
+
+ table = nftnl_table_alloc();
+ if (table == NULL)
+ return -1;
+
+ ret = netlink_markup_build_table(ctx, NFTNL_CMD_DELETE, table);
+ nftnl_table_free(table);
+
+ return ret;
+}
+
+int netlink_markup_parse_cb(const struct nftnl_parse_ctx *ctx)
+{
+ struct ruleset_parse *rp;
+ uint32_t type;
+ int ret = -1;
+
+ rp = nftnl_ruleset_ctx_get(ctx, NFTNL_RULESET_CTX_DATA);
+
+ type = nftnl_ruleset_ctx_get_u32(ctx, NFTNL_RULESET_CTX_TYPE);
+ switch (type) {
+ case NFTNL_RULESET_TABLE:
+ ret = netlink_markup_table(ctx);
+ break;
+ case NFTNL_RULESET_CHAIN:
+ ret = netlink_markup_chain(ctx);
+ break;
+ case NFTNL_RULESET_RULE:
+ ret = netlink_markup_rule(ctx);
+ break;
+ case NFTNL_RULESET_SET:
+ ret = netlink_markup_set(ctx);
+ break;
+ case NFTNL_RULESET_SET_ELEMS:
+ ret = netlink_markup_setelems(ctx);
+ break;
+ case NFTNL_RULESET_RULESET:
+ ret = netlink_markup_flush(ctx);
+ break;
+ default:
+ errno = EOPNOTSUPP;
+ break;
+ }
+
+ nftnl_ruleset_ctx_free(ctx);
+ if (ret < 0)
+ netlink_io_error(rp->nl_ctx, &rp->cmd->location,
+ "Could not import: %s", strerror(errno));
+
+ return 0;
+}
+
bool netlink_batch_supported(struct mnl_socket *nf_sock, uint32_t *seqnum)
{
return mnl_batch_supported(nf_sock, seqnum);
%token FLUSH "flush"
%token RENAME "rename"
%token DESCRIBE "describe"
+%token IMPORT "import"
%token EXPORT "export"
%token MONITOR "monitor"
%token XML "xml"
%token JSON "json"
+%token VM "vm"
%token NOTRACK "notrack"
%type <cmd> line
%destructor { cmd_free($$); } line
-%type <cmd> base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd
-%destructor { cmd_free($$); } base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd
+%type <cmd> base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd import_cmd
+%destructor { cmd_free($$); } base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd import_cmd
%type <handle> table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
%destructor { handle_free(&$$); } table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
%destructor { expr_free($$); } fib_expr
%type <val> fib_tuple fib_result fib_flag
-%type <val> export_format
+%type <val> markup_format
%type <string> monitor_event
%destructor { xfree($$); } monitor_event
%type <val> monitor_object monitor_format
| RESET reset_cmd { $$ = $2; }
| FLUSH flush_cmd { $$ = $2; }
| RENAME rename_cmd { $$ = $2; }
+ | IMPORT import_cmd { $$ = $2; }
| EXPORT export_cmd { $$ = $2; }
| MONITOR monitor_cmd { $$ = $2; }
| DESCRIBE describe_cmd { $$ = $2; }
}
;
-export_cmd : RULESET export_format
+import_cmd : RULESET markup_format
{
struct handle h = { .family = NFPROTO_UNSPEC };
- struct export *export = export_alloc($2);
- $$ = cmd_alloc(CMD_EXPORT, CMD_OBJ_EXPORT, &h, &@$, export);
+ struct markup *markup = markup_alloc($2);
+ $$ = cmd_alloc(CMD_IMPORT, CMD_OBJ_MARKUP, &h, &@$, markup);
}
- | export_format
+ | markup_format
{
struct handle h = { .family = NFPROTO_UNSPEC };
- struct export *export = export_alloc($1);
- $$ = cmd_alloc(CMD_EXPORT, CMD_OBJ_EXPORT, &h, &@$, export);
+ struct markup *markup = markup_alloc($1);
+ $$ = cmd_alloc(CMD_IMPORT, CMD_OBJ_MARKUP, &h, &@$, markup);
}
+ | JSON { $$ = NULL; }
+ ;
+
+export_cmd : RULESET markup_format
+ {
+ struct handle h = { .family = NFPROTO_UNSPEC };
+ struct markup *markup = markup_alloc($2);
+ $$ = cmd_alloc(CMD_EXPORT, CMD_OBJ_MARKUP, &h, &@$, markup);
+ }
+ | markup_format
+ {
+ struct handle h = { .family = NFPROTO_UNSPEC };
+ struct markup *markup = markup_alloc($1);
+ $$ = cmd_alloc(CMD_EXPORT, CMD_OBJ_MARKUP, &h, &@$, markup);
+ }
+ | JSON { $$ = NULL; }
;
monitor_cmd : monitor_event monitor_object monitor_format
;
monitor_format : /* empty */ { $$ = NFTNL_OUTPUT_DEFAULT; }
- | export_format
+ | markup_format
+ | JSON { $$ = NFTNL_OUTPUT_JSON; }
;
-export_format : XML { $$ = NFTNL_OUTPUT_XML; }
- | JSON { $$ = NFTNL_OUTPUT_JSON; }
+markup_format : XML { $$ = NFTNL_OUTPUT_XML; }
+ | VM JSON { $$ = NFTNL_OUTPUT_JSON; }
;
describe_cmd : primary_expr
}
}
-struct export *export_alloc(uint32_t format)
+struct markup *markup_alloc(uint32_t format)
{
- struct export *export;
+ struct markup *markup;
- export = xmalloc(sizeof(struct export));
- export->format = format;
+ markup = xmalloc(sizeof(struct markup));
+ markup->format = format;
- return export;
+ return markup;
}
-void export_free(struct export *e)
+void markup_free(struct markup *m)
{
- xfree(e);
+ xfree(m);
}
struct monitor *monitor_alloc(uint32_t format, uint32_t type, const char *event)
case CMD_OBJ_MONITOR:
monitor_free(cmd->monitor);
break;
- case CMD_OBJ_EXPORT:
- export_free(cmd->export);
+ case CMD_OBJ_MARKUP:
+ markup_free(cmd->markup);
break;
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
return -1;
} while (rs == NULL);
- nftnl_ruleset_fprintf(fp, rs, cmd->export->format, 0);
+ nftnl_ruleset_fprintf(fp, rs, cmd->markup->format, NFTNL_OF_EVENT_NEW);
+
nft_print(ctx->octx, "\n");
nftnl_ruleset_free(rs);
return 0;
}
+static int do_command_import(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ int ret;
+ struct nftnl_parse_err *err;
+ struct ruleset_parse rp = {
+ .nl_ctx = ctx,
+ .cmd = cmd
+ };
+
+ err = nftnl_parse_err_alloc();
+ if (err == NULL)
+ return -1;
+
+ ret = nftnl_ruleset_parse_file_cb(cmd->markup->format, stdin, err, &rp,
+ netlink_markup_parse_cb);
+ if (ret < 0)
+ nftnl_parse_perror("unable to import: parsing failed", err);
+
+ nftnl_parse_err_free(err);
+ return ret;
+}
+
static int do_list_table(struct netlink_ctx *ctx, struct cmd *cmd,
struct table *table)
{
return do_command_flush(ctx, cmd);
case CMD_RENAME:
return do_command_rename(ctx, cmd);
+ case CMD_IMPORT:
+ return do_command_import(ctx, cmd);
case CMD_EXPORT:
return do_command_export(ctx, cmd);
case CMD_MONITOR: