Support simple (suffix) wildcards in NFTNL_CHAIN_DEV(ICES) and NFTA_FLOWTABLE_HOOK_DEVS identified by non-NUL-terminated strings. Add helpers converting to and from the human-readable asterisk-suffix notation. Signed-off-by: Phil Sutter <phil@xxxxxx> --- Changes since v3: - Use uint16_t for 'attr' parameter and size_t for internal 'len' variable - nftnl_attr_get_ifname to return allocated buffer, 'attr' parameter may be const Changes since v2: - Use 'nftnl' prefix for introduced helpers - Forward-declare struct nlattr to avoid extra include in utils.h - Sanity-check array indexes to avoid out-of-bounds access --- include/utils.h | 6 ++++++ src/chain.c | 8 +++++--- src/flowtable.c | 2 +- src/str_array.c | 2 +- src/utils.c | 31 +++++++++++++++++++++++++++++++ 5 files changed, 44 insertions(+), 5 deletions(-) diff --git a/include/utils.h b/include/utils.h index 247d99d19dd7f..f232e7e2f3dd7 100644 --- a/include/utils.h +++ b/include/utils.h @@ -83,4 +83,10 @@ int nftnl_fprintf(FILE *fpconst, const void *obj, uint32_t cmd, uint32_t type, int nftnl_set_str_attr(const char **dptr, uint32_t *flags, uint16_t attr, const void *data, uint32_t data_len); +struct nlattr; + +void nftnl_attr_put_ifname(struct nlmsghdr *nlh, + uint16_t attr, const char *ifname); +char *nftnl_attr_get_ifname(const struct nlattr *attr); + #endif diff --git a/src/chain.c b/src/chain.c index 895108cddad51..b401526c367fb 100644 --- a/src/chain.c +++ b/src/chain.c @@ -457,14 +457,14 @@ 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); + nftnl_attr_put_ifname(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); nftnl_str_array_foreach(dev, &c->dev_array, i) - mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev); + nftnl_attr_put_ifname(nlh, NFTA_DEVICE_NAME, dev); mnl_attr_nest_end(nlh, nest_dev); } @@ -648,7 +648,9 @@ static int nftnl_chain_parse_hook(struct nlattr *attr, struct nftnl_chain *c) c->flags |= (1 << NFTNL_CHAIN_PRIO); } if (tb[NFTA_HOOK_DEV]) { - c->dev = strdup(mnl_attr_get_str(tb[NFTA_HOOK_DEV])); + if (c->flags & (1 << NFTNL_CHAIN_DEV)) + xfree(c->dev); + c->dev = nftnl_attr_get_ifname(tb[NFTA_HOOK_DEV]); if (!c->dev) return -1; c->flags |= (1 << NFTNL_CHAIN_DEV); diff --git a/src/flowtable.c b/src/flowtable.c index fbbe0a866368d..006d50743e78a 100644 --- a/src/flowtable.c +++ b/src/flowtable.c @@ -299,7 +299,7 @@ void nftnl_flowtable_nlmsg_build_payload(struct nlmsghdr *nlh, nest_dev = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK_DEVS); nftnl_str_array_foreach(dev, &c->dev_array, i) - mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev); + nftnl_attr_put_ifname(nlh, NFTA_DEVICE_NAME, dev); mnl_attr_nest_end(nlh, nest_dev); } diff --git a/src/str_array.c b/src/str_array.c index 5669c6154d394..02501c0cbdd79 100644 --- a/src/str_array.c +++ b/src/str_array.c @@ -56,7 +56,7 @@ int nftnl_parse_devs(struct nftnl_str_array *sa, const struct nlattr *nest) return -1; mnl_attr_for_each_nested(attr, nest) { - sa->array[sa->len] = strdup(mnl_attr_get_str(attr)); + sa->array[sa->len] = nftnl_attr_get_ifname(attr); if (!sa->array[sa->len]) { nftnl_str_array_clear(sa); return -1; diff --git a/src/utils.c b/src/utils.c index 5f2c5bff7c650..2a8669c6242b7 100644 --- a/src/utils.c +++ b/src/utils.c @@ -13,8 +13,11 @@ #include <errno.h> #include <inttypes.h> +#include <libmnl/libmnl.h> + #include <libnftnl/common.h> +#include <linux/if.h> #include <linux/netfilter.h> #include <linux/netfilter/nf_tables.h> @@ -146,3 +149,31 @@ int nftnl_set_str_attr(const char **dptr, uint32_t *flags, *flags |= (1 << attr); return 0; } + +void nftnl_attr_put_ifname(struct nlmsghdr *nlh, + uint16_t attr, const char *ifname) +{ + size_t len = strlen(ifname) + 1; + + if (len >= 2 && ifname[len - 2] == '*') + len -= 2; + + mnl_attr_put(nlh, attr, len, ifname); +} + +char *nftnl_attr_get_ifname(const struct nlattr *attr) +{ + size_t slen = mnl_attr_get_payload_len(attr); + const char *dev = mnl_attr_get_str(attr); + char buf[IFNAMSIZ]; + + if (slen > 0 && dev[slen - 1] == '\0') + return strdup(dev); + + if (slen > IFNAMSIZ - 2) + slen = IFNAMSIZ - 2; + + memcpy(buf, dev, slen); + memcpy(buf + slen, "*\0", 2); + return strdup(buf); +} -- 2.49.0