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

Reply via email to