diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/chain.c | 31 | ||||
-rw-r--r-- | src/expr.c | 4 | ||||
-rw-r--r-- | src/expr/bitwise.c | 2 | ||||
-rw-r--r-- | src/expr/data_reg.c | 6 | ||||
-rw-r--r-- | src/expr/dynset.c | 126 | ||||
-rw-r--r-- | src/expr/socket.c | 1 | ||||
-rw-r--r-- | src/libnftnl.map | 17 | ||||
-rw-r--r-- | src/object.c | 26 | ||||
-rw-r--r-- | src/rule.c | 6 | ||||
-rw-r--r-- | src/set.c | 111 | ||||
-rw-r--r-- | src/set_elem.c | 135 | ||||
-rw-r--r-- | src/table.c | 33 |
12 files changed, 441 insertions, 57 deletions
diff --git a/src/chain.c b/src/chain.c index 94efa90..aac9da6 100644 --- a/src/chain.c +++ b/src/chain.c @@ -51,6 +51,11 @@ struct nftnl_chain { uint32_t flags; uint32_t chain_id; + struct { + void *data; + uint32_t len; + } user; + struct list_head rule_list; }; @@ -125,6 +130,8 @@ void nftnl_chain_free(const struct nftnl_chain *c) xfree(c->type); if (c->flags & (1 << NFTNL_CHAIN_DEV)) xfree(c->dev); + if (c->flags & (1 << NFTNL_CHAIN_USERDATA)) + xfree(c->user.data); if (c->flags & (1 << NFTNL_CHAIN_DEVICES)) { for (i = 0; i < c->dev_array_len; i++) xfree(c->dev_array[i]); @@ -290,6 +297,16 @@ int nftnl_chain_set_data(struct nftnl_chain *c, uint16_t attr, case NFTNL_CHAIN_ID: memcpy(&c->chain_id, data, sizeof(c->chain_id)); break; + case NFTNL_CHAIN_USERDATA: + if (c->flags & (1 << NFTNL_CHAIN_USERDATA)) + xfree(c->user.data); + + c->user.data = malloc(data_len); + if (!c->user.data) + return -1; + memcpy(c->user.data, data, data_len); + c->user.len = data_len; + break; } c->flags |= (1 << attr); return 0; @@ -391,6 +408,9 @@ const void *nftnl_chain_get_data(const struct nftnl_chain *c, uint16_t attr, case NFTNL_CHAIN_ID: *data_len = sizeof(uint32_t); return &c->chain_id; + case NFTNL_CHAIN_USERDATA: + *data_len = c->user.len; + return c->user.data; } return NULL; } @@ -513,6 +533,8 @@ void nftnl_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_ch mnl_attr_put_u32(nlh, NFTA_CHAIN_FLAGS, htonl(c->chain_flags)); if (c->flags & (1 << NFTNL_CHAIN_ID)) mnl_attr_put_u32(nlh, NFTA_CHAIN_ID, htonl(c->chain_id)); + if (c->flags & (1 << NFTNL_CHAIN_USERDATA)) + mnl_attr_put(nlh, NFTA_CHAIN_USERDATA, c->user.len, c->user.data); } EXPORT_SYMBOL(nftnl_chain_rule_add); @@ -576,6 +598,10 @@ static int nftnl_chain_parse_attr_cb(const struct nlattr *attr, void *data) if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) abi_breakage(); break; + case NFTA_CHAIN_USERDATA: + if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) + abi_breakage(); + break; } tb[type] = attr; @@ -777,6 +803,11 @@ int nftnl_chain_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_chain *c) c->chain_id = ntohl(mnl_attr_get_u32(tb[NFTA_CHAIN_ID])); c->flags |= (1 << NFTNL_CHAIN_ID); } + if (tb[NFTA_CHAIN_USERDATA]) { + nftnl_chain_set_data(c, NFTNL_CHAIN_USERDATA, + mnl_attr_get_payload(tb[NFTA_CHAIN_USERDATA]), + mnl_attr_get_payload_len(tb[NFTA_CHAIN_USERDATA])); + } c->family = nfg->nfgen_family; c->flags |= (1 << NFTNL_CHAIN_FAMILY); @@ -42,6 +42,9 @@ struct nftnl_expr *nftnl_expr_alloc(const char *name) expr->flags |= (1 << NFTNL_EXPR_NAME); expr->ops = ops; + if (ops->init) + ops->init(expr); + return expr; } @@ -203,6 +206,7 @@ const char *nftnl_expr_get_str(const struct nftnl_expr *expr, uint16_t type) return (const char *)nftnl_expr_get(expr, type, &data_len); } +EXPORT_SYMBOL(nftnl_expr_build_payload); void nftnl_expr_build_payload(struct nlmsghdr *nlh, struct nftnl_expr *expr) { struct nlattr *nest; diff --git a/src/expr/bitwise.c b/src/expr/bitwise.c index 9ea2f66..ba379a8 100644 --- a/src/expr/bitwise.c +++ b/src/expr/bitwise.c @@ -215,7 +215,7 @@ nftnl_expr_bitwise_snprintf_bool(char *buf, size_t size, { int remain = size, offset = 0, ret; - ret = snprintf(buf, remain, "reg %u = (reg=%u & ", + ret = snprintf(buf, remain, "reg %u = ( reg %u & ", bitwise->dreg, bitwise->sreg); SNPRINTF_BUFFER_SIZE(ret, remain, offset); diff --git a/src/expr/data_reg.c b/src/expr/data_reg.c index 4e35a79..d3ccc61 100644 --- a/src/expr/data_reg.c +++ b/src/expr/data_reg.c @@ -29,10 +29,14 @@ nftnl_data_reg_value_snprintf_default(char *buf, size_t size, const union nftnl_data_reg *reg, uint32_t flags) { + const char *pfx = flags & DATA_F_NOPFX ? "" : "0x"; int remain = size, offset = 0, ret, i; + + for (i = 0; i < div_round_up(reg->len, sizeof(uint32_t)); i++) { - ret = snprintf(buf + offset, remain, "0x%.8x ", reg->val[i]); + ret = snprintf(buf + offset, remain, + "%s%.8x ", pfx, reg->val[i]); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } diff --git a/src/expr/dynset.c b/src/expr/dynset.c index 91dbea9..a9b11f2 100644 --- a/src/expr/dynset.c +++ b/src/expr/dynset.c @@ -26,9 +26,10 @@ struct nftnl_expr_dynset { enum nft_registers sreg_data; enum nft_dynset_ops op; uint64_t timeout; - struct nftnl_expr *expr; + struct list_head expr_list; char *set_name; uint32_t set_id; + uint32_t dynset_flags; }; static int @@ -36,6 +37,7 @@ nftnl_expr_dynset_set(struct nftnl_expr *e, uint16_t type, const void *data, uint32_t data_len) { struct nftnl_expr_dynset *dynset = nftnl_expr_data(e); + struct nftnl_expr *expr, *next; switch (type) { case NFTNL_EXPR_DYNSET_SREG_KEY: @@ -59,7 +61,14 @@ nftnl_expr_dynset_set(struct nftnl_expr *e, uint16_t type, memcpy(&dynset->set_id, data, sizeof(dynset->set_id)); break; case NFTNL_EXPR_DYNSET_EXPR: - dynset->expr = (void *)data; + list_for_each_entry_safe(expr, next, &dynset->expr_list, head) + nftnl_expr_free(expr); + + expr = (void *)data; + list_add(&expr->head, &dynset->expr_list); + break; + case NFTNL_EXPR_DYNSET_FLAGS: + memcpy(&dynset->dynset_flags, data, sizeof(dynset->dynset_flags)); break; default: return -1; @@ -72,6 +81,7 @@ nftnl_expr_dynset_get(const struct nftnl_expr *e, uint16_t type, uint32_t *data_len) { struct nftnl_expr_dynset *dynset = nftnl_expr_data(e); + struct nftnl_expr *expr; switch (type) { case NFTNL_EXPR_DYNSET_SREG_KEY: @@ -93,7 +103,12 @@ nftnl_expr_dynset_get(const struct nftnl_expr *e, uint16_t type, *data_len = sizeof(dynset->set_id); return &dynset->set_id; case NFTNL_EXPR_DYNSET_EXPR: - return dynset->expr; + list_for_each_entry(expr, &dynset->expr_list, head) + break; + return expr; + case NFTNL_EXPR_DYNSET_FLAGS: + *data_len = sizeof(dynset->dynset_flags); + return &dynset->dynset_flags; } return NULL; } @@ -111,6 +126,7 @@ static int nftnl_expr_dynset_cb(const struct nlattr *attr, void *data) case NFTA_DYNSET_SREG_DATA: case NFTA_DYNSET_SET_ID: case NFTA_DYNSET_OP: + case NFTA_DYNSET_FLAGS: if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) abi_breakage(); break; @@ -137,6 +153,7 @@ nftnl_expr_dynset_build(struct nlmsghdr *nlh, const struct nftnl_expr *e) { struct nftnl_expr_dynset *dynset = nftnl_expr_data(e); struct nlattr *nest; + int num_exprs = 0; if (e->flags & (1 << NFTNL_EXPR_DYNSET_SREG_KEY)) mnl_attr_put_u32(nlh, NFTA_DYNSET_SREG_KEY, htonl(dynset->sreg_key)); @@ -150,11 +167,58 @@ nftnl_expr_dynset_build(struct nlmsghdr *nlh, const struct nftnl_expr *e) mnl_attr_put_strz(nlh, NFTA_DYNSET_SET_NAME, dynset->set_name); if (e->flags & (1 << NFTNL_EXPR_DYNSET_SET_ID)) mnl_attr_put_u32(nlh, NFTA_DYNSET_SET_ID, htonl(dynset->set_id)); - if (e->flags & (1 << NFTNL_EXPR_DYNSET_EXPR)) { - nest = mnl_attr_nest_start(nlh, NFTA_DYNSET_EXPR); - nftnl_expr_build_payload(nlh, dynset->expr); - mnl_attr_nest_end(nlh, nest); + if (!list_empty(&dynset->expr_list)) { + struct nftnl_expr *expr; + + list_for_each_entry(expr, &dynset->expr_list, head) + num_exprs++; + + if (num_exprs == 1) { + nest = mnl_attr_nest_start(nlh, NFTA_DYNSET_EXPR); + list_for_each_entry(expr, &dynset->expr_list, head) + nftnl_expr_build_payload(nlh, expr); + mnl_attr_nest_end(nlh, nest); + } else if (num_exprs > 1) { + struct nlattr *nest1, *nest2; + + nest1 = mnl_attr_nest_start(nlh, NFTA_DYNSET_EXPRESSIONS); + list_for_each_entry(expr, &dynset->expr_list, head) { + nest2 = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM); + nftnl_expr_build_payload(nlh, expr); + mnl_attr_nest_end(nlh, nest2); + } + mnl_attr_nest_end(nlh, nest1); + } + } + if (e->flags & (1 << NFTNL_EXPR_DYNSET_FLAGS)) + mnl_attr_put_u32(nlh, NFTA_DYNSET_FLAGS, + htonl(dynset->dynset_flags)); +} + +EXPORT_SYMBOL(nftnl_expr_add_expr); +void nftnl_expr_add_expr(struct nftnl_expr *e, uint32_t type, + struct nftnl_expr *expr) +{ + struct nftnl_expr_dynset *dynset = nftnl_expr_data(e); + + list_add_tail(&expr->head, &dynset->expr_list); +} + +EXPORT_SYMBOL(nftnl_expr_expr_foreach); +int nftnl_expr_expr_foreach(const struct nftnl_expr *e, + int (*cb)(struct nftnl_expr *e, void *data), + void *data) +{ + struct nftnl_expr_dynset *dynset = nftnl_expr_data(e); + struct nftnl_expr *cur, *tmp; + int ret; + + list_for_each_entry_safe(cur, tmp, &dynset->expr_list, head) { + ret = cb(cur, data); + if (ret < 0) + return ret; } + return 0; } static int @@ -162,6 +226,7 @@ nftnl_expr_dynset_parse(struct nftnl_expr *e, struct nlattr *attr) { struct nftnl_expr_dynset *dynset = nftnl_expr_data(e); struct nlattr *tb[NFTA_SET_MAX+1] = {}; + struct nftnl_expr *expr, *next; int ret = 0; if (mnl_attr_parse_nested(attr, nftnl_expr_dynset_cb, tb) < 0) @@ -195,13 +260,38 @@ nftnl_expr_dynset_parse(struct nftnl_expr *e, struct nlattr *attr) e->flags |= (1 << NFTNL_EXPR_DYNSET_SET_ID); } if (tb[NFTA_DYNSET_EXPR]) { - e->flags |= (1 << NFTNL_EXPR_DYNSET_EXPR); - dynset->expr = nftnl_expr_parse(tb[NFTA_DYNSET_EXPR]); - if (dynset->expr == NULL) + expr = nftnl_expr_parse(tb[NFTA_DYNSET_EXPR]); + if (expr == NULL) return -1; + + list_add(&expr->head, &dynset->expr_list); + e->flags |= (1 << NFTNL_EXPR_DYNSET_EXPR); + } else if (tb[NFTA_DYNSET_EXPRESSIONS]) { + struct nlattr *attr2; + + mnl_attr_for_each_nested(attr2, tb[NFTA_DYNSET_EXPRESSIONS]) { + if (mnl_attr_get_type(attr2) != NFTA_LIST_ELEM) + goto out_dynset_expr; + + expr = nftnl_expr_parse(attr2); + if (!expr) + goto out_dynset_expr; + + list_add_tail(&expr->head, &dynset->expr_list); + } + e->flags |= (1 << NFTNL_EXPR_DYNSET_EXPRESSIONS); + } + if (tb[NFTA_DYNSET_FLAGS]) { + dynset->dynset_flags = ntohl(mnl_attr_get_u32(tb[NFTA_DYNSET_FLAGS])); + e->flags |= (1 << NFTNL_EXPR_DYNSET_FLAGS); } return ret; +out_dynset_expr: + list_for_each_entry_safe(expr, next, &dynset->expr_list, head) + nftnl_expr_free(expr); + + return -1; } static const char *op2str_array[] = { @@ -239,8 +329,7 @@ nftnl_expr_dynset_snprintf_default(char *buf, size_t size, dynset->timeout); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } - if (e->flags & (1 << NFTNL_EXPR_DYNSET_EXPR)) { - expr = dynset->expr; + list_for_each_entry(expr, &dynset->expr_list, head) { ret = snprintf(buf + offset, remain, "expr [ %s ", expr->ops->name); SNPRINTF_BUFFER_SIZE(ret, remain, offset); @@ -272,19 +361,28 @@ nftnl_expr_dynset_snprintf(char *buf, size_t size, uint32_t type, return -1; } +static void nftnl_expr_dynset_init(const struct nftnl_expr *e) +{ + struct nftnl_expr_dynset *dynset = nftnl_expr_data(e); + + INIT_LIST_HEAD(&dynset->expr_list); +} + static void nftnl_expr_dynset_free(const struct nftnl_expr *e) { struct nftnl_expr_dynset *dynset = nftnl_expr_data(e); + struct nftnl_expr *expr, *next; xfree(dynset->set_name); - if (dynset->expr) - nftnl_expr_free(dynset->expr); + list_for_each_entry_safe(expr, next, &dynset->expr_list, head) + nftnl_expr_free(expr); } struct expr_ops expr_ops_dynset = { .name = "dynset", .alloc_len = sizeof(struct nftnl_expr_dynset), .max_attr = NFTA_DYNSET_MAX, + .init = nftnl_expr_dynset_init, .free = nftnl_expr_dynset_free, .set = nftnl_expr_dynset_set, .get = nftnl_expr_dynset_get, diff --git a/src/expr/socket.c b/src/expr/socket.c index 96550d5..8cd4536 100644 --- a/src/expr/socket.c +++ b/src/expr/socket.c @@ -115,6 +115,7 @@ nftnl_expr_socket_parse(struct nftnl_expr *e, struct nlattr *attr) static const char *socket_key2str_array[NFT_SOCKET_MAX + 1] = { [NFT_SOCKET_TRANSPARENT] = "transparent", [NFT_SOCKET_MARK] = "mark", + [NFT_SOCKET_WILDCARD] = "wildcard", }; static const char *socket_key2str(uint8_t key) diff --git a/src/libnftnl.map b/src/libnftnl.map index f62640f..e707b89 100644 --- a/src/libnftnl.map +++ b/src/libnftnl.map @@ -169,7 +169,7 @@ global: nftnl_set_elem_parse; nftnl_set_elem_parse_file; nftnl_set_elem_snprintf; - nftnl_set_elem_fprinf; + nftnl_set_elem_fprintf; nftnl_set_elems_nlmsg_build_payload; nftnl_set_elems_nlmsg_parse; @@ -368,3 +368,18 @@ LIBNFTNL_14 { nftnl_flowtable_set_array; nftnl_flowtable_get_array; } LIBNFTNL_13; + +LIBNFTNL_15 { + nftnl_obj_get_data; + nftnl_expr_build_payload; + nftnl_rule_del_expr; +} LIBNFTNL_14; + +LIBNFTNL_16 { + nftnl_set_add_expr; + nftnl_set_expr_foreach; + nftnl_set_elem_add_expr; + nftnl_set_elem_expr_foreach; + nftnl_expr_add_expr; + nftnl_expr_expr_foreach; +} LIBNFTNL_15; diff --git a/src/object.c b/src/object.c index 4f58272..008bade 100644 --- a/src/object.c +++ b/src/object.c @@ -57,6 +57,8 @@ void nftnl_obj_free(const struct nftnl_obj *obj) xfree(obj->table); if (obj->flags & (1 << NFTNL_OBJ_NAME)) xfree(obj->name); + if (obj->flags & (1 << NFTNL_OBJ_USERDATA)) + xfree(obj->user.data); xfree(obj); } @@ -103,6 +105,16 @@ void nftnl_obj_set_data(struct nftnl_obj *obj, uint16_t attr, case NFTNL_OBJ_HANDLE: memcpy(&obj->handle, data, sizeof(obj->handle)); break; + case NFTNL_OBJ_USERDATA: + if (obj->flags & (1 << NFTNL_OBJ_USERDATA)) + xfree(obj->user.data); + + obj->user.data = malloc(data_len); + if (!obj->user.data) + return; + memcpy(obj->user.data, data, data_len); + obj->user.len = data_len; + break; default: if (obj->ops) obj->ops->set(obj, attr, data, data_len); @@ -174,6 +186,9 @@ const void *nftnl_obj_get_data(struct nftnl_obj *obj, uint16_t attr, case NFTNL_OBJ_HANDLE: *data_len = sizeof(uint64_t); return &obj->handle; + case NFTNL_OBJ_USERDATA: + *data_len = obj->user.len; + return obj->user.data; default: if (obj->ops) return obj->ops->get(obj, attr, data_len); @@ -235,6 +250,8 @@ void nftnl_obj_nlmsg_build_payload(struct nlmsghdr *nlh, mnl_attr_put_u32(nlh, NFTA_OBJ_TYPE, htonl(obj->ops->type)); if (obj->flags & (1 << NFTNL_OBJ_HANDLE)) mnl_attr_put_u64(nlh, NFTA_OBJ_HANDLE, htobe64(obj->handle)); + if (obj->flags & (1 << NFTNL_OBJ_USERDATA)) + mnl_attr_put(nlh, NFTA_OBJ_USERDATA, obj->user.len, obj->user.data); if (obj->ops) { struct nlattr *nest = mnl_attr_nest_start(nlh, NFTA_OBJ_DATA); @@ -269,6 +286,10 @@ static int nftnl_obj_parse_attr_cb(const struct nlattr *attr, void *data) if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) abi_breakage(); break; + case NFTA_OBJ_USERDATA: + if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) + abi_breakage(); + break; } tb[type] = attr; @@ -315,6 +336,11 @@ int nftnl_obj_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_obj *obj) obj->handle = be64toh(mnl_attr_get_u64(tb[NFTA_OBJ_HANDLE])); obj->flags |= (1 << NFTNL_OBJ_HANDLE); } + if (tb[NFTA_OBJ_USERDATA]) { + nftnl_obj_set_data(obj, NFTNL_OBJ_USERDATA, + mnl_attr_get_payload(tb[NFTA_OBJ_USERDATA]), + mnl_attr_get_payload_len(tb[NFTA_OBJ_USERDATA])); + } obj->family = nfg->nfgen_family; obj->flags |= (1 << NFTNL_OBJ_FAMILY); @@ -330,6 +330,12 @@ void nftnl_rule_add_expr(struct nftnl_rule *r, struct nftnl_expr *expr) list_add_tail(&expr->head, &r->expr_list); } +EXPORT_SYMBOL(nftnl_rule_del_expr); +void nftnl_rule_del_expr(struct nftnl_expr *expr) +{ + list_del(&expr->head); +} + static int nftnl_rule_parse_attr_cb(const struct nlattr *attr, void *data) { const struct nlattr **tb = data; @@ -37,6 +37,7 @@ struct nftnl_set *nftnl_set_alloc(void) return NULL; INIT_LIST_HEAD(&s->element_list); + INIT_LIST_HEAD(&s->expr_list); return s; } @@ -44,6 +45,7 @@ EXPORT_SYMBOL(nftnl_set_free); void nftnl_set_free(const struct nftnl_set *s) { struct nftnl_set_elem *elem, *tmp; + struct nftnl_expr *expr, *next; if (s->flags & (1 << NFTNL_SET_TABLE)) xfree(s->table); @@ -51,8 +53,9 @@ void nftnl_set_free(const struct nftnl_set *s) xfree(s->name); if (s->flags & (1 << NFTNL_SET_USERDATA)) xfree(s->user.data); - if (s->flags & (1 << NFTNL_SET_EXPR)) - nftnl_expr_free(s->expr); + + list_for_each_entry_safe(expr, next, &s->expr_list, head) + nftnl_expr_free(expr); list_for_each_entry_safe(elem, tmp, &s->element_list, head) { list_del(&elem->head); @@ -70,6 +73,8 @@ bool nftnl_set_is_set(const struct nftnl_set *s, uint16_t attr) EXPORT_SYMBOL(nftnl_set_unset); void nftnl_set_unset(struct nftnl_set *s, uint16_t attr) { + struct nftnl_expr *expr, *tmp; + if (!(s->flags & (1 << attr))) return; @@ -99,7 +104,9 @@ void nftnl_set_unset(struct nftnl_set *s, uint16_t attr) xfree(s->user.data); break; case NFTNL_SET_EXPR: - nftnl_expr_free(s->expr); + case NFTNL_SET_EXPRESSIONS: + list_for_each_entry_safe(expr, tmp, &s->expr_list, head) + nftnl_expr_free(expr); break; default: return; @@ -127,6 +134,8 @@ EXPORT_SYMBOL(nftnl_set_set_data); int nftnl_set_set_data(struct nftnl_set *s, uint16_t attr, const void *data, uint32_t data_len) { + struct nftnl_expr *expr, *tmp; + nftnl_assert_attr_exists(attr, NFTNL_SET_MAX); nftnl_assert_validate(data, nftnl_set_validate, attr, data_len); @@ -201,10 +210,11 @@ int nftnl_set_set_data(struct nftnl_set *s, uint16_t attr, const void *data, s->user.len = data_len; break; case NFTNL_SET_EXPR: - if (s->flags & (1 << NFTNL_SET_EXPR)) - nftnl_expr_free(s->expr); + list_for_each_entry_safe(expr, tmp, &s->expr_list, head) + nftnl_expr_free(expr); - s->expr = (void *)data; + expr = (void *)data; + list_add(&expr->head, &s->expr_list); break; } s->flags |= (1 << attr); @@ -239,6 +249,8 @@ EXPORT_SYMBOL(nftnl_set_get_data); const void *nftnl_set_get_data(const struct nftnl_set *s, uint16_t attr, uint32_t *data_len) { + struct nftnl_expr *expr; + if (!(s->flags & (1 << attr))) return NULL; @@ -295,7 +307,9 @@ const void *nftnl_set_get_data(const struct nftnl_set *s, uint16_t attr, *data_len = s->user.len; return s->user.data; case NFTNL_SET_EXPR: - return s->expr; + list_for_each_entry(expr, &s->expr_list, head) + break; + return expr; } return NULL; } @@ -414,6 +428,8 @@ nftnl_set_nlmsg_build_desc_payload(struct nlmsghdr *nlh, struct nftnl_set *s) EXPORT_SYMBOL(nftnl_set_nlmsg_build_payload); void nftnl_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set *s) { + int num_exprs = 0; + if (s->flags & (1 << NFTNL_SET_TABLE)) mnl_attr_put_strz(nlh, NFTA_SET_TABLE, s->table); if (s->flags & (1 << NFTNL_SET_NAME)) @@ -445,15 +461,55 @@ void nftnl_set_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set *s) mnl_attr_put_u32(nlh, NFTA_SET_GC_INTERVAL, htonl(s->gc_interval)); if (s->flags & (1 << NFTNL_SET_USERDATA)) mnl_attr_put(nlh, NFTA_SET_USERDATA, s->user.len, s->user.data); - if (s->flags & (1 << NFTNL_SET_EXPR)) { - struct nlattr *nest1; - - nest1 = mnl_attr_nest_start(nlh, NFTA_SET_EXPR); - nftnl_expr_build_payload(nlh, s->expr); - mnl_attr_nest_end(nlh, nest1); + if (!list_empty(&s->expr_list)) { + struct nftnl_expr *expr; + + list_for_each_entry(expr, &s->expr_list, head) + num_exprs++; + + if (num_exprs == 1) { + struct nlattr *nest1; + + nest1 = mnl_attr_nest_start(nlh, NFTA_SET_EXPR); + list_for_each_entry(expr, &s->expr_list, head) + nftnl_expr_build_payload(nlh, expr); + + mnl_attr_nest_end(nlh, nest1); + } else if (num_exprs > 1) { + struct nlattr *nest1, *nest2; + + nest1 = mnl_attr_nest_start(nlh, NFTA_SET_EXPRESSIONS); + list_for_each_entry(expr, &s->expr_list, head) { + nest2 = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM); + nftnl_expr_build_payload(nlh, expr); + mnl_attr_nest_end(nlh, nest2); + } + mnl_attr_nest_end(nlh, nest1); + } } } +EXPORT_SYMBOL(nftnl_set_add_expr); +void nftnl_set_add_expr(struct nftnl_set *s, struct nftnl_expr *expr) +{ + list_add_tail(&expr->head, &s->expr_list); +} + +EXPORT_SYMBOL(nftnl_set_expr_foreach); +int nftnl_set_expr_foreach(const struct nftnl_set *s, + int (*cb)(struct nftnl_expr *e, void *data), + void *data) +{ + struct nftnl_expr *cur, *tmp; + int ret; + + list_for_each_entry_safe(cur, tmp, &s->expr_list, head) { + ret = cb(cur, data); + if (ret < 0) + return ret; + } + return 0; +} static int nftnl_set_parse_attr_cb(const struct nlattr *attr, void *data) { @@ -493,6 +549,8 @@ static int nftnl_set_parse_attr_cb(const struct nlattr *attr, void *data) abi_breakage(); break; case NFTA_SET_DESC: + case NFTA_SET_EXPR: + case NFTA_SET_EXPRESSIONS: if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) abi_breakage(); break; @@ -578,6 +636,7 @@ int nftnl_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_set *s) { struct nlattr *tb[NFTA_SET_MAX+1] = {}; struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); + struct nftnl_expr *expr, *next; int ret; if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_set_parse_attr_cb, tb) < 0) @@ -656,17 +715,37 @@ int nftnl_set_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_set *s) return ret; } if (tb[NFTA_SET_EXPR]) { - s->expr = nftnl_expr_parse(tb[NFTA_SET_EXPR]); - if (!s->expr) - return -1; + expr = nftnl_expr_parse(tb[NFTA_SET_EXPR]); + if (!expr) + goto out_set_expr; + list_add(&expr->head, &s->expr_list); s->flags |= (1 << NFTNL_SET_EXPR); + } else if (tb[NFTA_SET_EXPRESSIONS]) { + struct nlattr *attr; + + mnl_attr_for_each_nested(attr, tb[NFTA_SET_EXPRESSIONS]) { + if (mnl_attr_get_type(attr) != NFTA_LIST_ELEM) + goto out_set_expr; + + expr = nftnl_expr_parse(attr); + if (expr == NULL) + goto out_set_expr; + + list_add_tail(&expr->head, &s->expr_list); + } + s->flags |= (1 << NFTNL_SET_EXPRESSIONS); } s->family = nfg->nfgen_family; s->flags |= (1 << NFTNL_SET_FAMILY); return 0; +out_set_expr: + list_for_each_entry_safe(expr, next, &s->expr_list, head) + nftnl_expr_free(expr); + + return -1; } static int nftnl_set_do_parse(struct nftnl_set *s, enum nftnl_parse_type type, diff --git a/src/set_elem.c b/src/set_elem.c index 4421322..8f634e7 100644 --- a/src/set_elem.c +++ b/src/set_elem.c @@ -36,17 +36,21 @@ struct nftnl_set_elem *nftnl_set_elem_alloc(void) if (s == NULL) return NULL; + INIT_LIST_HEAD(&s->expr_list); + return s; } EXPORT_SYMBOL(nftnl_set_elem_free); void nftnl_set_elem_free(struct nftnl_set_elem *s) { + struct nftnl_expr *e, *tmp; + if (s->flags & (1 << NFTNL_SET_ELEM_CHAIN)) xfree(s->data.chain); - if (s->flags & (1 << NFTNL_SET_ELEM_EXPR)) - nftnl_expr_free(s->expr); + list_for_each_entry_safe(e, tmp, &s->expr_list, head) + nftnl_expr_free(e); if (s->flags & (1 << NFTNL_SET_ELEM_USERDATA)) xfree(s->user.data); @@ -66,6 +70,8 @@ bool nftnl_set_elem_is_set(const struct nftnl_set_elem *s, uint16_t attr) EXPORT_SYMBOL(nftnl_set_elem_unset); void nftnl_set_elem_unset(struct nftnl_set_elem *s, uint16_t attr) { + struct nftnl_expr *expr, *tmp; + if (!(s->flags & (1 << attr))) return; @@ -85,7 +91,9 @@ void nftnl_set_elem_unset(struct nftnl_set_elem *s, uint16_t attr) xfree(s->user.data); break; case NFTNL_SET_ELEM_EXPR: - nftnl_expr_free(s->expr); + case NFTNL_SET_ELEM_EXPRESSIONS: + list_for_each_entry_safe(expr, tmp, &s->expr_list, head) + nftnl_expr_free(expr); break; case NFTNL_SET_ELEM_OBJREF: xfree(s->objref); @@ -108,6 +116,8 @@ EXPORT_SYMBOL(nftnl_set_elem_set); int nftnl_set_elem_set(struct nftnl_set_elem *s, uint16_t attr, const void *data, uint32_t data_len) { + struct nftnl_expr *expr, *tmp; + nftnl_assert_attr_exists(attr, NFTNL_SET_ELEM_MAX); nftnl_assert_validate(data, nftnl_set_elem_validate, attr, data_len); @@ -163,10 +173,11 @@ int nftnl_set_elem_set(struct nftnl_set_elem *s, uint16_t attr, return -1; break; case NFTNL_SET_ELEM_EXPR: - if (s->flags & (1 << NFTNL_SET_ELEM_EXPR)) - nftnl_expr_free(s->expr); + list_for_each_entry_safe(expr, tmp, &s->expr_list, head) + nftnl_expr_free(expr); - s->expr = (void *)data; + expr = (void *)data; + list_add(&expr->head, &s->expr_list); break; } s->flags |= (1 << attr); @@ -194,6 +205,8 @@ int nftnl_set_elem_set_str(struct nftnl_set_elem *s, uint16_t attr, const char * EXPORT_SYMBOL(nftnl_set_elem_get); const void *nftnl_set_elem_get(struct nftnl_set_elem *s, uint16_t attr, uint32_t *data_len) { + struct nftnl_expr *expr; + if (!(s->flags & (1 << attr))) return NULL; @@ -226,7 +239,9 @@ const void *nftnl_set_elem_get(struct nftnl_set_elem *s, uint16_t attr, uint32_t *data_len = s->user.len; return s->user.data; case NFTNL_SET_ELEM_EXPR: - return s->expr; + list_for_each_entry(expr, &s->expr_list, head) + break; + return expr; case NFTNL_SET_ELEM_OBJREF: *data_len = strlen(s->objref) + 1; return s->objref; @@ -288,6 +303,9 @@ err: void nftnl_set_elem_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set_elem *e) { + struct nftnl_expr *expr; + int num_exprs = 0; + if (e->flags & (1 << NFTNL_SET_ELEM_FLAGS)) mnl_attr_put_u32(nlh, NFTA_SET_ELEM_FLAGS, htonl(e->set_elem_flags)); if (e->flags & (1 << NFTNL_SET_ELEM_TIMEOUT)) @@ -332,12 +350,30 @@ void nftnl_set_elem_nlmsg_build_payload(struct nlmsghdr *nlh, mnl_attr_put(nlh, NFTA_SET_ELEM_USERDATA, e->user.len, e->user.data); if (e->flags & (1 << NFTNL_SET_ELEM_OBJREF)) mnl_attr_put_strz(nlh, NFTA_SET_ELEM_OBJREF, e->objref); - if (e->flags & (1 << NFTNL_SET_ELEM_EXPR)) { - struct nlattr *nest1; - nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_EXPR); - nftnl_expr_build_payload(nlh, e->expr); - mnl_attr_nest_end(nlh, nest1); + if (!list_empty(&e->expr_list)) { + list_for_each_entry(expr, &e->expr_list, head) + num_exprs++; + + if (num_exprs == 1) { + struct nlattr *nest1; + + nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_EXPR); + list_for_each_entry(expr, &e->expr_list, head) + nftnl_expr_build_payload(nlh, expr); + + mnl_attr_nest_end(nlh, nest1); + } else if (num_exprs > 1) { + struct nlattr *nest1, *nest2; + + nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_EXPRESSIONS); + list_for_each_entry(expr, &e->expr_list, head) { + nest2 = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM); + nftnl_expr_build_payload(nlh, expr); + mnl_attr_nest_end(nlh, nest2); + } + mnl_attr_nest_end(nlh, nest1); + } } } @@ -383,6 +419,28 @@ void nftnl_set_elems_nlmsg_build_payload(struct nlmsghdr *nlh, struct nftnl_set mnl_attr_nest_end(nlh, nest1); } +EXPORT_SYMBOL(nftnl_set_elem_add_expr); +void nftnl_set_elem_add_expr(struct nftnl_set_elem *e, struct nftnl_expr *expr) +{ + list_add_tail(&expr->head, &e->expr_list); +} + +EXPORT_SYMBOL(nftnl_set_elem_expr_foreach); +int nftnl_set_elem_expr_foreach(struct nftnl_set_elem *e, + int (*cb)(struct nftnl_expr *e, void *data), + void *data) +{ + struct nftnl_expr *cur, *tmp; + int ret; + + list_for_each_entry_safe(cur, tmp, &e->expr_list, head) { + ret = cb(cur, data); + if (ret < 0) + return ret; + } + return 0; +} + static int nftnl_set_elem_parse_attr_cb(const struct nlattr *attr, void *data) { const struct nlattr **tb = data; @@ -405,6 +463,7 @@ static int nftnl_set_elem_parse_attr_cb(const struct nlattr *attr, void *data) case NFTA_SET_ELEM_KEY_END: case NFTA_SET_ELEM_DATA: case NFTA_SET_ELEM_EXPR: + case NFTA_SET_ELEM_EXPRESSIONS: if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) abi_breakage(); break; @@ -476,12 +535,32 @@ static int nftnl_set_elems_parse2(struct nftnl_set *s, const struct nlattr *nest } } if (tb[NFTA_SET_ELEM_EXPR]) { - e->expr = nftnl_expr_parse(tb[NFTA_SET_ELEM_EXPR]); - if (e->expr == NULL) { + struct nftnl_expr *expr; + + expr = nftnl_expr_parse(tb[NFTA_SET_ELEM_EXPR]); + if (expr == NULL) { ret = -1; goto out_set_elem; } + list_add_tail(&expr->head, &e->expr_list); e->flags |= (1 << NFTNL_SET_ELEM_EXPR); + } else if (tb[NFTA_SET_ELEM_EXPRESSIONS]) { + struct nftnl_expr *expr; + struct nlattr *attr; + + mnl_attr_for_each_nested(attr, tb[NFTA_SET_ELEM_EXPRESSIONS]) { + if (mnl_attr_get_type(attr) != NFTA_LIST_ELEM) { + ret = -1; + goto out_set_elem; + } + expr = nftnl_expr_parse(attr); + if (expr == NULL) { + ret = -1; + goto out_set_elem; + } + list_add_tail(&expr->head, &e->expr_list); + } + e->flags |= (1 << NFTNL_SET_ELEM_EXPRESSIONS); } if (tb[NFTA_SET_ELEM_USERDATA]) { const void *udata = @@ -494,7 +573,7 @@ static int nftnl_set_elems_parse2(struct nftnl_set *s, const struct nlattr *nest e->user.data = malloc(e->user.len); if (e->user.data == NULL) { ret = -1; - goto out_expr; + goto out_set_elem; } memcpy(e->user.data, udata, e->user.len); e->flags |= (1 << NFTNL_RULE_USERDATA); @@ -512,8 +591,6 @@ static int nftnl_set_elems_parse2(struct nftnl_set *s, const struct nlattr *nest list_add_tail(&e->head, &s->element_list); return 0; -out_expr: - nftnl_expr_free(e->expr); out_set_elem: nftnl_set_elem_free(e); return ret; @@ -629,18 +706,28 @@ static int nftnl_set_elem_snprintf_default(char *buf, size_t size, ret = snprintf(buf, remain, "element "); SNPRINTF_BUFFER_SIZE(ret, remain, offset); - for (i = 0; i < div_round_up(e->key.len, sizeof(uint32_t)); i++) { - ret = snprintf(buf + offset, remain, "%.8x ", e->key.val[i]); + ret = nftnl_data_reg_snprintf(buf + offset, remain, &e->key, + NFTNL_OUTPUT_DEFAULT, + DATA_F_NOPFX, DATA_VALUE); + SNPRINTF_BUFFER_SIZE(ret, remain, offset); + + if (e->flags & (1 << NFTNL_SET_ELEM_KEY_END)) { + ret = snprintf(buf + offset, remain, " - "); + SNPRINTF_BUFFER_SIZE(ret, remain, offset); + + ret = nftnl_data_reg_snprintf(buf + offset, remain, &e->key_end, + NFTNL_OUTPUT_DEFAULT, + DATA_F_NOPFX, DATA_VALUE); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } ret = snprintf(buf + offset, remain, " : "); SNPRINTF_BUFFER_SIZE(ret, remain, offset); - for (i = 0; i < div_round_up(e->data.len, sizeof(uint32_t)); i++) { - ret = snprintf(buf + offset, remain, "%.8x ", e->data.val[i]); - SNPRINTF_BUFFER_SIZE(ret, remain, offset); - } + ret = nftnl_data_reg_snprintf(buf + offset, remain, &e->data, + NFTNL_OUTPUT_DEFAULT, + DATA_F_NOPFX, DATA_VALUE); + SNPRINTF_BUFFER_SIZE(ret, remain, offset); ret = snprintf(buf + offset, remain, "%u [end]", e->set_elem_flags); SNPRINTF_BUFFER_SIZE(ret, remain, offset); @@ -706,7 +793,7 @@ static int nftnl_set_elem_do_snprintf(char *buf, size_t size, const void *e, } EXPORT_SYMBOL(nftnl_set_elem_fprintf); -int nftnl_set_elem_fprintf(FILE *fp, struct nftnl_set_elem *se, uint32_t type, +int nftnl_set_elem_fprintf(FILE *fp, const struct nftnl_set_elem *se, uint32_t type, uint32_t flags) { return nftnl_fprintf(fp, se, NFTNL_CMD_UNSPEC, type, flags, diff --git a/src/table.c b/src/table.c index 94d522b..731c818 100644 --- a/src/table.c +++ b/src/table.c @@ -34,6 +34,10 @@ struct nftnl_table { uint64_t handle; uint32_t use; uint32_t flags; + struct { + void *data; + uint32_t len; + } user; }; EXPORT_SYMBOL(nftnl_table_alloc); @@ -47,6 +51,8 @@ void nftnl_table_free(const struct nftnl_table *t) { if (t->flags & (1 << NFTNL_TABLE_NAME)) xfree(t->name); + if (t->flags & (1 << NFTNL_TABLE_USERDATA)) + xfree(t->user.data); xfree(t); } @@ -111,6 +117,16 @@ int nftnl_table_set_data(struct nftnl_table *t, uint16_t attr, case NFTNL_TABLE_USE: memcpy(&t->use, data, sizeof(t->use)); break; + case NFTNL_TABLE_USERDATA: + if (t->flags & (1 << NFTNL_TABLE_USERDATA)) + xfree(t->user.data); + + t->user.data = malloc(data_len); + if (!t->user.data) + return -1; + memcpy(t->user.data, data, data_len); + t->user.len = data_len; + break; } t->flags |= (1 << attr); return 0; @@ -169,6 +185,9 @@ const void *nftnl_table_get_data(const struct nftnl_table *t, uint16_t attr, case NFTNL_TABLE_USE: *data_len = sizeof(uint32_t); return &t->use; + case NFTNL_TABLE_USERDATA: + *data_len = t->user.len; + return t->user.data; } return NULL; } @@ -216,6 +235,8 @@ void nftnl_table_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_ta mnl_attr_put_u64(nlh, NFTA_TABLE_HANDLE, htobe64(t->handle)); if (t->flags & (1 << NFTNL_TABLE_FLAGS)) mnl_attr_put_u32(nlh, NFTA_TABLE_FLAGS, htonl(t->table_flags)); + if (t->flags & (1 << NFTNL_TABLE_USERDATA)) + mnl_attr_put(nlh, NFTA_TABLE_USERDATA, t->user.len, t->user.data); } static int nftnl_table_parse_attr_cb(const struct nlattr *attr, void *data) @@ -240,6 +261,10 @@ static int nftnl_table_parse_attr_cb(const struct nlattr *attr, void *data) if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) abi_breakage(); break; + case NFTA_TABLE_USERDATA: + if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) + abi_breakage(); + break; } tb[type] = attr; @@ -251,6 +276,7 @@ int nftnl_table_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_table *t) { struct nlattr *tb[NFTA_TABLE_MAX+1] = {}; struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); + int ret; if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_table_parse_attr_cb, tb) < 0) return -1; @@ -275,6 +301,13 @@ int nftnl_table_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_table *t) t->handle = be64toh(mnl_attr_get_u64(tb[NFTA_TABLE_HANDLE])); t->flags |= (1 << NFTNL_TABLE_HANDLE); } + if (tb[NFTA_TABLE_USERDATA]) { + ret = nftnl_table_set_data(t, NFTNL_TABLE_USERDATA, + mnl_attr_get_payload(tb[NFTA_TABLE_USERDATA]), + mnl_attr_get_payload_len(tb[NFTA_TABLE_USERDATA])); + if (ret < 0) + return ret; + } t->family = nfg->nfgen_family; t->flags |= (1 << NFTNL_TABLE_FAMILY); |