All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nft 0/6] allow s/dnat to map to both addr and port
@ 2020-02-24  0:03 Florian Westphal
  2020-02-24  0:03 ` [PATCH nft 1/6] tests: add initial nat map test Florian Westphal
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Florian Westphal @ 2020-02-24  0:03 UTC (permalink / raw)
  To: netfilter-devel; +Cc: nevola

Right now its not possible to use a map with snat/dnat to alter both
address and port at the same time.

This series teaches nft to accept this:

	map y4 {
		type ipv4_addr : ipv4_addr . inet_service
		elements = { 192.168.7.2 : 10.1.1.1 . 4242 }
	}
 	meta l4proto tcp meta nfproto ipv4 dnat ip to ip saddr map @y4

i.e., it allows:
1. A mapping that contains a concatenated expression.
2. nat expression will peek into set type and detect when
   the mapping is of 'addr + port' type.
   Linearization will compute the register that contains the port
   part of the mapping.
3. Delinarization will figure out when this trick was used by looking
   at the length of the mapping: 64 == ipv4addr+service, 160 == ipv6addr+service.

What does not work:
Anonymous mappings, i.e.
meta l4proto tcp meta nfproto ipv4 dnat ip to ip saddr map { 1.2.3.4 : 1.2.3.5 . 53, ..

doesn't work.  When evaluating "1.2.3.4", this is still a symbol and
unlike with named sets, nft doesn't have a properly declared set type.

This is similar to the 'maps-on-LHS-side' issue.
Phil suggested to allow this:
 ...  to ip saddr map { type ipv4_addr : ipv4_addr . inet_service; 1.2.3.4 : 1.2.3.5 . 53, ..

i.e. re-use the declarative syntax from map code.

Another related issue:
"typeof" doesn't work with concatenations so far.

I don't know when I will have time to look into this more.
I have incomplete patches for concat typeof (udata) support
and a patch to extend the grammar for the proposed { type ... in
anon sets (doesn't cause grammar problems).

I will continue to work on it but don't know yet when I will do so, so
I am sending the finished patches I have at this time.



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH nft 1/6] tests: add initial nat map test
  2020-02-24  0:03 [PATCH nft 0/6] allow s/dnat to map to both addr and port Florian Westphal
@ 2020-02-24  0:03 ` Florian Westphal
  2020-02-24  0:03 ` [PATCH nft 2/6] evaluate: process concat expressions when used as mapped-to expr Florian Westphal
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Florian Westphal @ 2020-02-24  0:03 UTC (permalink / raw)
  To: netfilter-devel; +Cc: nevola, Florian Westphal

Will be extended to cover upcoming
'dnat to ip saddr . tcp dport map { \
  1.2.3.4 . 80 : 5.6.7.8 : 8080,
  2.2.3.4 . 80 : 7.6.7.8 : 1234,
   ...

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 .../testcases/maps/dumps/nat_addr_port.nft    | 13 +++
 tests/shell/testcases/maps/nat_addr_port      | 83 +++++++++++++++++++
 2 files changed, 96 insertions(+)
 create mode 100644 tests/shell/testcases/maps/dumps/nat_addr_port.nft
 create mode 100755 tests/shell/testcases/maps/nat_addr_port

diff --git a/tests/shell/testcases/maps/dumps/nat_addr_port.nft b/tests/shell/testcases/maps/dumps/nat_addr_port.nft
new file mode 100644
index 000000000000..3ed6812e585f
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/nat_addr_port.nft
@@ -0,0 +1,13 @@
+table ip ipfoo {
+	map x {
+		type ipv4_addr : ipv4_addr
+	}
+
+	chain c {
+		type nat hook prerouting priority dstnat; policy accept;
+		iifname != "foobar" accept
+		dnat to ip daddr map @x
+		ip saddr 10.1.1.1 dnat to 10.2.3.4
+		ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
+	}
+}
diff --git a/tests/shell/testcases/maps/nat_addr_port b/tests/shell/testcases/maps/nat_addr_port
new file mode 100755
index 000000000000..77a2f110aeb9
--- /dev/null
+++ b/tests/shell/testcases/maps/nat_addr_port
@@ -0,0 +1,83 @@
+#!/bin/bash
+
+# skeleton
+$NFT -f /dev/stdin <<EOF || exit 1
+table ip ipfoo {
+	map x {
+		type ipv4_addr : ipv4_addr
+	}
+
+	chain c {
+		type nat hook prerouting priority dstnat; policy accept;
+		meta iifname != "foobar" accept
+		dnat to ip daddr map @x
+		ip saddr 10.1.1.1 dnat to 10.2.3.4
+		ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
+	}
+}
+EOF
+
+# should fail: rule has no test for l4 protocol
+$NFT add rule 'ip ipfoo c ip saddr 10.1.1.2 dnat to 10.2.3.4:4242' && exit 1
+
+# should fail: map has wrong family: 4->6
+$NFT add rule 'inet inetfoo c dnat to ip daddr map @x6' && exit 1
+
+# should fail: map has wrong family: 6->4
+$NFT add rule 'inet inetfoo c dnat to ip6 daddr map @x4' && exit 1
+
+# should fail: rule has no test for l4 protocol
+$NFT add rule 'inet inetfoo c ip6 saddr f0:0b::a3 dnat to [1c::3]:42' && exit 1
+
+# should fail: rule has no test for l4 protocol, but map has inet_service
+$NFT add rule 'inet inetfoo c dnat to ip daddr map @y4' && exit 1
+
+# should fail: rule has test for l4 protocol, but map has wrong family: 4->6
+$NFT add rule 'inet inetfoo c meta l4proto tcp dnat to ip daddr map @y6' && exit 1
+
+# should fail: rule has test for l4 protocol, but map has wrong family: 6->4
+$NFT add rule 'inet inetfoo c meta l4proto tcp dnat to ip6 daddr map @y4' && exit 1
+
+# fail: inet_service, but expect ipv4_addr
+$NFT -f /dev/stdin <<EOF && exit 1
+table inet inetfoo {
+	map a {
+		type ipv4_addr : inet_service
+	}
+
+	chain c {
+		type nat hook prerouting priority dstnat; policy accept;
+		meta l4proto tcp dnat ip to ip saddr map @a
+	}
+}
+EOF
+
+# fail: maps to inet_service . inet_service, not addr . service
+$NFT -f /dev/stdin <<EOF && exit 1
+table inet inetfoo {
+	map b {
+		type ipv4_addr : inet_service . inet_service
+	}
+
+	chain c {
+		type nat hook prerouting priority dstnat; policy accept;
+		meta l4proto tcp dnat ip to ip saddr map @a
+	}
+}
+EOF
+
+# fail: only accept exactly two sub-expressions: 'addr . service'
+$NFT -f /dev/stdin <<EOF && exit 1
+table inet inetfoo {
+	map b {
+		type ipv4_addr : inet_addr . inet_service . inet_service
+	}
+
+	chain c {
+		type nat hook prerouting priority dstnat; policy accept;
+		meta l4proto tcp dnat ip to ip saddr map @a
+	}
+}
+EOF
+
+exit 0
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH nft 2/6] evaluate: process concat expressions when used as mapped-to expr
  2020-02-24  0:03 [PATCH nft 0/6] allow s/dnat to map to both addr and port Florian Westphal
  2020-02-24  0:03 ` [PATCH nft 1/6] tests: add initial nat map test Florian Westphal
@ 2020-02-24  0:03 ` Florian Westphal
  2020-02-24  0:03 ` [PATCH nft 3/6] netlink: handle concatenations on set elements mappings Florian Westphal
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Florian Westphal @ 2020-02-24  0:03 UTC (permalink / raw)
  To: netfilter-devel; +Cc: nevola, Florian Westphal

Needed to avoid triggering the 'dtype->size == 0' tests.
Evaluation will build a new concatenated type that holds the
size of the aggregate.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 src/evaluate.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/evaluate.c b/src/evaluate.c
index ae629abe247a..7a70eff95998 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -3368,6 +3368,10 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
 			return set_error(ctx, set, "map definition does not "
 					 "specify mapping data type");
 
+		if (set->data->etype == EXPR_CONCAT &&
+		    expr_evaluate_concat(ctx, &set->data, false) < 0)
+			return -1;
+
 		if (set->data->len == 0 && set->data->dtype->type != TYPE_VERDICT)
 			return set_key_data_error(ctx, set,
 						  set->data->dtype, type);
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH nft 3/6] netlink: handle concatenations on set elements mappings
  2020-02-24  0:03 [PATCH nft 0/6] allow s/dnat to map to both addr and port Florian Westphal
  2020-02-24  0:03 ` [PATCH nft 1/6] tests: add initial nat map test Florian Westphal
  2020-02-24  0:03 ` [PATCH nft 2/6] evaluate: process concat expressions when used as mapped-to expr Florian Westphal
@ 2020-02-24  0:03 ` Florian Westphal
  2020-02-24  0:03 ` [PATCH nft 4/6] evaluate: add two new helpers Florian Westphal
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Florian Westphal @ 2020-02-24  0:03 UTC (permalink / raw)
  To: netfilter-devel; +Cc: nevola, Florian Westphal

We can already handle concatenated keys, this extends concat
coverage to the data type as well, i.e. this can be dissected:

type ipv4_addr : ipv4_addr . inet_service

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 src/netlink.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/netlink.c b/src/netlink.c
index e41289631380..0c6b8c58238b 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -169,6 +169,9 @@ static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
 				nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_CHAIN,
 						   nld.chain, strlen(nld.chain));
 			break;
+		case EXPR_CONCAT:
+			assert(nld.len > 0);
+			/* fallthrough */
 		case EXPR_VALUE:
 			nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_DATA,
 					   nld.value, nld.len);
@@ -1005,6 +1008,10 @@ key_end:
 					  NFT_REG_VERDICT : NFT_REG_1);
 		datatype_set(data, set->data->dtype);
 		data->byteorder = set->data->byteorder;
+
+		if (set->data->dtype->subtypes)
+			data = netlink_parse_concat_elem(set->data->dtype, data);
+
 		if (data->byteorder == BYTEORDER_HOST_ENDIAN)
 			mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE);
 
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH nft 4/6] evaluate: add two new helpers
  2020-02-24  0:03 [PATCH nft 0/6] allow s/dnat to map to both addr and port Florian Westphal
                   ` (2 preceding siblings ...)
  2020-02-24  0:03 ` [PATCH nft 3/6] netlink: handle concatenations on set elements mappings Florian Westphal
@ 2020-02-24  0:03 ` Florian Westphal
  2020-02-24  0:03 ` [PATCH nft 5/6] src: allow nat maps containing both ip(6) address and port Florian Westphal
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Florian Westphal @ 2020-02-24  0:03 UTC (permalink / raw)
  To: netfilter-devel; +Cc: nevola, Florian Westphal

In order to support 'dnat to ip saddr map @foo', where @foo returns
both an address and a inet_service, we will need to peek into the map
and process the concatenations sub-expressions.

Add two helpers for this, will be used in followup patches.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 src/evaluate.c | 61 ++++++++++++++++++++++++++------------------------
 1 file changed, 32 insertions(+), 29 deletions(-)

diff --git a/src/evaluate.c b/src/evaluate.c
index 7a70eff95998..ce1e65f48995 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2102,14 +2102,10 @@ static int stmt_prefix_conversion(struct eval_ctx *ctx, struct expr **expr,
 	return 0;
 }
 
-static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
-			     const struct datatype *dtype, unsigned int len,
-			     enum byteorder byteorder, struct expr **expr)
+static int __stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
+			       const struct datatype *dtype, unsigned int len,
+			       enum byteorder byteorder, struct expr **expr)
 {
-	__expr_set_context(&ctx->ectx, dtype, byteorder, len, 0);
-	if (expr_evaluate(ctx, expr) < 0)
-		return -1;
-
 	if ((*expr)->etype == EXPR_PAYLOAD &&
 	    (*expr)->dtype->type == TYPE_INTEGER &&
 	    ((*expr)->dtype->type != datatype_basetype(dtype)->type ||
@@ -2147,6 +2143,17 @@ static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
 	return 0;
 }
 
+static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
+			     const struct datatype *dtype, unsigned int len,
+			     enum byteorder byteorder, struct expr **expr)
+{
+	__expr_set_context(&ctx->ectx, dtype, byteorder, len, 0);
+	if (expr_evaluate(ctx, expr) < 0)
+		return -1;
+
+	return __stmt_evaluate_arg(ctx, stmt, dtype, len, byteorder, expr);
+}
+
 static int stmt_evaluate_verdict(struct eval_ctx *ctx, struct stmt *stmt)
 {
 	if (stmt_evaluate_arg(ctx, stmt, &verdict_type, 0, 0, &stmt->expr) < 0)
@@ -2762,22 +2769,28 @@ static int nat_evaluate_family(struct eval_ctx *ctx, struct stmt *stmt)
 	}
 }
 
+static const struct datatype *get_addr_dtype(uint8_t family)
+{
+	switch (family) {
+	case NFPROTO_IPV4:
+		return &ipaddr_type;
+	case NFPROTO_IPV6:
+		return &ip6addr_type;
+	}
+
+	return &invalid_type;
+}
+
 static int evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt,
 			     struct expr **expr)
 {
 	struct proto_ctx *pctx = &ctx->pctx;
 	const struct datatype *dtype;
-	unsigned int len;
 
-	if (pctx->family == NFPROTO_IPV4) {
-		dtype = &ipaddr_type;
-		len   = 4 * BITS_PER_BYTE;
-	} else {
-		dtype = &ip6addr_type;
-		len   = 16 * BITS_PER_BYTE;
-	}
+	dtype = get_addr_dtype(pctx->family);
 
-	return stmt_evaluate_arg(ctx, stmt, dtype, len, BYTEORDER_BIG_ENDIAN,
+	return stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+				 BYTEORDER_BIG_ENDIAN,
 				 expr);
 }
 
@@ -2819,25 +2832,15 @@ static int stmt_evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt,
 			      struct expr **addr)
 {
 	const struct datatype *dtype;
-	unsigned int len;
 	int err;
 
 	if (ctx->pctx.family == NFPROTO_INET) {
-		switch (family) {
-		case NFPROTO_IPV4:
-			dtype = &ipaddr_type;
-			len   = 4 * BITS_PER_BYTE;
-			break;
-		case NFPROTO_IPV6:
-			dtype = &ip6addr_type;
-			len   = 16 * BITS_PER_BYTE;
-			break;
-		default:
+		dtype = get_addr_dtype(family);
+		if (dtype->size == 0)
 			return stmt_error(ctx, stmt,
 					  "ip or ip6 must be specified with address for inet tables.");
-		}
 
-		err = stmt_evaluate_arg(ctx, stmt, dtype, len,
+		err = stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
 					BYTEORDER_BIG_ENDIAN, addr);
 	} else {
 		err = evaluate_addr(ctx, stmt, addr);
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH nft 5/6] src: allow nat maps containing both ip(6) address and port
  2020-02-24  0:03 [PATCH nft 0/6] allow s/dnat to map to both addr and port Florian Westphal
                   ` (3 preceding siblings ...)
  2020-02-24  0:03 ` [PATCH nft 4/6] evaluate: add two new helpers Florian Westphal
@ 2020-02-24  0:03 ` Florian Westphal
  2020-02-24  0:03 ` [PATCH nft 6/6] tests: nat: add and use maps with both address and service Florian Westphal
  2020-02-24 18:44 ` [PATCH nft 0/6] allow s/dnat to map to both addr and port Pablo Neira Ayuso
  6 siblings, 0 replies; 10+ messages in thread
From: Florian Westphal @ 2020-02-24  0:03 UTC (permalink / raw)
  To: netfilter-devel; +Cc: nevola, Florian Westphal

nft will now be able to handle
map destinations {
	type ipv4_addr . inet_service : ipv4_addr . inet_service
}

chain f {
	dnat to ip daddr . tcp dport map @destinations
}

Something like this won't work though:
 meta l4proto tcp dnat ip6 to numgen inc mod 4 map { 0 : dead::f001 . 8080, ..

as we lack the type info to properly dissect "dead::f001" as an ipv6
address.

For the named map case, this info is available in the map
definition, but for the anon case we'd need to resort to guesswork.

Support is added by peeking into the map definition when evaluating
a nat statement with a map.
Right now, when a map is provided as address, we will only check that
the mapped-to data type matches the expected size (of an ipv4 or ipv6
address).

After this patch, if the mapped-to type is a concatenation, it will
take a peek at the individual concat expressions.  If its a combination
of address and service, nft will translate this so that the kernel nat
expression looks at the returned register that would store the
inet_service part of the octet soup returned from the lookup expression.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 include/statement.h       |  1 +
 src/evaluate.c            | 56 +++++++++++++++++++++++++++++++++++++++
 src/netlink_delinearize.c | 36 +++++++++++++++++++++++++
 src/netlink_linearize.c   | 31 +++++++++++++++++++++-
 4 files changed, 123 insertions(+), 1 deletion(-)

diff --git a/include/statement.h b/include/statement.h
index 585908de7da2..8fb459ca1cd4 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -125,6 +125,7 @@ struct nat_stmt {
 	struct expr		*proto;
 	uint32_t		flags;
 	uint8_t			family;
+	bool			ipportmap;
 };
 
 extern struct stmt *nat_stmt_alloc(const struct location *loc,
diff --git a/src/evaluate.c b/src/evaluate.c
index ce1e65f48995..0afd0403d3a4 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2849,6 +2849,52 @@ static int stmt_evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt,
 	return err;
 }
 
+static int stmt_evaluate_nat_map(struct eval_ctx *ctx, struct stmt *stmt)
+{
+	struct expr *one, *two, *data, *tmp;
+	const struct datatype *dtype;
+	int err;
+
+	dtype = get_addr_dtype(stmt->nat.family);
+
+	expr_set_context(&ctx->ectx, dtype, dtype->size);
+	if (expr_evaluate(ctx, &stmt->nat.addr))
+		return -1;
+
+	data = stmt->nat.addr->mappings->set->data;
+	if (expr_ops(data)->type != EXPR_CONCAT)
+		return __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+					   BYTEORDER_BIG_ENDIAN,
+					   &stmt->nat.addr);
+
+	one = list_first_entry(&data->expressions, struct expr, list);
+	two = list_entry(one->list.next, struct expr, list);
+
+	if (one == two || !list_is_last(&two->list, &data->expressions))
+		return __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+					   BYTEORDER_BIG_ENDIAN,
+					   &stmt->nat.addr);
+
+	tmp = one;
+	err = __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+				  BYTEORDER_BIG_ENDIAN,
+				  &tmp);
+	if (err < 0)
+		return err;
+	if (tmp != one)
+		BUG("Internal error: Unexpected alteration of l3 expression");
+
+	tmp = two;
+	err = nat_evaluate_transport(ctx, stmt, &tmp);
+	if (err < 0)
+		return err;
+	if (tmp != two)
+		BUG("Internal error: Unexpected alteration of l4 expression");
+
+	stmt->nat.ipportmap = true;
+	return err;
+}
+
 static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt)
 {
 	int err;
@@ -2862,6 +2908,16 @@ static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt)
 		if (err < 0)
 			return err;
 
+		if (stmt->nat.proto == NULL &&
+		    expr_ops(stmt->nat.addr)->type == EXPR_MAP) {
+			err = stmt_evaluate_nat_map(ctx, stmt);
+			if (err < 0)
+				return err;
+
+			stmt->flags |= STMT_F_TERMINAL;
+			return 0;
+		}
+
 		err = stmt_evaluate_addr(ctx, stmt, stmt->nat.family,
 					 &stmt->nat.addr);
 		if (err < 0)
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 4f774fb9f150..6203a53c6154 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -978,6 +978,35 @@ static void netlink_parse_reject(struct netlink_parse_ctx *ctx,
 	ctx->stmt = stmt;
 }
 
+static bool is_nat_proto_map(const struct expr *addr, uint8_t family)
+{
+	const struct expr *mappings, *data;
+	const struct set *set;
+
+	if (!addr ||
+	    expr_ops(addr)->type != EXPR_MAP)
+		return false;
+
+	mappings = addr->right;
+	if (expr_ops(mappings)->type != EXPR_SET_REF)
+		return false;
+
+	set = mappings->set;
+	data = set->data;
+
+	/* if we're dealing with an address:inet_service map,
+	 * the length will be bit_sizeof(addr) + 32 (one register).
+	 */
+	switch (family) {
+	case NFPROTO_IPV4:
+		return data->len == 32 + 32;
+	case NFPROTO_IPV6:
+		return data->len == 128 + 32;
+	}
+
+	return false;
+}
+
 static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
 			      const struct location *loc,
 			      const struct nftnl_expr *nle)
@@ -998,6 +1027,7 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
 	if (nftnl_expr_is_set(nle, NFTNL_EXPR_NAT_FLAGS))
 		stmt->nat.flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_NAT_FLAGS);
 
+	addr = NULL;
 	reg1 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MIN);
 	if (reg1) {
 		addr = netlink_get_register(ctx, loc, reg1);
@@ -1034,6 +1064,12 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
 		stmt->nat.addr = addr;
 	}
 
+	if (is_nat_proto_map(addr, family)) {
+		stmt->nat.ipportmap = true;
+		ctx->stmt = stmt;
+		return;
+	}
+
 	reg1 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_PROTO_MIN);
 	if (reg1) {
 		proto = netlink_get_register(ctx, loc, reg1);
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index b542aa3be23f..de461775a7e1 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -1052,14 +1052,25 @@ static void netlink_gen_reject_stmt(struct netlink_linearize_ctx *ctx,
 	nftnl_rule_add_expr(ctx->nlr, nle);
 }
 
+static unsigned int nat_addrlen(uint8_t family)
+{
+	switch (family) {
+	case NFPROTO_IPV4: return 32;
+	case NFPROTO_IPV6: return 128;
+	}
+
+	BUG("invalid nat family %u\n", family);
+	return 0;
+}
+
 static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
 				 const struct stmt *stmt)
 {
 	struct nftnl_expr *nle;
 	enum nft_registers amin_reg, amax_reg;
 	enum nft_registers pmin_reg, pmax_reg;
+	uint8_t family = 0;
 	int registers = 0;
-	int family;
 	int nftnl_flag_attr;
 	int nftnl_reg_pmin, nftnl_reg_pmax;
 
@@ -1118,6 +1129,24 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
 					     amin_reg);
 		}
 
+		if (stmt->nat.ipportmap) {
+			/* nat_stmt evaluation step doesn't allow
+			 * stmt->nat.ipportmap && stmt->nat.proto.
+			 */
+			assert(stmt->nat.proto == NULL);
+
+			pmin_reg = amin_reg;
+
+			/* if ipportmap is set, the mapped type is a
+			 * concatenation of 'addr . inet_service'.
+			 * The map lookup will then return the
+			 * concatenated value, so we need to skip
+			 * the address and use the register that
+			 * will hold the inet_service part.
+			 */
+			pmin_reg += netlink_register_space(nat_addrlen(family));
+			netlink_put_register(nle, nftnl_reg_pmin, pmin_reg);
+		}
 	}
 
 	if (stmt->nat.proto) {
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH nft 6/6] tests: nat: add and use maps with both address and service
  2020-02-24  0:03 [PATCH nft 0/6] allow s/dnat to map to both addr and port Florian Westphal
                   ` (4 preceding siblings ...)
  2020-02-24  0:03 ` [PATCH nft 5/6] src: allow nat maps containing both ip(6) address and port Florian Westphal
@ 2020-02-24  0:03 ` Florian Westphal
  2020-02-24 13:22   ` Pablo Neira Ayuso
  2020-02-24 18:44 ` [PATCH nft 0/6] allow s/dnat to map to both addr and port Pablo Neira Ayuso
  6 siblings, 1 reply; 10+ messages in thread
From: Florian Westphal @ 2020-02-24  0:03 UTC (permalink / raw)
  To: netfilter-devel; +Cc: nevola, Florian Westphal

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 .../testcases/maps/dumps/nat_addr_port.nft    | 76 +++++++++++++++++
 tests/shell/testcases/maps/nat_addr_port      | 84 +++++++++++++++++++
 2 files changed, 160 insertions(+)

diff --git a/tests/shell/testcases/maps/dumps/nat_addr_port.nft b/tests/shell/testcases/maps/dumps/nat_addr_port.nft
index 3ed6812e585f..bd20ae7e65c7 100644
--- a/tests/shell/testcases/maps/dumps/nat_addr_port.nft
+++ b/tests/shell/testcases/maps/dumps/nat_addr_port.nft
@@ -3,11 +3,87 @@ table ip ipfoo {
 		type ipv4_addr : ipv4_addr
 	}
 
+	map y {
+		type ipv4_addr : ipv4_addr . inet_service
+		elements = { 192.168.7.2 : 10.1.1.1 . 4242 }
+	}
+
+	map z {
+		type ipv4_addr . inet_service : ipv4_addr . inet_service
+		elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+	}
+
 	chain c {
 		type nat hook prerouting priority dstnat; policy accept;
 		iifname != "foobar" accept
 		dnat to ip daddr map @x
 		ip saddr 10.1.1.1 dnat to 10.2.3.4
 		ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
+		meta l4proto tcp dnat to ip saddr map @y
+		dnat to ip saddr . tcp dport map @z
+	}
+}
+table ip6 ip6foo {
+	map x {
+		type ipv6_addr : ipv6_addr
+	}
+
+	map y {
+		type ipv6_addr : ipv6_addr . inet_service
+	}
+
+	map z {
+		type ipv6_addr . inet_service : ipv6_addr . inet_service
+	}
+
+	chain c {
+		type nat hook prerouting priority dstnat; policy accept;
+		iifname != "foobar" accept
+		dnat to ip6 daddr map @x
+		ip6 saddr dead::1 dnat to feed::1
+		ip6 saddr dead::2 tcp dport 42 dnat to [c0::1a]:4242
+		meta l4proto tcp dnat to ip6 saddr map @y
+		dnat to ip6 saddr . tcp dport map @z
+	}
+}
+table inet inetfoo {
+	map x4 {
+		type ipv4_addr : ipv4_addr
+	}
+
+	map y4 {
+		type ipv4_addr : ipv4_addr . inet_service
+	}
+
+	map z4 {
+		type ipv4_addr . inet_service : ipv4_addr . inet_service
+		elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+	}
+
+	map x6 {
+		type ipv6_addr : ipv6_addr
+	}
+
+	map y6 {
+		type ipv6_addr : ipv6_addr . inet_service
+	}
+
+	map z6 {
+		type ipv6_addr . inet_service : ipv6_addr . inet_service
+	}
+
+	chain c {
+		type nat hook prerouting priority dstnat; policy accept;
+		iifname != "foobar" accept
+		dnat ip to ip daddr map @x4
+		ip saddr 10.1.1.1 dnat ip to 10.2.3.4
+		ip saddr 10.1.1.2 tcp dport 42 dnat ip to 10.2.3.4:4242
+		meta l4proto tcp meta nfproto ipv4 dnat ip to ip saddr map @y4
+		meta nfproto ipv4 dnat ip to ip saddr . tcp dport map @z4
+		dnat ip6 to ip6 daddr map @x6
+		ip6 saddr dead::1 dnat ip6 to feed::1
+		ip6 saddr dead::2 tcp dport 42 dnat ip6 to [c0::1a]:4242
+		meta l4proto tcp meta nfproto ipv6 dnat ip6 to ip6 saddr map @y6
+		meta nfproto ipv6 dnat ip6 to ip6 saddr . tcp dport map @z6
 	}
 }
diff --git a/tests/shell/testcases/maps/nat_addr_port b/tests/shell/testcases/maps/nat_addr_port
index 77a2f110aeb9..58bb8942720c 100755
--- a/tests/shell/testcases/maps/nat_addr_port
+++ b/tests/shell/testcases/maps/nat_addr_port
@@ -6,6 +6,14 @@ table ip ipfoo {
 	map x {
 		type ipv4_addr : ipv4_addr
 	}
+	map y {
+		type ipv4_addr : ipv4_addr . inet_service
+		elements = { 192.168.7.2 : 10.1.1.1 . 4242 }
+	}
+	map z {
+		type ipv4_addr . inet_service : ipv4_addr . inet_service
+		elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+	}
 
 	chain c {
 		type nat hook prerouting priority dstnat; policy accept;
@@ -13,6 +21,8 @@ table ip ipfoo {
 		dnat to ip daddr map @x
 		ip saddr 10.1.1.1 dnat to 10.2.3.4
 		ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
+		meta l4proto tcp dnat to ip saddr map @y
+		meta l4proto tcp dnat to ip saddr . tcp dport map @z
 	}
 }
 EOF
@@ -20,6 +30,80 @@ EOF
 # should fail: rule has no test for l4 protocol
 $NFT add rule 'ip ipfoo c ip saddr 10.1.1.2 dnat to 10.2.3.4:4242' && exit 1
 
+# should fail: rule has no test for l4 protocol, but map has inet_service
+$NFT add rule 'ip ipfoo c dnat to ip daddr map @y' && exit 1
+
+# skeleton 6
+$NFT -f /dev/stdin <<EOF || exit 1
+table ip6 ip6foo {
+	map x {
+		type ipv6_addr : ipv6_addr
+	}
+	map y {
+		type ipv6_addr : ipv6_addr . inet_service
+	}
+	map z {
+		type ipv6_addr . inet_service : ipv6_addr . inet_service
+	}
+
+	chain c {
+		type nat hook prerouting priority dstnat; policy accept;
+		meta iifname != "foobar" accept
+		dnat to ip6 daddr map @x
+		ip6 saddr dead::1 dnat to feed::1
+		ip6 saddr dead::2 tcp dport 42 dnat to [c0::1a]:4242
+		meta l4proto tcp dnat to ip6 saddr map @y
+		meta l4proto tcp dnat to ip6 saddr . tcp dport map @z
+	}
+}
+EOF
+
+# should fail: rule has no test for l4 protocol
+$NFT add rule 'ip6 ip6foo c ip6 saddr f0:0b::a3 dnat to [1c::3]:42' && exit 1
+
+# should fail: rule has no test for l4 protocol, but map has inet_service
+$NFT add rule 'ip6 ip6foo c dnat to ip daddr map @y' && exit 1
+
+# skeleton inet
+$NFT -f /dev/stdin <<EOF || exit 1
+table inet inetfoo {
+	map x4 {
+		type ipv4_addr : ipv4_addr
+	}
+	map y4 {
+		type ipv4_addr : ipv4_addr . inet_service
+	}
+	map z4 {
+		type ipv4_addr . inet_service : ipv4_addr . inet_service
+		elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+	}
+	map x6 {
+		type ipv6_addr : ipv6_addr
+	}
+	map y6 {
+		type ipv6_addr : ipv6_addr . inet_service
+	}
+	map z6 {
+		type ipv6_addr . inet_service : ipv6_addr . inet_service
+	}
+
+	chain c {
+		type nat hook prerouting priority dstnat; policy accept;
+		meta iifname != "foobar" accept
+		dnat ip to ip daddr map @x4
+		ip saddr 10.1.1.1 dnat to 10.2.3.4
+		ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
+		meta l4proto tcp dnat ip to ip saddr map @y4
+		meta l4proto tcp dnat ip to ip saddr . tcp dport map @z4
+		dnat ip6 to ip6 daddr map @x6
+		ip6 saddr dead::1 dnat to feed::1
+		ip6 saddr dead::2 tcp dport 42 dnat to [c0::1a]:4242
+		meta l4proto tcp dnat ip6 to ip6 saddr map @y6
+		meta l4proto tcp dnat ip6 to ip6 saddr . tcp dport map @z6
+	}
+}
+EOF
+
 # should fail: map has wrong family: 4->6
 $NFT add rule 'inet inetfoo c dnat to ip daddr map @x6' && exit 1
 
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH nft 6/6] tests: nat: add and use maps with both address and service
  2020-02-24  0:03 ` [PATCH nft 6/6] tests: nat: add and use maps with both address and service Florian Westphal
@ 2020-02-24 13:22   ` Pablo Neira Ayuso
  0 siblings, 0 replies; 10+ messages in thread
From: Pablo Neira Ayuso @ 2020-02-24 13:22 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel, nevola

[-- Attachment #1: Type: text/plain, Size: 490 bytes --]

I have adapted this test to the new syntax, but it stills fails here:

# ./run-tests.sh testcases/maps/nat_addr_port 
I: using nft binary ./../../src/nft

W: [FAILED]     testcases/maps/nat_addr_port: got 1
/dev/stdin:6:20-28: Error: datatype mismatch: expected concatenation of (IPv4 address, internet network service), expression has type IPv4 address
                type ipv4_addr : ipv4_addr . inet_service
                                 ^^^^^^^^^

Attaching the patch to update it.

[-- Attachment #2: x.patch --]
[-- Type: text/x-diff, Size: 4094 bytes --]

diff --git a/tests/shell/testcases/maps/dumps/nat_addr_port.nft b/tests/shell/testcases/maps/dumps/nat_addr_port.nft
index bd20ae7e..210cab7f 100644
--- a/tests/shell/testcases/maps/dumps/nat_addr_port.nft
+++ b/tests/shell/testcases/maps/dumps/nat_addr_port.nft
@@ -19,8 +19,8 @@ table ip ipfoo {
 		dnat to ip daddr map @x
 		ip saddr 10.1.1.1 dnat to 10.2.3.4
 		ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
-		meta l4proto tcp dnat to ip saddr map @y
-		dnat to ip saddr . tcp dport map @z
+		meta l4proto tcp dnat ip addr . port to ip saddr map @y
+		dnat ip addr . port to ip saddr . tcp dport map @z
 	}
 }
 table ip6 ip6foo {
@@ -42,8 +42,8 @@ table ip6 ip6foo {
 		dnat to ip6 daddr map @x
 		ip6 saddr dead::1 dnat to feed::1
 		ip6 saddr dead::2 tcp dport 42 dnat to [c0::1a]:4242
-		meta l4proto tcp dnat to ip6 saddr map @y
-		dnat to ip6 saddr . tcp dport map @z
+		meta l4proto tcp dnat ip6 addr . port to ip6 saddr map @y
+		dnat ip6 addr . port to ip6 saddr . tcp dport map @z
 	}
 }
 table inet inetfoo {
@@ -78,12 +78,12 @@ table inet inetfoo {
 		dnat ip to ip daddr map @x4
 		ip saddr 10.1.1.1 dnat ip to 10.2.3.4
 		ip saddr 10.1.1.2 tcp dport 42 dnat ip to 10.2.3.4:4242
-		meta l4proto tcp meta nfproto ipv4 dnat ip to ip saddr map @y4
-		meta nfproto ipv4 dnat ip to ip saddr . tcp dport map @z4
+		meta l4proto tcp meta nfproto ipv4 dnat ip addr . port to ip saddr map @y4
+		meta nfproto ipv4 dnat ip addr . port to ip saddr . tcp dport map @z4
 		dnat ip6 to ip6 daddr map @x6
 		ip6 saddr dead::1 dnat ip6 to feed::1
 		ip6 saddr dead::2 tcp dport 42 dnat ip6 to [c0::1a]:4242
-		meta l4proto tcp meta nfproto ipv6 dnat ip6 to ip6 saddr map @y6
-		meta nfproto ipv6 dnat ip6 to ip6 saddr . tcp dport map @z6
+		meta l4proto tcp meta nfproto ipv6 dnat ip6 addr . port to ip6 saddr map @y6
+		meta nfproto ipv6 dnat ip6 addr . port to ip6 saddr . tcp dport map @z6
 	}
 }
diff --git a/tests/shell/testcases/maps/nat_addr_port b/tests/shell/testcases/maps/nat_addr_port
index 58bb8942..1a0c8521 100755
--- a/tests/shell/testcases/maps/nat_addr_port
+++ b/tests/shell/testcases/maps/nat_addr_port
@@ -21,8 +21,8 @@ table ip ipfoo {
 		dnat to ip daddr map @x
 		ip saddr 10.1.1.1 dnat to 10.2.3.4
 		ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
-		meta l4proto tcp dnat to ip saddr map @y
-		meta l4proto tcp dnat to ip saddr . tcp dport map @z
+		meta l4proto tcp dnat ip addr . port to ip saddr map @y
+		meta l4proto tcp dnat ip addr . port to ip saddr . tcp dport map @z
 	}
 }
 EOF
@@ -31,7 +31,7 @@ EOF
 $NFT add rule 'ip ipfoo c ip saddr 10.1.1.2 dnat to 10.2.3.4:4242' && exit 1
 
 # should fail: rule has no test for l4 protocol, but map has inet_service
-$NFT add rule 'ip ipfoo c dnat to ip daddr map @y' && exit 1
+$NFT add rule 'ip ipfoo c dnat ip addr . port to ip daddr map @y' && exit 1
 
 # skeleton 6
 $NFT -f /dev/stdin <<EOF || exit 1
@@ -52,8 +52,8 @@ table ip6 ip6foo {
 		dnat to ip6 daddr map @x
 		ip6 saddr dead::1 dnat to feed::1
 		ip6 saddr dead::2 tcp dport 42 dnat to [c0::1a]:4242
-		meta l4proto tcp dnat to ip6 saddr map @y
-		meta l4proto tcp dnat to ip6 saddr . tcp dport map @z
+		meta l4proto tcp dnat ip6 addr . port to ip6 saddr map @y
+		meta l4proto tcp dnat ip addr . port to ip6 saddr . tcp dport map @z
 	}
 }
 EOF
@@ -93,13 +93,13 @@ table inet inetfoo {
 		dnat ip to ip daddr map @x4
 		ip saddr 10.1.1.1 dnat to 10.2.3.4
 		ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
-		meta l4proto tcp dnat ip to ip saddr map @y4
-		meta l4proto tcp dnat ip to ip saddr . tcp dport map @z4
+		meta l4proto tcp dnat ip addr . port to ip saddr map @y4
+		meta l4proto tcp dnat ip addr . port to ip saddr . tcp dport map @z4
 		dnat ip6 to ip6 daddr map @x6
 		ip6 saddr dead::1 dnat to feed::1
 		ip6 saddr dead::2 tcp dport 42 dnat to [c0::1a]:4242
-		meta l4proto tcp dnat ip6 to ip6 saddr map @y6
-		meta l4proto tcp dnat ip6 to ip6 saddr . tcp dport map @z6
+		meta l4proto tcp dnat ip6 addr . port to ip6 saddr map @y6
+		meta l4proto tcp dnat ip6 addr . port to ip6 saddr . tcp dport map @z6
 	}
 }
 EOF

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH nft 0/6] allow s/dnat to map to both addr and port
  2020-02-24  0:03 [PATCH nft 0/6] allow s/dnat to map to both addr and port Florian Westphal
                   ` (5 preceding siblings ...)
  2020-02-24  0:03 ` [PATCH nft 6/6] tests: nat: add and use maps with both address and service Florian Westphal
@ 2020-02-24 18:44 ` Pablo Neira Ayuso
  2020-02-24 18:47   ` Pablo Neira Ayuso
  6 siblings, 1 reply; 10+ messages in thread
From: Pablo Neira Ayuso @ 2020-02-24 18:44 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel, nevola

On Mon, Feb 24, 2020 at 01:03:18AM +0100, Florian Westphal wrote:
> Right now its not possible to use a map with snat/dnat to alter both
> address and port at the same time.
> 
> This series teaches nft to accept this:
> 
> 	map y4 {
> 		type ipv4_addr : ipv4_addr . inet_service
> 		elements = { 192.168.7.2 : 10.1.1.1 . 4242 }
> 	}
>  	meta l4proto tcp meta nfproto ipv4 dnat ip to ip saddr map @y4
> 
> i.e., it allows:
> 1. A mapping that contains a concatenated expression.
> 2. nat expression will peek into set type and detect when
>    the mapping is of 'addr + port' type.
>    Linearization will compute the register that contains the port
>    part of the mapping.
> 3. Delinarization will figure out when this trick was used by looking
>    at the length of the mapping: 64 == ipv4addr+service, 160 == ipv6addr+service.
> 
> What does not work:
> Anonymous mappings, i.e.
> meta l4proto tcp meta nfproto ipv4 dnat ip to ip saddr map { 1.2.3.4 : 1.2.3.5 . 53, ..
>
> doesn't work.  When evaluating "1.2.3.4", this is still a symbol and
> unlike with named sets, nft doesn't have a properly declared set type.

This is now working, test has been adjusted and it is passing.

> This is similar to the 'maps-on-LHS-side' issue.
> Phil suggested to allow this:
>  ...  to ip saddr map { type ipv4_addr : ipv4_addr . inet_service; 1.2.3.4 : 1.2.3.5 . 53, ..
> 
> i.e. re-use the declarative syntax from map code.
> 
> Another related issue:
> "typeof" doesn't work with concatenations so far.

typeof support is still lacking.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH nft 0/6] allow s/dnat to map to both addr and port
  2020-02-24 18:44 ` [PATCH nft 0/6] allow s/dnat to map to both addr and port Pablo Neira Ayuso
@ 2020-02-24 18:47   ` Pablo Neira Ayuso
  0 siblings, 0 replies; 10+ messages in thread
From: Pablo Neira Ayuso @ 2020-02-24 18:47 UTC (permalink / raw)
  To: Florian Westphal; +Cc: netfilter-devel, nevola

On Mon, Feb 24, 2020 at 07:44:08PM +0100, Pablo Neira Ayuso wrote:
> On Mon, Feb 24, 2020 at 01:03:18AM +0100, Florian Westphal wrote:
> > Right now its not possible to use a map with snat/dnat to alter both
> > address and port at the same time.
> > 
> > This series teaches nft to accept this:
> > 
> > 	map y4 {
> > 		type ipv4_addr : ipv4_addr . inet_service
> > 		elements = { 192.168.7.2 : 10.1.1.1 . 4242 }
> > 	}
> >  	meta l4proto tcp meta nfproto ipv4 dnat ip to ip saddr map @y4
> > 
> > i.e., it allows:
> > 1. A mapping that contains a concatenated expression.
> > 2. nat expression will peek into set type and detect when
> >    the mapping is of 'addr + port' type.
> >    Linearization will compute the register that contains the port
> >    part of the mapping.
> > 3. Delinarization will figure out when this trick was used by looking
> >    at the length of the mapping: 64 == ipv4addr+service, 160 == ipv6addr+service.
> > 
> > What does not work:
> > Anonymous mappings, i.e.
> > meta l4proto tcp meta nfproto ipv4 dnat ip to ip saddr map { 1.2.3.4 : 1.2.3.5 . 53, ..
> >
> > doesn't work.  When evaluating "1.2.3.4", this is still a symbol and
> > unlike with named sets, nft doesn't have a properly declared set type.
> 
> This is now working, test has been adjusted and it is passing.
> 
> > This is similar to the 'maps-on-LHS-side' issue.
> > Phil suggested to allow this:
> >  ...  to ip saddr map { type ipv4_addr : ipv4_addr . inet_service; 1.2.3.4 : 1.2.3.5 . 53, ..
> > 
> > i.e. re-use the declarative syntax from map code.
> > 
> > Another related issue:
> > "typeof" doesn't work with concatenations so far.
> 
> typeof support is still lacking.

I mean, the listing does not show typeof yet, this is what it is missing.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2020-02-24 18:47 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-24  0:03 [PATCH nft 0/6] allow s/dnat to map to both addr and port Florian Westphal
2020-02-24  0:03 ` [PATCH nft 1/6] tests: add initial nat map test Florian Westphal
2020-02-24  0:03 ` [PATCH nft 2/6] evaluate: process concat expressions when used as mapped-to expr Florian Westphal
2020-02-24  0:03 ` [PATCH nft 3/6] netlink: handle concatenations on set elements mappings Florian Westphal
2020-02-24  0:03 ` [PATCH nft 4/6] evaluate: add two new helpers Florian Westphal
2020-02-24  0:03 ` [PATCH nft 5/6] src: allow nat maps containing both ip(6) address and port Florian Westphal
2020-02-24  0:03 ` [PATCH nft 6/6] tests: nat: add and use maps with both address and service Florian Westphal
2020-02-24 13:22   ` Pablo Neira Ayuso
2020-02-24 18:44 ` [PATCH nft 0/6] allow s/dnat to map to both addr and port Pablo Neira Ayuso
2020-02-24 18:47   ` Pablo Neira Ayuso

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.