summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2021-08-30 14:38:27 +0200
committerPhil Sutter <phil@nwl.cc>2024-10-29 23:26:43 +0100
commit0576274ad54a3aae2750e7a49bed1e0f406b61cc (patch)
tree103b004cdb5c58529e253c873c0c47d08afc7aff /src
parentfaab4a300784cc04f35a0cf40b7fdb858a7ece3e (diff)
Introduce struct nftnl_str_array
This data structure holds an array of allocated strings for use in nftnl_chain and nftnl_flowtable structs. For convenience, implement functions to clear, populate and iterate over contents. While at it, extend chain and flowtable tests to cover these attributes, too. Signed-off-by: Phil Sutter <phil@nwl.cc> Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/chain.c90
-rw-r--r--src/flowtable.c94
-rw-r--r--src/str_array.c68
4 files changed, 96 insertions, 157 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 3cd259c..1c38d00 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -17,6 +17,7 @@ libnftnl_la_SOURCES = utils.c \
rule.c \
set.c \
set_elem.c \
+ str_array.c \
ruleset.c \
udata.c \
expr.c \
diff --git a/src/chain.c b/src/chain.c
index 0b68939..c9fbc3a 100644
--- a/src/chain.c
+++ b/src/chain.c
@@ -37,8 +37,7 @@ struct nftnl_chain {
const char *type;
const char *table;
const char *dev;
- const char **dev_array;
- int dev_array_len;
+ struct nftnl_str_array dev_array;
uint32_t family;
uint32_t policy;
uint32_t hooknum;
@@ -117,7 +116,6 @@ EXPORT_SYMBOL(nftnl_chain_free);
void nftnl_chain_free(const struct nftnl_chain *c)
{
struct nftnl_rule *r, *tmp;
- int i;
list_for_each_entry_safe(r, tmp, &c->rule_list, head)
nftnl_rule_free(r);
@@ -132,12 +130,8 @@ void nftnl_chain_free(const struct nftnl_chain *c)
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]);
-
- xfree(c->dev_array);
- }
+ if (c->flags & (1 << NFTNL_CHAIN_DEVICES))
+ nftnl_str_array_clear((struct nftnl_str_array *)&c->dev_array);
xfree(c);
}
@@ -150,8 +144,6 @@ bool nftnl_chain_is_set(const struct nftnl_chain *c, uint16_t attr)
EXPORT_SYMBOL(nftnl_chain_unset);
void nftnl_chain_unset(struct nftnl_chain *c, uint16_t attr)
{
- int i;
-
if (!(c->flags & (1 << attr)))
return;
@@ -181,9 +173,7 @@ void nftnl_chain_unset(struct nftnl_chain *c, uint16_t attr)
xfree(c->dev);
break;
case NFTNL_CHAIN_DEVICES:
- for (i = 0; i < c->dev_array_len; i++)
- xfree(c->dev_array[i]);
- xfree(c->dev_array);
+ nftnl_str_array_clear(&c->dev_array);
break;
case NFTNL_CHAIN_USERDATA:
xfree(c->user.data);
@@ -212,9 +202,6 @@ EXPORT_SYMBOL(nftnl_chain_set_data);
int nftnl_chain_set_data(struct nftnl_chain *c, uint16_t attr,
const void *data, uint32_t data_len)
{
- const char **dev_array;
- int len = 0, i;
-
nftnl_assert_attr_exists(attr, NFTNL_CHAIN_MAX);
nftnl_assert_validate(data, nftnl_chain_validate, attr, data_len);
@@ -256,24 +243,8 @@ int nftnl_chain_set_data(struct nftnl_chain *c, uint16_t attr,
return nftnl_set_str_attr(&c->dev, &c->flags,
attr, data, data_len);
case NFTNL_CHAIN_DEVICES:
- dev_array = (const char **)data;
- while (dev_array[len] != NULL)
- len++;
-
- if (c->flags & (1 << NFTNL_CHAIN_DEVICES)) {
- for (i = 0; i < c->dev_array_len; i++)
- xfree(c->dev_array[i]);
- xfree(c->dev_array);
- }
-
- c->dev_array = calloc(len + 1, sizeof(char *));
- if (!c->dev_array)
+ if (nftnl_str_array_set(&c->dev_array, data) < 0)
return -1;
-
- for (i = 0; i < len; i++)
- c->dev_array[i] = strdup(dev_array[i]);
-
- c->dev_array_len = len;
break;
case NFTNL_CHAIN_FLAGS:
memcpy(&c->chain_flags, data, sizeof(c->chain_flags));
@@ -385,7 +356,7 @@ const void *nftnl_chain_get_data(const struct nftnl_chain *c, uint16_t attr,
return c->dev;
case NFTNL_CHAIN_DEVICES:
*data_len = 0;
- return &c->dev_array[0];
+ return c->dev_array.array;
case NFTNL_CHAIN_FLAGS:
*data_len = sizeof(uint32_t);
return &c->chain_flags;
@@ -493,11 +464,11 @@ void nftnl_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_ch
mnl_attr_put_strz(nlh, NFTA_HOOK_DEV, c->dev);
else if (c->flags & (1 << NFTNL_CHAIN_DEVICES)) {
struct nlattr *nest_dev;
+ const char *dev;
nest_dev = mnl_attr_nest_start(nlh, NFTA_HOOK_DEVS);
- for (i = 0; i < c->dev_array_len; i++)
- mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME,
- c->dev_array[i]);
+ nftnl_str_array_foreach(dev, &c->dev_array, i)
+ mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev);
mnl_attr_nest_end(nlh, nest_dev);
}
@@ -664,42 +635,6 @@ static int nftnl_chain_parse_hook_cb(const struct nlattr *attr, void *data)
return MNL_CB_OK;
}
-static int nftnl_chain_parse_devs(struct nlattr *nest, struct nftnl_chain *c)
-{
- const char **dev_array, **tmp;
- int len = 0, size = 8;
- struct nlattr *attr;
-
- dev_array = calloc(8, sizeof(char *));
- if (!dev_array)
- return -1;
-
- mnl_attr_for_each_nested(attr, nest) {
- if (mnl_attr_get_type(attr) != NFTA_DEVICE_NAME)
- goto err;
- dev_array[len++] = strdup(mnl_attr_get_str(attr));
- if (len >= size) {
- tmp = realloc(dev_array, size * 2 * sizeof(char *));
- if (!tmp)
- goto err;
-
- size *= 2;
- memset(&tmp[len], 0, (size - len) * sizeof(char *));
- dev_array = tmp;
- }
- }
-
- c->dev_array = dev_array;
- c->dev_array_len = len;
-
- return 0;
-err:
- while (len--)
- xfree(dev_array[len]);
- xfree(dev_array);
- return -1;
-}
-
static int nftnl_chain_parse_hook(struct nlattr *attr, struct nftnl_chain *c)
{
struct nlattr *tb[NFTA_HOOK_MAX+1] = {};
@@ -723,7 +658,7 @@ static int nftnl_chain_parse_hook(struct nlattr *attr, struct nftnl_chain *c)
c->flags |= (1 << NFTNL_CHAIN_DEV);
}
if (tb[NFTA_HOOK_DEVS]) {
- ret = nftnl_chain_parse_devs(tb[NFTA_HOOK_DEVS], c);
+ ret = nftnl_parse_devs(&c->dev_array, tb[NFTA_HOOK_DEVS]);
if (ret < 0)
return -1;
c->flags |= (1 << NFTNL_CHAIN_DEVICES);
@@ -823,6 +758,7 @@ static int nftnl_chain_snprintf_default(char *buf, size_t remain,
const struct nftnl_chain *c)
{
int ret, offset = 0, i;
+ const char *dev;
ret = snprintf(buf, remain, "%s %s %s use %u",
nftnl_family2str(c->family), c->table, c->name, c->use);
@@ -854,9 +790,9 @@ static int nftnl_chain_snprintf_default(char *buf, size_t remain,
ret = snprintf(buf + offset, remain, " dev { ");
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
- for (i = 0; i < c->dev_array_len; i++) {
+ nftnl_str_array_foreach(dev, &c->dev_array, i) {
ret = snprintf(buf + offset, remain, " %s ",
- c->dev_array[i]);
+ dev);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
}
ret = snprintf(buf + offset, remain, " } ");
diff --git a/src/flowtable.c b/src/flowtable.c
index 41a1456..2a8d374 100644
--- a/src/flowtable.c
+++ b/src/flowtable.c
@@ -26,8 +26,7 @@ struct nftnl_flowtable {
uint32_t hooknum;
int32_t prio;
uint32_t size;
- const char **dev_array;
- uint32_t dev_array_len;
+ struct nftnl_str_array dev_array;
uint32_t ft_flags;
uint32_t use;
uint32_t flags;
@@ -43,18 +42,12 @@ struct nftnl_flowtable *nftnl_flowtable_alloc(void)
EXPORT_SYMBOL(nftnl_flowtable_free);
void nftnl_flowtable_free(const struct nftnl_flowtable *c)
{
- int i;
-
if (c->flags & (1 << NFTNL_FLOWTABLE_NAME))
xfree(c->name);
if (c->flags & (1 << NFTNL_FLOWTABLE_TABLE))
xfree(c->table);
- if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
- for (i = 0; i < c->dev_array_len; i++)
- xfree(c->dev_array[i]);
-
- xfree(c->dev_array);
- }
+ if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES))
+ nftnl_str_array_clear((struct nftnl_str_array *)&c->dev_array);
xfree(c);
}
@@ -67,8 +60,6 @@ bool nftnl_flowtable_is_set(const struct nftnl_flowtable *c, uint16_t attr)
EXPORT_SYMBOL(nftnl_flowtable_unset);
void nftnl_flowtable_unset(struct nftnl_flowtable *c, uint16_t attr)
{
- int i;
-
if (!(c->flags & (1 << attr)))
return;
@@ -87,9 +78,7 @@ void nftnl_flowtable_unset(struct nftnl_flowtable *c, uint16_t attr)
case NFTNL_FLOWTABLE_HANDLE:
break;
case NFTNL_FLOWTABLE_DEVICES:
- for (i = 0; i < c->dev_array_len; i++)
- xfree(c->dev_array[i]);
- xfree(c->dev_array);
+ nftnl_str_array_clear(&c->dev_array);
break;
default:
return;
@@ -111,9 +100,6 @@ EXPORT_SYMBOL(nftnl_flowtable_set_data);
int nftnl_flowtable_set_data(struct nftnl_flowtable *c, uint16_t attr,
const void *data, uint32_t data_len)
{
- const char **dev_array;
- int len = 0, i;
-
nftnl_assert_attr_exists(attr, NFTNL_FLOWTABLE_MAX);
nftnl_assert_validate(data, nftnl_flowtable_validate, attr, data_len);
@@ -135,24 +121,8 @@ int nftnl_flowtable_set_data(struct nftnl_flowtable *c, uint16_t attr,
memcpy(&c->family, data, sizeof(c->family));
break;
case NFTNL_FLOWTABLE_DEVICES:
- dev_array = (const char **)data;
- while (dev_array[len] != NULL)
- len++;
-
- if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
- for (i = 0; i < c->dev_array_len; i++)
- xfree(c->dev_array[i]);
- xfree(c->dev_array);
- }
-
- c->dev_array = calloc(len + 1, sizeof(char *));
- if (!c->dev_array)
+ if (nftnl_str_array_set(&c->dev_array, data) < 0)
return -1;
-
- for (i = 0; i < len; i++)
- c->dev_array[i] = strdup(dev_array[i]);
-
- c->dev_array_len = len;
break;
case NFTNL_FLOWTABLE_SIZE:
memcpy(&c->size, data, sizeof(c->size));
@@ -230,7 +200,7 @@ const void *nftnl_flowtable_get_data(const struct nftnl_flowtable *c,
return &c->family;
case NFTNL_FLOWTABLE_DEVICES:
*data_len = 0;
- return &c->dev_array[0];
+ return c->dev_array.array;
case NFTNL_FLOWTABLE_SIZE:
*data_len = sizeof(int32_t);
return &c->size;
@@ -325,12 +295,11 @@ void nftnl_flowtable_nlmsg_build_payload(struct nlmsghdr *nlh,
if (c->flags & (1 << NFTNL_FLOWTABLE_DEVICES)) {
struct nlattr *nest_dev;
+ const char *dev;
nest_dev = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK_DEVS);
- for (i = 0; i < c->dev_array_len; i++) {
- mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME,
- c->dev_array[i]);
- }
+ nftnl_str_array_foreach(dev, &c->dev_array, i)
+ mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev);
mnl_attr_nest_end(nlh, nest_dev);
}
@@ -402,43 +371,6 @@ static int nftnl_flowtable_parse_hook_cb(const struct nlattr *attr, void *data)
return MNL_CB_OK;
}
-static int nftnl_flowtable_parse_devs(struct nlattr *nest,
- struct nftnl_flowtable *c)
-{
- const char **dev_array, **tmp;
- int len = 0, size = 8;
- struct nlattr *attr;
-
- dev_array = calloc(8, sizeof(char *));
- if (!dev_array)
- return -1;
-
- mnl_attr_for_each_nested(attr, nest) {
- if (mnl_attr_get_type(attr) != NFTA_DEVICE_NAME)
- goto err;
- dev_array[len++] = strdup(mnl_attr_get_str(attr));
- if (len >= size) {
- tmp = realloc(dev_array, size * 2 * sizeof(char *));
- if (!tmp)
- goto err;
-
- size *= 2;
- memset(&tmp[len], 0, (size - len) * sizeof(char *));
- dev_array = tmp;
- }
- }
-
- c->dev_array = dev_array;
- c->dev_array_len = len;
-
- return 0;
-err:
- while (len--)
- xfree(dev_array[len]);
- xfree(dev_array);
- return -1;
-}
-
static int nftnl_flowtable_parse_hook(struct nlattr *attr, struct nftnl_flowtable *c)
{
struct nlattr *tb[NFTA_FLOWTABLE_HOOK_MAX + 1] = {};
@@ -456,7 +388,8 @@ static int nftnl_flowtable_parse_hook(struct nlattr *attr, struct nftnl_flowtabl
c->flags |= (1 << NFTNL_FLOWTABLE_PRIO);
}
if (tb[NFTA_FLOWTABLE_HOOK_DEVS]) {
- ret = nftnl_flowtable_parse_devs(tb[NFTA_FLOWTABLE_HOOK_DEVS], c);
+ ret = nftnl_parse_devs(&c->dev_array,
+ tb[NFTA_FLOWTABLE_HOOK_DEVS]);
if (ret < 0)
return -1;
c->flags |= (1 << NFTNL_FLOWTABLE_DEVICES);
@@ -587,6 +520,7 @@ static int nftnl_flowtable_snprintf_default(char *buf, size_t remain,
const struct nftnl_flowtable *c)
{
int ret, offset = 0, i;
+ const char *dev;
ret = snprintf(buf, remain, "flow table %s %s use %u size %u flags %x",
c->table, c->name, c->use, c->size, c->ft_flags);
@@ -602,9 +536,9 @@ static int nftnl_flowtable_snprintf_default(char *buf, size_t remain,
ret = snprintf(buf + offset, remain, " dev { ");
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
- for (i = 0; i < c->dev_array_len; i++) {
+ nftnl_str_array_foreach(dev, &c->dev_array, i) {
ret = snprintf(buf + offset, remain, " %s ",
- c->dev_array[i]);
+ dev);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
}
ret = snprintf(buf + offset, remain, " } ");
diff --git a/src/str_array.c b/src/str_array.c
new file mode 100644
index 0000000..63471bd
--- /dev/null
+++ b/src/str_array.c
@@ -0,0 +1,68 @@
+/*
+ * (C) 2024 Red Hat GmbH
+ * Author: Phil Sutter <phil@nwl.cc>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include <libmnl/libmnl.h>
+#include <linux/netfilter/nf_tables.h>
+
+#include "str_array.h"
+#include "utils.h"
+
+void nftnl_str_array_clear(struct nftnl_str_array *sa)
+{
+ while (sa->len > 0)
+ free(sa->array[--sa->len]);
+ free(sa->array);
+}
+
+int nftnl_str_array_set(struct nftnl_str_array *sa, const char * const *array)
+{
+ int len = 0;
+
+ while (array[len])
+ len++;
+
+ nftnl_str_array_clear(sa);
+ sa->array = calloc(len + 1, sizeof(char *));
+ if (!sa->array)
+ return -1;
+
+ while (sa->len < len) {
+ sa->array[sa->len] = strdup(array[sa->len]);
+ if (!sa->array[sa->len]) {
+ nftnl_str_array_clear(sa);
+ return -1;
+ }
+ sa->len++;
+ }
+ return 0;
+}
+
+int nftnl_parse_devs(struct nftnl_str_array *sa, const struct nlattr *nest)
+{
+ struct nlattr *attr;
+ int len = 0;
+
+ mnl_attr_for_each_nested(attr, nest) {
+ if (mnl_attr_get_type(attr) != NFTA_DEVICE_NAME)
+ return -1;
+ len++;
+ }
+
+ nftnl_str_array_clear(sa);
+ sa->array = calloc(len + 1, sizeof(char *));
+ if (!sa->array)
+ return -1;
+
+ mnl_attr_for_each_nested(attr, nest) {
+ sa->array[sa->len] = strdup(mnl_attr_get_str(attr));
+ if (!sa->array[sa->len]) {
+ nftnl_str_array_clear(sa);
+ return -1;
+ }
+ sa->len++;
+ }
+ return 0;
+}