[PATCH] src: allow to map key to nfqueue number

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Allow to specify a numeric queue id as part of a map.
The parser side is easy, but the reverse direction (listing) is not.

'queue' is a statement, it doesn't have an expression.

Add a generic 'queue_type' datatype as a TYPE_TYPEOF shim to the real
basetype with constant expressions, this is used only for udata
build/parse, it stores the "key" (the parser token, here "queue") as
udata in kernel and can then restore the original key.

Add a dumpfile to validate parser & output.

JSON support is missing because JSON allow typeof only since quite
recently.

Joint work with Pablo.

Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1455
Signed-off-by: Florian Westphal <fw@xxxxxxxxx>
Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx>
---
 include/datatype.h                            |  3 +
 src/datatype.c                                | 17 ++++
 src/expression.c                              | 80 +++++++++++++++++++
 src/json.                                     |  0
 src/netlink.c                                 |  6 +-
 src/parser_bison.y                            |  4 +
 tests/shell/testcases/nft-f/dumps/nfqueue.nft | 11 +++
 tests/shell/testcases/nft-f/nfqueue           |  6 ++
 8 files changed, 126 insertions(+), 1 deletion(-)
 create mode 100644 src/json.
 create mode 100644 tests/shell/testcases/nft-f/dumps/nfqueue.nft
 create mode 100755 tests/shell/testcases/nft-f/nfqueue

diff --git a/include/datatype.h b/include/datatype.h
index 75d6d6b8c628..61c6bf595e9e 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -102,6 +102,8 @@ enum datatypes {
 };
 #define TYPE_MAX		(__TYPE_MAX - 1)
 
+#define TYPE_TYPEOF		__TYPE_MAX
+
 #define TYPE_BITS		6
 #define TYPE_MASK		((1 << TYPE_BITS) - 1)
 
@@ -271,6 +273,7 @@ extern const struct datatype boolean_type;
 extern const struct datatype priority_type;
 extern const struct datatype policy_type;
 extern const struct datatype cgroupv2_type;
+extern const struct datatype queue_type;
 
 /* private datatypes for reject statement. */
 extern const struct datatype reject_icmp_code_type;
diff --git a/src/datatype.c b/src/datatype.c
index ea73eaf9a691..c9c5a198bd3b 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -505,6 +505,23 @@ const struct datatype xinteger_type = {
 	.parse		= integer_type_parse,
 };
 
+static void queue_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+	nft_gmp_print(octx, "queue");
+}
+
+/* Dummy queue_type for set declaration with typeof, see
+ * constant_expr_build_udata and constant_expr_parse_udata,
+ * basetype is used for elements.
+*/
+const struct datatype queue_type = {
+	.type		= TYPE_TYPEOF,
+	.name		= "queue",
+	.desc		= "queue",
+	.basetype	= &integer_type,
+	.print		= queue_type_print,
+};
+
 static void string_type_print(const struct expr *expr, struct output_ctx *octx)
 {
 	unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
diff --git a/src/expression.c b/src/expression.c
index c0cb7f22eb73..62786f483eed 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -371,6 +371,84 @@ struct expr *variable_expr_alloc(const struct location *loc,
 	return expr;
 }
 
+#define NFTNL_UDATA_CONSTANT_TYPE 0
+#define NFTNL_UDATA_CONSTANT_MAX NFTNL_UDATA_CONSTANT_TYPE
+
+#define CONSTANT_EXPR_NFQUEUE_ID 0
+
+static int constant_expr_build_udata(struct nftnl_udata_buf *udbuf,
+				     const struct expr *expr)
+{
+	uint32_t type;
+
+	if (expr->dtype == &queue_type)
+		type = CONSTANT_EXPR_NFQUEUE_ID;
+	else
+		return -1;
+
+	if (!nftnl_udata_put_u32(udbuf, NFTNL_UDATA_CONSTANT_TYPE, type))
+		return -1;
+
+	return 0;
+}
+
+static int constant_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+	const struct nftnl_udata **ud = data;
+	uint8_t type = nftnl_udata_type(attr);
+	uint8_t len = nftnl_udata_len(attr);
+	uint32_t value;
+
+	switch (type) {
+	case NFTNL_UDATA_CONSTANT_TYPE:
+		if (len != sizeof(uint32_t))
+			return -1;
+
+		value = nftnl_udata_get_u32(attr);
+		switch (value) {
+		case CONSTANT_EXPR_NFQUEUE_ID:
+			break;
+		default:
+			return -1;
+		}
+		break;
+	default:
+		return 0;
+	}
+
+	ud[type] = attr;
+
+	return 0;
+}
+
+static struct expr *constant_expr_parse_udata(const struct nftnl_udata *attr)
+{
+	const struct nftnl_udata *ud[NFTNL_UDATA_CONSTANT_MAX + 1] = {};
+	const struct datatype *dtype = NULL;
+	uint32_t type;
+	int err;
+
+	err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+				constant_parse_udata, ud);
+	if (err < 0)
+		return NULL;
+
+	if (!ud[NFTNL_UDATA_CONSTANT_TYPE])
+		return NULL;
+
+	type = nftnl_udata_get_u32(ud[NFTNL_UDATA_CONSTANT_TYPE]);
+	switch (type) {
+	case CONSTANT_EXPR_NFQUEUE_ID:
+		dtype = &queue_type;
+		break;
+	default:
+		break;
+	}
+
+	return constant_expr_alloc(&internal_location, dtype, BYTEORDER_HOST_ENDIAN,
+				   16, NULL);
+}
+
 static void constant_expr_print(const struct expr *expr,
 				 struct output_ctx *octx)
 {
@@ -401,6 +479,8 @@ static const struct expr_ops constant_expr_ops = {
 	.cmp		= constant_expr_cmp,
 	.clone		= constant_expr_clone,
 	.destroy	= constant_expr_destroy,
+	.build_udata	= constant_expr_build_udata,
+	.parse_udata	= constant_expr_parse_udata,
 };
 
 struct expr *constant_expr_alloc(const struct location *loc,
diff --git a/src/json. b/src/json.
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/src/netlink.c b/src/netlink.c
index 25ee3419772b..68e7da68ed68 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1466,7 +1466,11 @@ key_end:
 		data = netlink_alloc_data(&netlink_location, &nld,
 					  set->data->dtype->type == TYPE_VERDICT ?
 					  NFT_REG_VERDICT : NFT_REG_1);
-		datatype_set(data, set->data->dtype);
+
+		if (set->data->dtype->type == TYPE_TYPEOF)
+			datatype_set(data, set->data->dtype->basetype);
+		else
+			datatype_set(data, set->data->dtype);
 		data->byteorder = set->data->byteorder;
 
 		if (set->data->dtype->subtypes) {
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 602fc60e6de3..6e6f3cf8335d 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -2173,6 +2173,10 @@ typeof_data_expr	:	INTERVAL	typeof_expr
 			{
 				$$ = $1;
 			}
+			|	QUEUE
+			{
+				$$ = constant_expr_alloc(&@$, &queue_type, BYTEORDER_HOST_ENDIAN, 16, NULL);
+			}
 			;
 
 typeof_expr		:	primary_expr
diff --git a/tests/shell/testcases/nft-f/dumps/nfqueue.nft b/tests/shell/testcases/nft-f/dumps/nfqueue.nft
new file mode 100644
index 000000000000..7fe3ca669544
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/nfqueue.nft
@@ -0,0 +1,11 @@
+table inet t {
+	map get_queue_id {
+		typeof ip saddr . ip daddr . tcp dport : queue
+		elements = { 127.0.0.1 . 127.0.0.1 . 22 : 1,
+			     127.0.0.1 . 127.0.0.2 . 22 : 2 }
+	}
+
+	chain test {
+		queue flags bypass to ip saddr . ip daddr . tcp dport map @get_queue_id
+	}
+}
diff --git a/tests/shell/testcases/nft-f/nfqueue b/tests/shell/testcases/nft-f/nfqueue
new file mode 100755
index 000000000000..07820b7c4fdd
--- /dev/null
+++ b/tests/shell/testcases/nft-f/nfqueue
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
-- 
2.30.2


--gu4Y/oIARLFVpfrF--




[Index of Archives]     [Netfitler Users]     [Berkeley Packet Filter]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux