This patch adds two new expression operations to build and to parse the userdata area that describe the set key and data typeof definitions. Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- include/expression.h | 4 ++ src/mnl.c | 28 +++++--------- src/netlink.c | 105 +++++++++++++++++---------------------------------- src/payload.c | 80 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 89 deletions(-) diff --git a/include/expression.h b/include/expression.h index d502fc2a8611..b3e79c490b1a 100644 --- a/include/expression.h +++ b/include/expression.h @@ -10,6 +10,7 @@ #include <utils.h> #include <list.h> #include <json.h> +#include <libnftnl/udata.h> /** * enum expr_types @@ -166,6 +167,9 @@ struct expr_ops { const struct expr *e2); void (*pctx_update)(struct proto_ctx *ctx, const struct expr *expr); + int (*build_udata)(struct nftnl_udata_buf *udbuf, + const struct expr *expr); + struct expr * (*parse_udata)(const struct nftnl_udata *ud); }; const struct expr_ops *expr_ops(const struct expr *e); diff --git a/src/mnl.c b/src/mnl.c index bcf633002f15..1d6d82e3332d 100644 --- a/src/mnl.c +++ b/src/mnl.c @@ -816,28 +816,18 @@ static void set_key_expression(struct netlink_ctx *ctx, struct nftnl_udata_buf *udbuf, unsigned int type) { - struct output_ctx octx = {}; - char buf[64]; + struct nftnl_udata *nest1, *nest2; if (expr->flags & EXPR_F_CONSTANT || set_flags & NFT_SET_ANONYMOUS) return; - buf[0] = 0; - /* Set definition uses typeof to define datatype. */ - octx.output_fp = fmemopen(buf, sizeof(buf), "w"); - if (octx.output_fp) { - char *end; - - expr_print(expr, &octx); - fclose(octx.output_fp); - end = strchr(buf, '&'); - if (end) - * end = 0; - - if (!nftnl_udata_put(udbuf, type, strlen(buf) + 1, buf)) - memory_allocation_error(); - } + nest1 = nftnl_udata_nest_start(udbuf, type); + nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_TYPEOF_EXPR, expr->etype); + nest2 = nftnl_udata_nest_start(udbuf, NFTNL_UDATA_SET_TYPEOF_DATA); + expr_ops(expr)->build_udata(udbuf, expr); + nftnl_udata_nest_end(udbuf, nest2); + nftnl_udata_nest_end(udbuf, nest1); } /* @@ -910,9 +900,9 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd, set->automerge)) memory_allocation_error(); - set_key_expression(ctx, set->key, set->flags, udbuf, NFTNL_UDATA_SET_TYPEOF_KEY); + set_key_expression(ctx, set->key, set->flags, udbuf, NFTNL_UDATA_SET_KEY_TYPEOF); if (set->data) - set_key_expression(ctx, set->data, set->flags, udbuf, NFTNL_UDATA_SET_TYPEOF_DATA); + set_key_expression(ctx, set->data, set->flags, udbuf, NFTNL_UDATA_SET_DATA_TYPEOF); nftnl_set_set_data(nls, NFTNL_SET_USERDATA, nftnl_udata_buf_data(udbuf), nftnl_udata_buf_len(udbuf)); diff --git a/src/netlink.c b/src/netlink.c index 790c663ccd6d..3ceeba68dc94 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -27,6 +27,7 @@ #include <libnftnl/udata.h> #include <libnftnl/ruleset.h> #include <libnftnl/common.h> +#include <libnftnl/udata.h> #include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nf_tables.h> #include <linux/netfilter.h> @@ -571,8 +572,8 @@ static int set_parse_udata_cb(const struct nftnl_udata *attr, void *data) if (len != sizeof(uint32_t)) return -1; break; - case NFTNL_UDATA_SET_TYPEOF_KEY: - case NFTNL_UDATA_SET_TYPEOF_DATA: + case NFTNL_UDATA_SET_KEY_TYPEOF: + case NFTNL_UDATA_SET_DATA_TYPEOF: if (len < 3) return -1; break; @@ -583,87 +584,50 @@ static int set_parse_udata_cb(const struct nftnl_udata *attr, void *data) return 0; } -static int parse_desc(struct nft_ctx *nft, const char *buf, struct list_head *cmds) +static int set_key_parse_udata(const struct nftnl_udata *attr, void *data) { - static const struct input_descriptor indesc_udata = { - .type = INDESC_BUFFER, - .name = "<setudata>", - }; - struct error_record *erec, *nexte; - LIST_HEAD(errors); - int ret; - - parser_init(nft, nft->state, &errors, cmds, nft->top_scope); - nft->scanner = scanner_init(nft->state); - scanner_push_buffer(nft->scanner, &indesc_udata, buf); - - ret = nft_parse(nft, nft->scanner, nft->state); - - list_for_each_entry_safe(erec, nexte, &errors, list) { - list_del(&erec->list); - erec_destroy(erec); - } + const struct nftnl_udata **tb = data; + uint8_t type = nftnl_udata_type(attr); + uint8_t len = nftnl_udata_len(attr); - if (nft->scanner) { - scanner_destroy(nft); - nft->scanner = NULL; + switch (type) { + case NFTNL_UDATA_SET_TYPEOF_EXPR: + if (len != sizeof(uint32_t)) + return -1; + break; + case NFTNL_UDATA_SET_TYPEOF_DATA: + break; + default: + return 0; } - - if (ret != 0 || nft->state->nerrs > 0) - return -1; - + tb[type] = attr; return 0; } -static struct expr *set_make_key(const struct nftnl_udata *ud) +static struct expr *set_make_key(const struct nftnl_udata *attr) { - struct cmd *cmd, *nextc; - struct nft_ctx *nft; - char cmdline[1024]; + const struct nftnl_udata *ud[NFTNL_UDATA_SET_TYPEOF_MAX + 1] = {}; + const struct expr_ops *ops; + enum expr_types etype; struct expr *expr; - const char *buf; - LIST_HEAD(cmds); - uint8_t len; - int i; - - if (!ud) - return NULL; + int err; - len = nftnl_udata_len(ud); - if (!len) + err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr), + set_key_parse_udata, ud); + if (err < 0) return NULL; - buf = nftnl_udata_get(ud); - if (!buf) + if (!ud[NFTNL_UDATA_SET_TYPEOF_EXPR] || + !ud[NFTNL_UDATA_SET_TYPEOF_DATA]) return NULL; - for (i = 0; i < len; i++) { - if (buf[i] > 'z') - return NULL; - if (buf[i] == ' ' || buf[i] == '6') - continue; - if (buf[i] < 'a') { - if (buf[i] == '\0' && i == len - 1) - continue; + etype = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_TYPEOF_EXPR]); + ops = expr_ops_by_type(etype); - return NULL; - } - } - - snprintf(cmdline, sizeof(cmdline), "describe %s\n", buf); - - nft = __nft_ctx_new(); - parse_desc(nft, cmdline, &cmds); - - expr = NULL; - list_for_each_entry_safe(cmd, nextc, &cmds, list) { - if (cmd->op == CMD_DESCRIBE && !expr) - expr = expr_get(cmd->expr); - list_del(&cmd->list); - cmd_free(cmd); - } + expr = ops->parse_udata(ud[NFTNL_UDATA_SET_TYPEOF_DATA]); + if (!expr) + return NULL; - __nft_ctx_free(nft); return expr; } @@ -710,8 +674,9 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx, GET_U32_UDATA(automerge, NFTNL_UDATA_SET_MERGE_ELEMENTS); #undef GET_U32_UDATA - typeof_expr_key = set_make_key(ud[NFTNL_UDATA_SET_TYPEOF_KEY]); - typeof_expr_data = set_make_key(ud[NFTNL_UDATA_SET_TYPEOF_DATA]); + typeof_expr_key = set_make_key(ud[NFTNL_UDATA_SET_KEY_TYPEOF]); + if (ud[NFTNL_UDATA_SET_DATA_TYPEOF]) + typeof_expr_data = set_make_key(ud[NFTNL_UDATA_SET_DATA_TYPEOF]); } key = nftnl_set_get_u32(nls, NFTNL_SET_KEY_TYPE); diff --git a/src/payload.c b/src/payload.c index 3576400bbfc8..664d95df67e8 100644 --- a/src/payload.c +++ b/src/payload.c @@ -105,6 +105,84 @@ static void payload_expr_pctx_update(struct proto_ctx *ctx, proto_ctx_update(ctx, desc->base, &expr->location, desc); } +#define NFTNL_SET_KEY_PAYLOAD_DESC 1 +#define NFTNL_SET_KEY_PAYLOAD_TYPE 2 + +static unsigned int expr_payload_type(const struct proto_desc *desc, + const struct proto_hdr_template *tmpl) +{ + unsigned int offset = (unsigned int)(tmpl - &desc->templates[0]); + + return offset / sizeof(*tmpl); +} + +static int payload_expr_build_udata(struct nftnl_udata_buf *udbuf, + const struct expr *expr) +{ + const struct proto_hdr_template *tmpl = expr->payload.tmpl; + const struct proto_desc *desc = expr->payload.desc; + unsigned int type = expr_payload_type(desc, tmpl); + + nftnl_udata_put_u32(udbuf, NFTNL_SET_KEY_PAYLOAD_DESC, desc->id); + nftnl_udata_put_u32(udbuf, NFTNL_SET_KEY_PAYLOAD_TYPE, type); + + return 0; +} + +static const struct proto_desc *find_proto_desc(const struct nftnl_udata *ud) +{ + return NULL; +} + +#define NFTNL_UDATA_SET_KEY_PAYLOAD_DESC 0 +#define NFTNL_UDATA_SET_KEY_PAYLOAD_TYPE 1 +#define NFTNL_UDATA_SET_KEY_PAYLOAD_MAX 2 + +static int payload_parse_udata(const struct nftnl_udata *attr, void *data) +{ + const struct nftnl_udata **ud = data; + uint8_t type = nftnl_udata_type(attr); + uint8_t len = nftnl_udata_len(attr); + + switch (type) { + case NFTNL_UDATA_SET_KEY_PAYLOAD_DESC: + case NFTNL_UDATA_SET_KEY_PAYLOAD_TYPE: + if (len != sizeof(uint32_t)) + return -1; + break; + default: + return 0; + } + + ud[type] = attr; + return 0; +} + +static struct expr *payload_expr_parse_udata(const struct nftnl_udata *attr) +{ + const struct nftnl_udata *ud[NFTNL_UDATA_SET_KEY_PAYLOAD_MAX + 1] = {}; + const struct proto_desc *desc; + unsigned int type; + int err; + + err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr), + payload_parse_udata, ud); + if (err < 0) + return NULL; + + if (!ud[NFTNL_UDATA_SET_KEY_PAYLOAD_DESC] || + !ud[NFTNL_UDATA_SET_KEY_PAYLOAD_TYPE]) + return NULL; + + desc = find_proto_desc(ud[NFTNL_SET_KEY_PAYLOAD_DESC]); + if (!desc) + return NULL; + + type = nftnl_udata_get_u32(ud[NFTNL_SET_KEY_PAYLOAD_TYPE]); + + return payload_expr_alloc(&internal_location, desc, type); +} + const struct expr_ops payload_expr_ops = { .type = EXPR_PAYLOAD, .name = "payload", @@ -113,6 +191,8 @@ const struct expr_ops payload_expr_ops = { .cmp = payload_expr_cmp, .clone = payload_expr_clone, .pctx_update = payload_expr_pctx_update, + .build_udata = payload_expr_build_udata, + .parse_udata = payload_expr_parse_udata, }; /* -- 2.11.0