summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2018-03-03 22:52:35 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2018-03-04 00:22:50 +0100
commit3b20f47277c0cb4ea07ad30f94496c9f383035e7 (patch)
treec5b0b1fc569dd64cd3fdcedaecfacf22b0abe6dd /src
parent8162d2b96718041dadc52ab127db9d91a2c223cc (diff)
src: add variable expression and use it to allow redefinitions
Add new variable expression that we can use to attach symbols in runtime, this allows us to redefine variables via new keyword, eg. table ip x { chain y { define address = { 1.1.1.1, 2.2.2.2 } ip saddr $address redefine address = { 3.3.3.3 } ip saddr $address } } # nft list ruleset table ip x { chain y { ip saddr { 1.1.1.1, 2.2.2.2 } ip saddr { 3.3.3.3 } } } Note that redefinition just places a new symbol version before the existing one, so symbol lookups always find the latest version. The undefine keyword decrements the reference counter and removes the symbol from the list, so it cannot be used anymore. Still, previous references to this symbol via variable expression are still valid. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r--src/evaluate.c21
-rw-r--r--src/expression.c39
-rw-r--r--src/parser_bison.y9
-rw-r--r--src/rule.c39
4 files changed, 88 insertions, 20 deletions
diff --git a/src/evaluate.c b/src/evaluate.c
index 40a9292f..cc8eac83 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -168,7 +168,6 @@ static struct table *table_lookup_global(struct eval_ctx *ctx)
static int expr_evaluate_symbol(struct eval_ctx *ctx, struct expr **expr)
{
struct error_record *erec;
- struct symbol *sym;
struct table *table;
struct set *set;
struct expr *new;
@@ -183,14 +182,6 @@ static int expr_evaluate_symbol(struct eval_ctx *ctx, struct expr **expr)
return -1;
}
break;
- case SYMBOL_DEFINE:
- sym = symbol_lookup((*expr)->scope, (*expr)->identifier);
- if (sym == NULL)
- return expr_error(ctx->msgs, *expr,
- "undefined identifier '%s'",
- (*expr)->identifier);
- new = expr_clone(sym->expr);
- break;
case SYMBOL_SET:
ret = cache_update(ctx->nf_sock, ctx->cache, ctx->cmd->op,
ctx->msgs, ctx->debug_mask & NFT_DEBUG_NETLINK, ctx->octx);
@@ -1776,6 +1767,16 @@ static int expr_evaluate_meta(struct eval_ctx *ctx, struct expr **exprp)
return expr_evaluate_primary(ctx, exprp);
}
+static int expr_evaluate_variable(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct expr *new = expr_clone((*exprp)->sym->expr);
+
+ expr_free(*exprp);
+ *exprp = new;
+
+ return expr_evaluate(ctx, exprp);
+}
+
static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
{
if (ctx->debug_mask & NFT_DEBUG_EVALUATION) {
@@ -1791,6 +1792,8 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
switch ((*expr)->ops->type) {
case EXPR_SYMBOL:
return expr_evaluate_symbol(ctx, expr);
+ case EXPR_VARIABLE:
+ return expr_evaluate_variable(ctx, expr);
case EXPR_SET_REF:
return 0;
case EXPR_VALUE:
diff --git a/src/expression.c b/src/expression.c
index 393c1b2b..ee75284e 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -254,6 +254,45 @@ struct expr *symbol_expr_alloc(const struct location *loc,
return expr;
}
+static void variable_expr_print(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ nft_print(octx, "$%s", expr->sym->identifier);
+}
+
+static void variable_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->scope = expr->scope;
+ new->sym = expr->sym;
+
+ expr->sym->refcnt++;
+}
+
+static void variable_expr_destroy(struct expr *expr)
+{
+ expr->sym->refcnt--;
+}
+
+static const struct expr_ops variable_expr_ops = {
+ .type = EXPR_VARIABLE,
+ .name = "variable",
+ .print = variable_expr_print,
+ .clone = variable_expr_clone,
+ .destroy = variable_expr_destroy,
+};
+
+struct expr *variable_expr_alloc(const struct location *loc,
+ struct scope *scope, struct symbol *sym)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, &variable_expr_ops, &invalid_type,
+ BYTEORDER_INVALID, 0);
+ expr->scope = scope;
+ expr->sym = sym;
+ return expr;
+}
+
static void constant_expr_print(const struct expr *expr,
struct output_ctx *octx)
{
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 58bc6805..ee6729f1 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -771,8 +771,6 @@ common_block : INCLUDE QUOTED_STRING stmt_separator
{
struct scope *scope = current_scope(state);
- /* ignore missing identifier */
- symbol_unbind(scope, $2);
symbol_bind(scope, $2, $4);
xfree($2);
}
@@ -2584,16 +2582,17 @@ match_stmt : relational_expr
variable_expr : '$' identifier
{
struct scope *scope = current_scope(state);
+ struct symbol *sym;
- if (symbol_lookup(scope, $2) == NULL) {
+ sym = symbol_get(scope, $2);
+ if (!sym) {
erec_queue(error(&@2, "unknown identifier '%s'", $2),
state->msgs);
xfree($2);
YYERROR;
}
- $$ = symbol_expr_alloc(&@$, SYMBOL_DEFINE,
- scope, $2);
+ $$ = variable_expr_alloc(&@$, scope, sym);
xfree($2);
}
;
diff --git a/src/rule.c b/src/rule.c
index c0b42b1c..b331416a 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -467,6 +467,7 @@ void scope_release(const struct scope *scope)
struct symbol *sym, *next;
list_for_each_entry_safe(sym, next, &scope->symbols, list) {
+ assert(sym->refcnt == 1);
list_del(&sym->list);
xfree(sym->identifier);
expr_free(sym->expr);
@@ -481,22 +482,48 @@ void symbol_bind(struct scope *scope, const char *identifier, struct expr *expr)
sym = xzalloc(sizeof(*sym));
sym->identifier = xstrdup(identifier);
sym->expr = expr;
+ sym->refcnt = 1;
- list_add_tail(&sym->list, &scope->symbols);
+ list_add(&sym->list, &scope->symbols);
}
-int symbol_unbind(struct scope *scope, const char *identifier)
+struct symbol *symbol_get(const struct scope *scope, const char *identifier)
{
struct symbol *sym;
sym = symbol_lookup(scope, identifier);
if (!sym)
- return -1;
+ return NULL;
+
+ sym->refcnt++;
+ return sym;
+}
+
+static void symbol_put(struct symbol *sym)
+{
+ if (--sym->refcnt == 0) {
+ xfree(sym->identifier);
+ expr_free(sym->expr);
+ xfree(sym);
+ }
+}
+
+static void symbol_remove(struct symbol *sym)
+{
list_del(&sym->list);
- xfree(sym->identifier);
- expr_free(sym->expr);
- xfree(sym);
+ symbol_put(sym);
+}
+
+int symbol_unbind(const struct scope *scope, const char *identifier)
+{
+ struct symbol *sym, *next;
+
+ list_for_each_entry_safe(sym, next, &scope->symbols, list) {
+ if (!strcmp(sym->identifier, identifier))
+ symbol_remove(sym);
+ }
+
return 0;
}