summaryrefslogtreecommitdiffstats
path: root/src/chain.c
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2019-10-16 10:16:52 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2019-10-28 11:02:41 +0100
commite3ac19b5ec16224710b02178647e8369c47cb44d (patch)
treed13eaf9eb8a77037a6540b37e51a060ec7be6f2c /src/chain.c
parent7f99639dd92174e7a486a1ee3b565b9bbeb2a264 (diff)
chain: multi-device support
Add support for NFTA_HOOK_DEVS. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/chain.c')
-rw-r--r--src/chain.c109
1 files changed, 108 insertions, 1 deletions
diff --git a/src/chain.c b/src/chain.c
index 26f9b9d..84e5414 100644
--- a/src/chain.c
+++ b/src/chain.c
@@ -38,6 +38,8 @@ struct nftnl_chain {
const char *type;
const char *table;
const char *dev;
+ const char **dev_array;
+ int dev_array_len;
uint32_t family;
uint32_t policy;
uint32_t hooknum;
@@ -109,6 +111,7 @@ 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);
@@ -121,6 +124,12 @@ 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_DEVICES)) {
+ for (i = 0; i < c->dev_array_len; i++)
+ xfree(c->dev_array[i]);
+
+ xfree(c->dev_array);
+ }
xfree(c);
}
@@ -133,6 +142,8 @@ 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;
@@ -159,6 +170,11 @@ void nftnl_chain_unset(struct nftnl_chain *c, uint16_t attr)
case NFTNL_CHAIN_DEV:
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);
+ break;
default:
return;
}
@@ -180,6 +196,9 @@ 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);
@@ -240,6 +259,26 @@ int nftnl_chain_set_data(struct nftnl_chain *c, uint16_t attr,
if (!c->dev)
return -1;
break;
+ 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)
+ return -1;
+
+ for (i = 0; i < len; i++)
+ c->dev_array[i] = strdup(dev_array[i]);
+
+ c->dev_array_len = len;
+ break;
}
c->flags |= (1 << attr);
return 0;
@@ -325,6 +364,8 @@ const void *nftnl_chain_get_data(const struct nftnl_chain *c, uint16_t attr,
case NFTNL_CHAIN_DEV:
*data_len = strlen(c->dev) + 1;
return c->dev;
+ case NFTNL_CHAIN_DEVICES:
+ return &c->dev_array[0];
}
return NULL;
}
@@ -389,6 +430,8 @@ uint8_t nftnl_chain_get_u8(const struct nftnl_chain *c, uint16_t attr)
EXPORT_SYMBOL(nftnl_chain_nlmsg_build_payload);
void nftnl_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_chain *c)
{
+ int i;
+
if (c->flags & (1 << NFTNL_CHAIN_TABLE))
mnl_attr_put_strz(nlh, NFTA_CHAIN_TABLE, c->table);
if (c->flags & (1 << NFTNL_CHAIN_NAME))
@@ -402,6 +445,15 @@ void nftnl_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_ch
mnl_attr_put_u32(nlh, NFTA_HOOK_PRIORITY, htonl(c->prio));
if (c->flags & (1 << NFTNL_CHAIN_DEV))
mnl_attr_put_strz(nlh, NFTA_HOOK_DEV, c->dev);
+ else if (c->flags & (1 << NFTNL_CHAIN_DEVICES)) {
+ struct nlattr *nest_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]);
+ mnl_attr_nest_end(nlh, nest_dev);
+ }
mnl_attr_nest_end(nlh, nest);
}
if (c->flags & (1 << NFTNL_CHAIN_POLICY))
@@ -551,9 +603,46 @@ 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;
+ 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) {
+ dev_array = realloc(dev_array,
+ size * 2 * sizeof(char *));
+ if (!dev_array)
+ goto err;
+
+ size *= 2;
+ memset(&dev_array[len], 0,
+ (size - len) * sizeof(char *));
+ }
+ }
+
+ c->dev_array = dev_array;
+ c->dev_array_len = len;
+
+ return 0;
+err:
+ while (len--)
+ xfree(dev_array[len]);
+ return -1;
+}
+
static int nftnl_chain_parse_hook(struct nlattr *attr, struct nftnl_chain *c)
{
struct nlattr *tb[NFTA_HOOK_MAX+1] = {};
+ int ret;
if (mnl_attr_parse_nested(attr, nftnl_chain_parse_hook_cb, tb) < 0)
return -1;
@@ -572,6 +661,12 @@ static int nftnl_chain_parse_hook(struct nlattr *attr, struct nftnl_chain *c)
return -1;
c->flags |= (1 << NFTNL_CHAIN_DEV);
}
+ if (tb[NFTA_HOOK_DEVS]) {
+ ret = nftnl_chain_parse_devs(tb[NFTA_HOOK_DEVS], c);
+ if (ret < 0)
+ return -1;
+ c->flags |= (1 << NFTNL_CHAIN_DEVICES);
+ }
return 0;
}
@@ -653,7 +748,7 @@ static inline int nftnl_str2hooknum(int family, const char *hook)
static int nftnl_chain_snprintf_default(char *buf, size_t size,
const struct nftnl_chain *c)
{
- int ret, remain = size, offset = 0;
+ int ret, remain = size, offset = 0, i;
ret = snprintf(buf, remain, "%s %s %s use %u",
nftnl_family2str(c->family), c->table, c->name, c->use);
@@ -681,6 +776,18 @@ static int nftnl_chain_snprintf_default(char *buf, size_t size,
c->dev);
SNPRINTF_BUFFER_SIZE(ret, remain, offset);
}
+ if (c->flags & (1 << NFTNL_CHAIN_DEVICES)) {
+ ret = snprintf(buf + offset, remain, " dev { ");
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
+
+ for (i = 0; i < c->dev_array_len; i++) {
+ ret = snprintf(buf + offset, remain, " %s ",
+ c->dev_array[i]);
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
+ }
+ ret = snprintf(buf + offset, remain, " } ");
+ SNPRINTF_BUFFER_SIZE(ret, remain, offset);
+ }
}
return offset;