diff options
Diffstat (limited to 'src/netlink.c')
-rw-r--r-- | src/netlink.c | 127 |
1 files changed, 79 insertions, 48 deletions
diff --git a/src/netlink.c b/src/netlink.c index f1452d48..0088b742 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -9,12 +9,12 @@ * Development of this code funded by Astaro AG (http://www.astaro.com/) */ -#include <string.h> +#include <nft.h> + #include <errno.h> #include <libmnl/libmnl.h> #include <netinet/in.h> #include <arpa/inet.h> -#include <stdlib.h> #include <inttypes.h> #include <libnftnl/table.h> @@ -254,6 +254,11 @@ static int netlink_export_pad(unsigned char *data, const mpz_t v, return netlink_padded_len(i->len) / BITS_PER_BYTE; } +static void byteorder_switch_expr_value(mpz_t v, const struct expr *e) +{ + mpz_switch_byteorder(v, div_round_up(e->len, BITS_PER_BYTE)); +} + static int __netlink_gen_concat_key(uint32_t flags, const struct expr *i, unsigned char *data) { @@ -268,7 +273,7 @@ static int __netlink_gen_concat_key(uint32_t flags, const struct expr *i, if (expr_basetype(expr)->type == TYPE_INTEGER && expr->byteorder == BYTEORDER_HOST_ENDIAN) - mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE); + byteorder_switch_expr_value(expr->value, expr); i = expr; break; @@ -280,7 +285,7 @@ static int __netlink_gen_concat_key(uint32_t flags, const struct expr *i, mpz_init_bitmask(v, i->len - i->prefix_len); if (i->byteorder == BYTEORDER_HOST_ENDIAN) - mpz_switch_byteorder(v, i->len / BITS_PER_BYTE); + byteorder_switch_expr_value(v, i); mpz_add(v, i->prefix->value, v); count = netlink_export_pad(data, v, i); @@ -298,7 +303,7 @@ static int __netlink_gen_concat_key(uint32_t flags, const struct expr *i, expr = (struct expr *)i; if (expr_basetype(expr)->type == TYPE_INTEGER && expr->byteorder == BYTEORDER_HOST_ENDIAN) - mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE); + byteorder_switch_expr_value(expr->value, expr); break; default: BUG("invalid expression type '%s' in set", expr_ops(i)->name); @@ -307,6 +312,16 @@ static int __netlink_gen_concat_key(uint32_t flags, const struct expr *i, return netlink_export_pad(data, i->value, i); } +static void nft_data_memcpy(struct nft_data_linearize *nld, + const void *src, unsigned int len) +{ + if (len > sizeof(nld->value)) + BUG("nld buffer overflow: want to copy %u, max %u\n", len, (unsigned int)sizeof(nld->value)); + + memcpy(nld->value, src, len); + nld->len = len; +} + static void netlink_gen_concat_key(const struct expr *expr, struct nft_data_linearize *nld) { @@ -319,8 +334,7 @@ static void netlink_gen_concat_key(const struct expr *expr, list_for_each_entry(i, &expr->expressions, list) offset += __netlink_gen_concat_key(expr->flags, i, data + offset); - memcpy(nld->value, data, len); - nld->len = len; + nft_data_memcpy(nld, data, len); } static int __netlink_gen_concat_data(int end, const struct expr *i, @@ -366,8 +380,7 @@ static void __netlink_gen_concat_expand(const struct expr *expr, list_for_each_entry(i, &expr->expressions, list) offset += __netlink_gen_concat_data(true, i, data + offset); - memcpy(nld->value, data, len); - nld->len = len; + nft_data_memcpy(nld, data, len); } static void __netlink_gen_concat(const struct expr *expr, @@ -382,8 +395,7 @@ static void __netlink_gen_concat(const struct expr *expr, list_for_each_entry(i, &expr->expressions, list) offset += __netlink_gen_concat_data(expr->flags, i, data + offset); - memcpy(nld->value, data, len); - nld->len = len; + nft_data_memcpy(nld, data, len); } static void netlink_gen_concat_data(const struct expr *expr, @@ -452,26 +464,27 @@ static void netlink_gen_range(const struct expr *expr, memset(data, 0, len); offset = netlink_export_pad(data, expr->left->value, expr->left); netlink_export_pad(data + offset, expr->right->value, expr->right); - memcpy(nld->value, data, len); - nld->len = len; + nft_data_memcpy(nld, data, len); } static void netlink_gen_prefix(const struct expr *expr, struct nft_data_linearize *nld) { - unsigned int len = div_round_up(expr->len, BITS_PER_BYTE) * 2; - unsigned char data[len]; + unsigned int len = (netlink_padded_len(expr->len) / BITS_PER_BYTE) * 2; + unsigned char data[NFT_MAX_EXPR_LEN_BYTES]; int offset; mpz_t v; + if (len > sizeof(data)) + BUG("Value export of %u bytes would overflow", len); + offset = netlink_export_pad(data, expr->prefix->value, expr); mpz_init_bitmask(v, expr->len - expr->prefix_len); mpz_add(v, expr->prefix->value, v); netlink_export_pad(data + offset, v, expr->prefix); mpz_clear(v); - memcpy(nld->value, data, len); - nld->len = len; + nft_data_memcpy(nld, data, len); } static void netlink_gen_key(const struct expr *expr, @@ -617,18 +630,20 @@ static int qsort_device_cmp(const void *a, const void *b) struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx, const struct nftnl_chain *nlc) { - const struct nftnl_udata *ud[NFTNL_UDATA_OBJ_MAX + 1] = {}; + const struct nftnl_udata *ud[NFTNL_UDATA_CHAIN_MAX + 1] = {}; int priority, policy, len = 0, i; const char * const *dev_array; struct chain *chain; const char *udata; uint32_t ulen; - chain = chain_alloc(nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME)); + chain = chain_alloc(); chain->handle.family = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FAMILY); chain->handle.table.name = xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_TABLE)); + chain->handle.chain.name = + xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME)); chain->handle.handle.id = nftnl_chain_get_u64(nlc, NFTNL_CHAIN_HANDLE); if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_FLAGS)) @@ -795,13 +810,17 @@ enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype) static const struct datatype *dtype_map_from_kernel(enum nft_data_types type) { + /* The function always returns ownership of a reference. But for + * &verdict_Type and datatype_lookup(), those are static instances, + * we can omit the datatype_get() call. + */ switch (type) { case NFT_DATA_VERDICT: return &verdict_type; default: if (type & ~TYPE_MASK) return concat_type_alloc(type); - return datatype_lookup(type); + return datatype_lookup((enum datatypes) type); } } @@ -871,8 +890,8 @@ static struct expr *set_make_key(const struct nftnl_udata *attr) { const struct nftnl_udata *ud[NFTNL_UDATA_SET_TYPEOF_MAX + 1] = {}; const struct expr_ops *ops; - enum expr_types etype; struct expr *expr; + uint32_t etype; int err; if (!attr) @@ -888,7 +907,9 @@ static struct expr *set_make_key(const struct nftnl_udata *attr) return NULL; etype = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_TYPEOF_EXPR]); - ops = expr_ops_by_type(etype); + ops = expr_ops_by_type_u32(etype); + if (!ops) + return NULL; expr = ops->parse_udata(ud[NFTNL_UDATA_SET_TYPEOF_DATA]); if (!expr) @@ -930,21 +951,21 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx, const struct nftnl_udata *ud[NFTNL_UDATA_SET_MAX + 1] = {}; enum byteorder keybyteorder = BYTEORDER_INVALID; enum byteorder databyteorder = BYTEORDER_INVALID; - const struct datatype *keytype, *datatype = NULL; - struct expr *typeof_expr_key, *typeof_expr_data; struct setelem_parse_ctx set_parse_ctx; + const struct datatype *datatype = NULL; + const struct datatype *keytype = NULL; + const struct datatype *dtype2 = NULL; + const struct datatype *dtype = NULL; + struct expr *typeof_expr_data = NULL; + struct expr *typeof_expr_key = NULL; const char *udata, *comment = NULL; uint32_t flags, key, objtype = 0; - const struct datatype *dtype; uint32_t data_interval = 0; bool automerge = false; struct set *set; uint32_t ulen; uint32_t klen; - typeof_expr_key = NULL; - typeof_expr_data = NULL; - if (nftnl_set_is_set(nls, NFTNL_SET_USERDATA)) { udata = nftnl_set_get_data(nls, NFTNL_SET_USERDATA, &ulen); if (nftnl_udata_parse(udata, ulen, set_parse_udata_cb, ud) < 0) { @@ -987,8 +1008,8 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx, netlink_io_error(ctx, NULL, "Unknown data type in set key %u", data); - datatype_free(keytype); - return NULL; + set = NULL; + goto out; } } @@ -1023,17 +1044,28 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx, } list_splice_tail(&set_parse_ctx.stmt_list, &set->stmt_list); + set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS); + if (datatype) { - dtype = set_datatype_alloc(datatype, databyteorder); + uint32_t dlen; + + dtype2 = set_datatype_alloc(datatype, databyteorder); klen = nftnl_set_get_u32(nls, NFTNL_SET_DATA_LEN) * BITS_PER_BYTE; - if (set_udata_key_valid(typeof_expr_data, klen)) { - datatype_free(datatype_get(dtype)); + dlen = data_interval ? klen / 2 : klen; + + if (set_udata_key_valid(typeof_expr_data, dlen)) { + typeof_expr_data->len = klen; set->data = typeof_expr_data; + typeof_expr_data = NULL; + } else if (set->flags & NFT_SET_OBJECT) { + set->data = constant_expr_alloc(&netlink_location, + dtype2, + databyteorder, klen, + NULL); } else { - expr_free(typeof_expr_data); set->data = constant_expr_alloc(&netlink_location, - dtype, + dtype2, databyteorder, klen, NULL); @@ -1044,29 +1076,21 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx, if (data_interval) set->data->flags |= EXPR_F_INTERVAL; - - if (dtype != datatype) - datatype_free(datatype); } dtype = set_datatype_alloc(keytype, keybyteorder); klen = nftnl_set_get_u32(nls, NFTNL_SET_KEY_LEN) * BITS_PER_BYTE; if (set_udata_key_valid(typeof_expr_key, klen)) { - datatype_free(datatype_get(dtype)); set->key = typeof_expr_key; + typeof_expr_key = NULL; set->key_typeof_valid = true; } else { - expr_free(typeof_expr_key); set->key = constant_expr_alloc(&netlink_location, dtype, keybyteorder, klen, NULL); } - if (dtype != keytype) - datatype_free(keytype); - - set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS); set->handle.handle.id = nftnl_set_get_u64(nls, NFTNL_SET_HANDLE); set->objtype = objtype; @@ -1093,6 +1117,13 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx, } } +out: + expr_free(typeof_expr_data); + expr_free(typeof_expr_key); + datatype_free(datatype); + datatype_free(keytype); + datatype_free(dtype2); + datatype_free(dtype); return set; } @@ -1510,7 +1541,7 @@ static int list_setelements(struct nftnl_set *s, struct netlink_ctx *ctx) } int netlink_list_setelems(struct netlink_ctx *ctx, const struct handle *h, - struct set *set) + struct set *set, bool reset) { struct nftnl_set *nls; int err; @@ -1525,7 +1556,7 @@ int netlink_list_setelems(struct netlink_ctx *ctx, const struct handle *h, if (h->handle.id) nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id); - err = mnl_nft_setelem_get(ctx, nls); + err = mnl_nft_setelem_get(ctx, nls, reset); if (err < 0) { nftnl_set_free(nls); if (errno == EINTR) @@ -1553,7 +1584,7 @@ int netlink_list_setelems(struct netlink_ctx *ctx, const struct handle *h, int netlink_get_setelem(struct netlink_ctx *ctx, const struct handle *h, const struct location *loc, struct set *cache_set, - struct set *set, struct expr *init) + struct set *set, struct expr *init, bool reset) { struct nftnl_set *nls, *nls_out = NULL; int err = 0; @@ -1572,7 +1603,7 @@ int netlink_get_setelem(struct netlink_ctx *ctx, const struct handle *h, netlink_dump_set(nls, ctx); - nls_out = mnl_nft_setelem_get_one(ctx, nls); + nls_out = mnl_nft_setelem_get_one(ctx, nls, reset); if (!nls_out) { nftnl_set_free(nls); return -1; |