]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
netlink: Introduce struct nft_data_linearize::byteorder
authorPhil Sutter <phil@nwl.cc>
Thu, 13 Nov 2025 16:11:15 +0000 (17:11 +0100)
committerPhil Sutter <phil@nwl.cc>
Tue, 27 Jan 2026 22:01:54 +0000 (23:01 +0100)
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 <phil@nwl.cc>
include/netlink.h
src/netlink.c

index 2737d5708b2956391b451bd66d8baebf68da6484..a762cb485784fbcb9fdaa322a8110ac3f3d912f0 100644 (file)
@@ -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 {
index 26cf07c3792617b165e75582d7be31d4e340ec2e..3a512753c762477c6abeb089be8d38f3f76e0209 100644 (file)
@@ -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,