@@ -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),
old mode 100644
new mode 100755
@@ -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;
+ }
+ ;
%%
@@ -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;
}
old mode 100644
new mode 100755
@@ -236,6 +236,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"define" { return DEFINE; }
"redefine" { return REDEFINE; }
"undefine" { return UNDEFINE; }
+"global" { return GLOBAL; }
"describe" { return DESCRIBE; }