diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.in | 1 | ||||
-rw-r--r-- | src/erec.c | 2 | ||||
-rw-r--r-- | src/mnl.c | 478 | ||||
-rw-r--r-- | src/netlink.c | 846 | ||||
-rw-r--r-- | src/netlink_delinearize.c | 190 | ||||
-rw-r--r-- | src/netlink_linearize.c | 335 |
6 files changed, 1210 insertions, 642 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index 6bfcd645..658e9b33 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -21,6 +21,7 @@ nft-obj += rbtree.o nft-obj += gmputil.o nft-obj += utils.o nft-obj += erec.o +nft-obj += mnl.o nft-obj += parser.o nft-extra-clean-files += parser.c parser.h @@ -107,7 +107,7 @@ void erec_print(FILE *f, const struct error_record *erec) fprintf(f, "%s\n", erec->msg); for (l = 0; l < (int)erec->num_locations; l++) { loc = &erec->locations[l]; - netlink_dump_object(loc->nl_obj); + netlink_dump_expr(loc->nle); } fprintf(f, "\n"); } else { diff --git a/src/mnl.c b/src/mnl.c new file mode 100644 index 00000000..ea9637c8 --- /dev/null +++ b/src/mnl.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2013 Pablo Neira Ayuso <pablo@netfilter.org> + * + * 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. + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + */ + +#include <libmnl/libmnl.h> +#include <libnftables/table.h> +#include <libnftables/chain.h> +#include <libnftables/rule.h> +#include <libnftables/expr.h> +#include <libnftables/set.h> + +#include <linux/netfilter/nfnetlink.h> +#include <linux/netfilter/nf_tables.h> + +#include <mnl.h> +#include <errno.h> +#include <utils.h> + +static int seq; + +static int +mnl_talk(struct mnl_socket *nf_sock, const void *data, unsigned int len, + int (*cb)(const struct nlmsghdr *nlh, void *data), void *cb_data) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + uint32_t portid = mnl_socket_get_portid(nf_sock); + int ret; + + if (mnl_socket_sendto(nf_sock, data, len) < 0) + return -1; + + ret = mnl_socket_recvfrom(nf_sock, buf, sizeof(buf)); + while (ret > 0) { + ret = mnl_cb_run(buf, ret, seq, portid, cb, cb_data); + if (ret <= 0) + goto out; + + ret = mnl_socket_recvfrom(nf_sock, buf, sizeof(buf)); + } +out: + if (ret < 0 && errno == EAGAIN) + return 0; + + return ret; +} + +/* + * Rule + */ +int mnl_nft_rule_add(struct mnl_socket *nf_sock, struct nft_rule *nlr, + unsigned int flags) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + + nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_NEWRULE, + nft_rule_attr_get_u32(nlr, NFT_RULE_ATTR_FAMILY), + NLM_F_APPEND|NLM_F_ACK|NLM_F_CREATE, seq); + nft_rule_nlmsg_build_payload(nlh, nlr); + + return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL); +} + +int mnl_nft_rule_delete(struct mnl_socket *nf_sock, struct nft_rule *nlr, + unsigned int flags) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + + nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_DELRULE, + nft_rule_attr_get_u32(nlr, NFT_RULE_ATTR_FAMILY), + NLM_F_ACK, seq); + nft_rule_nlmsg_build_payload(nlh, nlr); + + return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL); +} + +static int rule_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nft_rule_list *nlr_list = data; + struct nft_rule *r; + + r = nft_rule_alloc(); + if (r == NULL) + memory_allocation_error(); + + if (nft_rule_nlmsg_parse(nlh, r) < 0) + goto err_free; + + nft_rule_list_add(r, nlr_list); + return MNL_CB_OK; + +err_free: + nft_rule_free(r); + return MNL_CB_OK; +} + +struct nft_rule_list *mnl_nft_rule_dump(struct mnl_socket *nf_sock, int family) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct nft_rule_list *nlr_list; + int ret; + + nlr_list = nft_rule_list_alloc(); + if (nlr_list == NULL) + memory_allocation_error(); + + nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, + NLM_F_DUMP, seq); + + ret = mnl_talk(nf_sock, nlh, nlh->nlmsg_len, rule_cb, nlr_list); + if (ret < 0) + goto err; + + return nlr_list; +err: + nft_rule_list_free(nlr_list); + return NULL; +} + +/* + * Chain + */ +int mnl_nft_chain_add(struct mnl_socket *nf_sock, struct nft_chain *nlc, + unsigned int flags) + +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + + nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, + nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_FAMILY), + NLM_F_ACK|flags, seq); + nft_chain_nlmsg_build_payload(nlh, nlc); + + return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL); +} + +int mnl_nft_chain_delete(struct mnl_socket *nf_sock, struct nft_chain *nlc, + unsigned int flags) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + + nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_DELCHAIN, + nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_FAMILY), + NLM_F_ACK, seq); + nft_chain_nlmsg_build_payload(nlh, nlc); + + return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL); +} + +static int chain_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nft_chain_list *nlc_list = data; + struct nft_chain *c; + + c = nft_chain_alloc(); + if (c == NULL) + memory_allocation_error(); + + if (nft_chain_nlmsg_parse(nlh, c) < 0) + goto err_free; + + nft_chain_list_add(c, nlc_list); + return MNL_CB_OK; + +err_free: + nft_chain_free(c); + return MNL_CB_OK; +} + +struct nft_chain_list *mnl_nft_chain_dump(struct mnl_socket *nf_sock, int family) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct nft_chain_list *nlc_list; + int ret; + + nlc_list = nft_chain_list_alloc(); + if (nlc_list == NULL) + memory_allocation_error(); + + nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, family, + NLM_F_DUMP, seq); + + ret = mnl_talk(nf_sock, nlh, nlh->nlmsg_len, chain_cb, nlc_list); + if (ret < 0) + goto err; + + return nlc_list; +err: + nft_chain_list_free(nlc_list); + return NULL; +} + +static int chain_get_cb(const struct nlmsghdr *nlh, void *data) +{ + nft_chain_nlmsg_parse(nlh, data); + return MNL_CB_OK; +} + +int mnl_nft_chain_get(struct mnl_socket *nf_sock, struct nft_chain *nlc, + unsigned int flags) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + + nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, + nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_FAMILY), + NLM_F_ACK|flags, seq); + nft_chain_nlmsg_build_payload(nlh, nlc); + + return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, chain_get_cb, nlc); +} + +/* + * Table + */ +int mnl_nft_table_add(struct mnl_socket *nf_sock, struct nft_table *nlt, + unsigned int flags) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + + nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_NEWTABLE, + nft_table_attr_get_u32(nlt, NFT_TABLE_ATTR_FAMILY), + NLM_F_EXCL|NLM_F_ACK, seq); + nft_table_nlmsg_build_payload(nlh, nlt); + + return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL); +} + +int mnl_nft_table_delete(struct mnl_socket *nf_sock, struct nft_table *nlt, + unsigned int flags) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + + nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_DELTABLE, + nft_table_attr_get_u32(nlt, NFT_TABLE_ATTR_FAMILY), + NLM_F_ACK, seq); + nft_table_nlmsg_build_payload(nlh, nlt); + + return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL); +} + +static int table_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nft_table_list *nlt_list = data; + struct nft_table *t; + + t = nft_table_alloc(); + if (t == NULL) + memory_allocation_error(); + + if (nft_table_nlmsg_parse(nlh, t) < 0) + goto err_free; + + nft_table_list_add(t, nlt_list); + return MNL_CB_OK; + +err_free: + nft_table_free(t); + return MNL_CB_OK; +} + +struct nft_table_list *mnl_nft_table_dump(struct mnl_socket *nf_sock, int family) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct nft_table_list *nlt_list; + int ret; + + nlt_list = nft_table_list_alloc(); + if (nlt_list == NULL) + memory_allocation_error(); + + nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, family, + NLM_F_DUMP, seq); + + ret = mnl_talk(nf_sock, nlh, nlh->nlmsg_len, table_cb, nlt_list); + if (ret < 0) + goto err; + + return nlt_list; +err: + nft_table_list_free(nlt_list); + return NULL; +} + +static int table_get_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nft_table *t = data; + + nft_table_nlmsg_parse(nlh, t); + return MNL_CB_OK; +} + +int mnl_nft_table_get(struct mnl_socket *nf_sock, struct nft_table *nlt, + unsigned int flags) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + + nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, + nft_table_attr_get_u32(nlt, NFT_TABLE_ATTR_FAMILY), + NLM_F_ACK, seq); + return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, table_get_cb, nlt); +} + +/* + * Set + */ +static int set_add_cb(const struct nlmsghdr *nlh, void *data) +{ + nft_set_nlmsg_parse(nlh, data); + return MNL_CB_OK; +} + +int mnl_nft_set_add(struct mnl_socket *nf_sock, struct nft_set *nls, + unsigned int flags) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + + nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_NEWSET, + nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY), + flags|NLM_F_CREATE|NLM_F_ACK, seq); + nft_set_nlmsg_build_payload(nlh, nls); + + return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, set_add_cb, nls); +} + +int mnl_nft_set_delete(struct mnl_socket *nf_sock, struct nft_set *nls, + unsigned int flags) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + + nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_DELSET, + nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY), + flags|NLM_F_ACK, seq); + nft_set_nlmsg_build_payload(nlh, nls); + + return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL); +} + +static int set_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nft_set_list *nls_list = data; + struct nft_set *s; + + s = nft_set_alloc(); + if (s == NULL) + memory_allocation_error(); + + if (nft_set_nlmsg_parse(nlh, s) < 0) + goto err_free; + + nft_set_list_add(s, nls_list); + return MNL_CB_OK; + +err_free: + nft_set_free(s); + return MNL_CB_OK; +} + +struct nft_set_list * +mnl_nft_set_dump(struct mnl_socket *nf_sock, int family, const char *table) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct nft_set *s; + struct nft_set_list *nls_list; + int ret; + + s = nft_set_alloc(); + if (s == NULL) + memory_allocation_error(); + + nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, family, + NLM_F_DUMP|NLM_F_ACK, seq); + nft_set_attr_set(s, NFT_SET_ATTR_TABLE, table); + nft_set_nlmsg_build_payload(nlh, s); + nft_set_free(s); + + nls_list = nft_set_list_alloc(); + if (nls_list == NULL) + memory_allocation_error(); + + ret = mnl_talk(nf_sock, nlh, nlh->nlmsg_len, set_cb, nls_list); + if (ret < 0) + goto err; + + return nls_list; +err: + nft_set_list_free(nls_list); + return NULL; +} + +static int set_get_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nft_set *s = data; + + nft_set_nlmsg_parse(nlh, s); + return MNL_CB_OK; +} + +int mnl_nft_set_get(struct mnl_socket *nf_sock, struct nft_set *nls) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + + nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_GETSET, + nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY), + NLM_F_ACK, seq); + nft_set_nlmsg_build_payload(nlh, nls); + + return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, set_get_cb, nls); +} + +/* + * Set elements + */ +int mnl_nft_setelem_add(struct mnl_socket *nf_sock, struct nft_set *nls, + unsigned int flags) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + + nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_NEWSETELEM, + nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY), + NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK, seq); + nft_set_elems_nlmsg_build_payload(nlh, nls); + + return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL); +} + +int mnl_nft_setelem_delete(struct mnl_socket *nf_sock, struct nft_set *nls, + unsigned int flags) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + + nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_DELSETELEM, + nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY), + NLM_F_ACK, seq); + nft_set_elems_nlmsg_build_payload(nlh, nls); + + return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, NULL, NULL); +} + +static int set_elem_cb(const struct nlmsghdr *nlh, void *data) +{ + nft_set_elems_nlmsg_parse(nlh, data); + return MNL_CB_OK; +} + +int mnl_nft_setelem_get(struct mnl_socket *nf_sock, struct nft_set *nls) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + + nlh = nft_set_nlmsg_build_hdr(buf, NFT_MSG_GETSETELEM, + nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY), + NLM_F_DUMP|NLM_F_ACK, seq); + nft_set_nlmsg_build_payload(nlh, nls); + + return mnl_talk(nf_sock, nlh, nlh->nlmsg_len, set_elem_cb, nls); +} diff --git a/src/netlink.c b/src/netlink.c index da290d58..d835281c 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2008-2012 Patrick McHardy <kaber@trash.net> + * Copyright (c) 2013 Pablo Neira Ayuso <pablo@netfilter.org> * * 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 @@ -8,59 +9,39 @@ * Development of this code funded by Astaro AG (http://www.astaro.com/) */ -#include <netlink/netfilter/nfnl.h> -#include <netlink/netfilter/netfilter.h> -#include <netlink/netfilter/nft_table.h> -#include <netlink/netfilter/nft_chain.h> -#include <netlink/netfilter/nft_rule.h> -#include <netlink/netfilter/nft_expr.h> -#include <netlink/netfilter/nft_data.h> -#include <netlink/netfilter/nft_setelem.h> -#include <netlink/netfilter/nft_set.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <libmnl/libmnl.h> + +#include <libnftables/table.h> +#include <libnftables/chain.h> +#include <libnftables/expr.h> +#include <libnftables/set.h> #include <linux/netfilter/nf_tables.h> #include <nftables.h> #include <netlink.h> +#include <mnl.h> #include <expression.h> #include <gmputil.h> #include <utils.h> #include <erec.h> -static struct nl_sock *nf_sock; +static struct mnl_socket *nf_sock; static void __init netlink_open_sock(void) { - nlmsg_set_default_size(65536); - nf_sock = nl_socket_alloc(); + nf_sock = mnl_socket_open(NETLINK_NETFILTER); if (nf_sock == NULL) memory_allocation_error(); - nfnl_connect(nf_sock); - nl_socket_set_nonblocking(nf_sock); + fcntl(mnl_socket_get_fd(nf_sock), F_SETFL, O_NONBLOCK); } static void __exit netlink_close_sock(void) { - nl_socket_free(nf_sock); -} - -static void netlink_set_callback(nl_recvmsg_msg_cb_t func, void *arg) -{ - nl_socket_modify_cb(nf_sock, NL_CB_VALID, NL_CB_CUSTOM, func, arg); -} - -void netlink_dump_object(struct nl_object *obj) -{ -#ifdef DEBUG - struct nl_dump_params params = { - .dp_fd = stdout, - .dp_type = NL_DUMP_DETAILS, - }; - - if (!(debug_level & DEBUG_NETLINK)) - return; - nl_object_dump(obj, ¶ms); -#endif + mnl_socket_close(nf_sock); } static int netlink_io_error(struct netlink_ctx *ctx, const struct location *loc, @@ -79,119 +60,128 @@ static int netlink_io_error(struct netlink_ctx *ctx, const struct location *loc, return -1; } -struct nfnl_nft_table *alloc_nft_table(const struct handle *h) +struct nft_table *alloc_nft_table(const struct handle *h) { - struct nfnl_nft_table *nlt; + struct nft_table *nlt; - nlt = nfnl_nft_table_alloc(); + nlt = nft_table_alloc(); if (nlt == NULL) memory_allocation_error(); - nfnl_nft_table_set_family(nlt, h->family); + + nft_table_attr_set_u32(nlt, NFT_TABLE_ATTR_FAMILY, h->family); if (h->table != NULL) - nfnl_nft_table_set_name(nlt, h->table, strlen(h->table) + 1); + nft_table_attr_set(nlt, NFT_TABLE_ATTR_NAME, h->table); return nlt; } -struct nfnl_nft_chain *alloc_nft_chain(const struct handle *h) +struct nft_chain *alloc_nft_chain(const struct handle *h) { - struct nfnl_nft_chain *nlc; + struct nft_chain *nlc; - nlc = nfnl_nft_chain_alloc(); + nlc = nft_chain_alloc(); if (nlc == NULL) memory_allocation_error(); - nfnl_nft_chain_set_family(nlc, h->family); - nfnl_nft_chain_set_table(nlc, h->table, strlen(h->table) + 1); + + nft_chain_attr_set_u32(nlc, NFT_CHAIN_ATTR_FAMILY, h->family); + nft_chain_attr_set_str(nlc, NFT_CHAIN_ATTR_TABLE, h->table); if (h->handle != 0) - nfnl_nft_chain_set_handle(nlc, h->handle); + nft_chain_attr_set_u64(nlc, NFT_CHAIN_ATTR_HANDLE, h->handle); if (h->chain != NULL) - nfnl_nft_chain_set_name(nlc, h->chain, strlen(h->chain) + 1); + nft_chain_attr_set_str(nlc, NFT_CHAIN_ATTR_NAME, h->chain); return nlc; } -struct nfnl_nft_rule *alloc_nft_rule(const struct handle *h) +struct nft_rule *alloc_nft_rule(const struct handle *h) { - struct nfnl_nft_rule *nlr; + struct nft_rule *nlr; - nlr = nfnl_nft_rule_alloc(); + nlr = nft_rule_alloc(); if (nlr == NULL) memory_allocation_error(); - nfnl_nft_rule_set_family(nlr, h->family); - nfnl_nft_rule_set_table(nlr, h->table, strlen(h->table) + 1); + + nft_rule_attr_set_u32(nlr, NFT_RULE_ATTR_FAMILY, h->family); + nft_rule_attr_set_str(nlr, NFT_RULE_ATTR_TABLE, h->table); if (h->chain != NULL) - nfnl_nft_rule_set_chain(nlr, h->chain, strlen(h->chain) + 1); + nft_rule_attr_set_str(nlr, NFT_RULE_ATTR_CHAIN, h->chain); if (h->handle) - nfnl_nft_rule_set_handle(nlr, h->handle); + nft_rule_attr_set_u64(nlr, NFT_RULE_ATTR_HANDLE, h->handle); return nlr; } -struct nfnl_nft_expr *alloc_nft_expr(int (*init)(struct nfnl_nft_expr *)) +struct nft_rule_expr *alloc_nft_expr(const char *name) { - struct nfnl_nft_expr *nle; + struct nft_rule_expr *nle; - nle = nfnl_nft_expr_alloc(); - if (nle == NULL || init(nle) != 0) + nle = nft_rule_expr_alloc(name); + if (nle == NULL) memory_allocation_error(); return nle; } -struct nfnl_nft_set *alloc_nft_set(const struct handle *h) +struct nft_set *alloc_nft_set(const struct handle *h) { - struct nfnl_nft_set *nls; + struct nft_set *nls; - nls = nfnl_nft_set_alloc(); + nls = nft_set_alloc(); if (nls == NULL) memory_allocation_error(); - nfnl_nft_set_set_family(nls, h->family); - nfnl_nft_set_set_table(nls, h->table, strlen(h->table) + 1); + + nft_set_attr_set_u32(nls, NFT_SET_ATTR_FAMILY, h->family); + nft_set_attr_set_str(nls, NFT_SET_ATTR_TABLE, h->table); if (h->set != NULL) - nfnl_nft_set_set_name(nls, h->set, strlen(h->set) + 1); + nft_set_attr_set_str(nls, NFT_SET_ATTR_NAME, h->set); + return nls; } -static struct nfnl_nft_setelem *alloc_nft_setelem(const struct expr *expr) +static struct nft_set_elem *alloc_nft_setelem(const struct expr *expr) { - struct nfnl_nft_setelem *nlse; + struct nft_set_elem *nlse; + struct nft_data_linearize nld; - nlse = nfnl_nft_setelem_alloc(); + nlse = nft_set_elem_alloc(); if (nlse == NULL) memory_allocation_error(); - if (expr->ops->type == EXPR_VALUE || expr->flags & EXPR_F_INTERVAL_END) - nfnl_nft_setelem_set_key(nlse, netlink_gen_data(expr)); - else { + if (expr->ops->type == EXPR_VALUE || + expr->flags & EXPR_F_INTERVAL_END) { + netlink_gen_data(expr, &nld); + nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_KEY, + &nld.value, nld.len); + } else { assert(expr->ops->type == EXPR_MAPPING); - nfnl_nft_setelem_set_key(nlse, netlink_gen_data(expr->left)); - nfnl_nft_setelem_set_data(nlse, netlink_gen_data(expr->right)); + netlink_gen_data(expr->left, &nld); + nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_KEY, + &nld.value, nld.len); + netlink_gen_data(expr->right, &nld); + if (expr->right->ops->type == EXPR_VERDICT) { + nft_set_elem_attr_set_u32(nlse, NFT_SET_ELEM_ATTR_VERDICT, + expr->right->verdict); + if (expr->chain != NULL) { + nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_CHAIN, + nld.chain, strlen(nld.chain)); + } + } } - if (expr->flags & EXPR_F_INTERVAL_END) - nfnl_nft_setelem_set_flags(nlse, NFT_SET_ELEM_INTERVAL_END); + if (expr->flags & EXPR_F_INTERVAL_END) { + nft_set_elem_attr_set_u32(nlse, NFT_SET_ELEM_ATTR_FLAGS, + NFT_SET_ELEM_INTERVAL_END); + } return nlse; } -struct nfnl_nft_data *alloc_nft_data(const void *data, unsigned int len) +void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder, + unsigned int len, struct nft_data_linearize *data) { - struct nfnl_nft_data *nld; - assert(len > 0); - nld = nfnl_nft_data_alloc(data, len); - if (nld == NULL) - memory_allocation_error(); - return nld; + mpz_export_data(data->value, value, byteorder, len); + data->len = len; } -struct nfnl_nft_data *netlink_gen_raw_data(const mpz_t value, - enum byteorder byteorder, - unsigned int len) -{ - unsigned char data[len]; - - mpz_export_data(data, value, byteorder, len); - return alloc_nft_data(data, len); -} - -static struct nfnl_nft_data *netlink_gen_concat_data(const struct expr *expr) +static void netlink_gen_concat_data(const struct expr *expr, + struct nft_data_linearize *nld) { const struct expr *i; unsigned int len, offset; @@ -210,79 +200,75 @@ static struct nfnl_nft_data *netlink_gen_concat_data(const struct expr *expr) i->len / BITS_PER_BYTE); offset += i->len / BITS_PER_BYTE; } - - return alloc_nft_data(data, len / BITS_PER_BYTE); + + memcpy(nld->value, data, len / BITS_PER_BYTE); + nld->len = len; } } -static struct nfnl_nft_data *netlink_gen_constant_data(const struct expr *expr) +static void netlink_gen_constant_data(const struct expr *expr, + struct nft_data_linearize *data) { assert(expr->ops->type == EXPR_VALUE); - return netlink_gen_raw_data(expr->value, expr->byteorder, - div_round_up(expr->len, BITS_PER_BYTE)); + netlink_gen_raw_data(expr->value, expr->byteorder, + div_round_up(expr->len, BITS_PER_BYTE), data); } -static struct nfnl_nft_data *netlink_gen_verdict(const struct expr *expr) +static void netlink_gen_verdict(const struct expr *expr, + struct nft_data_linearize *data) { - struct nfnl_nft_data *verdict; - - verdict = nfnl_nft_verdict_alloc(); - nfnl_nft_verdict_set_verdict(verdict, expr->verdict); + data->verdict = expr->verdict; switch (expr->verdict) { case NFT_JUMP: case NFT_GOTO: - nfnl_nft_verdict_set_chain(verdict, expr->chain); + strncpy(data->chain, expr->chain, NFT_CHAIN_MAXNAMELEN); + data->chain[NFT_CHAIN_MAXNAMELEN-1] = '\0'; break; } - - return verdict; } -struct nfnl_nft_data *netlink_gen_data(const struct expr *expr) +void netlink_gen_data(const struct expr *expr, struct nft_data_linearize *data) { switch (expr->ops->type) { case EXPR_VALUE: - return netlink_gen_constant_data(expr); + return netlink_gen_constant_data(expr, data); case EXPR_CONCAT: - return netlink_gen_concat_data(expr); + return netlink_gen_concat_data(expr, data); case EXPR_VERDICT: - return netlink_gen_verdict(expr); + return netlink_gen_verdict(expr, data); default: BUG("invalid data expression type %s\n", expr->ops->name); } } struct expr *netlink_alloc_value(const struct location *loc, - const struct nfnl_nft_data *nld) + const struct nft_data_delinearize *nld) { return constant_expr_alloc(loc, &invalid_type, BYTEORDER_INVALID, - nfnl_nft_data_get_size(nld) * BITS_PER_BYTE, - nfnl_nft_data_get(nld)); + nld->len * BITS_PER_BYTE, nld->value); } static struct expr *netlink_alloc_verdict(const struct location *loc, - const struct nfnl_nft_data *nld) + const struct nft_data_delinearize *nld) { - unsigned int code; char *chain; - code = nfnl_nft_verdict_get_verdict(nld); - switch (code) { + switch (nld->verdict) { case NFT_JUMP: case NFT_GOTO: - chain = xstrdup(nfnl_nft_verdict_get_chain(nld)); + chain = xstrdup(nld->chain); break; default: chain = NULL; break; } - return verdict_expr_alloc(loc, code, chain); + return verdict_expr_alloc(loc, nld->verdict, chain); } struct expr *netlink_alloc_data(const struct location *loc, - const struct nfnl_nft_data *nld, + const struct nft_data_delinearize *nld, enum nft_registers dreg) { switch (dreg) { @@ -296,230 +282,246 @@ struct expr *netlink_alloc_data(const struct location *loc, int netlink_add_rule(struct netlink_ctx *ctx, const struct handle *h, const struct rule *rule, uint32_t flags) { - struct nfnl_nft_rule *nlr; + struct nft_rule *nlr; int err; nlr = alloc_nft_rule(&rule->handle); err = netlink_linearize_rule(ctx, nlr, rule); if (err == 0) { - err = nfnl_nft_rule_add(nf_sock, nlr, flags | NLM_F_EXCL); + err = mnl_nft_rule_add(nf_sock, nlr, flags | NLM_F_EXCL); if (err < 0) netlink_io_error(ctx, &rule->location, - "Could not add rule: %s", nl_geterror(err)); + "Could not add rule: %s", + strerror(errno)); } - nfnl_nft_rule_put(nlr); + nft_rule_free(nlr); return err; } int netlink_delete_rule(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc) { - struct nfnl_nft_rule *nlr; + struct nft_rule *nlr; int err; nlr = alloc_nft_rule(h); - err = nfnl_nft_rule_delete(nf_sock, nlr, 0); - nfnl_nft_rule_put(nlr); + err = mnl_nft_rule_delete(nf_sock, nlr, 0); + nft_rule_free(nlr); if (err < 0) netlink_io_error(ctx, loc, "Could not delete rule: %s", - nl_geterror(err)); + strerror(errno)); return err; } -static void list_rule_cb(struct nl_object *obj, void *arg) +void netlink_dump_rule(struct nft_rule *nlr) { - const struct nfnl_nft_rule *nlr = (struct nfnl_nft_rule *)obj; - struct netlink_ctx *ctx = arg; - struct rule *rule; +#ifdef DEBUG + char buf[4096]; - netlink_dump_object(obj); - if (!nfnl_nft_rule_test_family(nlr) || - !nfnl_nft_rule_test_table(nlr) || - !nfnl_nft_rule_test_chain(nlr) || - !nfnl_nft_rule_test_handle(nlr)) { - netlink_io_error(ctx, NULL, "Incomplete rule received"); + if (!(debug_level & DEBUG_NETLINK)) return; - } - rule = netlink_delinearize_rule(ctx, obj); - list_add_tail(&rule->list, &ctx->list); + nft_rule_snprintf(buf, sizeof(buf), nlr, 0, 0); + fprintf(stderr, "%s\n", buf); +#endif } -static int netlink_list_rules(struct netlink_ctx *ctx, const struct handle *h, - const struct location *loc) +void netlink_dump_expr(struct nft_rule_expr *nle) { - struct nl_cache *rule_cache; - struct nfnl_nft_rule *nlr; - int err; +#ifdef DEBUG + char buf[4096]; - err = nfnl_nft_rule_alloc_cache(nf_sock, &rule_cache); - if (err < 0) - return netlink_io_error(ctx, loc, - "Could not receive rules from kernel: %s", - nl_geterror(err)); + if (!(debug_level & DEBUG_NETLINK)) + return; - nlr = alloc_nft_rule(h); - nl_cache_foreach_filter(rule_cache, OBJ_CAST(nlr), list_rule_cb, ctx); - nfnl_nft_rule_put(nlr); - nl_cache_free(rule_cache); - return 0; + nft_rule_expr_snprintf(buf, sizeof(buf), nle, 0, 0); + fprintf(stderr, "%s\n", buf); +#endif } -static int netlink_get_rule_cb(struct nl_msg *msg, void *arg) +static int list_rule_cb(struct nft_rule *nlr, void *arg) { - return nl_msg_parse(msg, list_rule_cb, arg); + struct netlink_ctx *ctx = arg; + const struct handle *h = ctx->data; + struct rule *rule; + + if ((h->family != nft_rule_attr_get_u32(nlr, NFT_RULE_ATTR_FAMILY)) || + strcmp(nft_rule_attr_get_str(nlr, NFT_RULE_ATTR_TABLE), h->table) != 0 || + (h->chain && + strcmp(nft_rule_attr_get_str(nlr, NFT_RULE_ATTR_CHAIN), h->chain) != 0)) + return 0; + + netlink_dump_rule(nlr); + rule = netlink_delinearize_rule(ctx, nlr); + list_add_tail(&rule->list, &ctx->list); + + return 0; } -int netlink_get_rule(struct netlink_ctx *ctx, const struct handle *h, - const struct location *loc) +static int netlink_list_rules(struct netlink_ctx *ctx, const struct handle *h, + const struct location *loc) { - struct nfnl_nft_rule *nlr; - int err; - - nlr = alloc_nft_rule(h); - netlink_set_callback(netlink_get_rule_cb, ctx); - err = nfnl_nft_rule_query(nf_sock, nlr, 0); - if (err == 0) - err = nl_recvmsgs_default(nf_sock); - nfnl_nft_rule_put(nlr); + struct nft_rule_list *rule_cache; - if (err < 0) + rule_cache = mnl_nft_rule_dump(nf_sock, h->family); + if (rule_cache == NULL) return netlink_io_error(ctx, loc, - "Could not receive rule from kernel: %s", - nl_geterror(err)); - return err; + "Could not receive rules from kernel: %s", + strerror(errno)); + + ctx->data = h; + nft_rule_list_foreach(rule_cache, list_rule_cb, ctx); + nft_rule_list_free(rule_cache); + return 0; } -static void flush_rule_cb(struct nl_object *obj, void *arg) +static int flush_rule_cb(struct nft_rule *nlr, void *arg) { struct netlink_ctx *ctx = arg; int err; - netlink_dump_object(obj); - err = nfnl_nft_rule_delete(nf_sock, (struct nfnl_nft_rule *)obj, 0); - if (err < 0) + netlink_dump_rule(nlr); + err = mnl_nft_rule_delete(nf_sock, nlr, 0); + if (err < 0) { netlink_io_error(ctx, NULL, "Could not delete rule: %s", - nl_geterror(err)); + strerror(errno)); + return err; + } + return 0; } static int netlink_flush_rules(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc) { - struct nl_cache *rule_cache; - struct nfnl_nft_rule *nlr; - int err; + struct nft_rule_list *rule_cache; + struct nft_rule *nlr; - err = nfnl_nft_rule_alloc_cache(nf_sock, &rule_cache); - if (err < 0) + rule_cache = mnl_nft_rule_dump(nf_sock, h->family); + if (rule_cache == NULL) return netlink_io_error(ctx, loc, "Could not receive rules from kernel: %s", - nl_geterror(err)); + strerror(errno)); nlr = alloc_nft_rule(h); - nl_cache_foreach_filter(rule_cache, OBJ_CAST(nlr), flush_rule_cb, ctx); - nfnl_nft_rule_put(nlr); - nl_cache_free(rule_cache); + nft_rule_list_foreach(rule_cache, flush_rule_cb, ctx); + nft_rule_free(nlr); + nft_rule_list_free(rule_cache); return 0; } +void netlink_dump_chain(struct nft_chain *nlc) +{ +#ifdef DEBUG + char buf[4096]; + + if (!(debug_level & DEBUG_NETLINK)) + return; + + nft_chain_snprintf(buf, sizeof(buf), nlc, 0, 0); + fprintf(stderr, "%s\n", buf); +#endif +} + int netlink_add_chain(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc, const struct chain *chain) { - struct nfnl_nft_chain *nlc; + struct nft_chain *nlc; int err; nlc = alloc_nft_chain(h); if (chain != NULL && chain->flags & CHAIN_F_BASECHAIN) { - nfnl_nft_chain_set_hooknum(nlc, chain->hooknum); - nfnl_nft_chain_set_priority(nlc, chain->priority); + nft_chain_attr_set_u32(nlc, NFT_CHAIN_ATTR_HOOKNUM, + chain->hooknum); + nft_chain_attr_set_u32(nlc, NFT_CHAIN_ATTR_PRIO, + chain->priority); } - netlink_dump_object(OBJ_CAST(nlc)); - err = nfnl_nft_chain_add(nf_sock, nlc, NLM_F_EXCL); - nfnl_nft_chain_put(nlc); + netlink_dump_chain(nlc); + err = mnl_nft_chain_add(nf_sock, nlc, NLM_F_EXCL); + nft_chain_free(nlc); if (err < 0) netlink_io_error(ctx, loc, "Could not add chain: %s", - nl_geterror(err)); + strerror(errno)); return err; } int netlink_rename_chain(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc, const char *name) { - struct nfnl_nft_chain *nlc; + struct nft_chain *nlc; int err; nlc = alloc_nft_chain(h); - nfnl_nft_chain_set_name(nlc, name, strlen(name) + 1); - netlink_dump_object(OBJ_CAST(nlc)); - err = nfnl_nft_chain_add(nf_sock, nlc, 0); - nfnl_nft_chain_put(nlc); + nft_chain_attr_set_str(nlc, NFT_CHAIN_ATTR_NAME, name); + netlink_dump_chain(nlc); + err = mnl_nft_chain_add(nf_sock, nlc, 0); + nft_chain_free(nlc); if (err < 0) netlink_io_error(ctx, loc, "Could not rename chain: %s", - nl_geterror(err)); + strerror(errno)); return err; } int netlink_delete_chain(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc) { - struct nfnl_nft_chain *nlc; + struct nft_chain *nlc; int err; nlc = alloc_nft_chain(h); - netlink_dump_object(OBJ_CAST(nlc)); - err = nfnl_nft_chain_delete(nf_sock, nlc, 0); - nfnl_nft_chain_put(nlc); + netlink_dump_chain(nlc); + err = mnl_nft_chain_delete(nf_sock, nlc, 0); + nft_chain_free(nlc); if (err < 0) netlink_io_error(ctx, loc, "Could not delete chain: %s", - nl_geterror(err)); + strerror(errno)); return err; } -static void list_chain_cb(struct nl_object *obj, void *arg) +static int list_chain_cb(struct nft_chain *nlc, void *arg) { - struct nfnl_nft_chain *nlc = (struct nfnl_nft_chain *)obj; struct netlink_ctx *ctx = arg; + const struct handle *h = ctx->data; struct chain *chain; - netlink_dump_object(obj); - if (!nfnl_nft_chain_test_family(nlc) || - !nfnl_nft_chain_test_table(nlc) || - !nfnl_nft_chain_test_name(nlc)) { - netlink_io_error(ctx, NULL, "Incomplete chain received"); - return; - } + if ((h->family != nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_FAMILY)) || + strcmp(nft_chain_attr_get_str(nlc, NFT_CHAIN_ATTR_TABLE), h->table) != 0) + return 0; - chain = chain_alloc(nfnl_nft_chain_get_name(nlc)); - chain->handle.family = nfnl_nft_chain_get_family(nlc); - chain->handle.table = xstrdup(nfnl_nft_chain_get_table(nlc)); - chain->handle.handle = nfnl_nft_chain_get_handle(nlc); - chain->hooknum = nfnl_nft_chain_get_hooknum(nlc); - chain->priority = nfnl_nft_chain_get_priority(nlc); + chain = chain_alloc(nft_chain_attr_get_str(nlc, NFT_CHAIN_ATTR_NAME)); + chain->handle.family = + nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_FAMILY); + chain->handle.table = + xstrdup(nft_chain_attr_get_str(nlc, NFT_CHAIN_ATTR_NAME)); + chain->handle.handle = + nft_chain_attr_get_u64(nlc, NFT_CHAIN_ATTR_HANDLE); + chain->hooknum = + nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_HOOKNUM); + chain->priority = + nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_PRIO); list_add_tail(&chain->list, &ctx->list); + + return 0; } int netlink_list_chains(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc) { - struct nl_cache *chain_cache; - struct nfnl_nft_chain *nlc; + struct nft_chain_list *chain_cache; struct chain *chain; - int err; - err = nfnl_nft_chain_alloc_cache(nf_sock, &chain_cache); - if (err < 0) + chain_cache = mnl_nft_chain_dump(nf_sock, h->family); + if (chain_cache == NULL) return netlink_io_error(ctx, loc, "Could not receive chains from kernel: %s", - nl_geterror(err)); + strerror(errno)); - nlc = alloc_nft_chain(h); - nl_cache_foreach_filter(chain_cache, OBJ_CAST(nlc), list_chain_cb, ctx); - nfnl_nft_chain_put(nlc); - nl_cache_free(chain_cache); + ctx->data = h; + nft_chain_list_foreach(chain_cache, list_chain_cb, ctx); + nft_chain_list_free(chain_cache); /* Caller wants all existing chains */ if (h->chain == NULL) @@ -534,32 +536,33 @@ int netlink_list_chains(struct netlink_ctx *ctx, const struct handle *h, return netlink_io_error(ctx, NULL, "Could not find chain `%s' in table `%s': %s", h->chain, h->table, - nl_geterror(NLE_OBJ_NOTFOUND)); -} - -static int netlink_get_chain_cb(struct nl_msg *msg, void *arg) -{ - return nl_msg_parse(msg, list_chain_cb, arg); + strerror(ENOENT)); } int netlink_get_chain(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc) { - struct nfnl_nft_chain *nlc; + struct nft_chain *nlc; + struct chain *chain; int err; nlc = alloc_nft_chain(h); - netlink_set_callback(netlink_get_chain_cb, ctx); - err = nfnl_nft_chain_query(nf_sock, nlc, 0); - if (err == 0) - err = nl_recvmsgs_default(nf_sock); - netlink_set_callback(NULL, NULL); - nfnl_nft_chain_put(nlc); + err = mnl_nft_chain_get(nf_sock, nlc, 0); + + chain = chain_alloc(nft_chain_attr_get_str(nlc, NFT_CHAIN_ATTR_NAME)); + chain->handle.family = nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_FAMILY); + chain->handle.table = xstrdup(nft_chain_attr_get_str(nlc, NFT_CHAIN_ATTR_TABLE)); + chain->handle.handle = nft_chain_attr_get_u64(nlc, NFT_CHAIN_ATTR_HANDLE); + chain->hooknum = nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_HOOKNUM); + chain->priority = nft_chain_attr_get_u32(nlc, NFT_CHAIN_ATTR_PRIO); + list_add_tail(&chain->list, &ctx->list); + + nft_chain_free(nlc); if (err < 0) return netlink_io_error(ctx, loc, "Could not receive chain from kernel: %s", - nl_geterror(err)); + strerror(errno)); return err; } @@ -578,96 +581,97 @@ int netlink_flush_chain(struct netlink_ctx *ctx, const struct handle *h, int netlink_add_table(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc, const struct table *table) { - struct nfnl_nft_table *nlt; + struct nft_table *nlt; int err; nlt = alloc_nft_table(h); - err = nfnl_nft_table_add(nf_sock, nlt, NLM_F_EXCL); - nfnl_nft_table_put(nlt); + err = mnl_nft_table_add(nf_sock, nlt, NLM_F_EXCL); + nft_table_free(nlt); if (err < 0) netlink_io_error(ctx, loc, "Could not add table: %s", - nl_geterror(err)); + strerror(errno)); return err; } int netlink_delete_table(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc) { - struct nfnl_nft_table *nlt; + struct nft_table *nlt; int err; nlt = alloc_nft_table(h); - err = nfnl_nft_table_delete(nf_sock, nlt, 0); - nfnl_nft_table_put(nlt); + err = mnl_nft_table_delete(nf_sock, nlt, 0); + nft_table_free(nlt); if (err < 0) netlink_io_error(ctx, loc, "Could not delete table: %s", - nl_geterror(err)); + strerror(errno)); return err; } -static void list_table_cb(struct nl_object *obj, void *arg) +void netlink_dump_table(struct nft_table *nlt) { - struct nfnl_nft_table *nlt = (struct nfnl_nft_table *)obj; - struct netlink_ctx *ctx = arg; - struct table *table; +#ifdef DEBUG + char buf[4096]; - netlink_dump_object(obj); - if (!nfnl_nft_table_test_family(nlt) || - !nfnl_nft_table_test_name(nlt)) { - netlink_io_error(ctx, NULL, "Incomplete table received"); + if (!(debug_level & DEBUG_NETLINK)) return; - } + nft_table_snprintf(buf, sizeof(buf), nlt, 0, 0); + fprintf(stderr, "%s\n", buf); +#endif +} + +static int list_table_cb(struct nft_table *nlt, void *arg) +{ + struct netlink_ctx *ctx = arg; + struct table *table; + + netlink_dump_table(nlt); table = table_alloc(); - table->handle.family = nfnl_nft_table_get_family(nlt); - table->handle.table = xstrdup(nfnl_nft_table_get_name(nlt)); + table->handle.family = + nft_table_attr_get_u32(nlt, NFT_TABLE_ATTR_FAMILY); + table->handle.table = + xstrdup(nft_table_attr_get_str(nlt, NFT_TABLE_ATTR_NAME)); list_add_tail(&table->list, &ctx->list); + + return 0; } int netlink_list_tables(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc) { - struct nl_cache *table_cache; - struct nfnl_nft_table *nlt; - int err; + struct nft_table_list *table_cache; + struct nft_table *nlt; - err = nfnl_nft_table_alloc_cache(nf_sock, &table_cache); - if (err < 0) + table_cache = mnl_nft_table_dump(nf_sock, h->family); + if (table_cache == NULL) return netlink_io_error(ctx, loc, "Could not receive tables from kernel: %s", - nl_geterror(err)); + strerror(errno)); nlt = alloc_nft_table(h); - nl_cache_foreach_filter(table_cache, OBJ_CAST(nlt), list_table_cb, ctx); - nfnl_nft_table_put(nlt); - nl_cache_free(table_cache); + nft_table_list_foreach(table_cache, list_table_cb, ctx); + nft_table_free(nlt); + nft_table_list_free(table_cache); return 0; } -static int netlink_get_table_cb(struct nl_msg *msg, void *arg) -{ - return nl_msg_parse(msg, list_table_cb, arg); -} - int netlink_get_table(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc) { - struct nfnl_nft_table *nlt; + struct nft_table *nlt; int err; nlt = alloc_nft_table(h); - netlink_set_callback(netlink_get_table_cb, ctx); - err = nfnl_nft_table_query(nf_sock, nlt, 0); - if (err == 0) - err = nl_recvmsgs_default(nf_sock); - nfnl_nft_table_put(nlt); + err = mnl_nft_table_get(nf_sock, nlt, 0); + nft_table_free(nlt); if (err < 0) return netlink_io_error(ctx, loc, "Could not receive table from kernel: %s", - nl_geterror(err)); + strerror(errno)); return err; } @@ -704,268 +708,261 @@ static const struct datatype *dtype_map_from_kernel(enum nft_data_types type) } } -static void add_set_cb(struct nl_object *obj, void *arg) +void netlink_dump_set(struct nft_set *nls) { - struct nfnl_nft_set *nls = (struct nfnl_nft_set *)obj; - struct netlink_ctx *ctx = arg; - struct set *set = ctx->set; +#ifdef DEBUG + char buf[4096]; - netlink_dump_object(OBJ_CAST(nls)); - set->handle.set = xstrdup(nfnl_nft_set_get_name(nls)); -} + if (!(debug_level & DEBUG_NETLINK)) + return; -static int netlink_add_set_cb(struct nl_msg *msg, void *arg) -{ - return nl_msg_parse(msg, add_set_cb, arg); + nft_set_snprintf(buf, sizeof(buf), nls, 0, 0); + fprintf(stderr, "%s\n", buf); +#endif } int netlink_add_set(struct netlink_ctx *ctx, const struct handle *h, struct set *set) { - struct nfnl_nft_set *nls; + struct nft_set *nls; int err; nls = alloc_nft_set(h); - nfnl_nft_set_set_flags(nls, set->flags); - nfnl_nft_set_set_keytype(nls, dtype_map_to_kernel(set->keytype)); - nfnl_nft_set_set_keylen(nls, set->keylen / BITS_PER_BYTE); + nft_set_attr_set_u32(nls, NFT_SET_ATTR_FLAGS, set->flags); + nft_set_attr_set_u32(nls, NFT_SET_ATTR_KEY_TYPE, + dtype_map_to_kernel(set->keytype)); + nft_set_attr_set_u32(nls, NFT_SET_ATTR_KEY_LEN, + set->keylen / BITS_PER_BYTE); if (set->flags & NFT_SET_MAP) { - nfnl_nft_set_set_datatype(nls, dtype_map_to_kernel(set->datatype)); - nfnl_nft_set_set_datalen(nls, set->datalen / BITS_PER_BYTE); + nft_set_attr_set_u32(nls, NFT_SET_ATTR_DATA_TYPE, + dtype_map_to_kernel(set->datatype)); + nft_set_attr_set_u32(nls, NFT_SET_ATTR_DATA_LEN, + set->datalen / BITS_PER_BYTE); } - netlink_dump_object(OBJ_CAST(nls)); - - ctx->set = set; - netlink_set_callback(netlink_add_set_cb, ctx); - err = nfnl_nft_set_add(nf_sock, nls, NLM_F_EXCL | NLM_F_ECHO); - if (err == 0) - err = nl_recvmsgs_default(nf_sock); - netlink_set_callback(NULL, NULL); - nfnl_nft_set_put(nls); - ctx->set = NULL; + netlink_dump_set(nls); + err = mnl_nft_set_add(nf_sock, nls, NLM_F_EXCL | NLM_F_ECHO); if (err < 0) netlink_io_error(ctx, NULL, "Could not add set: %s", - nl_geterror(err)); + strerror(errno)); + + set->handle.set = + xstrdup(nft_set_attr_get_str(nls, NFT_SET_ATTR_NAME)); + nft_set_free(nls); + return err; } int netlink_delete_set(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc) { - struct nfnl_nft_set *nls; + struct nft_set *nls; int err; nls = alloc_nft_set(h); - err = nfnl_nft_set_delete(nf_sock, nls, 0); - nfnl_nft_set_put(nls); + err = mnl_nft_set_delete(nf_sock, nls, 0); + nft_set_free(nls); if (err < 0) netlink_io_error(ctx, loc, "Could not delete set: %s", - nl_geterror(err)); + strerror(errno)); return err; } -static void list_set_cb(struct nl_object *obj, void *arg) +static int list_set_cb(struct nft_set *nls, void *arg) { - struct nfnl_nft_set *nls = (struct nfnl_nft_set *)obj; struct netlink_ctx *ctx = arg; const struct datatype *keytype, *datatype; - uint32_t flags; + uint32_t flags, key, data; struct set *set; - netlink_dump_object(obj); - if (!nfnl_nft_set_test_family(nls) || - !nfnl_nft_set_test_table(nls) || - !nfnl_nft_set_test_name(nls) || - !nfnl_nft_set_test_keytype(nls) || - !nfnl_nft_set_test_keylen(nls)) { - netlink_io_error(ctx, NULL, "Incomplete set received"); - return; - } - - keytype = dtype_map_from_kernel(nfnl_nft_set_get_keytype(nls)); + netlink_dump_set(nls); + key = nft_set_attr_get_u32(nls, NFT_SET_ATTR_KEY_TYPE); + keytype = dtype_map_from_kernel(key); if (keytype == NULL) { netlink_io_error(ctx, NULL, "Unknown data type in set key %u", - nfnl_nft_set_get_keytype(nls)); - return; + key); + return -1; } - flags = nfnl_nft_set_get_flags(nls); + flags = nft_set_attr_get_u32(nls, NFT_SET_ATTR_FLAGS); if (flags & NFT_SET_MAP) { - datatype = dtype_map_from_kernel(nfnl_nft_set_get_datatype(nls)); + data = nft_set_attr_get_u32(nls, NFT_SET_ATTR_DATA_TYPE); + datatype = dtype_map_from_kernel(data); if (datatype == NULL) { netlink_io_error(ctx, NULL, "Unknown data type in set key %u", - nfnl_nft_set_get_datatype(nls)); - return; + data); + return -1; } } else datatype = NULL; set = set_alloc(&internal_location); - set->handle.family = nfnl_nft_set_get_family(nls); - set->handle.table = xstrdup(nfnl_nft_set_get_table(nls)); - set->handle.set = xstrdup(nfnl_nft_set_get_name(nls)); + set->handle.family = nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY); + set->handle.table = + xstrdup(nft_set_attr_get_str(nls, NFT_SET_ATTR_TABLE)); + set->handle.set = + xstrdup(nft_set_attr_get_str(nls, NFT_SET_ATTR_NAME)); set->keytype = keytype; - set->keylen = nfnl_nft_set_get_keylen(nls) * BITS_PER_BYTE; + set->keylen = + nft_set_attr_get_u32(nls, NFT_SET_ATTR_KEY_LEN) * BITS_PER_BYTE; set->flags = flags; set->datatype = datatype; - set->datalen = nfnl_nft_set_get_datalen(nls) * BITS_PER_BYTE; + if (nft_set_attr_is_set(nls, NFT_SET_ATTR_DATA_LEN)) { + set->datalen = + nft_set_attr_get_u32(nls, NFT_SET_ATTR_DATA_LEN) * BITS_PER_BYTE; + } list_add_tail(&set->list, &ctx->list); + + return 0; } int netlink_list_sets(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc) { - struct nl_cache *set_cache; - int err; + struct nft_set_list *set_cache; - err = nfnl_nft_set_alloc_cache(nf_sock, h->family, h->table, &set_cache); - if (err < 0) + set_cache = mnl_nft_set_dump(nf_sock, h->family, h->table); + if (set_cache == NULL) return netlink_io_error(ctx, loc, "Could not receive sets from kernel: %s", - nl_geterror(err)); + strerror(errno)); - nl_cache_foreach(set_cache, list_set_cb, ctx); - nl_cache_free(set_cache); + nft_set_list_foreach(set_cache, list_set_cb, ctx); + nft_set_list_free(set_cache); return 0; } -static int netlink_get_set_cb(struct nl_msg *msg, void *arg) -{ - return nl_msg_parse(msg, list_set_cb, arg); -} - int netlink_get_set(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc) { - struct nfnl_nft_set *nls; + struct nft_set *nls; + struct set *set; int err; nls = alloc_nft_set(h); - netlink_dump_object(OBJ_CAST(nls)); - netlink_set_callback(netlink_get_set_cb, ctx); - err = nfnl_nft_set_query(nf_sock, nls, 0); - if (err == 0) - err = nl_recvmsgs_default(nf_sock); - netlink_set_callback(NULL, NULL); - - nfnl_nft_set_put(nls); - + netlink_dump_set(nls); + err = mnl_nft_set_get(nf_sock, nls); if (err < 0) return netlink_io_error(ctx, loc, "Could not receive set from kernel: %s", - nl_geterror(err)); + strerror(errno)); + + set = set_alloc(&internal_location); + set->handle.family = nft_set_attr_get_u32(nls, NFT_SET_ATTR_FAMILY); + set->handle.table = + xstrdup(nft_set_attr_get_str(nls, NFT_SET_ATTR_TABLE)); + set->handle.set = + xstrdup(nft_set_attr_get_str(nls, NFT_SET_ATTR_NAME)); + set->keytype = + dtype_map_from_kernel(nft_set_attr_get_u32(nls, NFT_SET_ATTR_KEY_TYPE)); + set->keylen = + nft_set_attr_get_u32(nls, NFT_SET_ATTR_KEY_LEN) * BITS_PER_BYTE; + set->flags = nft_set_attr_get_u32(nls, NFT_SET_ATTR_FLAGS); + set->datatype = + dtype_map_from_kernel(nft_set_attr_get_u32(nls, NFT_SET_ATTR_DATA_TYPE)); + if (nft_set_attr_is_set(nls, NFT_SET_ATTR_DATA_LEN)) { + set->datalen = + nft_set_attr_get_u32(nls, NFT_SET_ATTR_DATA_LEN) * BITS_PER_BYTE; + } + list_add_tail(&set->list, &ctx->list); + nft_set_free(nls); + return err; } -static int alloc_setelem_cache(const struct expr *set, struct nl_cache **res) +static void alloc_setelem_cache(const struct expr *set, struct nft_set *nls) { - struct nfnl_nft_setelem *nlse; - struct nl_cache *elements; + struct nft_set_elem *nlse; const struct expr *expr; - int err; - err = nl_cache_alloc_name("netfilter/nft_setelem", &elements); - if (err < 0) - return err; list_for_each_entry(expr, &set->expressions, list) { nlse = alloc_nft_setelem(expr); - netlink_dump_object(OBJ_CAST(nlse)); - nl_cache_add(elements, OBJ_CAST(nlse)); + nft_set_elem_add(nls, nlse); } - *res = elements; - return 0; } int netlink_add_setelems(struct netlink_ctx *ctx, const struct handle *h, const struct expr *expr) { - struct nfnl_nft_set *nls; - struct nl_cache *elements; + struct nft_set *nls; int err; nls = alloc_nft_set(h); - netlink_dump_object(OBJ_CAST(nls)); + alloc_setelem_cache(expr, nls); + netlink_dump_set(nls); - err = alloc_setelem_cache(expr, &elements); - if (err < 0) - goto out; - err = nfnl_nft_setelem_add(nf_sock, nls, elements, 0); - if (err < 0) - goto out; - err = nl_recvmsgs_default(nf_sock); -out: - nfnl_nft_set_put(nls); + err = mnl_nft_setelem_add(nf_sock, nls, 0); + nft_set_free(nls); if (err < 0) netlink_io_error(ctx, &expr->location, "Could not add set elements: %s", - nl_geterror(err)); + strerror(errno)); return err; } int netlink_delete_setelems(struct netlink_ctx *ctx, const struct handle *h, const struct expr *expr) { - struct nfnl_nft_set *nls; - struct nl_cache *elements; + struct nft_set *nls; int err; nls = alloc_nft_set(h); - err = alloc_setelem_cache(expr, &elements); - if (err < 0) - goto out; - err = nfnl_nft_setelem_delete(nf_sock, nls, elements, 0); - if (err < 0) - goto out; - err = nl_recvmsgs_default(nf_sock); -out: - nfnl_nft_set_put(nls); + alloc_setelem_cache(expr, nls); + netlink_dump_set(nls); + + err = mnl_nft_setelem_delete(nf_sock, nls, 0); + nft_set_free(nls); if (err < 0) netlink_io_error(ctx, &expr->location, "Could not delete set elements: %s", - nl_geterror(err)); + strerror(errno)); return err; } -static void list_setelem_cb(struct nl_object *obj, void *arg) +static int list_setelem_cb(struct nft_set_elem *nlse, void *arg) { - struct nfnl_nft_setelem *nlse = nl_object_priv(obj); - struct nfnl_nft_data *nld; + struct nft_data_delinearize nld; struct netlink_ctx *ctx = arg; struct set *set = ctx->set; struct expr *expr, *data; - uint32_t flags; + uint32_t flags = 0; - netlink_dump_object(obj); - if (!nfnl_nft_setelem_test_key(nlse)) { - netlink_io_error(ctx, NULL, "Incomplete set element received"); - return; - } + nld.value = + nft_set_elem_attr_get(nlse, NFT_SET_ELEM_ATTR_KEY, &nld.len); + if (nft_set_elem_attr_is_set(nlse, NFT_SET_ELEM_ATTR_FLAGS)) + flags = nft_set_elem_attr_get_u32(nlse, NFT_SET_ELEM_ATTR_FLAGS); - nld = nfnl_nft_setelem_get_key(nlse); - flags = nfnl_nft_setelem_get_flags(nlse); - - expr = netlink_alloc_value(&internal_location, nld); + expr = netlink_alloc_value(&internal_location, &nld); expr->dtype = set->keytype; expr->byteorder = set->keytype->byteorder; if (expr->byteorder == BYTEORDER_HOST_ENDIAN) mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE); - if (flags & NFT_SET_ELEM_INTERVAL_END) + if (flags & NFT_SET_ELEM_INTERVAL_END) { expr->flags |= EXPR_F_INTERVAL_END; - else if (nfnl_nft_setelem_test_data(nlse)) { - nld = nfnl_nft_setelem_get_data(nlse); - - data = netlink_alloc_data(&internal_location, nld, + } else { + if (nft_set_elem_attr_is_set(nlse, NFT_SET_ELEM_ATTR_DATA)) { + nld.value = nft_set_elem_attr_get(nlse, NFT_SET_ELEM_ATTR_DATA, + &nld.len); + } else if (nft_set_elem_attr_is_set(nlse, NFT_SET_ELEM_ATTR_CHAIN)) { + nld.chain = nft_set_elem_attr_get_str(nlse, NFT_SET_ELEM_ATTR_CHAIN); + nld.verdict = nft_set_elem_attr_get_u32(nlse, NFT_SET_ELEM_ATTR_VERDICT); + } else if (nft_set_elem_attr_is_set(nlse, NFT_SET_ELEM_ATTR_VERDICT)) { + nld.verdict = nft_set_elem_attr_get_u32(nlse, NFT_SET_ELEM_ATTR_VERDICT); + } else + goto out; + + data = netlink_alloc_data(&internal_location, &nld, set->datatype->type == TYPE_VERDICT ? NFT_REG_VERDICT : NFT_REG_1); data->dtype = set->datatype; expr = mapping_expr_alloc(&internal_location, expr, data); } - +out: compound_expr_add(set->init, expr); + return 0; } extern void interval_map_decompose(struct expr *set); @@ -973,32 +970,27 @@ extern void interval_map_decompose(struct expr *set); int netlink_get_setelems(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc, struct set *set) { - struct nl_cache *elements; - struct nfnl_nft_set *nls; + struct nft_set *nls; int err; nls = alloc_nft_set(h); - netlink_dump_object(OBJ_CAST(nls)); + netlink_dump_set(nls); - err = nfnl_nft_setelem_alloc_cache(nf_sock, nls, &elements); - if (err < 0) - goto out; - err = nl_recvmsgs_default(nf_sock); + err = mnl_nft_setelem_get(nf_sock, nls); if (err < 0) goto out; ctx->set = set; set->init = set_expr_alloc(loc); - nl_cache_foreach(elements, list_setelem_cb, ctx); - nl_cache_free(elements); + nft_set_elem_foreach(nls, list_setelem_cb, ctx); + nft_set_free(nls); ctx->set = NULL; if (set->flags & NFT_SET_INTERVAL) interval_map_decompose(set->init); out: - nfnl_nft_set_put(nls); if (err < 0) netlink_io_error(ctx, loc, "Could not receive set elements: %s", - nl_geterror(err)); + strerror(errno)); return err; } diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 50672b98..c24e105c 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> + * Copyright (c) 2013 Pablo Neira Ayuso <pablo@netfilter.org> * * 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 @@ -8,6 +9,9 @@ * Development of this code funded by Astaro AG (http://www.astaro.com/) */ +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> #include <limits.h> #include <linux/netfilter/nf_tables.h> #include <netlink.h> @@ -69,14 +73,22 @@ static struct expr *netlink_get_register(struct netlink_parse_ctx *ctx, static void netlink_parse_immediate(struct netlink_parse_ctx *ctx, const struct location *loc, - const struct nfnl_nft_expr *nle) + const struct nft_rule_expr *nle) { - const struct nfnl_nft_data *data = nfnl_nft_immediate_get_data(nle); - enum nft_registers dreg = nfnl_nft_immediate_get_dreg(nle); + struct nft_data_delinearize nld; + enum nft_registers dreg; struct stmt *stmt; struct expr *expr; - expr = netlink_alloc_data(loc, data, dreg); + if (nft_rule_expr_is_set(nle, NFT_EXPR_IMM_VERDICT)) + nld.verdict = nft_rule_expr_get_u32(nle, NFT_EXPR_IMM_VERDICT); + else if (nft_rule_expr_is_set(nle, NFT_EXPR_IMM_DATA)) { + nld.value = nft_rule_expr_get(nle, NFT_EXPR_IMM_DATA, &nld.len); + } + + dreg = nft_rule_expr_get_u32(nle, NFT_EXPR_IMM_DREG); + + expr = netlink_alloc_data(loc, &nld, dreg); if (dreg == NFT_REG_VERDICT) { stmt = verdict_stmt_alloc(loc, expr); list_add_tail(&stmt->list, &ctx->rule->stmts); @@ -84,9 +96,9 @@ static void netlink_parse_immediate(struct netlink_parse_ctx *ctx, netlink_set_register(ctx, dreg, expr); } -static enum ops netlink_parse_cmp_op(const struct nfnl_nft_expr *nle) +static enum ops netlink_parse_cmp_op(const struct nft_rule_expr *nle) { - switch (nfnl_nft_cmp_get_op(nle)) { + switch (nft_rule_expr_get_u8(nle, NFT_EXPR_CMP_OP)) { case NFT_CMP_EQ: return OP_EQ; case NFT_CMP_NEQ: @@ -106,21 +118,23 @@ static enum ops netlink_parse_cmp_op(const struct nfnl_nft_expr *nle) static void netlink_parse_cmp(struct netlink_parse_ctx *ctx, const struct location *loc, - const struct nfnl_nft_expr *nle) + const struct nft_rule_expr *nle) { - const struct nfnl_nft_data *data = nfnl_nft_cmp_get_data(nle); + struct nft_data_delinearize nld; struct expr *expr, *left, *right; struct stmt *stmt; enum ops op; - left = netlink_get_register(ctx, loc, nfnl_nft_cmp_get_sreg(nle)); + nld.value = nft_rule_expr_get(nle, NFT_EXPR_CMP_DATA, &nld.len); + left = netlink_get_register(ctx, loc, + nft_rule_expr_get_u8(nle, NFT_EXPR_CMP_SREG)); if (left == NULL) return netlink_error(ctx, loc, "Relational expression has no left " "hand side"); op = netlink_parse_cmp_op(nle); - right = netlink_alloc_value(loc, data); + right = netlink_alloc_value(loc, &nld); // FIXME if (left->len && left->dtype && left->dtype->type != TYPE_STRING && @@ -135,28 +149,30 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx, static void netlink_parse_lookup(struct netlink_parse_ctx *ctx, const struct location *loc, - const struct nfnl_nft_expr *nle) + const struct nft_rule_expr *nle) { struct stmt *stmt; struct expr *expr, *left, *right; struct set *set; enum nft_registers dreg; - left = netlink_get_register(ctx, loc, nfnl_nft_lookup_get_sreg(nle)); + left = netlink_get_register(ctx, loc, + nft_rule_expr_get_u32(nle, NFT_EXPR_LOOKUP_SREG)); if (left == NULL) return netlink_error(ctx, loc, "Lookup expression has no left hand side"); - set = set_lookup(ctx->table, nfnl_nft_lookup_get_set(nle)); + set = set_lookup(ctx->table, + nft_rule_expr_get_str(nle, NFT_EXPR_LOOKUP_SET)); if (set == NULL) return netlink_error(ctx, loc, "Unknown set '%s' in lookup expression", - nfnl_nft_lookup_get_set(nle)); + nft_rule_expr_get_str(nle, NFT_EXPR_LOOKUP_SET)); right = set_ref_expr_alloc(loc, set); - if (nfnl_nft_lookup_test_dreg(nle)) { - dreg = nfnl_nft_lookup_get_dreg(nle); + if (nft_rule_expr_is_set(nle, NFT_EXPR_LOOKUP_DREG)) { + dreg = nft_rule_expr_get_u32(nle, NFT_EXPR_LOOKUP_DREG); expr = map_expr_alloc(loc, left, right); if (dreg != NFT_REG_VERDICT) return netlink_set_register(ctx, dreg, expr); @@ -170,12 +186,14 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx, static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx, const struct location *loc, - const struct nfnl_nft_expr *nle) + const struct nft_rule_expr *nle) { struct expr *expr, *left, *mask, *xor, *or; mpz_t m, x, o; + struct nft_data_delinearize nld; - left = netlink_get_register(ctx, loc, nfnl_nft_bitwise_get_sreg(nle)); + left = netlink_get_register(ctx, loc, + nft_rule_expr_get_u32(nle, NFT_EXPR_BITWISE_SREG)); if (left == NULL) return netlink_error(ctx, loc, "Bitwise expression has no left " @@ -183,10 +201,14 @@ static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx, expr = left; - mask = netlink_alloc_value(loc, nfnl_nft_bitwise_get_mask(nle)); + nld.value = nft_rule_expr_get(nle, NFT_EXPR_BITWISE_MASK, &nld.len); + + mask = netlink_alloc_value(loc, &nld); mpz_init_set(m, mask->value); - xor = netlink_alloc_value(loc, nfnl_nft_bitwise_get_xor(nle)); + nld.value = nft_rule_expr_get(nle, NFT_EXPR_BITWISE_XOR, &nld.len); + + xor = netlink_alloc_value(loc, &nld); mpz_init_set(x, xor->value); mpz_init_set_ui(o, 0); @@ -215,7 +237,10 @@ static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx, expr_free(xor); if (mpz_cmp_ui(o, 0)) { - or = netlink_alloc_value(loc, nfnl_nft_bitwise_get_xor(nle)); + nld.value = nft_rule_expr_get(nle, NFT_EXPR_BITWISE_XOR, + &nld.len); + + or = netlink_alloc_value(loc, &nld); mpz_set(or->value, o); expr = binop_expr_alloc(loc, OP_OR, expr, or); expr->len = left->len; @@ -225,23 +250,26 @@ static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx, mpz_clear(x); mpz_clear(o); - netlink_set_register(ctx, nfnl_nft_bitwise_get_dreg(nle), expr); + netlink_set_register(ctx, + nft_rule_expr_get_u32(nle, NFT_EXPR_BITWISE_DREG), + expr); } static void netlink_parse_byteorder(struct netlink_parse_ctx *ctx, const struct location *loc, - const struct nfnl_nft_expr *nle) + const struct nft_rule_expr *nle) { struct expr *expr, *arg; enum ops op; - arg = netlink_get_register(ctx, loc, nfnl_nft_byteorder_get_sreg(nle)); + arg = netlink_get_register(ctx, loc, + nft_rule_expr_get_u32(nle, NFT_EXPR_BYTEORDER_SREG)); if (arg == NULL) return netlink_error(ctx, loc, "Byteorder expression has no left " "hand side"); - switch (nfnl_nft_byteorder_get_op(nle)) { + switch (nft_rule_expr_get_u32(nle, NFT_EXPR_BYTEORDER_OP)) { case NFT_BYTEORDER_NTOH: op = OP_NTOH; break; @@ -250,106 +278,120 @@ static void netlink_parse_byteorder(struct netlink_parse_ctx *ctx, break; default: BUG("invalid byteorder operation %u\n", - nfnl_nft_byteorder_get_op(nle)); + nft_rule_expr_get_u32(nle, NFT_EXPR_BYTEORDER_OP)); } expr = unary_expr_alloc(loc, op, arg); expr->len = arg->len; - netlink_set_register(ctx, nfnl_nft_byteorder_get_dreg(nle), expr); + netlink_set_register(ctx, + nft_rule_expr_get_u32(nle, NFT_EXPR_BYTEORDER_DREG), + expr); } static void netlink_parse_payload(struct netlink_parse_ctx *ctx, const struct location *loc, - const struct nfnl_nft_expr *nle) + const struct nft_rule_expr *nle) { struct expr *expr; expr = payload_expr_alloc(loc, NULL, 0); - payload_init_raw(expr, nfnl_nft_payload_get_base(nle) + 1, - nfnl_nft_payload_get_offset(nle) * BITS_PER_BYTE, - nfnl_nft_payload_get_len(nle) * BITS_PER_BYTE); + payload_init_raw(expr, nft_rule_expr_get_u32(nle, NFT_EXPR_PAYLOAD_BASE) + 1, + nft_rule_expr_get_u32(nle, NFT_EXPR_PAYLOAD_OFFSET) * BITS_PER_BYTE, + nft_rule_expr_get_u32(nle, NFT_EXPR_PAYLOAD_LEN) * BITS_PER_BYTE); - netlink_set_register(ctx, nfnl_nft_payload_get_dreg(nle), expr); + netlink_set_register(ctx, + nft_rule_expr_get_u32(nle, NFT_EXPR_PAYLOAD_DREG), + expr); } static void netlink_parse_exthdr(struct netlink_parse_ctx *ctx, const struct location *loc, - const struct nfnl_nft_expr *nle) + const struct nft_rule_expr *nle) { struct expr *expr; expr = exthdr_expr_alloc(loc, NULL, 0); - exthdr_init_raw(expr, nfnl_nft_exthdr_get_type(nle), - nfnl_nft_exthdr_get_offset(nle) * BITS_PER_BYTE, - nfnl_nft_exthdr_get_len(nle) * BITS_PER_BYTE); + exthdr_init_raw(expr, nft_rule_expr_get_u8(nle, NFT_EXPR_EXTHDR_TYPE), + nft_rule_expr_get_u32(nle, NFT_EXPR_EXTHDR_OFFSET) * BITS_PER_BYTE, + nft_rule_expr_get_u32(nle, NFT_EXPR_EXTHDR_LEN) * BITS_PER_BYTE); - netlink_set_register(ctx, nfnl_nft_exthdr_get_dreg(nle), expr); + netlink_set_register(ctx, + nft_rule_expr_get_u32(nle, NFT_EXPR_EXTHDR_DREG), + expr); } static void netlink_parse_meta(struct netlink_parse_ctx *ctx, const struct location *loc, - const struct nfnl_nft_expr *nle) + const struct nft_rule_expr *nle) { struct expr *expr; - expr = meta_expr_alloc(loc, nfnl_nft_meta_get_key(nle)); - netlink_set_register(ctx, nfnl_nft_meta_get_dreg(nle), expr); + expr = meta_expr_alloc(loc, + nft_rule_expr_get_u8(nle, NFT_EXPR_META_KEY)); + netlink_set_register(ctx, + nft_rule_expr_get_u8(nle, NFT_EXPR_META_DREG), + expr); } static void netlink_parse_ct(struct netlink_parse_ctx *ctx, const struct location *loc, - const struct nfnl_nft_expr *nle) + const struct nft_rule_expr *nle) { struct expr *expr; - expr = ct_expr_alloc(loc, nfnl_nft_ct_get_key(nle)); - netlink_set_register(ctx, nfnl_nft_ct_get_dreg(nle), expr); + expr = ct_expr_alloc(loc, nft_rule_expr_get_u32(nle, NFT_EXPR_CT_KEY)); + netlink_set_register(ctx, + nft_rule_expr_get_u32(nle, NFT_EXPR_CT_DREG), + expr); } static void netlink_parse_counter(struct netlink_parse_ctx *ctx, const struct location *loc, - const struct nfnl_nft_expr *nle) + const struct nft_rule_expr *nle) { struct stmt *stmt; stmt = counter_stmt_alloc(loc); - stmt->counter.packets = nfnl_nft_counter_get_packets(nle); - stmt->counter.bytes = nfnl_nft_counter_get_bytes(nle); + stmt->counter.packets = + nft_rule_expr_get_u64(nle, NFT_EXPR_CTR_PACKETS); + stmt->counter.bytes = + nft_rule_expr_get_u64(nle, NFT_EXPR_CTR_BYTES); list_add_tail(&stmt->list, &ctx->rule->stmts); } static void netlink_parse_log(struct netlink_parse_ctx *ctx, const struct location *loc, - const struct nfnl_nft_expr *nle) + const struct nft_rule_expr *nle) { struct stmt *stmt; const char *prefix; stmt = log_stmt_alloc(loc); - prefix = nfnl_nft_log_get_prefix(nle); + prefix = nft_rule_expr_get_str(nle, NFT_EXPR_LOG_PREFIX); if (prefix != NULL) stmt->log.prefix = xstrdup(prefix); - stmt->log.group = nfnl_nft_log_get_group(nle); - stmt->log.snaplen = nfnl_nft_log_get_snaplen(nle); - stmt->log.qthreshold = nfnl_nft_log_get_qthreshold(nle); + stmt->log.group = nft_rule_expr_get_u32(nle, NFT_EXPR_LOG_GROUP); + stmt->log.snaplen = nft_rule_expr_get_u32(nle, NFT_EXPR_LOG_SNAPLEN); + stmt->log.qthreshold = + nft_rule_expr_get_u32(nle, NFT_EXPR_LOG_QTHRESHOLD); list_add_tail(&stmt->list, &ctx->rule->stmts); } static void netlink_parse_limit(struct netlink_parse_ctx *ctx, const struct location *loc, - const struct nfnl_nft_expr *nle) + const struct nft_rule_expr *nle) { struct stmt *stmt; stmt = limit_stmt_alloc(loc); - stmt->limit.rate = nfnl_nft_limit_get_rate(nle); - stmt->limit.depth = nfnl_nft_limit_get_depth(nle); + stmt->limit.rate = nft_rule_expr_get_u32(nle, NFT_EXPR_LIMIT_RATE); + stmt->limit.depth = nft_rule_expr_get_u32(nle, NFT_EXPR_LIMIT_DEPTH); list_add_tail(&stmt->list, &ctx->rule->stmts); } static void netlink_parse_reject(struct netlink_parse_ctx *ctx, const struct location *loc, - const struct nfnl_nft_expr *expr) + const struct nft_rule_expr *expr) { struct stmt *stmt; @@ -359,16 +401,16 @@ static void netlink_parse_reject(struct netlink_parse_ctx *ctx, static void netlink_parse_nat(struct netlink_parse_ctx *ctx, const struct location *loc, - const struct nfnl_nft_expr *nle) + const struct nft_rule_expr *nle) { struct stmt *stmt; struct expr *addr, *proto; enum nft_registers reg1, reg2; stmt = nat_stmt_alloc(loc); - stmt->nat.type = nfnl_nft_nat_get_type(nle); + stmt->nat.type = nft_rule_expr_get_u32(nle, NFT_EXPR_NAT_TYPE); - reg1 = nfnl_nft_nat_get_sreg_addr_min(nle); + reg1 = nft_rule_expr_get_u32(nle, NFT_EXPR_NAT_REG_ADDR_MIN); if (reg1) { addr = netlink_get_register(ctx, loc, reg1); if (addr == NULL) @@ -380,7 +422,7 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx, stmt->nat.addr = addr; } - reg2 = nfnl_nft_nat_get_sreg_addr_max(nle); + reg2 = nft_rule_expr_get_u32(nle, NFT_EXPR_NAT_REG_ADDR_MAX); if (reg2 && reg2 != reg1) { addr = netlink_get_register(ctx, loc, reg2); if (addr == NULL) @@ -394,7 +436,7 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx, stmt->nat.addr = addr; } - reg1 = nfnl_nft_nat_get_sreg_proto_min(nle); + reg1 = nft_rule_expr_get_u32(nle, NFT_EXPR_NAT_REG_PROTO_MIN); if (reg1) { proto = netlink_get_register(ctx, loc, reg1); if (proto == NULL) @@ -406,7 +448,7 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx, stmt->nat.proto = proto; } - reg2 = nfnl_nft_nat_get_sreg_proto_max(nle); + reg2 = nft_rule_expr_get_u32(nle, NFT_EXPR_NAT_REG_PROTO_MAX); if (reg2 && reg2 != reg1) { proto = netlink_get_register(ctx, loc, reg2); if (proto == NULL) @@ -427,7 +469,7 @@ static const struct { const char *name; void (*parse)(struct netlink_parse_ctx *ctx, const struct location *loc, - const struct nfnl_nft_expr *nle); + const struct nft_rule_expr *nle); } netlink_parsers[] = { { .name = "immediate", .parse = netlink_parse_immediate }, { .name = "cmp", .parse = netlink_parse_cmp }, @@ -450,25 +492,26 @@ static const struct input_descriptor indesc_netlink = { .type = INDESC_NETLINK, }; -static void netlink_parse_expr(struct nl_object *obj, void *arg) +static int netlink_parse_expr(struct nft_rule_expr *nle, void *arg) { - const struct nfnl_nft_expr *nle = (struct nfnl_nft_expr *)obj; - const char *type = nfnl_nft_expr_get_type(nle); + const char *type = nft_rule_expr_get_str(nle, NFT_RULE_EXPR_ATTR_NAME); struct netlink_parse_ctx *ctx = arg; struct location loc; unsigned int i; memset(&loc, 0, sizeof(loc)); loc.indesc = &indesc_netlink; - loc.nl_obj = obj; + loc.nle = nle; for (i = 0; i < array_size(netlink_parsers); i++) { if (strcmp(type, netlink_parsers[i].name)) continue; - return netlink_parsers[i].parse(ctx, &loc, nle); + netlink_parsers[i].parse(ctx, &loc, nle); + return 0; } netlink_error(ctx, &loc, "unknown expression type '%s'", type); + return 0; } struct rule_pp_ctx { @@ -697,9 +740,8 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r } struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx, - const struct nl_object *obj) + const struct nft_rule *nlr) { - const struct nfnl_nft_rule *nlr = (const struct nfnl_nft_rule *)obj; struct netlink_parse_ctx _ctx, *pctx = &_ctx; struct handle h; @@ -707,15 +749,15 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx, _ctx.msgs = ctx->msgs; memset(&h, 0, sizeof(h)); - h.family = nfnl_nft_rule_get_family(nlr); - h.table = xstrdup(nfnl_nft_rule_get_table(nlr)); - h.chain = xstrdup(nfnl_nft_rule_get_chain(nlr)); - h.handle = nfnl_nft_rule_get_handle(nlr); + h.family = nft_rule_attr_get_u32(nlr, NFT_RULE_ATTR_FAMILY); + h.table = xstrdup(nft_rule_attr_get_str(nlr, NFT_RULE_ATTR_TABLE)); + h.chain = xstrdup(nft_rule_attr_get_str(nlr, NFT_RULE_ATTR_CHAIN)); + h.handle = nft_rule_attr_get_u64(nlr, NFT_RULE_ATTR_HANDLE); pctx->rule = rule_alloc(&internal_location, &h); pctx->table = table_lookup(&h); assert(pctx->table != NULL); - nfnl_nft_rule_foreach_expr(nlr, netlink_parse_expr, pctx); + nft_rule_expr_foreach((struct nft_rule *)nlr, netlink_parse_expr, pctx); rule_parse_postprocess(pctx, pctx->rule); return pctx->rule; diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index accab9c2..044815a3 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> + * Copyright (c) 2013 Pablo Neira Ayuso <pablo@netfilter.org> * * 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 @@ -10,6 +11,7 @@ #include <linux/netfilter/nf_tables.h> +#include <string.h> #include <rule.h> #include <statement.h> #include <expression.h> @@ -18,7 +20,7 @@ #include <utils.h> struct netlink_linearize_ctx { - struct nfnl_nft_rule *nlr; + struct nft_rule *nlr; unsigned int reg_low; }; @@ -52,59 +54,65 @@ static void netlink_gen_payload(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) { - struct nfnl_nft_expr *nle; - - nle = alloc_nft_expr(nfnl_nft_payload_init); - nfnl_nft_payload_set_dreg(nle, dreg); - nfnl_nft_payload_set_base(nle, expr->payload.base - 1); - nfnl_nft_payload_set_offset(nle, expr->payload.offset / BITS_PER_BYTE); - nfnl_nft_payload_set_len(nle, expr->len / BITS_PER_BYTE); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + struct nft_rule_expr *nle; + + nle = alloc_nft_expr("payload"); + nft_rule_expr_set_u32(nle, NFT_EXPR_PAYLOAD_DREG, dreg); + nft_rule_expr_set_u32(nle, NFT_EXPR_PAYLOAD_BASE, + expr->payload.base - 1); + nft_rule_expr_set_u32(nle, NFT_EXPR_PAYLOAD_OFFSET, + expr->payload.offset / BITS_PER_BYTE); + nft_rule_expr_set_u32(nle, NFT_EXPR_PAYLOAD_LEN, + expr->len / BITS_PER_BYTE); + nft_rule_add_expr(ctx->nlr, nle); } static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) { - struct nfnl_nft_expr *nle; - - nle = alloc_nft_expr(nfnl_nft_exthdr_init); - nfnl_nft_exthdr_set_dreg(nle, dreg); - nfnl_nft_exthdr_set_type(nle, expr->exthdr.desc->type); - nfnl_nft_exthdr_set_offset(nle, expr->exthdr.tmpl->offset / BITS_PER_BYTE); - nfnl_nft_exthdr_set_len(nle, expr->len / BITS_PER_BYTE); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + struct nft_rule_expr *nle; + + nle = alloc_nft_expr("exthdr"); + nft_rule_expr_set_u32(nle, NFT_EXPR_EXTHDR_DREG, dreg); + nft_rule_expr_set_u8(nle, NFT_EXPR_EXTHDR_TYPE, + expr->exthdr.desc->type); + nft_rule_expr_set_u32(nle, NFT_EXPR_EXTHDR_OFFSET, + expr->exthdr.tmpl->offset / BITS_PER_BYTE); + nft_rule_expr_set_u32(nle, NFT_EXPR_EXTHDR_LEN, + expr->len / BITS_PER_BYTE); + nft_rule_add_expr(ctx->nlr, nle); } static void netlink_gen_meta(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) { - struct nfnl_nft_expr *nle; + struct nft_rule_expr *nle; - nle = alloc_nft_expr(nfnl_nft_meta_init); - nfnl_nft_meta_set_dreg(nle, dreg); - nfnl_nft_meta_set_key(nle, expr->meta.key); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + nle = alloc_nft_expr("meta"); + nft_rule_expr_set_u32(nle, NFT_EXPR_META_DREG, dreg); + nft_rule_expr_set_u32(nle, NFT_EXPR_META_KEY, expr->meta.key); + nft_rule_add_expr(ctx->nlr, nle); } static void netlink_gen_ct(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) { - struct nfnl_nft_expr *nle; + struct nft_rule_expr *nle; - nle = alloc_nft_expr(nfnl_nft_ct_init); - nfnl_nft_ct_set_dreg(nle, dreg); - nfnl_nft_ct_set_key(nle, expr->ct.key); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + nle = alloc_nft_expr("ct"); + nft_rule_expr_set_u32(nle, NFT_EXPR_CT_DREG, dreg); + nft_rule_expr_set_u32(nle, NFT_EXPR_CT_KEY, expr->ct.key); + nft_rule_add_expr(ctx->nlr, nle); } static void netlink_gen_map(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) { - struct nfnl_nft_expr *nle; + struct nft_rule_expr *nle; enum nft_registers sreg; assert(expr->mappings->ops->type == EXPR_SET_REF); @@ -116,22 +124,23 @@ static void netlink_gen_map(struct netlink_linearize_ctx *ctx, netlink_gen_expr(ctx, expr->map, sreg); - nle = alloc_nft_expr(nfnl_nft_lookup_init); - nfnl_nft_lookup_set_sreg(nle, sreg); - nfnl_nft_lookup_set_dreg(nle, dreg); - nfnl_nft_lookup_set_set(nle, expr->mappings->set->handle.set); + nle = alloc_nft_expr("lookup"); + nft_rule_expr_set_u32(nle, NFT_EXPR_LOOKUP_SREG, sreg); + nft_rule_expr_set_u32(nle, NFT_EXPR_LOOKUP_DREG, dreg); + nft_rule_expr_set_str(nle, NFT_EXPR_LOOKUP_SET, + expr->mappings->set->handle.set); if (dreg == NFT_REG_VERDICT) release_register(ctx); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + nft_rule_add_expr(ctx->nlr, nle); } static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) { - struct nfnl_nft_expr *nle; + struct nft_rule_expr *nle; enum nft_registers sreg; assert(expr->right->ops->type == EXPR_SET_REF); @@ -140,12 +149,13 @@ static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx, sreg = get_register(ctx); netlink_gen_expr(ctx, expr->left, sreg); - nle = alloc_nft_expr(nfnl_nft_lookup_init); - nfnl_nft_lookup_set_sreg(nle, sreg); - nfnl_nft_lookup_set_set(nle, expr->right->set->handle.set); + nle = alloc_nft_expr("lookup"); + nft_rule_expr_set_u32(nle, NFT_EXPR_LOOKUP_SREG, sreg); + nft_rule_expr_set_str(nle, NFT_EXPR_LOOKUP_SET, + expr->right->set->handle.set); release_register(ctx); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + nft_rule_add_expr(ctx->nlr, nle); } static enum nft_cmp_ops netlink_gen_cmp_op(enum ops op) @@ -172,21 +182,24 @@ static void netlink_gen_cmp(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) { - struct nfnl_nft_expr *nle; + struct nft_rule_expr *nle; enum nft_registers sreg; + struct nft_data_linearize nld; assert(dreg == NFT_REG_VERDICT); sreg = get_register(ctx); netlink_gen_expr(ctx, expr->left, sreg); - nle = alloc_nft_expr(nfnl_nft_cmp_init); - nfnl_nft_cmp_set_sreg(nle, sreg); - nfnl_nft_cmp_set_op(nle, netlink_gen_cmp_op(expr->op)); - nfnl_nft_cmp_set_data(nle, netlink_gen_data(expr->right)); + nle = alloc_nft_expr("cmp"); + nft_rule_expr_set_u8(nle, NFT_EXPR_CMP_SREG, sreg); + nft_rule_expr_set_u8(nle, NFT_EXPR_CMP_OP, + netlink_gen_cmp_op(expr->op)); + netlink_gen_data(expr->right, &nld); + nft_rule_expr_set(nle, NFT_EXPR_CMP_DATA, nld.value, nld.len); release_register(ctx); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + nft_rule_add_expr(ctx->nlr, nle); } static void netlink_gen_range(struct netlink_linearize_ctx *ctx, @@ -194,25 +207,30 @@ static void netlink_gen_range(struct netlink_linearize_ctx *ctx, enum nft_registers dreg) { struct expr *range = expr->right; - struct nfnl_nft_expr *nle; + struct nft_rule_expr *nle; enum nft_registers sreg; + struct nft_data_linearize nld; assert(dreg == NFT_REG_VERDICT); sreg = get_register(ctx); netlink_gen_expr(ctx, expr->left, sreg); - nle = alloc_nft_expr(nfnl_nft_cmp_init); - nfnl_nft_cmp_set_sreg(nle, sreg); - nfnl_nft_cmp_set_op(nle, netlink_gen_cmp_op(OP_GTE)); - nfnl_nft_cmp_set_data(nle, netlink_gen_data(range->left)); - nfnl_nft_rule_add_expr(ctx->nlr, nle); - - nle = alloc_nft_expr(nfnl_nft_cmp_init); - nfnl_nft_cmp_set_sreg(nle, sreg); - nfnl_nft_cmp_set_op(nle, netlink_gen_cmp_op(OP_LTE)); - nfnl_nft_cmp_set_data(nle, netlink_gen_data(range->right)); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + nle = alloc_nft_expr("cmp"); + nft_rule_expr_set_u8(nle, NFT_EXPR_CMP_SREG, sreg); + nft_rule_expr_set_u32(nle, NFT_EXPR_CMP_OP, + netlink_gen_cmp_op(OP_GTE)); + netlink_gen_data(range->left, &nld); + nft_rule_expr_set(nle, NFT_EXPR_CMP_DATA, nld.value, nld.len); + nft_rule_add_expr(ctx->nlr, nle); + + nle = alloc_nft_expr("cmp"); + nft_rule_expr_set_u8(nle, NFT_EXPR_CMP_SREG, sreg); + nft_rule_expr_set_u32(nle, NFT_EXPR_CMP_OP, + netlink_gen_cmp_op(OP_LTE)); + netlink_gen_data(range->right, &nld); + nft_rule_expr_set(nle, NFT_EXPR_CMP_DATA, nld.value, nld.len); + nft_rule_add_expr(ctx->nlr, nle); release_register(ctx); } @@ -221,8 +239,8 @@ static void netlink_gen_flagcmp(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) { - struct nfnl_nft_expr *nle; - struct nfnl_nft_data *nld; + struct nft_rule_expr *nle; + struct nft_data_linearize nld, nld2; enum nft_registers sreg; unsigned int len; mpz_t zero; @@ -235,21 +253,23 @@ static void netlink_gen_flagcmp(struct netlink_linearize_ctx *ctx, mpz_init_set_ui(zero, 0); - nle = alloc_nft_expr(nfnl_nft_bitwise_init); - nld = netlink_gen_raw_data(zero, expr->right->byteorder, len); - nfnl_nft_bitwise_set_sreg(nle, sreg); - nfnl_nft_bitwise_set_dreg(nle, sreg); - nfnl_nft_bitwise_set_len(nle, len); - nfnl_nft_bitwise_set_mask(nle, netlink_gen_data(expr->right)); - nfnl_nft_bitwise_set_xor(nle, nld); - nfnl_nft_rule_add_expr(ctx->nlr, nle); - - nle = alloc_nft_expr(nfnl_nft_cmp_init); - nld = netlink_gen_raw_data(zero, expr->right->byteorder, len); - nfnl_nft_cmp_set_sreg(nle, sreg); - nfnl_nft_cmp_set_op(nle, NFT_CMP_NEQ); - nfnl_nft_cmp_set_data(nle, nld); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + nle = alloc_nft_expr("bitwise"); + netlink_gen_raw_data(zero, expr->right->byteorder, len, &nld); + nft_rule_expr_set_u32(nle, NFT_EXPR_BITWISE_SREG, sreg); + nft_rule_expr_set_u32(nle, NFT_EXPR_BITWISE_DREG, sreg); + nft_rule_expr_set_u32(nle, NFT_EXPR_BITWISE_LEN, len); + netlink_gen_data(expr->right, &nld2); + nft_rule_expr_set(nle, NFT_EXPR_BITWISE_MASK, &nld2.value, nld2.len); + nft_rule_expr_set(nle, NFT_EXPR_BITWISE_XOR, &nld.value, nld.len); + nft_rule_add_expr(ctx->nlr, nle); + + nle = alloc_nft_expr("cmp"); + netlink_gen_raw_data(zero, expr->right->byteorder, len, &nld); + nft_rule_expr_set_u8(nle, NFT_EXPR_CMP_SREG, sreg); + nft_rule_expr_set_u8(nle, NFT_EXPR_CMP_OP, NFT_CMP_NEQ); + netlink_gen_data(expr->right, &nld); + nft_rule_expr_set(nle, NFT_EXPR_CMP_DATA, nld.value, nld.len); + nft_rule_add_expr(ctx->nlr, nle); mpz_clear(zero); release_register(ctx); @@ -291,8 +311,8 @@ static void netlink_gen_binop(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) { - struct nfnl_nft_expr *nle; - struct nfnl_nft_data *nld; + struct nft_rule_expr *nle; + struct nft_data_linearize nld; struct expr *left, *i; struct expr *binops[16]; mpz_t mask, xor, val, tmp; @@ -337,23 +357,22 @@ static void netlink_gen_binop(struct netlink_linearize_ctx *ctx, len = div_round_up(expr->len, BITS_PER_BYTE); - nle = alloc_nft_expr(nfnl_nft_bitwise_init); - nfnl_nft_bitwise_set_sreg(nle, dreg); - nfnl_nft_bitwise_set_dreg(nle, dreg); - nfnl_nft_bitwise_set_len(nle, len); - - nld = netlink_gen_raw_data(mask, expr->byteorder, len); - nfnl_nft_bitwise_set_mask(nle, nld); + nle = alloc_nft_expr("bitwise"); + nft_rule_expr_set_u32(nle, NFT_EXPR_BITWISE_SREG, dreg); + nft_rule_expr_set_u32(nle, NFT_EXPR_BITWISE_DREG, dreg); + nft_rule_expr_set_u32(nle, NFT_EXPR_BITWISE_LEN, len); - nld = netlink_gen_raw_data(xor, expr->byteorder, len); - nfnl_nft_bitwise_set_xor(nle, nld); + netlink_gen_raw_data(mask, expr->byteorder, len, &nld); + nft_rule_expr_set(nle, NFT_EXPR_BITWISE_MASK, nld.value, nld.len); + netlink_gen_raw_data(xor, expr->byteorder, len, &nld); + nft_rule_expr_set(nle, NFT_EXPR_BITWISE_XOR, nld.value, nld.len); mpz_clear(tmp); mpz_clear(val); mpz_clear(xor); mpz_clear(mask); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + nft_rule_add_expr(ctx->nlr, nle); } static enum nft_byteorder_ops netlink_gen_unary_op(enum ops op) @@ -372,29 +391,47 @@ static void netlink_gen_unary(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) { - struct nfnl_nft_expr *nle; + struct nft_rule_expr *nle; netlink_gen_expr(ctx, expr->arg, dreg); - nle = alloc_nft_expr(nfnl_nft_byteorder_init); - nfnl_nft_byteorder_set_sreg(nle, dreg); - nfnl_nft_byteorder_set_dreg(nle, dreg); - nfnl_nft_byteorder_set_len(nle, expr->len / BITS_PER_BYTE); - nfnl_nft_byteorder_set_size(nle, expr->arg->len % 32 ? 2 : 4); - nfnl_nft_byteorder_set_op(nle, netlink_gen_unary_op(expr->op)); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + nle = alloc_nft_expr("byteorder"); + nft_rule_expr_set_u32(nle, NFT_EXPR_BYTEORDER_SREG, dreg); + nft_rule_expr_set_u32(nle, NFT_EXPR_BYTEORDER_DREG, dreg); + nft_rule_expr_set_u32(nle, NFT_EXPR_BYTEORDER_LEN, + expr->len / BITS_PER_BYTE); + nft_rule_expr_set_u32(nle, NFT_EXPR_BYTEORDER_SIZE, + expr->arg->len % 32 ? 2 : 4); + nft_rule_expr_set_u32(nle, NFT_EXPR_BYTEORDER_OP, + netlink_gen_unary_op(expr->op)); + nft_rule_add_expr(ctx->nlr, nle); } static void netlink_gen_immediate(struct netlink_linearize_ctx *ctx, const struct expr *expr, enum nft_registers dreg) { - struct nfnl_nft_expr *nle; + struct nft_rule_expr *nle; + struct nft_data_linearize nld; - nle = alloc_nft_expr(nfnl_nft_immediate_init); - nfnl_nft_immediate_set_dreg(nle, dreg); - nfnl_nft_immediate_set_data(nle, netlink_gen_data(expr)); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + nle = alloc_nft_expr("immediate"); + nft_rule_expr_set_u32(nle, NFT_EXPR_IMM_DREG, dreg); + netlink_gen_data(expr, &nld); + switch (expr->ops->type) { + case EXPR_VALUE: + nft_rule_expr_set(nle, NFT_EXPR_IMM_DATA, nld.value, nld.len); + break; + case EXPR_VERDICT: + if (nft_rule_expr_is_set(nle, NFT_EXPR_IMM_CHAIN)) { + nft_rule_expr_set_str(nle, NFT_EXPR_IMM_CHAIN, + nld.chain); + } + nft_rule_expr_set_u32(nle, NFT_EXPR_IMM_VERDICT, nld.verdict); + break; + default: + break; + } + nft_rule_add_expr(ctx->nlr, nle); } static void netlink_gen_expr(struct netlink_linearize_ctx *ctx, @@ -437,77 +474,89 @@ static void netlink_gen_verdict_stmt(struct netlink_linearize_ctx *ctx, static void netlink_gen_counter_stmt(struct netlink_linearize_ctx *ctx, const struct stmt *stmt) { - struct nfnl_nft_expr *nle; - - nle = alloc_nft_expr(nfnl_nft_counter_init); - if (stmt->counter.packets) - nfnl_nft_counter_set_packets(nle, stmt->counter.packets); - if (stmt->counter.bytes) - nfnl_nft_counter_set_bytes(nle, stmt->counter.bytes); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + struct nft_rule_expr *nle; + + nle = alloc_nft_expr("counter"); + if (stmt->counter.packets) { + nft_rule_expr_set_u64(nle, NFT_EXPR_CTR_PACKETS, + stmt->counter.packets); + } + if (stmt->counter.bytes) { + nft_rule_expr_set_u64(nle, NFT_EXPR_CTR_BYTES, + stmt->counter.packets); + } + nft_rule_add_expr(ctx->nlr, nle); } static void netlink_gen_meta_stmt(struct netlink_linearize_ctx *ctx, const struct stmt *stmt) { - struct nfnl_nft_expr *nle; + struct nft_rule_expr *nle; enum nft_registers sreg; sreg = get_register(ctx); netlink_gen_expr(ctx, stmt->meta.expr, sreg); release_register(ctx); - nle = alloc_nft_expr(nfnl_nft_meta_init); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + nle = alloc_nft_expr("meta"); + nft_rule_add_expr(ctx->nlr, nle); } static void netlink_gen_log_stmt(struct netlink_linearize_ctx *ctx, const struct stmt *stmt) { - struct nfnl_nft_expr *nle; - - nle = alloc_nft_expr(nfnl_nft_log_init); - if (stmt->log.prefix != NULL) - nfnl_nft_log_set_prefix(nle, stmt->log.prefix); - if (stmt->log.group) - nfnl_nft_log_set_group(nle, stmt->log.group); - if (stmt->log.snaplen) - nfnl_nft_log_set_snaplen(nle, stmt->log.snaplen); - if (stmt->log.qthreshold) - nfnl_nft_log_set_qthreshold(nle, stmt->log.qthreshold); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + struct nft_rule_expr *nle; + + nle = alloc_nft_expr("log"); + if (stmt->log.prefix != NULL) { + nft_rule_expr_set_str(nle, NFT_EXPR_LOG_PREFIX, + stmt->log.prefix); + } + if (stmt->log.group) { + nft_rule_expr_set_u32(nle, NFT_EXPR_LOG_GROUP, + stmt->log.group); + } + if (stmt->log.snaplen) { + nft_rule_expr_set_u32(nle, NFT_EXPR_LOG_SNAPLEN, + stmt->log.snaplen); + } + if (stmt->log.qthreshold) { + nft_rule_expr_set_u32(nle, NFT_EXPR_LOG_QTHRESHOLD, + stmt->log.qthreshold); + } + nft_rule_add_expr(ctx->nlr, nle); } static void netlink_gen_limit_stmt(struct netlink_linearize_ctx *ctx, const struct stmt *stmt) { - struct nfnl_nft_expr *nle; + struct nft_rule_expr *nle; - nle = alloc_nft_expr(nfnl_nft_limit_init); - nfnl_nft_limit_set_rate(nle, stmt->limit.rate); - nfnl_nft_limit_set_depth(nle, stmt->limit.depth); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + nle = alloc_nft_expr("limit"); + nft_rule_expr_set_u32(nle, NFT_EXPR_LIMIT_RATE, stmt->limit.rate); + nft_rule_expr_set_u32(nle, NFT_EXPR_LIMIT_DEPTH, stmt->limit.depth); + nft_rule_add_expr(ctx->nlr, nle); } static void netlink_gen_reject_stmt(struct netlink_linearize_ctx *ctx, const struct stmt *stmt) { - struct nfnl_nft_expr *nle; + struct nft_rule_expr *nle; nle = alloc_nft_expr(NULL); - nfnl_nft_rule_add_expr(ctx->nlr, nle); + nft_rule_add_expr(ctx->nlr, nle); } static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx, const struct stmt *stmt) { - struct nfnl_nft_expr *nle; + struct nft_rule_expr *nle; enum nft_registers amin_reg, amax_reg; enum nft_registers pmin_reg, pmax_reg; int registers = 0; - nle = alloc_nft_expr(nfnl_nft_nat_init); - nfnl_nft_nat_set_type(nle, stmt->nat.type); + nle = alloc_nft_expr("nat"); + nft_rule_expr_set_u32(nle, NFT_EXPR_NAT_TYPE, stmt->nat.type); if (stmt->nat.addr) { amin_reg = get_register(ctx); @@ -519,11 +568,14 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx, netlink_gen_expr(ctx, stmt->nat.addr->left, amin_reg); netlink_gen_expr(ctx, stmt->nat.addr->right, amax_reg); - nfnl_nft_nat_set_sreg_addr_min(nle, amin_reg); - nfnl_nft_nat_set_sreg_addr_max(nle, amax_reg); + nft_rule_expr_set_u32(nle, NFT_EXPR_NAT_REG_ADDR_MIN, + amin_reg); + nft_rule_expr_set_u32(nle, NFT_EXPR_NAT_REG_ADDR_MAX, + amax_reg); } else { netlink_gen_expr(ctx, stmt->nat.addr, amin_reg); - nfnl_nft_nat_set_sreg_addr_min(nle, amin_reg); + nft_rule_expr_set_u32(nle, NFT_EXPR_NAT_REG_ADDR_MIN, + amin_reg); } } @@ -538,11 +590,14 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx, netlink_gen_expr(ctx, stmt->nat.proto->left, pmin_reg); netlink_gen_expr(ctx, stmt->nat.proto->right, pmax_reg); - nfnl_nft_nat_set_sreg_proto_min(nle, pmin_reg); - nfnl_nft_nat_set_sreg_proto_max(nle, pmax_reg); + nft_rule_expr_set_u32(nle, NFT_EXPR_NAT_REG_PROTO_MIN, + pmin_reg); + nft_rule_expr_set_u32(nle, NFT_EXPR_NAT_REG_PROTO_MAX, + pmax_reg); } else { netlink_gen_expr(ctx, stmt->nat.proto, pmin_reg); - nfnl_nft_nat_set_sreg_proto_min(nle, pmin_reg); + nft_rule_expr_set_u32(nle, NFT_EXPR_NAT_REG_PROTO_MIN, + pmin_reg); } } @@ -551,7 +606,7 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx, registers--; } - nfnl_nft_rule_add_expr(ctx->nlr, nle); + nft_rule_add_expr(ctx->nlr, nle); } static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx, @@ -579,7 +634,7 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx, } } -int netlink_linearize_rule(struct netlink_ctx *ctx, struct nfnl_nft_rule *nlr, +int netlink_linearize_rule(struct netlink_ctx *ctx, struct nft_rule *nlr, const struct rule *rule) { struct netlink_linearize_ctx lctx; @@ -592,6 +647,6 @@ int netlink_linearize_rule(struct netlink_ctx *ctx, struct nfnl_nft_rule *nlr, list_for_each_entry(stmt, &rule->stmts, list) netlink_gen_stmt(&lctx, stmt); - netlink_dump_object(OBJ_CAST(nlr)); + netlink_dump_rule(nlr); return 0; } |