From 5c2b2b0a2ba7c1403c6af3e59dd3f51d04a64645 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 2 Jan 2022 21:39:42 +0100 Subject: src: error reporting with -f and read from stdin Reading from stdin requires to store the ruleset in a buffer so error reporting works accordingly, eg. # cat ruleset.nft | nft -f - /dev/stdin:3:13-13: Error: unknown identifier 'x' ip saddr $x ^ The error reporting infrastructure performs a fseek() on the file descriptor which does not work in this case since the data from the descriptor has been already consumed. This patch adds a new stdin input descriptor to perform this special handling which consists on re-routing this request through the buffer functions. Fixes: 935f82e7dd49 ("Support 'nft -f -' to read from stdin") Signed-off-by: Pablo Neira Ayuso --- src/libnftables.c | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) (limited to 'src/libnftables.c') diff --git a/src/libnftables.c b/src/libnftables.c index 7b9d7efa..e76f32ef 100644 --- a/src/libnftables.c +++ b/src/libnftables.c @@ -424,13 +424,14 @@ static const struct input_descriptor indesc_cmdline = { }; static int nft_parse_bison_buffer(struct nft_ctx *nft, const char *buf, - struct list_head *msgs, struct list_head *cmds) + struct list_head *msgs, struct list_head *cmds, + const struct input_descriptor *indesc) { int ret; parser_init(nft, nft->state, msgs, cmds, nft->top_scope); nft->scanner = scanner_init(nft->state); - scanner_push_buffer(nft->scanner, &indesc_cmdline, buf); + scanner_push_buffer(nft->scanner, indesc, buf); ret = nft_parse(nft, nft->scanner, nft->state); if (ret != 0 || nft->state->nerrs > 0) @@ -439,11 +440,42 @@ static int nft_parse_bison_buffer(struct nft_ctx *nft, const char *buf, return 0; } +static char *stdin_to_buffer(void) +{ + unsigned int bufsiz = 16384, consumed = 0; + int numbytes; + char *buf; + + buf = xmalloc(bufsiz); + + numbytes = read(STDIN_FILENO, buf, bufsiz); + while (numbytes > 0) { + consumed += numbytes; + if (consumed == bufsiz) { + bufsiz *= 2; + buf = realloc(buf, bufsiz); + } + numbytes = read(STDIN_FILENO, buf + consumed, bufsiz - consumed); + } + buf[consumed] = '\0'; + + return buf; +} + +static const struct input_descriptor indesc_stdin = { + .type = INDESC_STDIN, + .name = "/dev/stdin", +}; + static int nft_parse_bison_filename(struct nft_ctx *nft, const char *filename, struct list_head *msgs, struct list_head *cmds) { int ret; + if (nft->stdin_buf) + return nft_parse_bison_buffer(nft, nft->stdin_buf, msgs, cmds, + &indesc_stdin); + parser_init(nft, nft->state, msgs, cmds, nft->top_scope); nft->scanner = scanner_init(nft->state); if (scanner_read_file(nft, filename, &internal_location) < 0) @@ -510,7 +542,8 @@ int nft_run_cmd_from_buffer(struct nft_ctx *nft, const char *buf) if (nft_output_json(&nft->output)) rc = nft_parse_json_buffer(nft, nlbuf, &msgs, &cmds); if (rc == -EINVAL) - rc = nft_parse_bison_buffer(nft, nlbuf, &msgs, &cmds); + rc = nft_parse_bison_buffer(nft, nlbuf, &msgs, &cmds, + &indesc_cmdline); parser_rc = rc; @@ -578,7 +611,7 @@ retry: } snprintf(buf + offset, bufsize - offset, "\n"); - rc = nft_parse_bison_buffer(ctx, buf, msgs, &cmds); + rc = nft_parse_bison_buffer(ctx, buf, msgs, &cmds, &indesc_cmdline); assert(list_empty(&cmds)); /* Stash the buffer that contains the variable definitions and zap the @@ -608,6 +641,10 @@ int nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename) if (!strcmp(filename, "-")) filename = "/dev/stdin"; + if (!strcmp(filename, "/dev/stdin") && + !nft_output_json(&nft->output)) + nft->stdin_buf = stdin_to_buffer(); + rc = -EINVAL; if (nft_output_json(&nft->output)) rc = nft_parse_json_filename(nft, filename, &msgs, &cmds); @@ -656,5 +693,8 @@ err: json_print_echo(nft); if (rc) nft_cache_release(&nft->cache); + + xfree(nft->stdin_buf); + return rc; } -- cgit v1.2.3