Bits in this field indicate data is in host byte order and thus may need conversion when being printed "byte-by-byte" in libnftnl. With regular immediate values, this field's value has boolean properties (if non-zero, data is in host byte order). Concatenations may contain components in different byte order, so with them each bit (at index N) indicates whether a component (at the same index) is in host byte order. Communicate a possible byte order conversion in __netlink_gen_concat_key() back to caller since this has to be respected when setting 'byteorder' field in struct nft_data_linearize. String-based values are special: While defined as being in host byte order in nftables, libnftnl shall print them without prior conversion like Big Endian values. Signed-off-by: Phil Sutter --- include/netlink.h | 1 + src/netlink.c | 60 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/include/netlink.h b/include/netlink.h index 2737d5708b295..a762cb485784f 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -106,6 +106,7 @@ struct nft_data_linearize { char chain[NFT_CHAIN_MAXNAMELEN]; uint32_t chain_id; int verdict; + uint32_t byteorder; }; struct nft_data_delinearize { diff --git a/src/netlink.c b/src/netlink.c index 26cf07c379261..3a512753c7624 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -248,6 +248,7 @@ void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder, assert(len > 0); mpz_export_data(data->value, value, byteorder, len); data->len = len; + data->byteorder = byteorder == BYTEORDER_HOST_ENDIAN ? UINT32_MAX : 0; } static int netlink_export_pad(unsigned char *data, const mpz_t v, @@ -265,12 +266,15 @@ static void byteorder_switch_expr_value(mpz_t v, const struct expr *e) } static int __netlink_gen_concat_key(uint32_t flags, const struct expr *i, - unsigned char *data) + unsigned char *data, + enum byteorder *byteorder) { struct expr *expr; mpz_t value; int ret; + *byteorder = i->byteorder; + switch (i->etype) { case EXPR_RANGE: if (flags & EXPR_F_INTERVAL_END) @@ -281,8 +285,10 @@ static int __netlink_gen_concat_key(uint32_t flags, const struct expr *i, mpz_init_set(value, expr->value); if (expr_basetype(expr)->type == TYPE_INTEGER && - expr->byteorder == BYTEORDER_HOST_ENDIAN) + expr->byteorder == BYTEORDER_HOST_ENDIAN) { byteorder_switch_expr_value(value, expr); + *byteorder = BYTEORDER_BIG_ENDIAN; + } i = expr; break; @@ -293,8 +299,10 @@ static int __netlink_gen_concat_key(uint32_t flags, const struct expr *i, mpz_init_set(value, i->range.low); if (expr_basetype(i)->type == TYPE_INTEGER && - i->byteorder == BYTEORDER_HOST_ENDIAN) + i->byteorder == BYTEORDER_HOST_ENDIAN) { byteorder_switch_expr_value(value, i); + *byteorder = BYTEORDER_BIG_ENDIAN; + } break; case EXPR_PREFIX: @@ -304,8 +312,10 @@ 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) + if (i->byteorder == BYTEORDER_HOST_ENDIAN) { byteorder_switch_expr_value(v, i); + *byteorder = BYTEORDER_BIG_ENDIAN; + } mpz_add(v, i->prefix->value, v); count = netlink_export_pad(data, v, i); @@ -323,9 +333,12 @@ static int __netlink_gen_concat_key(uint32_t flags, const struct expr *i, break; expr = (struct expr *)i; + if (expr_basetype(expr)->type == TYPE_INTEGER && - expr->byteorder == BYTEORDER_HOST_ENDIAN) + expr->byteorder == BYTEORDER_HOST_ENDIAN) { byteorder_switch_expr_value(value, expr); + *byteorder = BYTEORDER_BIG_ENDIAN; + } break; default: BUG("invalid expression type '%s' in set", expr_ops(i)->name); @@ -353,16 +366,24 @@ static void netlink_gen_concat_key(const struct expr *expr, { unsigned int len = netlink_padded_len(expr->len) / BITS_PER_BYTE; unsigned char data[NFT_MAX_EXPR_LEN_BYTES]; + enum byteorder byteorder; unsigned int offset = 0; const struct expr *i; + int n = 0; if (len > sizeof(data)) BUG("Value export of %u bytes would overflow", len); memset(data, 0, sizeof(data)); - list_for_each_entry(i, &expr_concat(expr)->expressions, list) - offset += __netlink_gen_concat_key(expr->flags, i, data + offset); + list_for_each_entry(i, &expr_concat(expr)->expressions, list) { + offset += __netlink_gen_concat_key(expr->flags, i, + data + offset, &byteorder); + if (byteorder == BYTEORDER_HOST_ENDIAN && + expr_basetype(i)->type != TYPE_STRING) + nld->byteorder |= 1 << n; + n++; + } nft_data_memcpy(nld, data, len); } @@ -419,17 +440,28 @@ static void __netlink_gen_concat_expand(const struct expr *expr, unsigned char data[NFT_MAX_EXPR_LEN_BYTES]; unsigned int offset = 0; const struct expr *i; + int n = 0; if (len > sizeof(data)) BUG("Value export of %u bytes would overflow", len); memset(data, 0, sizeof(data)); - list_for_each_entry(i, &expr_concat(expr)->expressions, list) + list_for_each_entry(i, &expr_concat(expr)->expressions, list) { offset += __netlink_gen_concat_data(false, i, data + offset); + if (i->byteorder == BYTEORDER_HOST_ENDIAN && + expr_basetype(i)->type != TYPE_STRING) + nld->byteorder |= 1 << n; + n++; + } - list_for_each_entry(i, &expr_concat(expr)->expressions, list) + list_for_each_entry(i, &expr_concat(expr)->expressions, list) { offset += __netlink_gen_concat_data(true, i, data + offset); + if (i->byteorder == BYTEORDER_HOST_ENDIAN && + expr_basetype(i)->type != TYPE_STRING) + nld->byteorder |= 1 << n; + n++; + } nft_data_memcpy(nld, data, len); } @@ -441,14 +473,20 @@ static void __netlink_gen_concat(const struct expr *expr, unsigned char data[NFT_MAX_EXPR_LEN_BYTES]; unsigned int offset = 0; const struct expr *i; + int n = 0; if (len > sizeof(data)) BUG("Value export of %u bytes would overflow", len); memset(data, 0, sizeof(data)); - list_for_each_entry(i, &expr_concat(expr)->expressions, list) + list_for_each_entry(i, &expr_concat(expr)->expressions, list) { offset += __netlink_gen_concat_data(expr->flags, i, data + offset); + if (i->byteorder == BYTEORDER_HOST_ENDIAN && + expr_basetype(i)->type != TYPE_STRING) + nld->byteorder |= 1 << n; + n++; + } nft_data_memcpy(nld, data, len); } @@ -468,6 +506,8 @@ static void netlink_gen_constant_data(const struct expr *expr, assert(expr->etype == EXPR_VALUE); netlink_gen_raw_data(expr->value, expr->byteorder, div_round_up(expr->len, BITS_PER_BYTE), data); + if (expr_basetype(expr)->type == TYPE_STRING) + data->byteorder = 0; } static void netlink_gen_chain(const struct expr *expr, -- 2.51.0