The import operation reads a XML or JSON file, with syntax: % nft import {xml|json} A basic way to test this new functionality is: % nft export xml | nft import xml Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@xxxxxxxxx> --- NOTE: This patchs requires: * [nft] mnl: delete useless parameter nf_sock in batch functions * [libnftnl] ruleset: deconstify _get interface Please comment :-) include/mnl.h | 12 ++++ include/netlink.h | 4 + include/rule.h | 13 ++++ src/evaluate.c | 1 src/mnl.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/netlink.c | 64 ++++++++++++++++++++ src/parser.y | 20 +++++- src/rule.c | 52 ++++++++++++++++ src/scanner.l | 1 9 files changed, 330 insertions(+), 7 deletions(-) diff --git a/include/mnl.h b/include/mnl.h index a0dfa1b..4126f18 100644 --- a/include/mnl.h +++ b/include/mnl.h @@ -24,6 +24,8 @@ void mnl_batch_end(void); int mnl_batch_talk(struct mnl_socket *nl, struct list_head *err_list); int mnl_nft_rule_batch_add(struct nft_rule *nlr, unsigned int flags, uint32_t seqnum); +int mnl_nft_rule_list_batch_add(struct nft_rule_list *nlrl, + unsigned int flags); int mnl_nft_rule_batch_del(struct nft_rule *nlr, unsigned int flags, uint32_t seqnum); @@ -38,6 +40,8 @@ int mnl_nft_chain_add(struct mnl_socket *nf_sock, struct nft_chain *nlc, unsigned int flags); int mnl_nft_chain_batch_add(struct nft_chain *nlc, unsigned int flags, uint32_t seq); +int mnl_nft_chain_list_batch_add(struct nft_chain_list *nlcl, + unsigned int flags); int mnl_nft_chain_delete(struct mnl_socket *nf_sock, struct nft_chain *nlc, unsigned int flags); int mnl_nft_chain_batch_del(struct nft_chain *nlc, @@ -51,6 +55,8 @@ int mnl_nft_table_add(struct mnl_socket *nf_sock, struct nft_table *nlt, unsigned int flags); int mnl_nft_table_batch_add(struct nft_table *nlt, unsigned int flags, uint32_t seq); +int mnl_nft_table_list_batch_add(struct nft_table_list *nltl, + unsigned int flags); int mnl_nft_table_delete(struct mnl_socket *nf_sock, struct nft_table *nlt, unsigned int flags); int mnl_nft_table_batch_del(struct nft_table *nlt, @@ -64,6 +70,7 @@ int mnl_nft_set_add(struct mnl_socket *nf_sock, struct nft_set *nls, unsigned int flags); int mnl_nft_set_batch_add(struct nft_set *nls, unsigned int flags, uint32_t seq); +int mnl_nft_set_list_batch_add(struct nft_set_list *nlsl, unsigned int flags); int mnl_nft_set_delete(struct mnl_socket *nf_sock, struct nft_set *nls, unsigned int flags); int mnl_nft_set_batch_del(struct nft_set *nls, @@ -76,6 +83,8 @@ int mnl_nft_setelem_add(struct mnl_socket *nf_sock, struct nft_set *nls, unsigned int flags); int mnl_nft_setelem_batch_add(struct nft_set *nls, unsigned int flags, uint32_t seq); +int mnl_nft_setelem_set_list_batch_add(struct nft_set_list *nlsl, + unsigned int flags); int mnl_nft_setelem_delete(struct mnl_socket *nf_sock, struct nft_set *nls, unsigned int flags); int mnl_nft_setelem_batch_del(struct nft_set *nls, @@ -84,6 +93,9 @@ int mnl_nft_setelem_get(struct mnl_socket *nf_sock, struct nft_set *nls); struct nft_ruleset *mnl_nft_ruleset_dump(struct mnl_socket *nf_sock, uint32_t family); +int mnl_nft_ruleset_batch_add(const struct nft_ruleset *rs, + uint32_t table_flags, uint32_t chain_flags, + uint32_t sets_flags, uint32_t rule_flags); int mnl_nft_event_listener(struct mnl_socket *nf_sock, int (*cb)(const struct nlmsghdr *nlh, void *data), void *cb_data); diff --git a/include/netlink.h b/include/netlink.h index 4f79470..6584277 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -154,6 +154,10 @@ extern int netlink_flush_ruleset(struct netlink_ctx *ctx, extern struct nft_ruleset *netlink_dump_ruleset(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc); +int netlink_add_ruleset(struct netlink_ctx *ctx, const struct handle *h, + const struct location *loc, + struct nft_ruleset *rs); + struct netlink_mon_handler { uint32_t monitor_flags; uint32_t format; diff --git a/include/rule.h b/include/rule.h index 936177b..4669ba4 100644 --- a/include/rule.h +++ b/include/rule.h @@ -223,6 +223,7 @@ extern void set_print_plain(const struct set *s); * @CMD_FLUSH: flush container * @CMD_RENAME: rename object * @CMD_EXPORT: export the ruleset in a given format + * @CMD_IMPORT: import a ruleset in a given format * @CMD_MONITOR: event listener * @CMD_DESCRIBE: describe an expression */ @@ -236,6 +237,7 @@ enum cmd_ops { CMD_FLUSH, CMD_RENAME, CMD_EXPORT, + CMD_IMPORT, CMD_MONITOR, CMD_DESCRIBE, }; @@ -254,6 +256,7 @@ enum cmd_ops { * @CMD_OBJ_EXPR: expression * @CMD_OBJ_MONITOR: monitor * @CMD_OBJ_EXPORT: export + * @CMD_OBJ_IMPORT: import */ enum cmd_obj { CMD_OBJ_INVALID, @@ -267,6 +270,7 @@ enum cmd_obj { CMD_OBJ_EXPR, CMD_OBJ_MONITOR, CMD_OBJ_EXPORT, + CMD_OBJ_IMPORT, }; struct export { @@ -276,6 +280,13 @@ struct export { struct export *export_alloc(uint32_t format); void export_free(struct export *e); +struct import { + uint32_t format; +}; + +struct import *import_alloc(uint32_t format); +void import_free(struct import *i); + enum { CMD_MONITOR_OBJ_ANY, CMD_MONITOR_OBJ_TABLES, @@ -308,7 +319,6 @@ void monitor_free(struct monitor *m); * @seqnum: sequence number to match netlink errors * @union: object * @arg: argument data - * @format: info about the export/import format */ struct cmd { struct list_head list; @@ -326,6 +336,7 @@ struct cmd { struct table *table; struct monitor *monitor; struct export *export; + struct import *import; }; const void *arg; }; diff --git a/src/evaluate.c b/src/evaluate.c index d61d76b..6085d5f 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -1776,6 +1776,7 @@ int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd) case CMD_FLUSH: case CMD_RENAME: case CMD_EXPORT: + case CMD_IMPORT: case CMD_DESCRIBE: return 0; case CMD_MONITOR: diff --git a/src/mnl.c b/src/mnl.c index f48ead5..ed1fc3c 100644 --- a/src/mnl.c +++ b/src/mnl.c @@ -342,6 +342,9 @@ int mnl_batch_talk(struct mnl_socket *nl, struct list_head *err_list) return ret; } +/* + * Rule + */ int mnl_nft_rule_batch_add(struct nft_rule *nlr, unsigned int flags, uint32_t seqnum) { @@ -358,6 +361,30 @@ int mnl_nft_rule_batch_add(struct nft_rule *nlr, unsigned int flags, return 0; } +int mnl_nft_rule_list_batch_add(struct nft_rule_list *nlrl, + unsigned int flags) +{ + struct nft_rule_list_iter *rli; + struct nft_rule *r; + int ret; + + rli = nft_rule_list_iter_create(nlrl); + if (rli == NULL) + memory_allocation_error(); + + r = nft_rule_list_iter_next(rli); + while (r != NULL) { + ret = mnl_nft_rule_batch_add(r, flags, seq++); + if (ret < 0) + return ret; + + r = nft_rule_list_iter_next(rli); + } + nft_rule_list_iter_destroy(rli); + + return 0; +} + int mnl_nft_rule_batch_del(struct nft_rule *nlr, unsigned int flags, uint32_t seqnum) { @@ -374,9 +401,6 @@ int mnl_nft_rule_batch_del(struct nft_rule *nlr, unsigned int flags, return 0; } -/* - * Rule - */ int mnl_nft_rule_add(struct mnl_socket *nf_sock, struct nft_rule *nlr, unsigned int flags) { @@ -486,6 +510,30 @@ int mnl_nft_chain_batch_add(struct nft_chain *nlc, unsigned int flags, return 0; } +int mnl_nft_chain_list_batch_add(struct nft_chain_list *nlcl, + unsigned int flags) +{ + struct nft_chain_list_iter *ci; + struct nft_chain *c; + int ret; + + ci = nft_chain_list_iter_create(nlcl); + if (ci == NULL) + memory_allocation_error(); + + c = nft_chain_list_iter_next(ci); + while (c != NULL) { + ret = mnl_nft_chain_batch_add(c, flags, seq++); + if (ret < 0) + return ret; + + c = nft_chain_list_iter_next(ci); + } + nft_chain_list_iter_destroy(ci); + + return 0; +} + int mnl_nft_chain_delete(struct mnl_socket *nf_sock, struct nft_chain *nlc, unsigned int flags) { @@ -614,6 +662,30 @@ int mnl_nft_table_batch_add(struct nft_table *nlt, unsigned int flags, return 0; } +int mnl_nft_table_list_batch_add(struct nft_table_list *nltl, + unsigned int flags) +{ + struct nft_table_list_iter *ti; + struct nft_table *t; + int ret; + + ti = nft_table_list_iter_create(nltl); + if (ti == NULL) + memory_allocation_error(); + + t = nft_table_list_iter_next(ti); + while (t != NULL) { + ret = mnl_nft_table_batch_add(t, flags, seq++); + if (ret < 0) + return ret; + + t = nft_table_list_iter_next(ti); + } + nft_table_list_iter_destroy(ti); + + return 0; +} + int mnl_nft_table_delete(struct mnl_socket *nf_sock, struct nft_table *nlt, unsigned int flags) { @@ -762,6 +834,29 @@ int mnl_nft_set_batch_add(struct nft_set *nls, unsigned int flags, return 0; } +int mnl_nft_set_list_batch_add(struct nft_set_list *nlsl, unsigned int flags) +{ + struct nft_set_list_iter *sli; + struct nft_set *s; + int ret; + + sli = nft_set_list_iter_create(nlsl); + if (sli == NULL) + memory_allocation_error(); + + s = nft_set_list_iter_next(sli); + while (s != NULL) { + ret = mnl_nft_set_batch_add(s, flags, seq++); + if (ret < 0) + return ret; + + s = nft_set_list_iter_next(sli); + } + nft_set_list_iter_destroy(sli); + + return 0; +} + int mnl_nft_set_batch_del(struct nft_set *nls, unsigned int flags, uint32_t seqnum) { @@ -946,6 +1041,30 @@ int mnl_nft_setelem_batch_del(struct nft_set *nls, unsigned int flags, return 0; } +int mnl_nft_setelem_set_list_batch_add(struct nft_set_list *nlsl, + unsigned int flags) +{ + struct nft_set_list_iter *sli; + struct nft_set *s; + int ret; + + sli = nft_set_list_iter_create(nlsl); + if (sli == NULL) + memory_allocation_error(); + + s = nft_set_list_iter_next(sli); + while (s != NULL) { + ret = mnl_nft_setelem_batch_add(s, flags, seq++); + if (ret < 0) + return ret; + + s = nft_set_list_iter_next(sli); + } + nft_set_list_iter_destroy(sli); + + return 0; +} + int mnl_nft_setelem_get(struct mnl_socket *nf_sock, struct nft_set *nls) { char buf[MNL_SOCKET_BUFFER_SIZE]; @@ -1019,6 +1138,51 @@ err: return NULL; } +int mnl_nft_ruleset_batch_add(const struct nft_ruleset *rs, + uint32_t table_flags, uint32_t chain_flags, + uint32_t set_flags, uint32_t rule_flags) +{ + struct nft_table_list *tl; + struct nft_chain_list *cl; + struct nft_rule_list *rl; + struct nft_set_list *sl; + int ret; + + tl = nft_ruleset_attr_get(rs, NFT_RULESET_ATTR_TABLELIST); + if (tl != NULL) { + ret = mnl_nft_table_list_batch_add(tl, table_flags); + if (ret < 0) + return ret; + } + + cl = nft_ruleset_attr_get(rs, NFT_RULESET_ATTR_CHAINLIST); + if (cl != NULL) { + ret = mnl_nft_chain_list_batch_add(cl, chain_flags); + if (ret < 0) + return ret; + } + + sl = nft_ruleset_attr_get(rs, NFT_RULESET_ATTR_SETLIST); + if (sl != NULL) { + ret = mnl_nft_set_list_batch_add(sl, set_flags); + if (ret < 0) + return ret; + + ret = mnl_nft_setelem_set_list_batch_add(sl, set_flags); + if (ret < 0) + return ret; + } + + rl = nft_ruleset_attr_get(rs, NFT_RULESET_ATTR_RULELIST); + if (rl != NULL) { + ret = mnl_nft_rule_list_batch_add(rl, rule_flags); + if (ret < 0) + return ret; + } + + return 0; +} + /* * events */ diff --git a/src/netlink.c b/src/netlink.c index 33e77ab..0331b65 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -22,6 +22,7 @@ #include <libnftnl/expr.h> #include <libnftnl/set.h> #include <libnftnl/common.h> +#include <libnftnl/ruleset.h> #include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nf_tables.h> #include <linux/netfilter.h> @@ -1510,6 +1511,69 @@ struct nft_ruleset *netlink_dump_ruleset(struct netlink_ctx *ctx, return rs; } +static void netlink_add_ruleset_setup(struct nft_ruleset *rs) +{ + struct nft_chain_list *cl; + struct nft_chain_list_iter *i; + struct nft_chain *c; + struct nft_rule_list *rl, *reverse_rule_list; + struct nft_rule_list_iter *rli; + struct nft_rule *r; + + if (nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_CHAINLIST)) { + cl = nft_ruleset_attr_get(rs, NFT_RULESET_ATTR_CHAINLIST); + i = nft_chain_list_iter_create(cl); + if (i == NULL) + memory_allocation_error(); + + c = nft_chain_list_iter_next(i); + while (c != NULL) { + nft_chain_attr_unset(c, NFT_CHAIN_ATTR_HANDLE); + c = nft_chain_list_iter_next(i); + } + nft_chain_list_iter_destroy(i); + } + + if (nft_ruleset_attr_is_set(rs, NFT_RULESET_ATTR_RULELIST)) { + rl = nft_ruleset_attr_get(rs, NFT_RULESET_ATTR_RULELIST); + rli = nft_rule_list_iter_create(rl); + if (rli == NULL) + memory_allocation_error(); + + reverse_rule_list = nft_rule_list_alloc(); + if (reverse_rule_list == NULL) + memory_allocation_error(); + + r = nft_rule_list_iter_next(rli); + while (r != NULL) { + nft_rule_attr_unset(r, NFT_RULE_ATTR_HANDLE); + nft_rule_attr_unset(r, NFT_RULE_ATTR_POSITION); + nft_rule_list_del(r); + nft_rule_list_add(r, reverse_rule_list); + r = nft_rule_list_iter_next(rli); + } + nft_rule_list_iter_destroy(rli); + nft_ruleset_attr_set(rs, NFT_RULESET_ATTR_RULELIST, + reverse_rule_list); + } +} + +int netlink_add_ruleset(struct netlink_ctx *ctx, const struct handle *h, + const struct location *loc, + struct nft_ruleset *rs) +{ + int ret; + + netlink_add_ruleset_setup(rs); + + ret = mnl_nft_ruleset_batch_add(rs, 0, 0, 0, 0); + if (ret < 0) + netlink_io_error(ctx, loc, "Could not add new ruleset: %s", + strerror(errno)); + + return ret; +} + static struct nft_table *netlink_table_alloc(const struct nlmsghdr *nlh) { struct nft_table *nlt = nft_table_alloc(); diff --git a/src/parser.y b/src/parser.y index 9e9a839..d1f884c 100644 --- a/src/parser.y +++ b/src/parser.y @@ -189,6 +189,7 @@ static void location_update(struct location *loc, struct location *rhs, int n) %token RENAME "rename" %token DESCRIBE "describe" %token EXPORT "export" +%token IMPORT "import" %token MONITOR "monitor" %token ACCEPT "accept" @@ -396,8 +397,8 @@ static void location_update(struct location *loc, struct location *rhs, int n) %type <cmd> line %destructor { cmd_free($$); } line -%type <cmd> base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd -%destructor { cmd_free($$); } base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd +%type <cmd> base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd import_cmd monitor_cmd describe_cmd +%destructor { cmd_free($$); } base_cmd add_cmd create_cmd insert_cmd delete_cmd list_cmd flush_cmd rename_cmd export_cmd import_cmd monitor_cmd describe_cmd %type <handle> table_spec tables_spec chain_spec chain_identifier ruleid_spec ruleset_spec %destructor { handle_free(&$$); } table_spec tables_spec chain_spec chain_identifier ruleid_spec ruleset_spec @@ -529,7 +530,7 @@ static void location_update(struct location *loc, struct location *rhs, int n) %destructor { expr_free($$); } ct_expr %type <val> ct_key -%type <val> export_format +%type <val> export_format import_format %type <string> monitor_event %destructor { xfree($$); } monitor_event %type <val> monitor_object monitor_format @@ -632,6 +633,7 @@ base_cmd : /* empty */ add_cmd { $$ = $1; } | FLUSH flush_cmd { $$ = $2; } | RENAME rename_cmd { $$ = $2; } | EXPORT export_cmd { $$ = $2; } + | IMPORT import_cmd { $$ = $2; } | MONITOR monitor_cmd { $$ = $2; } | DESCRIBE describe_cmd { $$ = $2; } ; @@ -803,6 +805,14 @@ export_cmd : export_format } ; +import_cmd : import_format + { + struct handle h = { .family = NFPROTO_UNSPEC }; + struct import *import = import_alloc($1); + $$ = cmd_alloc(CMD_IMPORT, CMD_OBJ_IMPORT, &h, &@$, import); + } + ; + monitor_cmd : monitor_event monitor_object monitor_format { struct handle h = { .family = NFPROTO_UNSPEC }; @@ -832,6 +842,10 @@ export_format : XML { $$ = NFT_OUTPUT_XML; } | JSON { $$ = NFT_OUTPUT_JSON; } ; +import_format : XML { $$ = NFT_PARSE_XML; } + | JSON { $$ = NFT_PARSE_JSON; } + ; + describe_cmd : primary_expr { struct handle h = { .family = NFPROTO_UNSPEC }; diff --git a/src/rule.c b/src/rule.c index a79a420..1702102 100644 --- a/src/rule.c +++ b/src/rule.c @@ -571,6 +571,21 @@ void export_free(struct export *e) xfree(e); } +struct import *import_alloc(uint32_t format) +{ + struct import *import; + + import = xmalloc(sizeof(struct import)); + import->format = format; + + return import; +} + +void import_free(struct import *i) +{ + xfree(i); +} + struct monitor *monitor_alloc(uint32_t format, uint32_t type, const char *event) { struct monitor *mon; @@ -618,6 +633,9 @@ void cmd_free(struct cmd *cmd) case CMD_OBJ_EXPORT: export_free(cmd->export); break; + case CMD_OBJ_IMPORT: + import_free(cmd->import); + break; default: BUG("invalid command object type %u\n", cmd->obj); } @@ -772,6 +790,38 @@ static int do_command_export(struct netlink_ctx *ctx, struct cmd *cmd) return 0; } +static int do_command_import(struct netlink_ctx *ctx, struct cmd *cmd) +{ + int ret; + struct nft_ruleset *rs = nft_ruleset_alloc(); + struct nft_parse_err *err = nft_parse_err_alloc(); + + if (rs == NULL) + return -1; + + if (err == NULL) + return -1; + + ret = nft_ruleset_parse_file(rs, cmd->import->format, stdin, err); + if (ret < 0) { + nft_parse_perror("E: Unable to import. Parsing failed", err); + goto out; + } + + ret = netlink_flush_ruleset(ctx, &cmd->handle, &cmd->location); + if (ret < 0) + goto out; + + ret = netlink_add_ruleset(ctx, &cmd->handle, &cmd->location, rs); + if (ret < 0) + goto out; + +out: + nft_ruleset_free(rs); + nft_parse_err_free(err); + return ret; +} + static void table_cleanup(struct table *table) { struct chain *chain, *nchain; @@ -1035,6 +1085,8 @@ int do_command(struct netlink_ctx *ctx, struct cmd *cmd) return do_command_rename(ctx, cmd); case CMD_EXPORT: return do_command_export(ctx, cmd); + case CMD_IMPORT: + return do_command_import(ctx, cmd); case CMD_MONITOR: return do_command_monitor(ctx, cmd); case CMD_DESCRIBE: diff --git a/src/scanner.l b/src/scanner.l index 32e59d9..880cb2f 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -259,6 +259,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "flush" { return FLUSH; } "rename" { return RENAME; } "export" { return EXPORT; } +"import" { return IMPORT; } "monitor" { return MONITOR; } "position" { return POSITION; } -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html