nftables: added support for per-file variable scopes and global variables

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

 



Hello,

this series of patches follows a discussion brought here about adding support 
for deeper variable scopes especially in the flat notation. These patches add 
a new variable scope to each include statement. The new scope is a child of 
the parent scope (script in which the include resides). All variables in the 
parent are still accessible in the child but the parent cannot access child 
variables. This effectively creates a tree hierarchy and with the support of 
redefine, one can even mask inherited variables in the child scopes. Sibling 
scopes are not accessible from each other.

If one wants to have some global definitions in a separate script and not 
pollute the top-level script, one can use a new keyword global in the define 
like:

define global global_var=eth0

This puts $global_var to the top-level scope which is accessible from 
everywhere and it survives any include. Global re-definitions and undefines 
are also supported.

-- 
S pozdravem,

David Fabian
Cluster Design, s.r.o.
>From c889e9b659559248f50c357a042aed25fb247057 Mon Sep 17 00:00:00 2001
From: David Fabian <david.fabian@xxxxxxxxx>
Date: Mon, 8 Aug 2016 14:24:33 +0200
Subject: [PATCH 1/7] Fixed SIGSEGV when basetype is not set

---
 src/evaluate.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/evaluate.c b/src/evaluate.c
index 265a73f..c550ce0 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1150,7 +1150,7 @@ static int expr_evaluate_list(struct eval_ctx *ctx, struct expr **expr)
 			return expr_error(ctx->msgs, i,
 					  "List member must be a constant "
 					  "value");
-		if (i->dtype->basetype->type != TYPE_BITMASK)
+		if (!i->dtype->basetype || i->dtype->basetype->type != TYPE_BITMASK)
 			return expr_error(ctx->msgs, i,
 					  "Basetype of type %s is not bitmask",
 					  i->dtype->desc);
-- 
2.13.6

>From 362b18f2fdc3445a12f076649031ab1377db52f3 Mon Sep 17 00:00:00 2001
From: David Fabian <david.fabian@xxxxxxxxx>
Date: Wed, 21 Mar 2018 12:30:37 +0100
Subject: [PATCH 2/7] Added implicit variable scope to each include command to
 support local variables

---
 include/parser.h   | 10 ++++++++--
 src/libnftables.c  |  2 ++
 src/parser_bison.y | 19 +++++++++++++++----
 src/rule.c         |  1 +
 src/scanner.l      | 18 +++++++++++++++++-
 5 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/include/parser.h b/include/parser.h
index ea41ca0..1f3eb5f 100644
--- a/include/parser.h
+++ b/include/parser.h
@@ -4,14 +4,14 @@
 #include <list.h>
 #include <rule.h> // FIXME
 
-#define MAX_INCLUDE_DEPTH		16
+#define MAX_INCLUDE_DEPTH		64
 #define TABSIZE				8
 
 #define YYLTYPE				struct location
 #define YYLTYPE_IS_TRIVIAL		0
 #define YYENABLE_NLS			0
 
-#define SCOPE_NEST_MAX			3
+#define SCOPE_NEST_MAX			(MAX_INCLUDE_DEPTH + 3)
 
 struct parser_state {
 	struct input_descriptor		*indesc;
@@ -33,6 +33,12 @@ struct mnl_socket;
 
 extern void parser_init(struct nft_ctx *nft, struct parser_state *state,
 			struct list_head *msgs, struct list_head *cmds);
+extern void parser_destroy(struct parser_state *state);
+
+extern void open_scope(struct parser_state *state, struct scope *scope);
+extern void close_scope(struct parser_state *state);
+extern struct scope *current_scope(const struct parser_state *state);
+
 extern int nft_parse(struct nft_ctx *ctx, void *, struct parser_state *state);
 
 extern void *scanner_init(struct parser_state *state);
diff --git a/src/libnftables.c b/src/libnftables.c
index f336dbc..959a5d6 100644
--- a/src/libnftables.c
+++ b/src/libnftables.c
@@ -421,6 +421,7 @@ int nft_run_cmd_from_buffer(struct nft_ctx *nft, char *buf, size_t buflen)
 	}
 	erec_print_list(&nft->output, &msgs, nft->debug_mask);
 	scanner_destroy(scanner);
+	parser_destroy(&state);
 	iface_cache_release();
 	free(nlbuf);
 
@@ -460,6 +461,7 @@ err:
 	}
 	erec_print_list(&nft->output, &msgs, nft->debug_mask);
 	scanner_destroy(scanner);
+	parser_destroy(&state);
 	iface_cache_release();
 
 	return rc;
diff --git a/src/parser_bison.y b/src/parser_bison.y
index f546b9e..bb74715 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -51,27 +51,38 @@ void parser_init(struct nft_ctx *nft, struct parser_state *state,
 	state->ectx.octx = &nft->output;
 }
 
+void parser_destroy(struct parser_state *state)
+{
+	scope_release(state->scopes[0]);
+}
+
 static void yyerror(struct location *loc, struct nft_ctx *nft, void *scanner,
 		    struct parser_state *state, const char *s)
 {
 	erec_queue(error(loc, "%s", s), state->msgs);
 }
 
-static struct scope *current_scope(const struct parser_state *state)
+static struct scope *toplevel_scope(const struct parser_state *state)
+{
+	return state->scopes[0];
+}
+
+struct scope *current_scope(const struct parser_state *state)
 {
 	return state->scopes[state->scope];
 }
 
-static void open_scope(struct parser_state *state, struct scope *scope)
+void open_scope(struct parser_state *state, struct scope *scope)
 {
 	assert(state->scope < array_size(state->scopes) - 1);
 	scope_init(scope, current_scope(state));
 	state->scopes[++state->scope] = scope;
 }
 
-static void close_scope(struct parser_state *state)
+void close_scope(struct parser_state *state)
 {
 	assert(state->scope > 0);
+	scope_release(state->scopes[state->scope]);
 	state->scope--;
 }
 
@@ -778,6 +789,7 @@ common_block		:	INCLUDE		QUOTED_STRING	stmt_separator
 					erec_queue(error(&@2, "redefinition of symbol '%s'", $2),
 						   state->msgs);
 					xfree($2);
+					expr_free($4);
 					YYERROR;
 				}
 
@@ -840,7 +852,6 @@ line			:	common_block			{ $$ = NULL; }
 				if (state->nerrs)
 					YYABORT;
 				$$ = NULL;
-
 				YYACCEPT;
 			}
 			;
diff --git a/src/rule.c b/src/rule.c
index 3066145..a348ba2 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -17,6 +17,7 @@
 #include <errno.h>
 
 #include <statement.h>
+#include <parser.h>
 #include <rule.h>
 #include <utils.h>
 #include <netdb.h>
diff --git a/src/scanner.l b/src/scanner.l
index 5f21bfd..e546134 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -627,7 +627,15 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 {comment}
 
 <<EOF>> 		{
-				update_pos(yyget_extra(yyscanner), yylloc, 1);
+				struct parser_state *state = yyget_extra(yyscanner);
+				struct scope *scope = current_scope(state);
+				update_pos(state, yylloc, 1);
+				/* only close scope if file was included, skip buffer parsing
+				   since it does not create new scope */
+				if (state->indesc && state->indesc->name) {
+					close_scope(state);
+					xfree(scope);
+				}
 				scanner_pop_buffer(yyscanner);
 				if (YY_CURRENT_BUFFER == NULL)
 					return TOKEN_EOF;
@@ -642,6 +650,10 @@ static void scanner_pop_buffer(yyscan_t scanner)
 	struct parser_state *state = yyget_extra(scanner);
 
 	yypop_buffer_state(scanner);
+	if (state->indesc && state->indesc->name) {
+		xfree(state->indesc->name);
+		state->indesc->name = NULL;
+	}
 	state->indesc = &state->indescs[--state->indesc_idx - 1];
 }
 
@@ -649,6 +661,7 @@ static struct error_record *scanner_push_file(void *scanner, const char *filenam
 					      FILE *f, const struct location *loc)
 {
 	struct parser_state *state = yyget_extra(scanner);
+	struct scope *scope = NULL;
 	YY_BUFFER_STATE b;
 
 	if (state->indesc_idx == MAX_INCLUDE_DEPTH) {
@@ -666,6 +679,9 @@ static struct error_record *scanner_push_file(void *scanner, const char *filenam
 	state->indesc->type	= INDESC_FILE;
 	state->indesc->name	= xstrdup(filename);
 	init_pos(state);
+	scope = xzalloc(sizeof(*scope));
+	init_list_head(&scope->symbols);
+	open_scope(state, scope);
 	return NULL;
 }
 
-- 
2.13.6

>From 947874e28a9ec00963dcedd801333691cb96a672 Mon Sep 17 00:00:00 2001
From: David Fabian <david.fabian@xxxxxxxxx>
Date: Mon, 30 Apr 2018 09:17:59 +0200
Subject: [PATCH 5/7] Added tests for nested file-based scopes

---
 tests/shell/testcases/include/0016sibling_scopes_0 | 33 ++++++++++++++++++
 .../shell/testcases/include/0017scope_hierarchy_0  | 39 ++++++++++++++++++++++
 tests/shell/testcases/include/0018global_define_0  | 36 ++++++++++++++++++++
 .../include/dumps/0016sibling_scopes_0.nft         |  0
 .../include/dumps/0017scope_hierarchy_0.nft        |  0
 .../include/dumps/0018global_define_0.nft          |  0
 6 files changed, 108 insertions(+)
 create mode 100755 tests/shell/testcases/include/0016sibling_scopes_0
 create mode 100755 tests/shell/testcases/include/0017scope_hierarchy_0
 create mode 100755 tests/shell/testcases/include/0018global_define_0
 create mode 100644 tests/shell/testcases/include/dumps/0016sibling_scopes_0.nft
 create mode 100644 tests/shell/testcases/include/dumps/0017scope_hierarchy_0.nft
 create mode 100644 tests/shell/testcases/include/dumps/0018global_define_0.nft

diff --git a/tests/shell/testcases/include/0016sibling_scopes_0 b/tests/shell/testcases/include/0016sibling_scopes_0
new file mode 100755
index 0000000..c8b4d7f
--- /dev/null
+++ b/tests/shell/testcases/include/0016sibling_scopes_0
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -e
+
+tmpdir=$(mktemp -d)
+if [ ! -d $tmpdir ] ; then
+        echo "Failed to create tmp directory" >&2
+        exit 0
+fi
+
+# cleanup if aborted
+trap "rm -rf $tmpdir" EXIT
+
+cat > $tmpdir/top.nft << EOF
+include "$tmpdir/a.nft"
+include "$tmpdir/b.nft"
+
+EOF
+
+cat > $tmpdir/a.nft << EOF
+define AAA = "testa"
+EOF
+
+cat > $tmpdir/b.nft << EOF
+define AAA = "testb"
+EOF
+
+$NFT -f $tmpdir/top.nft
+
+if [ $? -ne 0 ] ; then
+        echo "E: unable to load good ruleset" >&2
+        exit 1
+fi
\ No newline at end of file
diff --git a/tests/shell/testcases/include/0017scope_hierarchy_0 b/tests/shell/testcases/include/0017scope_hierarchy_0
new file mode 100755
index 0000000..ba99a58
--- /dev/null
+++ b/tests/shell/testcases/include/0017scope_hierarchy_0
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+set -e
+
+tmpdir=$(mktemp -d)
+if [ ! -d $tmpdir ] ; then
+        echo "Failed to create tmp directory" >&2
+        exit 0
+fi
+
+# cleanup if aborted
+trap "rm -rf $tmpdir" EXIT
+
+cat > $tmpdir/top.nft << EOF
+define TOP = "top"
+include "$tmpdir/a.nft"
+EOF
+
+cat > $tmpdir/a.nft << EOF
+define AAA = "testa"
+include "$tmpdir/sub/*.nft"
+EOF
+
+mkdir $tmpdir/sub &> /dev/null
+
+cat > $tmpdir/sub/b.nft << EOF
+define FOO = { \$TOP, abc }
+EOF
+
+cat > $tmpdir/sub/c.nft << EOF
+define BAR = { \$AAA, cdef }
+EOF
+
+$NFT -f $tmpdir/top.nft
+
+if [ $? -ne 0 ] ; then
+        echo "E: unable to load good ruleset" >&2
+        exit 1
+fi
\ No newline at end of file
diff --git a/tests/shell/testcases/include/0018global_define_0 b/tests/shell/testcases/include/0018global_define_0
new file mode 100755
index 0000000..c942a8b
--- /dev/null
+++ b/tests/shell/testcases/include/0018global_define_0
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+set -e
+
+tmpdir=$(mktemp -d)
+if [ ! -d $tmpdir ] ; then
+        echo "Failed to create tmp directory" >&2
+        exit 0
+fi
+
+# cleanup if aborted
+trap "rm -rf $tmpdir" EXIT
+
+cat > $tmpdir/top.nft << EOF
+define TOP = "top"
+include "$tmpdir/a.nft"
+define CCC = \$BBB
+EOF
+
+cat > $tmpdir/a.nft << EOF
+define AAA = "testa"
+include "$tmpdir/sub/b.nft"
+EOF
+
+mkdir $tmpdir/sub &> /dev/null
+
+cat > $tmpdir/sub/b.nft << EOF
+define global BBB = "global"
+EOF
+
+$NFT -f $tmpdir/top.nft
+
+if [ $? -ne 0 ] ; then
+        echo "E: unable to load good ruleset" >&2
+        exit 1
+fi
\ No newline at end of file
diff --git a/tests/shell/testcases/include/dumps/0016sibling_scopes_0.nft b/tests/shell/testcases/include/dumps/0016sibling_scopes_0.nft
new file mode 100644
index 0000000..e69de29
diff --git a/tests/shell/testcases/include/dumps/0017scope_hierarchy_0.nft b/tests/shell/testcases/include/dumps/0017scope_hierarchy_0.nft
new file mode 100644
index 0000000..e69de29
diff --git a/tests/shell/testcases/include/dumps/0018global_define_0.nft b/tests/shell/testcases/include/dumps/0018global_define_0.nft
new file mode 100644
index 0000000..e69de29
-- 
2.13.6

>From d5f70178197754e70322140b476542425096d969 Mon Sep 17 00:00:00 2001
From: David Fabian <david.fabian@xxxxxxxxx>
Date: Tue, 20 Mar 2018 11:24:57 +0100
Subject: [PATCH 3/7] Added support for global variable definitions. Global
 variables live only in the top-level scope and can be accessed from anywhere.
 They are unloaded at the end of parsing.

Fixed a SIGSEGV when a local variable is used in global definition and the local sope gets deleted
---
 include/rule.h     |   5 +-
 src/parser_bison.y | 334 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/rule.c         |  15 ++-
 src/scanner.l      |   1 +
 4 files changed, 346 insertions(+), 9 deletions(-)
 mode change 100644 => 100755 src/parser_bison.y
 mode change 100644 => 100755 src/scanner.l

diff --git a/include/rule.h b/include/rule.h
index 86f7281..7505898 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -88,8 +88,9 @@ extern void symbol_bind(struct scope *scope, const char *identifier,
 			struct expr *expr);
 extern int symbol_unbind(const struct scope *scope, const char *identifier);
 extern struct symbol *symbol_lookup(const struct scope *scope,
-				    const char *identifier);
-struct symbol *symbol_get(const struct scope *scope, const char *identifier);
+									const char *identifier, int *global);
+struct symbol *symbol_get(const struct scope *scope, const char *identifier,
+						  int *global);
 
 enum table_flags {
 	TABLE_F_DORMANT		= (1 << 0),
diff --git a/src/parser_bison.y b/src/parser_bison.y
old mode 100644
new mode 100755
index bb74715..4acdb44
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -198,6 +198,7 @@ int nft_lex(void *, void *, void *);
 %token DEFINE			"define"
 %token REDEFINE			"redefine"
 %token UNDEFINE			"undefine"
+%token GLOBAL			"global"
 
 %token FIB			"fib"
 
@@ -744,6 +745,18 @@ int nft_lex(void *, void *, void *);
 
 %type <val>			ct_l4protoname ct_obj_type
 
+%type <expr>		global_list_rhs_expr global_rhs_expr global_variable_expr global_basic_rhs_expr global_primary_rhs_expr global_symbol_expr
+%destructor { expr_free($$); }	global_list_rhs_expr global_rhs_expr global_variable_expr global_basic_rhs_expr global_primary_rhs_expr global_symbol_expr
+
+%type <expr>		 global_set_lhs_expr global_set_rhs_expr global_shift_rhs_expr global_and_rhs_expr global_exclusive_or_rhs_expr global_inclusive_or_rhs_expr
+%destructor { expr_free($$); }	 global_set_lhs_expr global_set_rhs_expr global_shift_rhs_expr global_and_rhs_expr global_exclusive_or_rhs_expr global_inclusive_or_rhs_expr
+
+%type <expr>		global_concat_rhs_expr global_prefix_rhs_expr global_initializer_expr
+%destructor { expr_free($$); }	global_concat_rhs_expr global_prefix_rhs_expr global_initializer_expr
+
+%type <expr>		global_range_rhs_expr global_set_list_expr global_set_list_member_expr global_set_elem_expr_alloc global_set_expr global_set_elem_expr global_multiton_rhs_expr
+%destructor { expr_free($$); }	global_range_rhs_expr global_set_list_expr global_set_list_member_expr global_set_elem_expr_alloc global_set_expr global_set_elem_expr global_multiton_rhs_expr
+
 %%
 
 input			:	/* empty */
@@ -785,7 +798,7 @@ common_block		:	INCLUDE		QUOTED_STRING	stmt_separator
 			{
 				struct scope *scope = current_scope(state);
 
-				if (symbol_lookup(scope, $2) != NULL) {
+				if (symbol_lookup(scope, $2, NULL) != NULL) {
 					erec_queue(error(&@2, "redefinition of symbol '%s'", $2),
 						   state->msgs);
 					xfree($2);
@@ -812,8 +825,45 @@ common_block		:	INCLUDE		QUOTED_STRING	stmt_separator
 						   state->msgs);
 					YYERROR;
 				}
+
 				xfree($2);
 			}
+			|	DEFINE	GLOBAL	identifier	'='	global_initializer_expr	stmt_separator
+			{
+				struct scope *scope = toplevel_scope(state);
+
+				if (symbol_lookup(scope, $3, NULL) != NULL) {
+					erec_queue(error(&@2, "redefinition of global symbol '%s'", $3),
+						   state->msgs);
+					xfree($3);
+					expr_free($5);
+					YYERROR;
+				}
+
+				symbol_bind(scope, $3, $5);
+				xfree($3);
+			}
+			|	REDEFINE	GLOBAL	identifier	'='	global_initializer_expr	stmt_separator
+			{
+				struct scope *scope = toplevel_scope(state);
+
+				/* ignore missing identifier */
+				symbol_unbind(scope, $3);
+				symbol_bind(scope, $3, $5);
+				xfree($3);
+			}
+			|	UNDEFINE	GLOBAL	identifier	stmt_separator
+			{
+				struct scope *scope = toplevel_scope(state);
+
+				if (symbol_unbind(scope, $3) < 0) {
+					erec_queue(error(&@2, "undefined global symbol '%s'", $3),
+						   state->msgs);
+					YYERROR;
+				}
+
+				xfree($3);
+			}
 			|	error		stmt_separator
 			{
 				if (++state->nerrs == nft->parser_max_errors)
@@ -2788,8 +2838,9 @@ variable_expr		:	'$'	identifier
 			{
 				struct scope *scope = current_scope(state);
 				struct symbol *sym;
+				int global;
 
-				sym = symbol_get(scope, $2);
+				sym = symbol_get(scope, $2, &global);
 				if (!sym) {
 					erec_queue(error(&@2, "unknown identifier '%s'", $2),
 						   state->msgs);
@@ -2797,7 +2848,13 @@ variable_expr		:	'$'	identifier
 					YYERROR;
 				}
 
-				$$ = variable_expr_alloc(&@$, scope, sym);
+				if (global)
+					/* global variables can only access top-level scope
+					   this prevents SIGSEGVs when the local scope in which
+					   the global is used has been freed */
+					$$ = variable_expr_alloc(&@$, toplevel_scope(state), sym);
+				else
+					$$ = variable_expr_alloc(&@$, scope, sym);
 				xfree($2);
 			}
 			;
@@ -4068,4 +4125,275 @@ exthdr_key		:	HBH	{ $$ = IPPROTO_HOPOPTS; }
 			|	MH	{ $$ = IPPROTO_MH; }
 			;
 
+global_initializer_expr	:	global_rhs_expr
+			|	global_list_rhs_expr
+			;
+
+global_list_rhs_expr		:	global_basic_rhs_expr		COMMA		global_basic_rhs_expr
+			{
+				$$ = list_expr_alloc(&@$);
+				compound_expr_add($$, $1);
+				compound_expr_add($$, $3);
+			}
+			|	global_list_rhs_expr		COMMA		global_basic_rhs_expr
+			{
+				$1->location = @$;
+				compound_expr_add($1, $3);
+				$$ = $1;
+			}
+			;
+
+global_rhs_expr		:	global_concat_rhs_expr		{ $$ = $1; }
+			|	global_multiton_rhs_expr	{ $$ = $1; }
+			|	global_set_expr		{ $$ = $1; }
+			;
+
+global_variable_expr		:	'$'	identifier
+			{
+				struct scope *scope = toplevel_scope(state);
+				struct symbol *sym;
+
+				sym = symbol_get(scope, $2, NULL);
+				if (!sym) {
+					scope = current_scope(state);
+					if (symbol_lookup(scope, $2, NULL) != NULL) {
+						erec_queue(error(&@2, "local variable '%s' not allowed in global definition", $2),
+							state->msgs);
+					} else {
+						erec_queue(error(&@2, "unknown identifier '%s'", $2),
+							state->msgs);
+					}
+					xfree($2);
+					YYERROR;
+				}
+				$$ = variable_expr_alloc(&@$, scope, sym);
+				xfree($2);
+			}
+			;
+
+global_symbol_expr		:	global_variable_expr
+			|	string
+			{
+				$$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
+						       toplevel_scope(state),
+						       $1);
+				xfree($1);
+			}
+			|	AT	identifier
+			{
+				$$ = symbol_expr_alloc(&@$, SYMBOL_SET,
+						       toplevel_scope(state),
+						       $2);
+				xfree($2);
+			}
+			;
+
+global_primary_rhs_expr	:	global_symbol_expr		{ $$ = $1; }
+			|	integer_expr		{ $$ = $1; }
+			|	boolean_expr		{ $$ = $1; }
+			|	keyword_expr		{ $$ = $1; }
+			|	TCP
+			{
+				uint8_t data = IPPROTO_TCP;
+				$$ = constant_expr_alloc(&@$, &inet_protocol_type,
+							 BYTEORDER_HOST_ENDIAN,
+							 sizeof(data) * BITS_PER_BYTE, &data);
+			}
+			|	UDP
+			{
+				uint8_t data = IPPROTO_UDP;
+				$$ = constant_expr_alloc(&@$, &inet_protocol_type,
+							 BYTEORDER_HOST_ENDIAN,
+							 sizeof(data) * BITS_PER_BYTE, &data);
+			}
+			|	UDPLITE
+			{
+				uint8_t data = IPPROTO_UDPLITE;
+				$$ = constant_expr_alloc(&@$, &inet_protocol_type,
+							 BYTEORDER_HOST_ENDIAN,
+							 sizeof(data) * BITS_PER_BYTE, &data);
+			}
+			|	ESP
+			{
+				uint8_t data = IPPROTO_ESP;
+				$$ = constant_expr_alloc(&@$, &inet_protocol_type,
+							 BYTEORDER_HOST_ENDIAN,
+							 sizeof(data) * BITS_PER_BYTE, &data);
+			}
+			|	AH
+			{
+				uint8_t data = IPPROTO_AH;
+				$$ = constant_expr_alloc(&@$, &inet_protocol_type,
+							 BYTEORDER_HOST_ENDIAN,
+							 sizeof(data) * BITS_PER_BYTE, &data);
+			}
+			|	ICMP
+			{
+				uint8_t data = IPPROTO_ICMP;
+				$$ = constant_expr_alloc(&@$, &inet_protocol_type,
+							 BYTEORDER_HOST_ENDIAN,
+							 sizeof(data) * BITS_PER_BYTE, &data);
+			}
+			|	ICMP6
+			{
+				uint8_t data = IPPROTO_ICMPV6;
+				$$ = constant_expr_alloc(&@$, &inet_protocol_type,
+							 BYTEORDER_HOST_ENDIAN,
+							 sizeof(data) * BITS_PER_BYTE, &data);
+			}
+			|	COMP
+			{
+				uint8_t data = IPPROTO_COMP;
+				$$ = constant_expr_alloc(&@$, &inet_protocol_type,
+							 BYTEORDER_HOST_ENDIAN,
+							 sizeof(data) * BITS_PER_BYTE, &data);
+			}
+			|	DCCP
+			{
+				uint8_t data = IPPROTO_DCCP;
+				$$ = constant_expr_alloc(&@$, &inet_protocol_type,
+							 BYTEORDER_HOST_ENDIAN,
+							 sizeof(data) * BITS_PER_BYTE, &data);
+			}
+			|	SCTP
+			{
+				uint8_t data = IPPROTO_SCTP;
+				$$ = constant_expr_alloc(&@$, &inet_protocol_type,
+							 BYTEORDER_HOST_ENDIAN,
+							 sizeof(data) * BITS_PER_BYTE, &data);
+			}
+			|	REDIRECT
+			{
+				uint8_t data = ICMP_REDIRECT;
+				$$ = constant_expr_alloc(&@$, &icmp_type_type,
+							 BYTEORDER_HOST_ENDIAN,
+							 sizeof(data) * BITS_PER_BYTE, &data);
+			}
+			;
+
+global_shift_rhs_expr		:	global_primary_rhs_expr
+			|	global_shift_rhs_expr		LSHIFT		global_primary_rhs_expr
+			{
+				$$ = binop_expr_alloc(&@$, OP_LSHIFT, $1, $3);
+			}
+			|	global_shift_rhs_expr		RSHIFT		global_primary_rhs_expr
+			{
+				$$ = binop_expr_alloc(&@$, OP_RSHIFT, $1, $3);
+			}
+			;
+
+global_and_rhs_expr		:	global_shift_rhs_expr
+			|	global_and_rhs_expr		AMPERSAND	global_shift_rhs_expr
+			{
+				$$ = binop_expr_alloc(&@$, OP_AND, $1, $3);
+			}
+			;
+
+global_exclusive_or_rhs_expr	:	global_and_rhs_expr
+			|	global_exclusive_or_rhs_expr	CARET		global_and_rhs_expr
+			{
+				$$ = binop_expr_alloc(&@$, OP_XOR, $1, $3);
+			}
+			;
+
+global_inclusive_or_rhs_expr	:	global_exclusive_or_rhs_expr
+			|	global_inclusive_or_rhs_expr	'|'		global_exclusive_or_rhs_expr
+			{
+				$$ = binop_expr_alloc(&@$, OP_OR, $1, $3);
+			}
+			;
+
+global_basic_rhs_expr		:	global_inclusive_or_rhs_expr
+			;
+
+global_concat_rhs_expr		:	global_basic_rhs_expr
+			|	global_concat_rhs_expr	DOT	global_basic_rhs_expr
+			{
+				if ($$->ops->type != EXPR_CONCAT) {
+					$$ = concat_expr_alloc(&@$);
+					compound_expr_add($$, $1);
+				} else {
+					struct location rhs[] = {
+						[1]	= @2,
+						[2]	= @3,
+					};
+					location_update(&$3->location, rhs, 2);
+
+					$$ = $1;
+					$$->location = @$;
+				}
+				compound_expr_add($$, $3);
+			}
+			;
+
+global_prefix_rhs_expr		:	global_basic_rhs_expr	SLASH	NUM
+			{
+				$$ = prefix_expr_alloc(&@$, $1, $3);
+			}
+			;
+
+global_range_rhs_expr		:	global_basic_rhs_expr	DASH	global_basic_rhs_expr
+			{
+				$$ = range_expr_alloc(&@$, $1, $3);
+			}
+			;
+
+global_multiton_rhs_expr	:	global_prefix_rhs_expr
+			|	global_range_rhs_expr
+			|	wildcard_rhs_expr
+			;
+
+
+
+global_set_list_expr		:	global_set_list_member_expr
+			{
+				$$ = set_expr_alloc(&@$, NULL);
+				compound_expr_add($$, $1);
+			}
+			|	global_set_list_expr		COMMA	global_set_list_member_expr
+			{
+				compound_expr_add($1, $3);
+				$$ = $1;
+			}
+			|	global_set_list_expr		COMMA	opt_newline
+			;
+
+global_set_list_member_expr	:	opt_newline	global_set_expr	opt_newline
+			{
+				$$ = $2;
+			}
+			|	opt_newline	global_set_elem_expr	opt_newline
+			{
+				$$ = $2;
+			}
+			|	opt_newline	global_set_elem_expr	COLON	global_set_rhs_expr	opt_newline
+			{
+				$$ = mapping_expr_alloc(&@$, $2, $4);
+			}
+			;
+
+global_set_lhs_expr		:	global_concat_rhs_expr
+			|	global_multiton_rhs_expr
+			;
+
+global_set_rhs_expr		:	global_concat_rhs_expr
+			|	verdict_expr
+			;
+
+global_set_elem_expr		:	global_set_elem_expr_alloc
+			|	global_set_elem_expr_alloc		set_elem_options
+			;
+
+global_set_elem_expr_alloc	:	global_set_lhs_expr
+			{
+				$$ = set_elem_expr_alloc(&@1, $1);
+			}
+			;
+
+global_set_expr		:	'{'	global_set_list_expr		'}'
+			{
+				$2->location = @$;
+				$$ = $2;
+			}
+			;
 %%
diff --git a/src/rule.c b/src/rule.c
index a348ba2..35debfe 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -520,11 +520,12 @@ void symbol_bind(struct scope *scope, const char *identifier, struct expr *expr)
 	list_add(&sym->list, &scope->symbols);
 }
 
-struct symbol *symbol_get(const struct scope *scope, const char *identifier)
+struct symbol *symbol_get(const struct scope *scope, const char *identifier,
+						  int *global)
 {
 	struct symbol *sym;
 
-	sym = symbol_lookup(scope, identifier);
+	sym = symbol_lookup(scope, identifier, global);
 	if (!sym)
 		return NULL;
 
@@ -560,14 +561,20 @@ int symbol_unbind(const struct scope *scope, const char *identifier)
 	return 0;
 }
 
-struct symbol *symbol_lookup(const struct scope *scope, const char *identifier)
+struct symbol *symbol_lookup(const struct scope *scope, const char *identifier,
+							 int *global)
 {
 	struct symbol *sym;
 
+	if (global)
+		*global = 0;
 	while (scope != NULL) {
 		list_for_each_entry(sym, &scope->symbols, list) {
-			if (!strcmp(sym->identifier, identifier))
+			if (!strcmp(sym->identifier, identifier)) {
+				if (global && scope->parent == NULL)
+					*global = 1;
 				return sym;
+			}
 		}
 		scope = scope->parent;
 	}
diff --git a/src/scanner.l b/src/scanner.l
old mode 100644
new mode 100755
index e546134..a576c23
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -235,6 +235,7 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "define"		{ return DEFINE; }
 "redefine"		{ return REDEFINE; }
 "undefine"		{ return UNDEFINE; }
+"global"		{ return GLOBAL; }
 
 "describe"		{ return DESCRIBE; }
 
-- 
2.13.6

>From f64e8d81da3088a0b73ab3c667301adf635482af Mon Sep 17 00:00:00 2001
From: David Fabian <david.fabian@xxxxxxxxx>
Date: Tue, 27 Mar 2018 09:18:03 +0200
Subject: [PATCH 4/7] Refactoring of indesc hierarchy. Indesc structure is now
 bound to scopes. Fixed issues with glob includes incorrectly increase the
 inclusion depth value. The entire scope tree gets cleaned up at the end of
 parsing now to properly support displaying of error messages.

---
 include/nftables.h |  10 +++--
 include/parser.h   |  15 +++----
 include/rule.h     |  15 +++++--
 src/parser_bison.y |  64 ++++++++++++++++++++--------
 src/rule.c         |  54 ++++++++++++++++++++----
 src/scanner.l      | 120 +++++++++++++++++++++--------------------------------
 6 files changed, 163 insertions(+), 115 deletions(-)

diff --git a/include/nftables.h b/include/nftables.h
index 5f2da8b..ddb9602 100644
--- a/include/nftables.h
+++ b/include/nftables.h
@@ -114,13 +114,15 @@ struct input_descriptor {
 	struct location			location;
 	enum input_descriptor_types	type;
 	const char			*name;
-	const char			*data;
+	union {
+		const char		*data;
+		FILE			*fp;
+	};
 	unsigned int			lineno;
 	unsigned int			column;
-	off_t				token_offset;
-	off_t				line_offset;
+	off_t					token_offset;
+	off_t					line_offset;
 };
-
 void ct_label_table_init(void);
 void mark_table_init(void);
 void gmp_init(void);
diff --git a/include/parser.h b/include/parser.h
index 1f3eb5f..eabb2f4 100644
--- a/include/parser.h
+++ b/include/parser.h
@@ -4,26 +4,19 @@
 #include <list.h>
 #include <rule.h> // FIXME
 
-#define MAX_INCLUDE_DEPTH		64
+#define MAX_INCLUDE_DEPTH		16
 #define TABSIZE				8
 
 #define YYLTYPE				struct location
 #define YYLTYPE_IS_TRIVIAL		0
 #define YYENABLE_NLS			0
 
-#define SCOPE_NEST_MAX			(MAX_INCLUDE_DEPTH + 3)
-
 struct parser_state {
-	struct input_descriptor		*indesc;
-	struct input_descriptor		indescs[MAX_INCLUDE_DEPTH];
-	unsigned int			indesc_idx;
-
 	struct list_head		*msgs;
 	unsigned int			nerrs;
 
-	struct scope			top_scope;
-	struct scope			*scopes[SCOPE_NEST_MAX];
-	unsigned int			scope;
+	struct scope 			*top_scope; // top-level scope
+	struct scope			*scope; // current scope
 
 	struct list_head		*cmds;
 	struct eval_ctx			ectx;
@@ -37,7 +30,9 @@ extern void parser_destroy(struct parser_state *state);
 
 extern void open_scope(struct parser_state *state, struct scope *scope);
 extern void close_scope(struct parser_state *state);
+extern struct scope *toplevel_scope(const struct parser_state *state);
 extern struct scope *current_scope(const struct parser_state *state);
+extern struct input_descriptor* get_indesc(struct parser_state *state);
 
 extern int nft_parse(struct nft_ctx *ctx, void *, struct parser_state *state);
 
diff --git a/include/rule.h b/include/rule.h
index 7505898..e6b53df 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -61,12 +61,19 @@ extern void handle_free(struct handle *h);
  * @parent:	pointer to parent scope
  * @symbols:	symbols bound in the scope
  */
+struct input_descriptor;
 struct scope {
-	const struct scope	*parent;
+	struct list_head	list;
+	struct scope	*parent;
+	struct list_head		scopes;
+	struct input_descriptor	*indesc;
+	int depth;
 	struct list_head	symbols;
 };
 
-extern struct scope *scope_init(struct scope *scope, const struct scope *parent);
+extern struct input_descriptor* indesc_alloc(void);
+extern struct scope *scope_alloc(struct scope *parent, 
+								 struct input_descriptor *parent_indesc);
 extern void scope_release(const struct scope *scope);
 
 /**
@@ -113,7 +120,7 @@ struct table {
 	struct list_head	list;
 	struct handle		handle;
 	struct location		location;
-	struct scope		scope;
+	struct scope		*scope;
 	struct list_head	chains;
 	struct list_head	sets;
 	struct list_head	objs;
@@ -166,7 +173,7 @@ struct chain {
 	int			policy;
 	const char		*type;
 	const char		*dev;
-	struct scope		scope;
+	struct scope		*scope;
 	struct list_head	rules;
 };
 
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 4acdb44..49ab064 100755
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -36,14 +36,23 @@
 
 #include "parser_bison.h"
 
+struct scope *toplevel_scope(const struct parser_state *state)
+{
+	return state->top_scope;
+}
+
+struct scope *current_scope(const struct parser_state *state)
+{
+	return state->scope;
+}
+
 void parser_init(struct nft_ctx *nft, struct parser_state *state,
 		 struct list_head *msgs, struct list_head *cmds)
 {
 	memset(state, 0, sizeof(*state));
-	init_list_head(&state->top_scope.symbols);
 	state->msgs = msgs;
 	state->cmds = cmds;
-	state->scopes[0] = scope_init(&state->top_scope, NULL);
+	state->top_scope = state->scope = scope_alloc(NULL, NULL);
 	state->ectx.cache = &nft->cache;
 	state->ectx.msgs = msgs;
 	state->ectx.nf_sock = nft->nf_sock;
@@ -53,7 +62,7 @@ void parser_init(struct nft_ctx *nft, struct parser_state *state,
 
 void parser_destroy(struct parser_state *state)
 {
-	scope_release(state->scopes[0]);
+	scope_release(state->top_scope);
 }
 
 static void yyerror(struct location *loc, struct nft_ctx *nft, void *scanner,
@@ -62,35 +71,50 @@ static void yyerror(struct location *loc, struct nft_ctx *nft, void *scanner,
 	erec_queue(error(loc, "%s", s), state->msgs);
 }
 
-static struct scope *toplevel_scope(const struct parser_state *state)
+void open_scope(struct parser_state *state, struct scope *scope)
 {
-	return state->scopes[0];
+	list_add_tail(&scope->list, &state->scope->scopes);
+	state->scope = scope;
 }
 
-struct scope *current_scope(const struct parser_state *state)
+void open_scope_glob(struct parser_state *state, struct scope *scope)
 {
-	return state->scopes[state->scope];
+	/* add the scope to the head of the current scope level list */
+	list_add(&scope->list, state->scope->list.prev);
+	state->scope = scope;
 }
 
-void open_scope(struct parser_state *state, struct scope *scope)
+void close_scope(struct parser_state *state)
 {
-	assert(state->scope < array_size(state->scopes) - 1);
-	scope_init(scope, current_scope(state));
-	state->scopes[++state->scope] = scope;
+	struct scope *scope = state->scope;
+	assert(state->scope->parent != NULL);
+
+	/* no additional globs, backtrack */
+	if (list_is_last(&scope->list, &scope->parent->scopes))
+		state->scope = scope->parent;
+	else
+		state->scope = list_entry(scope->list.next, struct scope, list);
 }
 
-void close_scope(struct parser_state *state)
+
+struct input_descriptor* get_indesc(struct parser_state *state)
 {
-	assert(state->scope > 0);
-	scope_release(state->scopes[state->scope]);
-	state->scope--;
+	struct scope *scope = state->scope;
+	while (scope) {
+		if (scope->indesc)
+			return scope->indesc;
+		scope = scope->parent;
+	}
+	/* should never happen */
+	assert(false);
+	return NULL;
 }
 
 static void location_init(void *scanner, struct parser_state *state,
 			  struct location *loc)
 {
 	memset(loc, 0, sizeof(*loc));
-	loc->indesc = state->indesc;
+	loc->indesc = get_indesc(state);
 }
 
 static void location_update(struct location *loc, struct location *rhs, int n)
@@ -1409,8 +1433,10 @@ describe_cmd		:	primary_expr
 
 table_block_alloc	:	/* empty */
 			{
+				struct scope *scope = scope_alloc(current_scope(state), NULL);
 				$$ = table_alloc();
-				open_scope(state, &$$->scope);
+				$$->scope->parent = current_scope(state);
+				open_scope(state, scope);
 			}
 			;
 
@@ -1520,8 +1546,10 @@ table_block		:	/* empty */	{ $$ = $<table>-1; }
 
 chain_block_alloc	:	/* empty */
 			{
+				struct scope *scope = scope_alloc(current_scope(state), NULL);
 				$$ = chain_alloc(NULL);
-				open_scope(state, &$$->scope);
+				$$->scope->parent = current_scope(state);
+				open_scope(state, scope);
 			}
 			;
 
diff --git a/src/rule.c b/src/rule.c
index 35debfe..cad23c9 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -489,15 +489,42 @@ struct rule *rule_lookup(const struct chain *chain, uint64_t handle)
 	return NULL;
 }
 
-struct scope *scope_init(struct scope *scope, const struct scope *parent)
+struct input_descriptor* indesc_alloc(void)
 {
+	struct input_descriptor* indesc = xzalloc(sizeof(struct input_descriptor));
+	return indesc;
+}
+
+struct scope *scope_alloc(struct scope *parent, 
+						  struct input_descriptor *parent_indesc)
+{
+	struct scope *scope = xzalloc(sizeof(*scope));
+	init_list_head(&scope->list);
+	init_list_head(&scope->symbols);
+	init_list_head(&scope->scopes);
 	scope->parent = parent;
+	scope->indesc = parent_indesc;
+	if (parent != NULL)
+		scope->depth = parent->depth + 1;
 	return scope;
 }
 
-void scope_release(const struct scope *scope)
+static void scope_indesc_release(const struct input_descriptor *indesc)
+{
+	if (indesc == NULL)
+		return;
+	xfree(indesc->name);
+	if (indesc->type == INDESC_FILE) {
+		fclose(indesc->fp);
+	}
+}
+
+static void single_scope_release(const struct scope *scope)
 {
 	struct symbol *sym, *next;
+	
+	if (scope == NULL)
+		return;
 
 	list_for_each_entry_safe(sym, next, &scope->symbols, list) {
 		assert(sym->refcnt == 1);
@@ -506,6 +533,18 @@ void scope_release(const struct scope *scope)
 		expr_free(sym->expr);
 		xfree(sym);
 	}
+	scope_indesc_release(scope->indesc);
+	xfree(scope->indesc);
+}
+
+void scope_release(const struct scope *scope)
+{
+	struct scope *other_scope, *next;
+	list_for_each_entry_safe(other_scope, next, &scope->scopes, list) {
+		scope_release(other_scope);
+	}
+	single_scope_release(scope);
+	xfree(scope);
 }
 
 void symbol_bind(struct scope *scope, const char *identifier, struct expr *expr)
@@ -629,10 +668,9 @@ struct chain *chain_alloc(const char *name)
 	chain = xzalloc(sizeof(*chain));
 	chain->refcnt = 1;
 	init_list_head(&chain->rules);
-	init_list_head(&chain->scope.symbols);
+	chain->scope = scope_alloc(NULL, NULL);
 	if (name != NULL)
 		chain->handle.chain = xstrdup(name);
-
 	chain->policy = -1;
 	return chain;
 }
@@ -652,7 +690,8 @@ void chain_free(struct chain *chain)
 	list_for_each_entry_safe(rule, next, &chain->rules, list)
 		rule_free(rule);
 	handle_free(&chain->handle);
-	scope_release(&chain->scope);
+	list_del(&chain->scope->list);
+	scope_release(chain->scope);
 	xfree(chain->type);
 	if (chain->dev != NULL)
 		xfree(chain->dev);
@@ -810,7 +849,7 @@ struct table *table_alloc(void)
 	init_list_head(&table->sets);
 	init_list_head(&table->objs);
 	init_list_head(&table->flowtables);
-	init_list_head(&table->scope.symbols);
+	table->scope = scope_alloc(NULL, NULL);
 	table->refcnt = 1;
 
 	return table;
@@ -831,7 +870,8 @@ void table_free(struct table *table)
 	list_for_each_entry_safe(obj, nobj, &table->objs, list)
 		obj_free(obj);
 	handle_free(&table->handle);
-	scope_release(&table->scope);
+	list_del(&table->scope->list);
+	scope_release(table->scope);
 	xfree(table);
 }
 
diff --git a/src/scanner.l b/src/scanner.l
index a576c23..45c07c4 100755
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -56,41 +56,43 @@
 	}									\
 }
 
-static void scanner_pop_buffer(yyscan_t scanner);
-
-
 static void init_pos(struct parser_state *state)
 {
-	state->indesc->lineno		= 1;
-	state->indesc->column		= 1;
-	state->indesc->token_offset	= 0;
-	state->indesc->line_offset 	= 0;
+	struct input_descriptor *indesc = get_indesc(state);
+/* 	printf("initializing pos to %p, name %s\n", indesc, indesc->name); */
+	indesc->lineno		= 1;
+	indesc->column		= 1;
+	indesc->token_offset	= 0;
+	indesc->line_offset 	= 0;
 }
 
 static void update_pos(struct parser_state *state, struct location *loc,
 		       int len)
 {
-	loc->indesc			= state->indesc;
-	loc->first_line			= state->indesc->lineno;
-	loc->last_line			= state->indesc->lineno;
-	loc->first_column		= state->indesc->column;
-	loc->last_column		= state->indesc->column + len - 1;
-	state->indesc->column		+= len;
+	struct input_descriptor *indesc = get_indesc(state);
+	loc->indesc			= indesc;
+	loc->first_line			= indesc->lineno;
+	loc->last_line			= indesc->lineno;
+	loc->first_column		= indesc->column;
+	loc->last_column		= indesc->column + len - 1;
+	indesc->column			+= len;
 }
 
 static void update_offset(struct parser_state *state, struct location *loc,
 			  unsigned int len)
 {
-	state->indesc->token_offset	+= len;
-	loc->token_offset		= state->indesc->token_offset;
-	loc->line_offset		= state->indesc->line_offset;
+	struct input_descriptor *indesc = get_indesc(state);
+	indesc->token_offset	+= len;
+	loc->token_offset		= indesc->token_offset;
+	loc->line_offset		= indesc->line_offset;
 }
 
 static void reset_pos(struct parser_state *state, struct location *loc)
 {
-	state->indesc->line_offset	= state->indesc->token_offset;
-	state->indesc->lineno		+= 1;
-	state->indesc->column		= 1;
+	struct input_descriptor *indesc = get_indesc(state);
+	indesc->line_offset	= indesc->token_offset;
+	indesc->lineno		+= 1;
+	indesc->column		= 1;
 }
 
 #define YY_USER_ACTION {					\
@@ -618,7 +620,7 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 				unsigned int diff;
 
 				diff = TABSIZE - strlen("\t");
-				diff -= (state->indesc->column -
+				diff -= (get_indesc(state)->column -
 					 strlen("\t") - 1) % TABSIZE;
 
 				update_pos(state, yylloc, diff);
@@ -629,15 +631,9 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 
 <<EOF>> 		{
 				struct parser_state *state = yyget_extra(yyscanner);
-				struct scope *scope = current_scope(state);
 				update_pos(state, yylloc, 1);
-				/* only close scope if file was included, skip buffer parsing
-				   since it does not create new scope */
-				if (state->indesc && state->indesc->name) {
-					close_scope(state);
-					xfree(scope);
-				}
-				scanner_pop_buffer(yyscanner);
+				close_scope(state);
+				yypop_buffer_state(yyscanner);
 				if (YY_CURRENT_BUFFER == NULL)
 					return TOKEN_EOF;
 			}
@@ -646,26 +642,15 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 
 %%
 
-static void scanner_pop_buffer(yyscan_t scanner)
-{
-	struct parser_state *state = yyget_extra(scanner);
-
-	yypop_buffer_state(scanner);
-	if (state->indesc && state->indesc->name) {
-		xfree(state->indesc->name);
-		state->indesc->name = NULL;
-	}
-	state->indesc = &state->indescs[--state->indesc_idx - 1];
-}
-
 static struct error_record *scanner_push_file(void *scanner, const char *filename,
-					      FILE *f, const struct location *loc)
+					      FILE *f, const struct location *loc, struct scope *parent)
 {
 	struct parser_state *state = yyget_extra(scanner);
-	struct scope *scope = NULL;
+	struct scope *scope = scope_alloc(parent, indesc_alloc());
 	YY_BUFFER_STATE b;
 
-	if (state->indesc_idx == MAX_INCLUDE_DEPTH) {
+	if (scope->depth == MAX_INCLUDE_DEPTH) {
+		scope_release(scope);
 		fclose(f);
 		return error(loc, "Include nested too deeply, max %u levels",
 			     MAX_INCLUDE_DEPTH);
@@ -674,20 +659,21 @@ static struct error_record *scanner_push_file(void *scanner, const char *filenam
 	b = yy_create_buffer(f, YY_BUF_SIZE, scanner);
 	yypush_buffer_state(b, scanner);
 
-	state->indesc = &state->indescs[state->indesc_idx++];
 	if (loc != NULL)
-		state->indesc->location = *loc;
-	state->indesc->type	= INDESC_FILE;
-	state->indesc->name	= xstrdup(filename);
+		scope->indesc->location = *loc;
+	scope->indesc->type	= INDESC_FILE;
+	scope->indesc->name	= xstrdup(filename);
+	scope->indesc->fp	= f;
+	if (current_scope(state)->parent == parent)
+		open_scope_glob(state, scope);
+	else
+		open_scope(state, scope);
 	init_pos(state);
-	scope = xzalloc(sizeof(*scope));
-	init_list_head(&scope->symbols);
-	open_scope(state, scope);
 	return NULL;
 }
 
 static int include_file(void *scanner, const char *filename,
-			const struct location *loc)
+			const struct location *loc, struct scope *parent)
 {
 	struct parser_state *state = yyget_extra(scanner);
 	struct error_record *erec;
@@ -700,7 +686,7 @@ static int include_file(void *scanner, const char *filename,
 		goto err;
 	}
 
-	erec = scanner_push_file(scanner, filename, f, loc);
+	erec = scanner_push_file(scanner, filename, f, loc, parent);
 	if (erec != NULL)
 		goto err;
 	return 0;
@@ -714,6 +700,7 @@ static int include_glob(void *scanner, const char *pattern,
 {
 	struct parser_state *state = yyget_extra(scanner);
 	struct error_record *erec = NULL;
+	struct scope *scope = current_scope(state);
 	bool wildcard = false;
 	glob_t glob_data;
 	unsigned int i;
@@ -773,7 +760,7 @@ static int include_glob(void *scanner, const char *pattern,
 			if (len == 0 || path[len - 1] == '/')
 				continue;
 
-			ret = include_file(scanner, path, loc);
+			ret = include_file(scanner, path, loc, scope);
 			if (ret != 0)
 				goto err;
 		}
@@ -810,7 +797,8 @@ err:
 int scanner_read_file(void *scanner, const char *filename,
 		      const struct location *loc)
 {
-	return include_file(scanner, filename, loc);
+	struct parser_state *state = yyget_extra(scanner);
+	return include_file(scanner, filename, loc, current_scope(state));
 }
 
 static bool search_in_include_path(const char *filename)
@@ -876,12 +864,14 @@ void scanner_push_buffer(void *scanner, const struct input_descriptor *indesc,
 			 const char *buffer)
 {
 	struct parser_state *state = yyget_extra(scanner);
+	struct scope *scope = scope_alloc(current_scope(state), indesc_alloc());
 	YY_BUFFER_STATE b;
 
-	state->indesc = &state->indescs[state->indesc_idx++];
-	memcpy(state->indesc, indesc, sizeof(*state->indesc));
-	state->indesc->data = buffer;
-	state->indesc->name = NULL;
+	open_scope(state, scope);
+	scope->indesc->type = indesc->type;
+	scope->indesc->name = xstrdup(indesc->name);
+	scope->indesc->data = buffer;
+	scope->indesc->name = NULL;
 
 	b = yy_scan_string(buffer, scanner);
 	assert(b != NULL);
@@ -892,8 +882,6 @@ void *scanner_init(struct parser_state *state)
 {
 	yyscan_t scanner;
 
-	state->indesc = state->indescs;
-
 	yylex_init_extra(state, &scanner);
 	yyset_out(NULL, scanner);
 
@@ -902,17 +890,5 @@ void *scanner_init(struct parser_state *state)
 
 void scanner_destroy(void *scanner)
 {
-	struct parser_state *state = yyget_extra(scanner);
-
-	do {
-		struct input_descriptor *inpdesc =
-			&state->indescs[state->indesc_idx];
-		if (inpdesc && inpdesc->name) {
-			xfree(inpdesc->name);
-			inpdesc->name = NULL;
-		}
-		yypop_buffer_state(scanner);
-	} while (state->indesc_idx--);
-
 	yylex_destroy(scanner);
 }
-- 
2.13.6

>From a1267f20786df483b4ebfdda5c5d6d5c3f05337b Mon Sep 17 00:00:00 2001
From: David Fabian <david.fabian@xxxxxxxxx>
Date: Mon, 30 Apr 2018 09:20:44 +0200
Subject: [PATCH 6/7] Make global redefine compatible with regular redefine

---
 src/parser_bison.y | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/parser_bison.y b/src/parser_bison.y
index 49ab064..2eaf604 100755
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -871,8 +871,6 @@ common_block		:	INCLUDE		QUOTED_STRING	stmt_separator
 			{
 				struct scope *scope = toplevel_scope(state);
 
-				/* ignore missing identifier */
-				symbol_unbind(scope, $3);
 				symbol_bind(scope, $3, $5);
 				xfree($3);
 			}
-- 
2.13.6

>From 12bdc9e48ddfc9fc539713f4dfb0204aaf3bbdfe Mon Sep 17 00:00:00 2001
From: David Fabian <david.fabian@xxxxxxxxx>
Date: Mon, 30 Apr 2018 09:21:44 +0200
Subject: [PATCH 7/7] Call proper nft binary in run-tests.sh

---
 tests/shell/run-tests.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/shell/run-tests.sh b/tests/shell/run-tests.sh
index b52611b..6a0830f 100755
--- a/tests/shell/run-tests.sh
+++ b/tests/shell/run-tests.sh
@@ -123,7 +123,7 @@ do
 
 			if [ "$DUMPGEN" == "y" ] && [ "$rc_got" == "${POSITIVE_RET}" ] && [ ! -f "${dumpfile}" ]; then
 				mkdir -p "${dumppath}"
-				nft list ruleset > "${dumpfile}"
+				$NFT list ruleset > "${dumpfile}"
 			fi
 		else
 			((failed++))
-- 
2.13.6


[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux