summaryrefslogtreecommitdiffstats
path: root/src/set.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/set.c')
-rw-r--r--src/set.c266
1 files changed, 173 insertions, 93 deletions
diff --git a/src/set.c b/src/set.c
index 15fa29d..54674bc 100644
--- a/src/set.c
+++ b/src/set.c
@@ -1,11 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* (C) 2012-2013 by 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 as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
* This code has been sponsored by Sophos Astaro <http://www.sophos.com>
*/
#include "internal.h"
@@ -37,6 +33,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 +41,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,13 +49,18 @@ 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) {
+ list_del(&expr->head);
+ nftnl_expr_free(expr);
+ }
list_for_each_entry_safe(elem, tmp, &s->element_list, head) {
list_del(&elem->head);
nftnl_set_elem_free(elem);
}
+
+ xfree(s->type);
xfree(s);
}
@@ -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;
@@ -94,12 +99,17 @@ void nftnl_set_unset(struct nftnl_set *s, uint16_t attr)
case NFTNL_SET_DESC_CONCAT:
case NFTNL_SET_TIMEOUT:
case NFTNL_SET_GC_INTERVAL:
+ case NFTNL_SET_COUNT:
break;
case NFTNL_SET_USERDATA:
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) {
+ list_del(&expr->head);
+ nftnl_expr_free(expr);
+ }
break;
default:
return;
@@ -117,36 +127,30 @@ static uint32_t nftnl_set_validate[NFTNL_SET_MAX + 1] = {
[NFTNL_SET_DATA_LEN] = sizeof(uint32_t),
[NFTNL_SET_OBJ_TYPE] = sizeof(uint32_t),
[NFTNL_SET_FAMILY] = sizeof(uint32_t),
+ [NFTNL_SET_ID] = sizeof(uint32_t),
[NFTNL_SET_POLICY] = sizeof(uint32_t),
[NFTNL_SET_DESC_SIZE] = sizeof(uint32_t),
[NFTNL_SET_TIMEOUT] = sizeof(uint64_t),
[NFTNL_SET_GC_INTERVAL] = sizeof(uint32_t),
+ [NFTNL_SET_COUNT] = sizeof(uint32_t),
};
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);
switch(attr) {
case NFTNL_SET_TABLE:
- if (s->flags & (1 << NFTNL_SET_TABLE))
- xfree(s->table);
-
- s->table = strdup(data);
- if (!s->table)
- return -1;
- break;
+ return nftnl_set_str_attr(&s->table, &s->flags,
+ attr, data, data_len);
case NFTNL_SET_NAME:
- if (s->flags & (1 << NFTNL_SET_NAME))
- xfree(s->name);
-
- s->name = strdup(data);
- if (!s->name)
- return -1;
- break;
+ return nftnl_set_str_attr(&s->name, &s->flags,
+ attr, data, data_len);
case NFTNL_SET_HANDLE:
memcpy(&s->handle, data, sizeof(s->handle));
break;
@@ -181,8 +185,16 @@ int nftnl_set_set_data(struct nftnl_set *s, uint16_t attr, const void *data,
memcpy(&s->desc.size, data, sizeof(s->desc.size));
break;
case NFTNL_SET_DESC_CONCAT:
+ if (data_len > sizeof(s->desc.field_len))
+ return -1;
+
memcpy(&s->desc.field_len, data, data_len);
- while (s->desc.field_len[++s->desc.field_count]);
+ for (s->desc.field_count = 0;
+ s->desc.field_count < NFT_REG32_COUNT;
+ s->desc.field_count++) {
+ if (!s->desc.field_len[s->desc.field_count])
+ break;
+ }
break;
case NFTNL_SET_TIMEOUT:
memcpy(&s->timeout, data, sizeof(s->timeout));
@@ -190,6 +202,9 @@ int nftnl_set_set_data(struct nftnl_set *s, uint16_t attr, const void *data,
case NFTNL_SET_GC_INTERVAL:
memcpy(&s->gc_interval, data, sizeof(s->gc_interval));
break;
+ case NFTNL_SET_COUNT:
+ memcpy(&s->elemcount, data, sizeof(s->elemcount));
+ break;
case NFTNL_SET_USERDATA:
if (s->flags & (1 << NFTNL_SET_USERDATA))
xfree(s->user.data);
@@ -201,10 +216,13 @@ 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) {
+ list_del(&expr->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 +257,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;
@@ -291,11 +311,16 @@ const void *nftnl_set_get_data(const struct nftnl_set *s, uint16_t attr,
case NFTNL_SET_GC_INTERVAL:
*data_len = sizeof(uint32_t);
return &s->gc_interval;
+ case NFTNL_SET_COUNT:
+ *data_len = sizeof(uint32_t);
+ return &s->elemcount;
case NFTNL_SET_USERDATA:
*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;
}
@@ -366,6 +391,8 @@ struct nftnl_set *nftnl_set_clone(const struct nftnl_set *set)
list_add_tail(&newelem->head, &newset->element_list);
}
+ newset->type = NULL;
+
return newset;
err:
nftnl_set_free(newset);
@@ -414,6 +441,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 +474,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)
{
@@ -466,6 +535,7 @@ static int nftnl_set_parse_attr_cb(const struct nlattr *attr, void *data)
switch(type) {
case NFTA_SET_TABLE:
case NFTA_SET_NAME:
+ case NFTA_SET_TYPE:
if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
abi_breakage();
break;
@@ -481,6 +551,7 @@ static int nftnl_set_parse_attr_cb(const struct nlattr *attr, void *data)
case NFTA_SET_ID:
case NFTA_SET_POLICY:
case NFTA_SET_GC_INTERVAL:
+ case NFTA_SET_COUNT:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
abi_breakage();
break;
@@ -493,6 +564,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,27 +651,18 @@ 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)
return -1;
- if (tb[NFTA_SET_TABLE]) {
- if (s->flags & (1 << NFTNL_SET_TABLE))
- xfree(s->table);
- s->table = strdup(mnl_attr_get_str(tb[NFTA_SET_TABLE]));
- if (!s->table)
- return -1;
- s->flags |= (1 << NFTNL_SET_TABLE);
- }
- if (tb[NFTA_SET_NAME]) {
- if (s->flags & (1 << NFTNL_SET_NAME))
- xfree(s->name);
- s->name = strdup(mnl_attr_get_str(tb[NFTA_SET_NAME]));
- if (!s->name)
- return -1;
- s->flags |= (1 << NFTNL_SET_NAME);
- }
+ if (nftnl_parse_str_attr(tb[NFTA_SET_TABLE], NFTNL_SET_TABLE,
+ &s->table, &s->flags) < 0)
+ return -1;
+ if (nftnl_parse_str_attr(tb[NFTA_SET_NAME], NFTNL_SET_NAME,
+ &s->name, &s->flags) < 0)
+ return -1;
if (tb[NFTA_SET_HANDLE]) {
s->handle = be64toh(mnl_attr_get_u64(tb[NFTA_SET_HANDLE]));
s->flags |= (1 << NFTNL_SET_HANDLE);
@@ -656,62 +720,75 @@ 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);
+ }
+
+ if (tb[NFTA_SET_TYPE]) {
+ xfree(s->type);
+ s->type = strdup(mnl_attr_get_str(tb[NFTA_SET_TYPE]));
+ }
+
+ if (tb[NFTA_SET_COUNT]) {
+ s->elemcount = ntohl(mnl_attr_get_u32(tb[NFTA_SET_COUNT]));
+ s->flags |= (1 << NFTNL_SET_COUNT);
}
s->family = nfg->nfgen_family;
s->flags |= (1 << NFTNL_SET_FAMILY);
return 0;
-}
-
-static int nftnl_set_do_parse(struct nftnl_set *s, enum nftnl_parse_type type,
- const void *data, struct nftnl_parse_err *err,
- enum nftnl_parse_input input)
-{
- int ret;
- struct nftnl_parse_err perr = {};
-
- switch (type) {
- case NFTNL_PARSE_JSON:
- case NFTNL_PARSE_XML:
- default:
- ret = -1;
- errno = EOPNOTSUPP;
- break;
+out_set_expr:
+ list_for_each_entry_safe(expr, next, &s->expr_list, head) {
+ list_del(&expr->head);
+ nftnl_expr_free(expr);
}
- if (err != NULL)
- *err = perr;
-
- return ret;
+ return -1;
}
EXPORT_SYMBOL(nftnl_set_parse);
int nftnl_set_parse(struct nftnl_set *s, enum nftnl_parse_type type,
const char *data, struct nftnl_parse_err *err)
{
- return nftnl_set_do_parse(s, type, data, err, NFTNL_PARSE_BUFFER);
+ errno = EOPNOTSUPP;
+
+ return -1;
}
EXPORT_SYMBOL(nftnl_set_parse_file);
int nftnl_set_parse_file(struct nftnl_set *s, enum nftnl_parse_type type,
FILE *fp, struct nftnl_parse_err *err)
{
- return nftnl_set_do_parse(s, type, fp, err, NFTNL_PARSE_FILE);
+ errno = EOPNOTSUPP;
+
+ return -1;
}
-static int nftnl_set_snprintf_default(char *buf, size_t size,
+static int nftnl_set_snprintf_default(char *buf, size_t remain,
const struct nftnl_set *s,
uint32_t type, uint32_t flags)
{
- int ret;
- int remain = size, offset = 0;
struct nftnl_set_elem *elem;
+ int ret, offset = 0;
ret = snprintf(buf, remain, "%s %s %x",
s->name, s->table, s->set_flags);
@@ -739,6 +816,16 @@ static int nftnl_set_snprintf_default(char *buf, size_t size,
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
}
+ if (s->type) {
+ ret = snprintf(buf + offset, remain, " backend %s", s->type);
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
+ }
+
+ if (s->elemcount) {
+ ret = snprintf(buf + offset, remain, " count %u", s->elemcount);
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
+ }
+
/* Empty set? Skip printinf of elements */
if (list_empty(&s->element_list))
return offset;
@@ -750,37 +837,30 @@ static int nftnl_set_snprintf_default(char *buf, size_t size,
ret = snprintf(buf + offset, remain, "\t");
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
- ret = nftnl_set_elem_snprintf(buf + offset, remain, elem, type,
- flags);
+ ret = nftnl_set_elem_snprintf_default(buf + offset, remain,
+ elem);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
}
return offset;
}
-static int nftnl_set_cmd_snprintf(char *buf, size_t size,
+static int nftnl_set_cmd_snprintf(char *buf, size_t remain,
const struct nftnl_set *s, uint32_t cmd,
uint32_t type, uint32_t flags)
{
- int ret, remain = size, offset = 0;
uint32_t inner_flags = flags;
+ int ret, offset = 0;
- if (type == NFTNL_OUTPUT_XML)
- return 0;
+ if (type != NFTNL_OUTPUT_DEFAULT)
+ return -1;
/* prevent set_elems to print as events */
inner_flags &= ~NFTNL_OF_EVENT_ANY;
- switch(type) {
- case NFTNL_OUTPUT_DEFAULT:
- ret = nftnl_set_snprintf_default(buf + offset, remain, s, type,
- inner_flags);
- SNPRINTF_BUFFER_SIZE(ret, remain, offset);
- break;
- default:
- return -1;
- }
-
+ ret = nftnl_set_snprintf_default(buf + offset, remain, s, type,
+ inner_flags);
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
return offset;
}