Consolidate prefix calculation in range_expr_is_prefix(). Add tests/py for 9208fb30dc49 ("src: Check range bounds before converting to prefix"). Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- src/netlink.c | 66 ++++++++++++++++-------------- tests/py/ip/snat.t | 2 + tests/py/ip/snat.t.json | 84 ++++++++++++++++++++++++++++++++++++++ tests/py/ip/snat.t.payload | 26 ++++++++++++ 4 files changed, 148 insertions(+), 30 deletions(-) diff --git a/src/netlink.c b/src/netlink.c index 0fd0b6647643..9a0d96f0b546 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -1048,48 +1048,54 @@ void alloc_setelem_cache(const struct expr *set, struct nftnl_set *nls) } } -static bool mpz_bitmask_is_prefix(mpz_t bitmask, uint32_t len) +static bool range_expr_is_prefix(const struct expr *range, uint32_t *prefix_len) { + const struct expr *right = range->right; + const struct expr *left = range->left; + uint32_t len = left->len; unsigned long n1, n2; + uint32_t plen; + mpz_t bitmask; - n1 = mpz_scan0(bitmask, 0); - if (n1 == ULONG_MAX) - return false; + mpz_init2(bitmask, left->len); + mpz_xor(bitmask, left->value, right->value); - n2 = mpz_scan1(bitmask, n1 + 1); - if (n2 < len) - return false; + n1 = mpz_scan0(bitmask, 0); + if (n1 == ULONG_MAX) + goto not_a_prefix; - return true; -} + n2 = mpz_scan1(bitmask, n1 + 1); + if (n2 < len) + goto not_a_prefix; -static uint32_t mpz_bitmask_to_prefix(mpz_t bitmask, uint32_t len) -{ - return len - mpz_scan0(bitmask, 0); + plen = len - n1; + + if (mpz_scan1(left->value, 0) < len - plen) + goto not_a_prefix; + + mpz_clear(bitmask); + *prefix_len = plen; + + return true; + +not_a_prefix: + mpz_clear(bitmask); + + return false; } struct expr *range_expr_to_prefix(struct expr *range) { - struct expr *left = range->left, *right = range->right, *prefix; - uint32_t len = left->len, prefix_len; - mpz_t bitmask; - - mpz_init2(bitmask, len); - mpz_xor(bitmask, left->value, right->value); + struct expr *prefix; + uint32_t prefix_len; - if (mpz_bitmask_is_prefix(bitmask, len)) { - prefix_len = mpz_bitmask_to_prefix(bitmask, len); - if (mpz_scan1(left->value, 0) >= len - prefix_len) { - prefix = prefix_expr_alloc(&range->location, - expr_get(left), - prefix_len); - mpz_clear(bitmask); - expr_free(range); - - return prefix; - } + if (range_expr_is_prefix(range, &prefix_len)) { + prefix = prefix_expr_alloc(&range->location, + expr_get(range->left), + prefix_len); + expr_free(range); + return prefix; } - mpz_clear(bitmask); return range; } diff --git a/tests/py/ip/snat.t b/tests/py/ip/snat.t index 38acf52ffe09..a8ff8d1a00c1 100644 --- a/tests/py/ip/snat.t +++ b/tests/py/ip/snat.t @@ -6,6 +6,8 @@ iifname "eth0" tcp dport 80-90 snat to 192.168.3.2;ok iifname "eth0" tcp dport != 80-90 snat to 192.168.3.2;ok iifname "eth0" tcp dport {80, 90, 23} snat to 192.168.3.2;ok iifname "eth0" tcp dport != {80, 90, 23} snat to 192.168.3.2;ok +iifname "eth0" tcp dport 80-90 snat to 192.168.3.0-192.168.3.255;ok;iifname "eth0" tcp dport 80-90 snat to 192.168.3.0/24 +iifname "eth0" tcp dport 80-90 snat to 192.168.3.15-192.168.3.240;ok iifname "eth0" tcp dport != 23-34 snat to 192.168.3.2;ok diff --git a/tests/py/ip/snat.t.json b/tests/py/ip/snat.t.json index 0e1485faedfc..0813086c8405 100644 --- a/tests/py/ip/snat.t.json +++ b/tests/py/ip/snat.t.json @@ -166,6 +166,90 @@ } ] +# iifname "eth0" tcp dport 80-90 snat to 192.168.3.0-192.168.3.255 +[ + { + "match": { + "left": { + "meta": { + "key": "iifname" + } + }, + "op": "==", + "right": "eth0" + } + }, + { + "match": { + "left": { + "payload": { + "field": "dport", + "protocol": "tcp" + } + }, + "op": "==", + "right": { + "range": [ + 80, + 90 + ] + } + } + }, + { + "snat": { + "addr": { + "prefix": { + "addr": "192.168.3.0", + "len": 24 + } + } + } + } +] + +# iifname "eth0" tcp dport 80-90 snat to 192.168.3.15-192.168.3.240 +[ + { + "match": { + "left": { + "meta": { + "key": "iifname" + } + }, + "op": "==", + "right": "eth0" + } + }, + { + "match": { + "left": { + "payload": { + "field": "dport", + "protocol": "tcp" + } + }, + "op": "==", + "right": { + "range": [ + 80, + 90 + ] + } + } + }, + { + "snat": { + "addr": { + "range": [ + "192.168.3.15", + "192.168.3.240" + ] + } + } + } +] + # snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 } [ { diff --git a/tests/py/ip/snat.t.payload b/tests/py/ip/snat.t.payload index 58b1c1a484eb..64f478964a40 100644 --- a/tests/py/ip/snat.t.payload +++ b/tests/py/ip/snat.t.payload @@ -60,6 +60,32 @@ ip test-ip4 postrouting [ immediate reg 1 0x0203a8c0 ] [ nat snat ip addr_min reg 1 ] +# iifname "eth0" tcp dport 80-90 snat to 192.168.3.0-192.168.3.255 +ip + [ meta load iifname => reg 1 ] + [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ] + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000006 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp gte reg 1 0x00005000 ] + [ cmp lte reg 1 0x00005a00 ] + [ immediate reg 1 0x0003a8c0 ] + [ immediate reg 2 0xff03a8c0 ] + [ nat snat ip addr_min reg 1 addr_max reg 2 ] + +# iifname "eth0" tcp dport 80-90 snat to 192.168.3.15-192.168.3.240 +ip + [ meta load iifname => reg 1 ] + [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ] + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000006 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp gte reg 1 0x00005000 ] + [ cmp lte reg 1 0x00005a00 ] + [ immediate reg 1 0x0f03a8c0 ] + [ immediate reg 2 0xf003a8c0 ] + [ nat snat ip addr_min reg 1 addr_max reg 2 ] + # snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 } __map%d test-ip4 b size 1 __map%d test-ip4 0 -- 2.20.1