Global variables live only in the top-level scope and can be accessed from
anywhere.
They are unloaded at the end of parsing.
Global definitions cannot contain local variables because those may get deleted
when
the local scope goes away and the subsequent use of the global would lead to a
SIGSEGV.
---
include/rule.h | 5 +-
src/parser_bison.y | 335 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/rule.c | 15 ++-
src/scanner.l | 1 +
4 files changed, 347 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 cfecf7f..8991025 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -109,8 +109,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 16a1f75..4500aac
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -62,6 +62,11 @@ 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)
+{
+ return state->scopes[0];
+}
+
struct scope *current_scope(const struct parser_state *state)
{
return state->scopes[state->scope];
@@ -192,6 +197,7 @@ int nft_lex(void *, void *, void *);
%token DEFINE "define"
%token REDEFINE "redefine"
%token UNDEFINE "undefine"
+%token GLOBAL "global"
%token FIB "fib"
@@ -739,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 */
@@ -780,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);
@@ -807,8 +825,43 @@ common_block : INCLUDE
QUOTED_STRING stmt_separator
state->msgs);
YYERROR;
}
+
xfree($2);
}
+ | GLOBAL DEFINE 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);
+ }
+ | GLOBAL REDEFINE identifier '='
global_initializer_expr stmt_separator
+ {
+ struct scope *scope = toplevel_scope(state);
+
+ symbol_bind(scope, $3, $5);
+ xfree($3);
+ }
+ | GLOBAL UNDEFINE 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)
@@ -2823,8 +2876,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);
@@ -2832,7 +2886,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);
}
;
@@ -4093,4 +4153,273 @@ 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_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 38529af..d40ec50 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -526,11 +526,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;
@@ -566,14 +567,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 e6e255d..96bb307
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -236,6 +236,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"define" { return DEFINE; }
"redefine" { return REDEFINE; }
"undefine" { return UNDEFINE; }
+"global" { return GLOBAL; }
"describe" { return DESCRIBE; }
--
2.13.6
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html