]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
datatype: add hint error handler
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 9 May 2023 15:46:54 +0000 (17:46 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 11 May 2023 16:18:35 +0000 (18:18 +0200)
If user provides a symbol that cannot be parsed and the datatype provides
an error handler, provide a hint through the misspell infrastructure.

For instance:

 # cat test.nft
 table ip x {
        map y {
                typeof ip saddr : verdict
                elements = { 1.2.3.4 : filter_server1 }
        }
 }
 # nft -f test.nft
 test.nft:4:26-39: Error: Could not parse netfilter verdict; did you mean `jump filter_server1'?
                 elements = { 1.2.3.4 : filter_server1 }
                                        ^^^^^^^^^^^^^^

While at it, normalize error to "Could not parse symbolic %s expression".

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/datatype.h
src/datatype.c

index 391d6ac8b4bd2237a229f5776fe9db5f2c4b5f42..4b59790b67f9780a66588d731dd123eac6e9ee18 100644 (file)
@@ -167,6 +167,7 @@ struct datatype {
        struct error_record             *(*parse)(struct parse_ctx *ctx,
                                                  const struct expr *sym,
                                                  struct expr **res);
+       struct error_record             *(*err)(const struct expr *sym);
        void                            (*describe)(struct output_ctx *octx);
        const struct symbol_table       *sym_tbl;
        unsigned int                    refcnt;
index 2cefd0f3f10ebdf9e28e83052ab75c48f26e5224..da802a18bccd49f92fae5e8ef26f45fdeb77b6e3 100644 (file)
@@ -124,6 +124,7 @@ struct error_record *symbol_parse(struct parse_ctx *ctx, const struct expr *sym,
                                  struct expr **res)
 {
        const struct datatype *dtype = sym->dtype;
+       struct error_record *erec;
 
        assert(sym->etype == EXPR_SYMBOL);
 
@@ -137,8 +138,14 @@ struct error_record *symbol_parse(struct parse_ctx *ctx, const struct expr *sym,
                                                       res);
        } while ((dtype = dtype->basetype));
 
-       return error(&sym->location,
-                    "Can't parse symbolic %s expressions",
+       dtype = sym->dtype;
+       if (dtype->err) {
+               erec = dtype->err(sym);
+               if (erec)
+                       return erec;
+       }
+
+       return error(&sym->location, "Could not parse symbolic %s expression",
                     sym->dtype->desc);
 }
 
@@ -367,11 +374,41 @@ static void verdict_type_print(const struct expr *expr, struct output_ctx *octx)
        }
 }
 
+static struct error_record *verdict_type_error(const struct expr *sym)
+{
+       /* Skip jump and goto from fuzzy match to provide better error
+        * reporting, fall back to `jump chain' if no clue.
+        */
+       static const char *verdict_array[] = {
+               "continue", "break", "return", "accept", "drop", "queue",
+               "stolen", NULL,
+       };
+       struct string_misspell_state st;
+       int i;
+
+       string_misspell_init(&st);
+
+       for (i = 0; verdict_array[i] != NULL; i++) {
+               string_misspell_update(sym->identifier, verdict_array[i],
+                                      (void *)verdict_array[i], &st);
+       }
+
+       if (st.obj) {
+               return error(&sym->location, "Could not parse %s; did you mean `%s'?",
+                            sym->dtype->desc, st.obj);
+       }
+
+       /* assume user would like to jump to chain as a hint. */
+       return error(&sym->location, "Could not parse %s; did you mean `jump %s'?",
+                    sym->dtype->desc, sym->identifier);
+}
+
 const struct datatype verdict_type = {
        .type           = TYPE_VERDICT,
        .name           = "verdict",
        .desc           = "netfilter verdict",
        .print          = verdict_type_print,
+       .err            = verdict_type_error,
 };
 
 static const struct symbol_table nfproto_tbl = {