Blob Blame History Raw
From 0100e69baee2e3a7e4bf5f0fb5c824d5c3e81286 Mon Sep 17 00:00:00 2001
From: Fernando Fernandez Mancera <ffmancera@riseup.net>
Date: Fri, 24 May 2019 15:06:50 +0200
Subject: [PATCH] src: Allow goto and jump to a variable

This patch introduces the use of nft input files variables in 'jump' and 'goto'
statements, e.g.

define dest = ber

add table ip foo
add chain ip foo bar {type filter hook input priority 0;}
add chain ip foo ber
add rule ip foo ber counter
add rule ip foo bar jump $dest

table ip foo {
        chain bar {
                type filter hook input priority filter; policy accept;
                jump ber
        }

        chain ber {
                counter packets 71 bytes 6664
        }
}

Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
(cherry picked from commit c64457cff9673fbb41f613a67e158b4d62235c09)

Conflicts:
-> Adjust for missing commits 72931553828af
   ("src: expr: add expression etype") and 68e76238749fb
   ("src: expr: add and use expr_name helper").

Signed-off-by: Phil Sutter <psutter@redhat.com>
---
 src/datatype.c                                | 11 ++++++++++
 src/evaluate.c                                |  7 +++++++
 src/parser_bison.y                            |  3 ++-
 .../shell/testcases/nft-f/0018jump_variable_0 | 19 ++++++++++++++++++
 .../shell/testcases/nft-f/0019jump_variable_1 | 20 +++++++++++++++++++
 .../shell/testcases/nft-f/0020jump_variable_1 | 20 +++++++++++++++++++
 .../nft-f/dumps/0018jump_variable_0.nft       |  8 ++++++++
 7 files changed, 87 insertions(+), 1 deletion(-)
 create mode 100755 tests/shell/testcases/nft-f/0018jump_variable_0
 create mode 100755 tests/shell/testcases/nft-f/0019jump_variable_1
 create mode 100755 tests/shell/testcases/nft-f/0020jump_variable_1
 create mode 100644 tests/shell/testcases/nft-f/dumps/0018jump_variable_0.nft

diff --git a/src/datatype.c b/src/datatype.c
index f7defa37ff196..5791a6a41599e 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -308,11 +308,22 @@ static void verdict_type_print(const struct expr *expr, struct output_ctx *octx)
 	}
 }
 
+static struct error_record *verdict_type_parse(const struct expr *sym,
+					       struct expr **res)
+{
+	*res = constant_expr_alloc(&sym->location, &string_type,
+				   BYTEORDER_HOST_ENDIAN,
+				   (strlen(sym->identifier) + 1) * BITS_PER_BYTE,
+				   sym->identifier);
+	return NULL;
+}
+
 const struct datatype verdict_type = {
 	.type		= TYPE_VERDICT,
 	.name		= "verdict",
 	.desc		= "netfilter verdict",
 	.print		= verdict_type_print,
+	.parse		= verdict_type_parse,
 };
 
 static const struct symbol_table nfproto_tbl = {
diff --git a/src/evaluate.c b/src/evaluate.c
index 5f0f3b36fd99f..8e15e71d8a33b 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1850,6 +1850,13 @@ static int stmt_evaluate_verdict(struct eval_ctx *ctx, struct stmt *stmt)
 		if (stmt->expr->chain != NULL) {
 			if (expr_evaluate(ctx, &stmt->expr->chain) < 0)
 				return -1;
+			if ((stmt->expr->chain->ops->type != EXPR_SYMBOL &&
+			    stmt->expr->chain->ops->type != EXPR_VALUE) ||
+			    stmt->expr->chain->symtype != SYMBOL_VALUE) {
+				return stmt_error(ctx, stmt,
+						  "invalid verdict chain expression %s\n",
+						  stmt->expr->chain->ops->name);
+			}
 		}
 		break;
 	case EXPR_MAP:
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 08dce52cebd1e..2e8ebde34eee6 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -3475,7 +3475,8 @@ verdict_expr		:	ACCEPT
 			}
 			;
 
-chain_expr		:	identifier
+chain_expr		:	variable_expr
+			|	identifier
 			{
 				$$ = constant_expr_alloc(&@$, &string_type,
 							 BYTEORDER_HOST_ENDIAN,
diff --git a/tests/shell/testcases/nft-f/0018jump_variable_0 b/tests/shell/testcases/nft-f/0018jump_variable_0
new file mode 100755
index 0000000000000..003a1bdf701f1
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0018jump_variable_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# Tests use of variables in jump statements
+
+set -e
+
+RULESET="
+define dest = ber
+
+table ip foo {
+	chain bar {
+		jump \$dest
+	}
+
+	chain ber {
+	}
+}"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0019jump_variable_1 b/tests/shell/testcases/nft-f/0019jump_variable_1
new file mode 100755
index 0000000000000..bda861c91df31
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0019jump_variable_1
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Tests use of variables in jump statements
+
+set -e
+
+RULESET="
+define dest = { 1024 }
+
+table ip foo {
+	chain bar {
+		jump \$dest
+	}
+
+	chain ber {
+	}
+}"
+
+$NFT -f - <<< "$RULESET" && exit 1
+exit 0
diff --git a/tests/shell/testcases/nft-f/0020jump_variable_1 b/tests/shell/testcases/nft-f/0020jump_variable_1
new file mode 100755
index 0000000000000..f753058f24f64
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0020jump_variable_1
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Tests use of variables in jump statements
+
+set -e
+
+RULESET="
+define dest = *
+
+table ip foo {
+	chain bar {
+		jump \$dest
+	}
+
+	chain ber {
+	}
+}"
+
+$NFT -f - <<< "$RULESET" && exit 1
+exit 0
diff --git a/tests/shell/testcases/nft-f/dumps/0018jump_variable_0.nft b/tests/shell/testcases/nft-f/dumps/0018jump_variable_0.nft
new file mode 100644
index 0000000000000..0ddaf07f0ea3b
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0018jump_variable_0.nft
@@ -0,0 +1,8 @@
+table ip foo {
+	chain bar {
+		jump ber
+	}
+
+	chain ber {
+	}
+}
-- 
2.21.0