Message ID | 1424115135-32323-2-git-send-email-alvaroneay@gmail.com |
---|---|
State | Changes Requested |
Delegated to: | Pablo Neira |
Headers | show |
Please, I'd suggest you rename the patch title to something like: examples: add nft-ruleset-parse-file On Mon, Feb 16, 2015 at 08:32:15PM +0100, Alvaro Neira Ayuso wrote: > With this example, we can parse the elements in the ruleset and create the by 'elements' here I guess you're refering to objects. Please, mind the word semantics when writing the descriptions. > netlink message with the action associated. For example: > > - Flush ruleset > - Add, delete or flush tables/chains > - Add, delete sets > - Add, delete set elements > - Add, delete, replace or prepend rules > > Signed-off-by: Alvaro Neira Ayuso <alvaroneay@gmail.com> > --- > [changes in v9] > * Fixed leaks in the error path > * Used the functions nft_ruleset_*_build_msg to make the code more clear > * Changed the code to make the set elements netlink message to use the function > nft_set_elems_nlmsg_build_payload_iter. > > examples/Makefile.am | 4 + > examples/nft-ruleset-parse-file.c | 486 +++++++++++++++++++++++++++++++++++++ > 2 files changed, 490 insertions(+) > create mode 100644 examples/nft-ruleset-parse-file.c > > diff --git a/examples/Makefile.am b/examples/Makefile.am > index fafcb76..e002d36 100644 > --- a/examples/Makefile.am > +++ b/examples/Makefile.am > @@ -22,6 +22,7 @@ check_PROGRAMS = nft-table-add \ > nft-set-elem-get \ > nft-set-elem-del \ > nft-ruleset-get \ > + nft-ruleset-parse-file \ > nft-compat-get > > nft_table_add_SOURCES = nft-table-add.c > @@ -90,5 +91,8 @@ nft_set_elem_get_LDADD = ../src/libnftnl.la ${LIBMNL_LIBS} > nft_ruleset_get_SOURCES = nft-ruleset-get.c > nft_ruleset_get_LDADD = ../src/libnftnl.la ${LIBMNL_LIBS} > > +nft_ruleset_parse_file_SOURCES = nft-ruleset-parse-file.c > +nft_ruleset_parse_file_LDADD = ../src/libnftnl.la ${LIBMNL_LIBS} > + > nft_compat_get_SOURCES = nft-compat-get.c > nft_compat_get_LDADD = ../src/libnftnl.la ${LIBMNL_LIBS} > diff --git a/examples/nft-ruleset-parse-file.c b/examples/nft-ruleset-parse-file.c > new file mode 100644 > index 0000000..7770a15 > --- /dev/null > +++ b/examples/nft-ruleset-parse-file.c > @@ -0,0 +1,486 @@ > +/* > + * (C) 2014 by Alvaro Neira Ayuso <alvaroneay@gmail.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + */ > + > +#include <stdlib.h> > +#include <time.h> > +#include <string.h> > +#include <stddef.h> /* for offsetof */ > +#include <netinet/in.h> > +#include <netinet/ip.h> > +#include <netinet/tcp.h> > +#include <arpa/inet.h> > +#include <sys/types.h> > +#include <sys/socket.h> > +#include <errno.h> > + > +#include <linux/netfilter.h> > +#include <linux/netfilter/nfnetlink.h> > +#include <linux/netfilter/nf_tables.h> > + > +#include <libmnl/libmnl.h> > +#include <libnftnl/ruleset.h> > +#include <libnftnl/table.h> > +#include <libnftnl/chain.h> > +#include <libnftnl/rule.h> > +#include <libnftnl/set.h> > + > +struct mnl_nlmsg_batch *batch; > +uint32_t seq; > + > +static int nft_ruleset_set_elems(const struct nft_parse_ctx *ctx) > +{ > + struct nft_set_elems_iter *iter_elems; > + uint16_t nl_type, nl_flags; > + uint32_t cmd; > + struct nlmsghdr *nlh; > + struct nft_set *set; > + > + cmd = nft_ruleset_ctx_get_u32(ctx, NFT_RULESET_CTX_CMD); > + > + set = nft_ruleset_ctx_get(ctx, NFT_RULESET_CTX_SET); > + if (set == NULL) > + return -1; > + > + switch (cmd) { > + case NFT_CMD_ADD: > + nl_type = NFT_MSG_NEWSETELEM; > + nl_flags = NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; > + break; > + case NFT_CMD_DELETE: > + nl_type = NFT_MSG_DELSETELEM; > + /* This will generate an ACK message for each request. When > + * removing NLM_F_ACK, the kernel will only report when things > + * go wrong > + */ > + nl_flags = NLM_F_ACK; > + break; > + default: > + goto err; > + } > + > + iter_elems = nft_set_elems_iter_create(set); > + if (iter_elems == NULL) > + goto err; > + > + nlh = nft_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), nl_type, > + nft_set_attr_get_u32(set, > + NFT_SET_ATTR_FAMILY), > + nl_flags, seq++); > + > + nft_set_elems_nlmsg_build_payload_iter(nlh, iter_elems); > + mnl_nlmsg_batch_next(batch); > + > + nft_set_elems_iter_destroy(iter_elems); > + nft_set_free(set); > + return 0; > +err: > + nft_set_free(set); > + return -1; > +} > + > +static int nft_ruleset_set(const struct nft_parse_ctx *ctx) > +{ > + > + struct nlmsghdr *nlh; > + uint16_t nl_type, nl_flags; > + struct nft_set *set; > + uint32_t cmd; > + int ret; > + > + cmd = nft_ruleset_ctx_get_u32(ctx, NFT_RULESET_CTX_CMD); > + > + set = nft_ruleset_ctx_get(ctx, NFT_RULESET_CTX_SET); > + if (set == NULL) > + return -1; > + > + switch (cmd) { > + case NFT_CMD_ADD: > + nl_type = NFT_MSG_NEWSET; > + nl_flags = NLM_F_CREATE|NLM_F_ACK; > + break; > + case NFT_CMD_DELETE: > + nl_type = NFT_MSG_DELSET; > + nl_flags = NLM_F_ACK; > + break; > + default: > + goto err; > + } > + > + nlh = nft_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), > + nl_type, > + nft_set_attr_get_u32(set, > + NFT_SET_ATTR_FAMILY), > + nl_flags, > + seq++); > + > + nft_set_nlmsg_build_payload(nlh, set); > + mnl_nlmsg_batch_next(batch); > + > + ret = nft_ruleset_set_elems(ctx); > + return ret; > +err: > + nft_set_free(set); > + return -1; > +} > + > +static int nft_ruleset_rule_build_msg(const struct nft_parse_ctx *ctx, > + uint32_t cmd, struct nft_rule *rule) > +{ > + struct nlmsghdr *nlh; > + uint16_t nl_type, nl_flags; > + > + switch (cmd) { > + case NFT_CMD_ADD: > + nl_type = NFT_MSG_NEWRULE; > + nl_flags = NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK; > + nft_rule_attr_unset(rule, NFT_RULE_ATTR_HANDLE); > + break; > + case NFT_CMD_DELETE: > + nl_type = NFT_MSG_DELRULE; > + nl_flags = NLM_F_ACK; > + break; > + case NFT_CMD_REPLACE: > + nl_type = NFT_MSG_NEWRULE; > + nl_flags = NLM_F_REPLACE|NLM_F_ACK; > + break; > + case NFT_CMD_INSERT: > + nl_type = NFT_MSG_NEWRULE; > + nl_flags = NLM_F_CREATE|NLM_F_ACK; > + nft_rule_attr_unset(rule, NFT_RULE_ATTR_HANDLE); > + break; > + default: > + return -1; > + } > + > + nlh = nft_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), > + nl_type, > + nft_rule_attr_get_u32(rule, > + NFT_RULE_ATTR_FAMILY), > + nl_flags, > + seq++); > + > + nft_rule_nlmsg_build_payload(nlh, rule); > + mnl_nlmsg_batch_next(batch); > + > + return 0; > +} > + > +static int nft_ruleset_rule(const struct nft_parse_ctx *ctx) > +{ > + struct nft_rule *rule; > + int ret; > + uint32_t cmd; > + > + cmd = nft_ruleset_ctx_get_u32(ctx, NFT_RULESET_CTX_CMD); > + > + rule = nft_ruleset_ctx_get(ctx, NFT_RULESET_CTX_RULE); > + if (rule == NULL) > + return -1; > + > + ret = nft_ruleset_rule_build_msg(ctx, cmd, rule); > + nft_rule_free(rule); > + > + return ret; > +} > + > +static int nft_ruleset_flush_rules(const struct nft_parse_ctx *ctx) > +{ > + struct nft_rule *nlr; > + struct nft_table *nlt; > + struct nft_chain *nlc; > + uint32_t type; > + int ret; > + > + nlr = nft_rule_alloc(); > + if (nlr == NULL) > + return -1; > + > + type = nft_ruleset_ctx_get_u32(ctx, NFT_RULESET_CTX_TYPE); > + switch (type) { > + case NFT_RULESET_TABLE: > + nlt = nft_ruleset_ctx_get(ctx, NFT_RULESET_CTX_TABLE); > + nft_rule_attr_set(nlr, NFT_RULE_ATTR_TABLE, > + nft_table_attr_get(nlt, NFT_TABLE_ATTR_NAME)); > + nft_rule_attr_set(nlr, NFT_RULE_ATTR_FAMILY, > + nft_table_attr_get(nlt, NFT_TABLE_ATTR_FAMILY)); > + break; > + case NFT_RULESET_CHAIN: > + nlc = nft_ruleset_ctx_get(ctx, NFT_RULESET_CTX_CHAIN); > + nft_rule_attr_set(nlr, NFT_RULE_ATTR_TABLE, > + nft_chain_attr_get(nlc, > + NFT_CHAIN_ATTR_TABLE)); > + nft_rule_attr_set(nlr, NFT_RULE_ATTR_CHAIN, > + nft_chain_attr_get(nlc, > + NFT_CHAIN_ATTR_NAME)); > + nft_rule_attr_set(nlr, NFT_RULE_ATTR_FAMILY, > + nft_chain_attr_get(nlc, NFT_TABLE_ATTR_FAMILY)); > + break; > + default: > + goto err; > + } > + > + ret = nft_ruleset_rule_build_msg(ctx, NFT_CMD_DELETE, nlr); > + nft_rule_free(nlr); > + > + return ret; > +err: > + nft_rule_free(nlr); > + return -1; > +} > + > +static int nft_ruleset_chain(const struct nft_parse_ctx *ctx) > +{ > + struct nlmsghdr *nlh; > + uint16_t nl_type, nl_flags; > + uint32_t cmd; > + struct nft_chain *chain; > + > + cmd = nft_ruleset_ctx_get_u32(ctx, NFT_RULESET_CTX_CMD); > + > + chain = nft_ruleset_ctx_get(ctx, NFT_RULESET_CTX_CHAIN); > + if (chain == NULL) > + return -1; > + > + switch (cmd) { > + case NFT_CMD_ADD: > + nl_type = NFT_MSG_NEWCHAIN; > + nl_flags = NLM_F_CREATE|NLM_F_ACK; > + break; > + case NFT_CMD_DELETE: > + nl_type = NFT_MSG_DELCHAIN; > + nl_flags = NLM_F_ACK; > + break; > + case NFT_CMD_FLUSH: > + return nft_ruleset_flush_rules(ctx); > + default: > + goto err; > + } > + > + nft_chain_attr_unset(chain, NFT_CHAIN_ATTR_HANDLE); > + nlh = nft_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), > + nl_type, > + nft_chain_attr_get_u32(chain, > + NFT_CHAIN_ATTR_FAMILY), > + nl_flags, > + seq++); > + > + nft_chain_nlmsg_build_payload(nlh, chain); > + mnl_nlmsg_batch_next(batch); > + > + nft_chain_free(chain); > + return 0; > +err: > + nft_chain_free(chain); > + return -1; > +} > + > +static int nft_ruleset_table_build_msg(const struct nft_parse_ctx *ctx, > + uint32_t cmd, struct nft_table *table) > +{ > + struct nlmsghdr *nlh; > + uint16_t nl_type, nl_flags; > + > + switch (cmd) { > + case NFT_CMD_ADD: > + nl_type = NFT_MSG_NEWTABLE; > + nl_flags = NLM_F_CREATE|NLM_F_ACK; > + break; > + case NFT_CMD_DELETE: > + nl_type = NFT_MSG_DELTABLE; > + nl_flags = NLM_F_ACK; > + break; > + case NFT_CMD_FLUSH: > + return nft_ruleset_flush_rules(ctx); > + default: > + return -1; > + } > + > + nlh = nft_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), > + nl_type, > + nft_table_attr_get_u32(table, > + NFT_TABLE_ATTR_FAMILY), > + nl_flags, > + seq++); > + > + nft_table_nlmsg_build_payload(nlh, table); > + mnl_nlmsg_batch_next(batch); > + > + return 0; > +} > + > +static int nft_ruleset_table(const struct nft_parse_ctx *ctx) > +{ > + struct nft_table *table; > + uint32_t cmd; > + int ret; > + > + cmd = nft_ruleset_ctx_get_u32(ctx, NFT_RULESET_CTX_CMD); > + > + table = nft_ruleset_ctx_get(ctx, NFT_RULESET_CTX_TABLE); > + if (table == NULL) > + return -1; > + > + ret = nft_ruleset_table_build_msg(ctx, cmd, table); > + nft_table_free(table); > + > + return ret; > +} > + > +static int nft_ruleset_flush_ruleset(const struct nft_parse_ctx *ctx) > +{ > + struct nft_table *table; > + int ret; > + > + table = nft_table_alloc(); > + if (table == NULL) > + return -1; > + > + ret = nft_ruleset_table_build_msg(ctx, NFT_CMD_DELETE, table); > + nft_table_free(table); > + > + return ret; > +} > + > +static int ruleset_elems_cb(const struct nft_parse_ctx *ctx) > +{ > + uint32_t type; > + int ret; > + > + type = nft_ruleset_ctx_get_u32(ctx, NFT_RULESET_CTX_TYPE); > + > + switch (type) { > + case NFT_RULESET_TABLE: > + ret = nft_ruleset_table(ctx); > + break; > + case NFT_RULESET_CHAIN: > + ret = nft_ruleset_chain(ctx); > + break; > + case NFT_RULESET_RULE: > + ret = nft_ruleset_rule(ctx); > + break; > + case NFT_RULESET_SET: > + ret = nft_ruleset_set(ctx); > + break; > + case NFT_RULESET_SET_ELEMS: > + ret = nft_ruleset_set_elems(ctx); > + break; > + case NFT_RULESET_RULESET: > + ret = nft_ruleset_flush_ruleset(ctx); > + break; > + default: > + return -1; > + } > + > + return ret; > +} > + > +int main(int argc, char *argv[]) > +{ > + struct nft_parse_err *err; > + const char *filename; > + FILE *fp; > + int ret = -1, len, batching, portid; > + uint32_t ruleset_seq; > + char buf[MNL_SOCKET_BUFFER_SIZE]; > + struct mnl_socket *nl; > + > + if (argc < 2) { > + printf("Usage: %s <file>\n", argv[0]); > + exit(EXIT_FAILURE); > + } > + > + fp = fopen(argv[1], "r"); > + if (fp == NULL) { > + printf("unable to open file %s: %s\n", argv[1], > + strerror(errno)); > + exit(EXIT_FAILURE); > + } > + > + err = nft_parse_err_alloc(); > + if (err == NULL) { > + perror("error"); > + exit(EXIT_FAILURE); > + } > + > + batching = nft_batch_is_supported(); > + if (batching < 0) { > + perror("Cannot talk to nfnetlink"); > + exit(EXIT_FAILURE); > + } > + > + seq = time(NULL); > + batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); > + > + if (batching) { > + nft_batch_begin(mnl_nlmsg_batch_current(batch), seq++); > + mnl_nlmsg_batch_next(batch); > + } > + ruleset_seq = seq; > + > + filename = argv[1]; > + len = strlen(filename); > + if (strcmp(&filename[len-5], ".json") == 0) If len - 5 is negative this will break, you better check before if len is >= 5. if (len >= 5 && strcmp(...) and use: filename[len - 5] > + ret = nft_ruleset_parse_file_cb(NFT_PARSE_JSON, fp, err, NULL, > + &ruleset_elems_cb); > + else if (strcmp(&filename[len-4], ".xml") == 0) > + ret = nft_ruleset_parse_file_cb(NFT_PARSE_XML, fp, err, NULL, > + &ruleset_elems_cb); > + else { > + printf("the filename %s must to end in .xml or .json\n", > + filename); > + exit(EXIT_FAILURE); > + } > + > + if (ret < 0) { > + nft_parse_perror("fail", err); > + exit(EXIT_FAILURE); > + } > + > + fclose(fp); > + > + if (batching) { > + nft_batch_end(mnl_nlmsg_batch_current(batch), seq++); > + mnl_nlmsg_batch_next(batch); > + } > + > + nl = mnl_socket_open(NETLINK_NETFILTER); > + if (nl == NULL) { > + perror("mnl_socket_open"); > + exit(EXIT_FAILURE); > + } > + > + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { > + perror("mnl_socket_bind"); > + exit(EXIT_FAILURE); > + } > + portid = mnl_socket_get_portid(nl); > + > + if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), > + mnl_nlmsg_batch_size(batch)) < 0) { > + perror("mnl_socket_send"); > + exit(EXIT_FAILURE); > + } > + > + mnl_nlmsg_batch_stop(batch); > + > + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); > + while (ret > 0) { > + ret = mnl_cb_run(buf, ret, ruleset_seq, portid, NULL, NULL); > + if (ret <= 0) > + break; > + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); > + } > + if (ret == -1) { > + perror("error"); > + exit(EXIT_FAILURE); > + } > + > + mnl_socket_close(nl); > + return EXIT_SUCCESS; > +} > -- > 1.7.10.4 > > -- > To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/examples/Makefile.am b/examples/Makefile.am index fafcb76..e002d36 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -22,6 +22,7 @@ check_PROGRAMS = nft-table-add \ nft-set-elem-get \ nft-set-elem-del \ nft-ruleset-get \ + nft-ruleset-parse-file \ nft-compat-get nft_table_add_SOURCES = nft-table-add.c @@ -90,5 +91,8 @@ nft_set_elem_get_LDADD = ../src/libnftnl.la ${LIBMNL_LIBS} nft_ruleset_get_SOURCES = nft-ruleset-get.c nft_ruleset_get_LDADD = ../src/libnftnl.la ${LIBMNL_LIBS} +nft_ruleset_parse_file_SOURCES = nft-ruleset-parse-file.c +nft_ruleset_parse_file_LDADD = ../src/libnftnl.la ${LIBMNL_LIBS} + nft_compat_get_SOURCES = nft-compat-get.c nft_compat_get_LDADD = ../src/libnftnl.la ${LIBMNL_LIBS} diff --git a/examples/nft-ruleset-parse-file.c b/examples/nft-ruleset-parse-file.c new file mode 100644 index 0000000..7770a15 --- /dev/null +++ b/examples/nft-ruleset-parse-file.c @@ -0,0 +1,486 @@ +/* + * (C) 2014 by Alvaro Neira Ayuso <alvaroneay@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <stdlib.h> +#include <time.h> +#include <string.h> +#include <stddef.h> /* for offsetof */ +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <errno.h> + +#include <linux/netfilter.h> +#include <linux/netfilter/nfnetlink.h> +#include <linux/netfilter/nf_tables.h> + +#include <libmnl/libmnl.h> +#include <libnftnl/ruleset.h> +#include <libnftnl/table.h> +#include <libnftnl/chain.h> +#include <libnftnl/rule.h> +#include <libnftnl/set.h> + +struct mnl_nlmsg_batch *batch; +uint32_t seq; + +static int nft_ruleset_set_elems(const struct nft_parse_ctx *ctx) +{ + struct nft_set_elems_iter *iter_elems; + uint16_t nl_type, nl_flags; + uint32_t cmd; + struct nlmsghdr *nlh; + struct nft_set *set; + + cmd = nft_ruleset_ctx_get_u32(ctx, NFT_RULESET_CTX_CMD); + + set = nft_ruleset_ctx_get(ctx, NFT_RULESET_CTX_SET); + if (set == NULL) + return -1; + + switch (cmd) { + case NFT_CMD_ADD: + nl_type = NFT_MSG_NEWSETELEM; + nl_flags = NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; + break; + case NFT_CMD_DELETE: + nl_type = NFT_MSG_DELSETELEM; + /* This will generate an ACK message for each request. When + * removing NLM_F_ACK, the kernel will only report when things + * go wrong + */ + nl_flags = NLM_F_ACK; + break; + default: + goto err; + } + + iter_elems = nft_set_elems_iter_create(set); + if (iter_elems == NULL) + goto err; + + nlh = nft_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), nl_type, + nft_set_attr_get_u32(set, + NFT_SET_ATTR_FAMILY), + nl_flags, seq++); + + nft_set_elems_nlmsg_build_payload_iter(nlh, iter_elems); + mnl_nlmsg_batch_next(batch); + + nft_set_elems_iter_destroy(iter_elems); + nft_set_free(set); + return 0; +err: + nft_set_free(set); + return -1; +} + +static int nft_ruleset_set(const struct nft_parse_ctx *ctx) +{ + + struct nlmsghdr *nlh; + uint16_t nl_type, nl_flags; + struct nft_set *set; + uint32_t cmd; + int ret; + + cmd = nft_ruleset_ctx_get_u32(ctx, NFT_RULESET_CTX_CMD); + + set = nft_ruleset_ctx_get(ctx, NFT_RULESET_CTX_SET); + if (set == NULL) + return -1; + + switch (cmd) { + case NFT_CMD_ADD: + nl_type = NFT_MSG_NEWSET; + nl_flags = NLM_F_CREATE|NLM_F_ACK; + break; + case NFT_CMD_DELETE: + nl_type = NFT_MSG_DELSET; + nl_flags = NLM_F_ACK; + break; + default: + goto err; + } + + nlh = nft_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), + nl_type, + nft_set_attr_get_u32(set, + NFT_SET_ATTR_FAMILY), + nl_flags, + seq++); + + nft_set_nlmsg_build_payload(nlh, set); + mnl_nlmsg_batch_next(batch); + + ret = nft_ruleset_set_elems(ctx); + return ret; +err: + nft_set_free(set); + return -1; +} + +static int nft_ruleset_rule_build_msg(const struct nft_parse_ctx *ctx, + uint32_t cmd, struct nft_rule *rule) +{ + struct nlmsghdr *nlh; + uint16_t nl_type, nl_flags; + + switch (cmd) { + case NFT_CMD_ADD: + nl_type = NFT_MSG_NEWRULE; + nl_flags = NLM_F_APPEND|NLM_F_CREATE|NLM_F_ACK; + nft_rule_attr_unset(rule, NFT_RULE_ATTR_HANDLE); + break; + case NFT_CMD_DELETE: + nl_type = NFT_MSG_DELRULE; + nl_flags = NLM_F_ACK; + break; + case NFT_CMD_REPLACE: + nl_type = NFT_MSG_NEWRULE; + nl_flags = NLM_F_REPLACE|NLM_F_ACK; + break; + case NFT_CMD_INSERT: + nl_type = NFT_MSG_NEWRULE; + nl_flags = NLM_F_CREATE|NLM_F_ACK; + nft_rule_attr_unset(rule, NFT_RULE_ATTR_HANDLE); + break; + default: + return -1; + } + + nlh = nft_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), + nl_type, + nft_rule_attr_get_u32(rule, + NFT_RULE_ATTR_FAMILY), + nl_flags, + seq++); + + nft_rule_nlmsg_build_payload(nlh, rule); + mnl_nlmsg_batch_next(batch); + + return 0; +} + +static int nft_ruleset_rule(const struct nft_parse_ctx *ctx) +{ + struct nft_rule *rule; + int ret; + uint32_t cmd; + + cmd = nft_ruleset_ctx_get_u32(ctx, NFT_RULESET_CTX_CMD); + + rule = nft_ruleset_ctx_get(ctx, NFT_RULESET_CTX_RULE); + if (rule == NULL) + return -1; + + ret = nft_ruleset_rule_build_msg(ctx, cmd, rule); + nft_rule_free(rule); + + return ret; +} + +static int nft_ruleset_flush_rules(const struct nft_parse_ctx *ctx) +{ + struct nft_rule *nlr; + struct nft_table *nlt; + struct nft_chain *nlc; + uint32_t type; + int ret; + + nlr = nft_rule_alloc(); + if (nlr == NULL) + return -1; + + type = nft_ruleset_ctx_get_u32(ctx, NFT_RULESET_CTX_TYPE); + switch (type) { + case NFT_RULESET_TABLE: + nlt = nft_ruleset_ctx_get(ctx, NFT_RULESET_CTX_TABLE); + nft_rule_attr_set(nlr, NFT_RULE_ATTR_TABLE, + nft_table_attr_get(nlt, NFT_TABLE_ATTR_NAME)); + nft_rule_attr_set(nlr, NFT_RULE_ATTR_FAMILY, + nft_table_attr_get(nlt, NFT_TABLE_ATTR_FAMILY)); + break; + case NFT_RULESET_CHAIN: + nlc = nft_ruleset_ctx_get(ctx, NFT_RULESET_CTX_CHAIN); + nft_rule_attr_set(nlr, NFT_RULE_ATTR_TABLE, + nft_chain_attr_get(nlc, + NFT_CHAIN_ATTR_TABLE)); + nft_rule_attr_set(nlr, NFT_RULE_ATTR_CHAIN, + nft_chain_attr_get(nlc, + NFT_CHAIN_ATTR_NAME)); + nft_rule_attr_set(nlr, NFT_RULE_ATTR_FAMILY, + nft_chain_attr_get(nlc, NFT_TABLE_ATTR_FAMILY)); + break; + default: + goto err; + } + + ret = nft_ruleset_rule_build_msg(ctx, NFT_CMD_DELETE, nlr); + nft_rule_free(nlr); + + return ret; +err: + nft_rule_free(nlr); + return -1; +} + +static int nft_ruleset_chain(const struct nft_parse_ctx *ctx) +{ + struct nlmsghdr *nlh; + uint16_t nl_type, nl_flags; + uint32_t cmd; + struct nft_chain *chain; + + cmd = nft_ruleset_ctx_get_u32(ctx, NFT_RULESET_CTX_CMD); + + chain = nft_ruleset_ctx_get(ctx, NFT_RULESET_CTX_CHAIN); + if (chain == NULL) + return -1; + + switch (cmd) { + case NFT_CMD_ADD: + nl_type = NFT_MSG_NEWCHAIN; + nl_flags = NLM_F_CREATE|NLM_F_ACK; + break; + case NFT_CMD_DELETE: + nl_type = NFT_MSG_DELCHAIN; + nl_flags = NLM_F_ACK; + break; + case NFT_CMD_FLUSH: + return nft_ruleset_flush_rules(ctx); + default: + goto err; + } + + nft_chain_attr_unset(chain, NFT_CHAIN_ATTR_HANDLE); + nlh = nft_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), + nl_type, + nft_chain_attr_get_u32(chain, + NFT_CHAIN_ATTR_FAMILY), + nl_flags, + seq++); + + nft_chain_nlmsg_build_payload(nlh, chain); + mnl_nlmsg_batch_next(batch); + + nft_chain_free(chain); + return 0; +err: + nft_chain_free(chain); + return -1; +} + +static int nft_ruleset_table_build_msg(const struct nft_parse_ctx *ctx, + uint32_t cmd, struct nft_table *table) +{ + struct nlmsghdr *nlh; + uint16_t nl_type, nl_flags; + + switch (cmd) { + case NFT_CMD_ADD: + nl_type = NFT_MSG_NEWTABLE; + nl_flags = NLM_F_CREATE|NLM_F_ACK; + break; + case NFT_CMD_DELETE: + nl_type = NFT_MSG_DELTABLE; + nl_flags = NLM_F_ACK; + break; + case NFT_CMD_FLUSH: + return nft_ruleset_flush_rules(ctx); + default: + return -1; + } + + nlh = nft_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), + nl_type, + nft_table_attr_get_u32(table, + NFT_TABLE_ATTR_FAMILY), + nl_flags, + seq++); + + nft_table_nlmsg_build_payload(nlh, table); + mnl_nlmsg_batch_next(batch); + + return 0; +} + +static int nft_ruleset_table(const struct nft_parse_ctx *ctx) +{ + struct nft_table *table; + uint32_t cmd; + int ret; + + cmd = nft_ruleset_ctx_get_u32(ctx, NFT_RULESET_CTX_CMD); + + table = nft_ruleset_ctx_get(ctx, NFT_RULESET_CTX_TABLE); + if (table == NULL) + return -1; + + ret = nft_ruleset_table_build_msg(ctx, cmd, table); + nft_table_free(table); + + return ret; +} + +static int nft_ruleset_flush_ruleset(const struct nft_parse_ctx *ctx) +{ + struct nft_table *table; + int ret; + + table = nft_table_alloc(); + if (table == NULL) + return -1; + + ret = nft_ruleset_table_build_msg(ctx, NFT_CMD_DELETE, table); + nft_table_free(table); + + return ret; +} + +static int ruleset_elems_cb(const struct nft_parse_ctx *ctx) +{ + uint32_t type; + int ret; + + type = nft_ruleset_ctx_get_u32(ctx, NFT_RULESET_CTX_TYPE); + + switch (type) { + case NFT_RULESET_TABLE: + ret = nft_ruleset_table(ctx); + break; + case NFT_RULESET_CHAIN: + ret = nft_ruleset_chain(ctx); + break; + case NFT_RULESET_RULE: + ret = nft_ruleset_rule(ctx); + break; + case NFT_RULESET_SET: + ret = nft_ruleset_set(ctx); + break; + case NFT_RULESET_SET_ELEMS: + ret = nft_ruleset_set_elems(ctx); + break; + case NFT_RULESET_RULESET: + ret = nft_ruleset_flush_ruleset(ctx); + break; + default: + return -1; + } + + return ret; +} + +int main(int argc, char *argv[]) +{ + struct nft_parse_err *err; + const char *filename; + FILE *fp; + int ret = -1, len, batching, portid; + uint32_t ruleset_seq; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct mnl_socket *nl; + + if (argc < 2) { + printf("Usage: %s <file>\n", argv[0]); + exit(EXIT_FAILURE); + } + + fp = fopen(argv[1], "r"); + if (fp == NULL) { + printf("unable to open file %s: %s\n", argv[1], + strerror(errno)); + exit(EXIT_FAILURE); + } + + err = nft_parse_err_alloc(); + if (err == NULL) { + perror("error"); + exit(EXIT_FAILURE); + } + + batching = nft_batch_is_supported(); + if (batching < 0) { + perror("Cannot talk to nfnetlink"); + exit(EXIT_FAILURE); + } + + seq = time(NULL); + batch = mnl_nlmsg_batch_start(buf, sizeof(buf)); + + if (batching) { + nft_batch_begin(mnl_nlmsg_batch_current(batch), seq++); + mnl_nlmsg_batch_next(batch); + } + ruleset_seq = seq; + + filename = argv[1]; + len = strlen(filename); + if (strcmp(&filename[len-5], ".json") == 0) + ret = nft_ruleset_parse_file_cb(NFT_PARSE_JSON, fp, err, NULL, + &ruleset_elems_cb); + else if (strcmp(&filename[len-4], ".xml") == 0) + ret = nft_ruleset_parse_file_cb(NFT_PARSE_XML, fp, err, NULL, + &ruleset_elems_cb); + else { + printf("the filename %s must to end in .xml or .json\n", + filename); + exit(EXIT_FAILURE); + } + + if (ret < 0) { + nft_parse_perror("fail", err); + exit(EXIT_FAILURE); + } + + fclose(fp); + + if (batching) { + nft_batch_end(mnl_nlmsg_batch_current(batch), seq++); + mnl_nlmsg_batch_next(batch); + } + + nl = mnl_socket_open(NETLINK_NETFILTER); + if (nl == NULL) { + perror("mnl_socket_open"); + exit(EXIT_FAILURE); + } + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { + perror("mnl_socket_bind"); + exit(EXIT_FAILURE); + } + portid = mnl_socket_get_portid(nl); + + if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), + mnl_nlmsg_batch_size(batch)) < 0) { + perror("mnl_socket_send"); + exit(EXIT_FAILURE); + } + + mnl_nlmsg_batch_stop(batch); + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, ruleset_seq, portid, NULL, NULL); + if (ret <= 0) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) { + perror("error"); + exit(EXIT_FAILURE); + } + + mnl_socket_close(nl); + return EXIT_SUCCESS; +}
With this example, we can parse the elements in the ruleset and create the netlink message with the action associated. For example: - Flush ruleset - Add, delete or flush tables/chains - Add, delete sets - Add, delete set elements - Add, delete, replace or prepend rules Signed-off-by: Alvaro Neira Ayuso <alvaroneay@gmail.com> --- [changes in v9] * Fixed leaks in the error path * Used the functions nft_ruleset_*_build_msg to make the code more clear * Changed the code to make the set elements netlink message to use the function nft_set_elems_nlmsg_build_payload_iter. examples/Makefile.am | 4 + examples/nft-ruleset-parse-file.c | 486 +++++++++++++++++++++++++++++++++++++ 2 files changed, 490 insertions(+) create mode 100644 examples/nft-ruleset-parse-file.c