]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
netlink: fix dictionary feature with data mappings
authorPablo Neira Ayuso <pablo@netfilter.org>
Fri, 27 Dec 2013 11:48:40 +0000 (12:48 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sat, 28 Dec 2013 22:05:36 +0000 (23:05 +0100)
This patch fixes dictionary feature, that allows you to conditionally
set packet fields based on a given selector, eg.

 add rule ip filter input meta dnat set tcp dport map { 22 => 1.1.1.1, 23 => 2.2.2.2 }

This means that traffic flowing to tcp port 22 is dnatted to address
1.1.1.1 and tcp port 23 is dnatted to address 2.2.2.2.

This feature was partially broken by aae836a ("src: use libnftables")
although it also needs the kernel fix ("netfilter: nf_tables: fix wrong
datatype in nft_validate_data_load()").

This patch also fixes endianness issues when displaying the mark
via `list table' related to list_setelem_cb() since the byteorder
was left unset for the data part of a set element.

 meta mark set tcp dport map { telnet => 0x02000000, ssh => 0x01000000}
                                            ^                  ^
Note the wrong endianness in the example above.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/netlink.c

index cab8cf4b51fa584452550dd86ea92578b7a508e6..59bd8e4986eb043675ed1026900722bd1106acb5 100644 (file)
@@ -157,13 +157,22 @@ static struct nft_set_elem *alloc_nft_setelem(const struct expr *expr)
                nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_KEY,
                                      &nld.value, nld.len);
                netlink_gen_data(expr->right, &nld);
-               if (expr->right->ops->type == EXPR_VERDICT) {
+               switch (expr->right->ops->type) {
+               case EXPR_VERDICT:
                        nft_set_elem_attr_set_u32(nlse, NFT_SET_ELEM_ATTR_VERDICT,
                                                  expr->right->verdict);
                        if (expr->chain != NULL) {
                                nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_CHAIN,
                                                nld.chain, strlen(nld.chain));
                        }
+                       break;
+               case EXPR_VALUE:
+                       nft_set_elem_attr_set(nlse, NFT_SET_ELEM_ATTR_DATA,
+                                             nld.value, nld.len);
+                       break;
+               default:
+                       BUG("unexpected set element expression\n");
+                       break;
                }
        }
 
@@ -994,6 +1003,9 @@ static int list_setelem_cb(struct nft_set_elem *nlse, void *arg)
                                          set->datatype->type == TYPE_VERDICT ?
                                          NFT_REG_VERDICT : NFT_REG_1);
                data->dtype = set->datatype;
+               data->byteorder = set->datatype->byteorder;
+               if (data->byteorder == BYTEORDER_HOST_ENDIAN)
+                       mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE);
 
                expr = mapping_expr_alloc(&internal_location, expr, data);
        }