diff options
Diffstat (limited to 'src/chain.c')
-rw-r--r-- | src/chain.c | 274 |
1 files changed, 228 insertions, 46 deletions
diff --git a/src/chain.c b/src/chain.c index 26f9b9d..c7026f4 100644 --- a/src/chain.c +++ b/src/chain.c @@ -28,7 +28,6 @@ #include <libnftnl/chain.h> #include <libnftnl/rule.h> -#include <buffer.h> struct nftnl_chain { struct list_head head; @@ -38,15 +37,24 @@ 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; int32_t prio; + uint32_t chain_flags; uint32_t use; uint64_t packets; uint64_t bytes; uint64_t handle; uint32_t flags; + uint32_t chain_id; + + struct { + void *data; + uint32_t len; + } user; struct list_head rule_list; }; @@ -109,6 +117,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 +130,14 @@ 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]); + + xfree(c->dev_array); + } xfree(c); } @@ -133,6 +150,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; @@ -155,10 +174,17 @@ void nftnl_chain_unset(struct nftnl_chain *c, uint16_t attr) case NFTNL_CHAIN_PACKETS: case NFTNL_CHAIN_HANDLE: case NFTNL_CHAIN_FAMILY: + case NFTNL_CHAIN_FLAGS: + case NFTNL_CHAIN_ID: break; 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; } @@ -170,36 +196,32 @@ static uint32_t nftnl_chain_validate[NFTNL_CHAIN_MAX + 1] = { [NFTNL_CHAIN_HOOKNUM] = sizeof(uint32_t), [NFTNL_CHAIN_PRIO] = sizeof(int32_t), [NFTNL_CHAIN_POLICY] = sizeof(uint32_t), + [NFTNL_CHAIN_USE] = sizeof(uint32_t), [NFTNL_CHAIN_BYTES] = sizeof(uint64_t), [NFTNL_CHAIN_PACKETS] = sizeof(uint64_t), [NFTNL_CHAIN_HANDLE] = sizeof(uint64_t), [NFTNL_CHAIN_FAMILY] = sizeof(uint32_t), + [NFTNL_CHAIN_FLAGS] = sizeof(uint32_t), + [NFTNL_CHAIN_ID] = sizeof(uint32_t), }; 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); switch(attr) { case NFTNL_CHAIN_NAME: - if (c->flags & (1 << NFTNL_CHAIN_NAME)) - xfree(c->name); - - c->name = strdup(data); - if (!c->name) - return -1; - break; + return nftnl_set_str_attr(&c->name, &c->flags, + attr, data, data_len); case NFTNL_CHAIN_TABLE: - if (c->flags & (1 << NFTNL_CHAIN_TABLE)) - xfree(c->table); - - c->table = strdup(data); - if (!c->table) - return -1; - break; + return nftnl_set_str_attr(&c->table, &c->flags, + attr, data, data_len); case NFTNL_CHAIN_HOOKNUM: memcpy(&c->hooknum, data, sizeof(c->hooknum)); break; @@ -225,27 +247,53 @@ int nftnl_chain_set_data(struct nftnl_chain *c, uint16_t attr, memcpy(&c->family, data, sizeof(c->family)); break; case NFTNL_CHAIN_TYPE: - if (c->flags & (1 << NFTNL_CHAIN_TYPE)) - xfree(c->type); + return nftnl_set_str_attr(&c->type, &c->flags, + attr, data, data_len); + case NFTNL_CHAIN_DEV: + 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->type = strdup(data); - if (!c->type) + 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; - case NFTNL_CHAIN_DEV: - if (c->flags & (1 << NFTNL_CHAIN_DEV)) - xfree(c->dev); + case NFTNL_CHAIN_FLAGS: + memcpy(&c->chain_flags, data, sizeof(c->chain_flags)); + break; + 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->dev = strdup(data); - if (!c->dev) + 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; } -EXPORT_SYMBOL(nftnl_chain_set); +void nftnl_chain_set(struct nftnl_chain *c, uint16_t attr, const void *data) __visible; void nftnl_chain_set(struct nftnl_chain *c, uint16_t attr, const void *data) { nftnl_chain_set_data(c, attr, data, nftnl_chain_validate[attr]); @@ -281,6 +329,13 @@ int nftnl_chain_set_str(struct nftnl_chain *c, uint16_t attr, const char *str) return nftnl_chain_set_data(c, attr, str, strlen(str) + 1); } +EXPORT_SYMBOL(nftnl_chain_set_array); +int nftnl_chain_set_array(struct nftnl_chain *c, uint16_t attr, + const char **data) +{ + return nftnl_chain_set_data(c, attr, data, 0); +} + EXPORT_SYMBOL(nftnl_chain_get_data); const void *nftnl_chain_get_data(const struct nftnl_chain *c, uint16_t attr, uint32_t *data_len) @@ -325,6 +380,18 @@ 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: + *data_len = 0; + return &c->dev_array[0]; + case NFTNL_CHAIN_FLAGS: + *data_len = sizeof(uint32_t); + return &c->chain_flags; + 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; } @@ -386,32 +453,63 @@ uint8_t nftnl_chain_get_u8(const struct nftnl_chain *c, uint16_t attr) return val ? *val : 0; } +EXPORT_SYMBOL(nftnl_chain_get_array); +const char *const *nftnl_chain_get_array(const struct nftnl_chain *c, uint16_t attr) +{ + uint32_t data_len; + const char * const *val = nftnl_chain_get_data(c, attr, &data_len); + + nftnl_assert(val, attr, attr == NFTNL_CHAIN_DEVICES); + + return val; +} + EXPORT_SYMBOL(nftnl_chain_nlmsg_build_payload); void nftnl_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_chain *c) { + struct nlattr *nest = NULL; + 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)) mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME, c->name); - if ((c->flags & (1 << NFTNL_CHAIN_HOOKNUM)) && - (c->flags & (1 << NFTNL_CHAIN_PRIO))) { - struct nlattr *nest; + if ((c->flags & (1 << NFTNL_CHAIN_HOOKNUM)) || + (c->flags & (1 << NFTNL_CHAIN_PRIO)) || + (c->flags & (1 << NFTNL_CHAIN_DEV)) || + (c->flags & (1 << NFTNL_CHAIN_DEVICES))) nest = mnl_attr_nest_start(nlh, NFTA_CHAIN_HOOK); + + if ((c->flags & (1 << NFTNL_CHAIN_HOOKNUM))) mnl_attr_put_u32(nlh, NFTA_HOOK_HOOKNUM, htonl(c->hooknum)); + if ((c->flags & (1 << NFTNL_CHAIN_PRIO))) 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); - mnl_attr_nest_end(nlh, nest); + + 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); } + + if ((c->flags & (1 << NFTNL_CHAIN_HOOKNUM)) || + (c->flags & (1 << NFTNL_CHAIN_PRIO)) || + (c->flags & (1 << NFTNL_CHAIN_DEV)) || + (c->flags & (1 << NFTNL_CHAIN_DEVICES))) + mnl_attr_nest_end(nlh, nest); + if (c->flags & (1 << NFTNL_CHAIN_POLICY)) mnl_attr_put_u32(nlh, NFTA_CHAIN_POLICY, htonl(c->policy)); if (c->flags & (1 << NFTNL_CHAIN_USE)) mnl_attr_put_u32(nlh, NFTA_CHAIN_USE, htonl(c->use)); if ((c->flags & (1 << NFTNL_CHAIN_PACKETS)) && (c->flags & (1 << NFTNL_CHAIN_BYTES))) { - struct nlattr *nest; - nest = mnl_attr_nest_start(nlh, NFTA_CHAIN_COUNTERS); mnl_attr_put_u64(nlh, NFTA_COUNTER_PACKETS, be64toh(c->packets)); mnl_attr_put_u64(nlh, NFTA_COUNTER_BYTES, be64toh(c->bytes)); @@ -421,6 +519,12 @@ void nftnl_chain_nlmsg_build_payload(struct nlmsghdr *nlh, const struct nftnl_ch mnl_attr_put_u64(nlh, NFTA_CHAIN_HANDLE, be64toh(c->handle)); if (c->flags & (1 << NFTNL_CHAIN_TYPE)) mnl_attr_put_strz(nlh, NFTA_CHAIN_TYPE, c->type); + if (c->flags & (1 << NFTNL_CHAIN_FLAGS)) + 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); @@ -475,6 +579,8 @@ static int nftnl_chain_parse_attr_cb(const struct nlattr *attr, void *data) break; case NFTA_CHAIN_POLICY: case NFTA_CHAIN_USE: + case NFTA_CHAIN_FLAGS: + case NFTA_CHAIN_ID: if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) abi_breakage(); break; @@ -482,6 +588,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; @@ -551,9 +661,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, **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] = {}; + int ret; if (mnl_attr_parse_nested(attr, nftnl_chain_parse_hook_cb, tb) < 0) return -1; @@ -572,6 +719,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; } @@ -632,6 +785,19 @@ int nftnl_chain_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_chain *c) return -1; c->flags |= (1 << NFTNL_CHAIN_TYPE); } + if (tb[NFTA_CHAIN_FLAGS]) { + c->chain_flags = ntohl(mnl_attr_get_u32(tb[NFTA_CHAIN_FLAGS])); + c->flags |= (1 << NFTNL_CHAIN_FLAGS); + } + if (tb[NFTA_CHAIN_ID]) { + 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); @@ -650,10 +816,10 @@ static inline int nftnl_str2hooknum(int family, const char *hook) return -1; } -static int nftnl_chain_snprintf_default(char *buf, size_t size, +static int nftnl_chain_snprintf_default(char *buf, size_t remain, const struct nftnl_chain *c) { - int ret, remain = size, offset = 0; + int ret, offset = 0, i; ret = snprintf(buf, remain, "%s %s %s use %u", nftnl_family2str(c->family), c->table, c->name, c->use); @@ -681,28 +847,44 @@ 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); + } + if (c->flags & (1 << NFTNL_CHAIN_FLAGS)) { + ret = snprintf(buf + offset, remain, " flags %x", + c->chain_flags); + SNPRINTF_BUFFER_SIZE(ret, remain, offset); + } + if (c->flags & (1 << NFTNL_CHAIN_ID)) { + ret = snprintf(buf + offset, remain, " id %x", + c->chain_id); + SNPRINTF_BUFFER_SIZE(ret, remain, offset); + } } return offset; } -static int nftnl_chain_cmd_snprintf(char *buf, size_t size, +static int nftnl_chain_cmd_snprintf(char *buf, size_t remain, const struct nftnl_chain *c, uint32_t cmd, uint32_t type, uint32_t flags) { - int ret, remain = size, offset = 0; + int ret, offset = 0; - switch (type) { - case NFTNL_OUTPUT_DEFAULT: - ret = nftnl_chain_snprintf_default(buf + offset, remain, c); - SNPRINTF_BUFFER_SIZE(ret, remain, offset); - break; - case NFTNL_OUTPUT_XML: - case NFTNL_OUTPUT_JSON: - default: + if (type != NFTNL_OUTPUT_DEFAULT) return -1; - } + ret = nftnl_chain_snprintf_default(buf + offset, remain, c); + SNPRINTF_BUFFER_SIZE(ret, remain, offset); return offset; } |