]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: error reporting with -f and read from stdin
authorPablo Neira Ayuso <pablo@netfilter.org>
Sun, 2 Jan 2022 20:39:42 +0000 (21:39 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sat, 15 Jan 2022 17:11:22 +0000 (18:11 +0100)
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 <pablo@netfilter.org>
include/nftables.h
src/erec.c
src/libnftables.c
src/scanner.l

index 7b6339053b54f7486f4088ba7441c8ac8e0eebdb..d6d9b9cc7206e47a04babdc87eddb05186e826c7 100644 (file)
@@ -128,6 +128,7 @@ struct nft_ctx {
        struct scope            *top_scope;
        void                    *json_root;
        json_t                  *json_echo;
+       const char              *stdin_buf;
 };
 
 enum nftables_exit_codes {
@@ -175,6 +176,7 @@ enum input_descriptor_types {
        INDESC_FILE,
        INDESC_CLI,
        INDESC_NETLINK,
+       INDESC_STDIN,
 };
 
 /**
index 7c9165c290d89c7b3ba44c1d4e9cd8a6563caabb..32fb079fa8b482af480b663b0028ce0a38f29210 100644 (file)
@@ -101,10 +101,11 @@ void print_location(FILE *f, const struct input_descriptor *indesc,
                        iloc = &tmp->location;
                }
        }
-       if (indesc->name != NULL)
+       if (indesc->type != INDESC_BUFFER && indesc->name) {
                fprintf(f, "%s:%u:%u-%u: ", indesc->name,
                        loc->first_line, loc->first_column,
                        loc->last_column);
+       }
 }
 
 const char *line_location(const struct input_descriptor *indesc,
@@ -145,6 +146,11 @@ void erec_print(struct output_ctx *octx, const struct error_record *erec,
                line = indesc->data;
                *strchrnul(line, '\n') = '\0';
                break;
+       case INDESC_STDIN:
+               line = indesc->data;
+               line += loc->line_offset;
+               *strchrnul(line, '\n') = '\0';
+               break;
        case INDESC_FILE:
                line = line_location(indesc, loc, buf, sizeof(buf));
                break;
index 7b9d7efaeaae91cb1d94954bccea0fe21e31e421..e76f32eff7cac18e843fd5c3553aefc3291b9223 100644 (file)
@@ -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;
 }
index f28bf3153f0b0090c139a341fde41161976edc11..7dcc45c2fd505516f71e988addf70969aa77f6f9 100644 (file)
@@ -1032,7 +1032,7 @@ void scanner_push_buffer(void *scanner, const struct input_descriptor *indesc,
        new_indesc = xzalloc(sizeof(struct input_descriptor));
        memcpy(new_indesc, indesc, sizeof(*new_indesc));
        new_indesc->data = buffer;
-       new_indesc->name = NULL;
+       new_indesc->name = xstrdup(indesc->name);
        scanner_push_indesc(state, new_indesc);
 
        b = yy_scan_string(buffer, scanner);