summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2021-09-06 22:04:51 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2021-09-09 01:13:47 +0200
commit34f31e741d961b059a990579c2402dc39981e1e8 (patch)
tree5fd872e9d48bd603d2078165aeebe6b6e969f0da
parent10105b3fb0123dd4bb84e39f0611102247765b7b (diff)
netlink: rework range_expr_to_prefix()
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@netfilter.org>
-rw-r--r--src/netlink.c66
-rw-r--r--tests/py/ip/snat.t2
-rw-r--r--tests/py/ip/snat.t.json84
-rw-r--r--tests/py/ip/snat.t.payload26
4 files changed, 148 insertions, 30 deletions
diff --git a/src/netlink.c b/src/netlink.c
index 0fd0b664..9a0d96f0 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 38acf52f..a8ff8d1a 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 0e1485fa..0813086c 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 58b1c1a4..64f47896 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