diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2020-07-07 17:42:37 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2020-07-08 11:25:25 +0200 |
commit | e76bb379401816bbea773e73b524cd747324760a (patch) | |
tree | 226b13363d4c3ecc36919645cf94c82e16733661 /src/parser_bison.y | |
parent | 8f56db64be3f2c57a196a5eaef0286ec71782950 (diff) |
src: allow for variables in the log prefix string
For example:
define test = "state"
define foo = "match"
table x {
chain y {
ct state invalid log prefix "invalid $test $foo:"
}
}
This patch scans for variables in the log prefix string. The log prefix
expression is a list of constant and variable expression that are
converted into a constant expression from the evaluation phase.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/parser_bison.y')
-rw-r--r-- | src/parser_bison.y | 122 |
1 files changed, 118 insertions, 4 deletions
diff --git a/src/parser_bison.y b/src/parser_bison.y index 2fecc347..face9950 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -2636,11 +2636,125 @@ log_args : log_arg log_arg : PREFIX string { - struct expr *expr; + struct scope *scope = current_scope(state); + bool done = false, another_var = false; + char *start, *end, scratch = '\0'; + struct expr *expr, *item; + struct symbol *sym; + enum { + PARSE_TEXT, + PARSE_VAR, + } prefix_state; + + /* No variables in log prefix, skip. */ + if (!strchr($2, '$')) { + expr = constant_expr_alloc(&@$, &string_type, + BYTEORDER_HOST_ENDIAN, + (strlen($2) + 1) * BITS_PER_BYTE, $2); + $<stmt>0->log.prefix = expr; + $<stmt>0->log.flags |= STMT_LOG_PREFIX; + break; + } - expr = constant_expr_alloc(&@$, &string_type, - BYTEORDER_HOST_ENDIAN, - strlen($2) * BITS_PER_BYTE, $2); + /* Parse variables in log prefix string using a + * state machine parser with two states. This + * parser creates list of expressions composed + * of constant and variable expressions. + */ + expr = compound_expr_alloc(&@$, EXPR_LIST); + + start = (char *)$2; + + if (*start != '$') { + prefix_state = PARSE_TEXT; + } else { + prefix_state = PARSE_VAR; + start++; + } + end = start; + + /* Not nice, but works. */ + while (!done) { + switch (prefix_state) { + case PARSE_TEXT: + while (*end != '\0' && *end != '$') + end++; + + if (*end == '\0') + done = true; + + *end = '\0'; + item = constant_expr_alloc(&@$, &string_type, + BYTEORDER_HOST_ENDIAN, + (strlen(start) + 1) * BITS_PER_BYTE, + start); + compound_expr_add(expr, item); + + if (done) + break; + + start = end + 1; + end = start; + + /* fall through */ + case PARSE_VAR: + while (isalnum(*end) || *end == '_') + end++; + + if (*end == '\0') + done = true; + else if (*end == '$') + another_var = true; + else + scratch = *end; + + *end = '\0'; + + sym = symbol_get(scope, start); + if (!sym) { + sym = symbol_lookup_fuzzy(scope, start); + if (sym) { + erec_queue(error(&@2, "unknown identifier '%s'; " + "did you mean identifier ā%sā?", + start, sym->identifier), + state->msgs); + } else { + erec_queue(error(&@2, "unknown identifier '%s'", + start), + state->msgs); + } + expr_free(expr); + xfree($2); + YYERROR; + } + item = variable_expr_alloc(&@$, scope, sym); + compound_expr_add(expr, item); + + if (done) + break; + + /* Restore original byte after + * symbol lookup. + */ + if (scratch) { + *end = scratch; + scratch = '\0'; + } + + start = end; + if (another_var) { + another_var = false; + start++; + prefix_state = PARSE_VAR; + } else { + prefix_state = PARSE_TEXT; + } + end = start; + break; + } + } + + xfree($2); $<stmt>0->log.prefix = expr; $<stmt>0->log.flags |= STMT_LOG_PREFIX; } |