This patch restricts the getopt parser to the top-level scope. This is implicitly providing a fix for the following error reporting: # nft add chain x k { type filter hook input priority -10\; } nft: invalid option -- '1' When defining basechains using a negative priority number. This patch is processing the input to escape all dash (-) after leaving the top-level scope (ie. {), then it removes the escaping before entering the bison parser. Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- src/main.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 3 deletions(-) diff --git a/src/main.c b/src/main.c index fde8b15c5870..c96953e3cd2f 100644 --- a/src/main.c +++ b/src/main.c @@ -202,29 +202,107 @@ static const struct { }, }; +struct nft_opts { + char **argv; + int argc; +}; + +static int nft_opts_init(int argc, char * const argv[], struct nft_opts *opts) +{ + uint32_t scope = 0; + char *new_argv; + int i; + + opts->argv = calloc(argc + 1, sizeof(char *)); + if (!opts->argv) + return -1; + + for (i = 0; i < argc; i++) { + if (scope > 0) { + if (argv[i][0] == '-') { + new_argv = malloc(strlen(argv[i]) + 2); + if (!new_argv) + return -1; + + sprintf(new_argv, "\\-%s", &argv[i][1]); + opts->argv[opts->argc++] = new_argv; + continue; + } + } else if (argv[i][0] == '{') { + scope++; + } else if (argv[i][0] == '}') { + scope--; + } + + opts->argv[opts->argc++] = strdup(argv[i]); + } + + return 0; +} + +static int nft_opts_update(struct nft_opts *opts) +{ + char *new_argv; + int i; + + for (i = 0; i < opts->argc; i++) { + if (opts->argv[i][0] == '\\') { + new_argv = malloc(strlen(opts->argv[i]) + 1); + if (!new_argv) + return -1; + + sprintf(new_argv, "-%s", &opts->argv[i][2]); + free(opts->argv[i]); + opts->argv[i] = new_argv; + } + } + + return 0; +} + +static void nft_opts_release(struct nft_opts *opts) +{ + int i; + + for (i = 0; i < opts->argc; i++) + free(opts->argv[i]); + + free(opts->argv); +} + int main(int argc, char * const *argv) { char *buf = NULL, *filename = NULL; unsigned int output_flags = 0; + struct nft_opts opts = {}; bool interactive = false; unsigned int debug_mask; unsigned int len; int i, val, rc; + if (nft_opts_init(argc, argv, &opts) < 0) { + nft_opts_release(&opts); + fprintf(stderr, "OOM\n"); + exit(EXIT_FAILURE); + } + nft = nft_ctx_new(NFT_CTX_DEFAULT); while (1) { - val = getopt_long(argc, argv, OPTSTRING, options, NULL); + val = getopt_long(opts.argc, opts.argv, OPTSTRING, options, + NULL); if (val == -1) break; switch (val) { case OPT_HELP: show_help(argv[0]); + nft_opts_release(&opts); exit(EXIT_SUCCESS); case OPT_VERSION: printf("%s v%s (%s)\n", PACKAGE_NAME, PACKAGE_VERSION, RELEASE_NAME); + nft_opts_release(&opts); exit(EXIT_SUCCESS); case OPT_CHECK: nft_ctx_set_dry_run(nft, true); @@ -240,6 +318,7 @@ int main(int argc, char * const *argv) fprintf(stderr, "Failed to add include path '%s'\n", optarg); + nft_opts_release(&opts); exit(EXIT_FAILURE); } break; @@ -275,6 +354,7 @@ int main(int argc, char * const *argv) if (i == array_size(debug_param)) { fprintf(stderr, "invalid debug parameter `%s'\n", optarg); + nft_opts_release(&opts); exit(EXIT_FAILURE); } @@ -295,6 +375,7 @@ int main(int argc, char * const *argv) output_flags |= NFT_CTX_OUTPUT_JSON; #else fprintf(stderr, "JSON support not compiled-in\n"); + nft_opts_release(&opts); exit(EXIT_FAILURE); #endif break; @@ -314,24 +395,32 @@ int main(int argc, char * const *argv) output_flags |= NFT_CTX_OUTPUT_TERSE; break; case OPT_INVALID: + nft_opts_release(&opts); exit(EXIT_FAILURE); } } nft_ctx_output_set_flags(nft, output_flags); + if (nft_opts_update(&opts) < 0) { + nft_opts_release(&opts); + fprintf(stderr, "OOM\n"); + exit(EXIT_FAILURE); + } + if (optind != argc) { for (len = 0, i = optind; i < argc; i++) - len += strlen(argv[i]) + strlen(" "); + len += strlen(opts.argv[i]) + strlen(" "); buf = calloc(1, len); if (buf == NULL) { fprintf(stderr, "%s:%u: Memory allocation failure\n", __FILE__, __LINE__); + nft_opts_release(&opts); exit(EXIT_FAILURE); } for (i = optind; i < argc; i++) { - strcat(buf, argv[i]); + strcat(buf, opts.argv[i]); if (i + 1 < argc) strcat(buf, " "); } @@ -342,14 +431,17 @@ int main(int argc, char * const *argv) if (cli_init(nft) < 0) { fprintf(stderr, "%s: interactive CLI not supported in this build\n", argv[0]); + nft_opts_release(&opts); exit(EXIT_FAILURE); } return EXIT_SUCCESS; } else { fprintf(stderr, "%s: no command specified\n", argv[0]); + nft_opts_release(&opts); exit(EXIT_FAILURE); } + nft_opts_release(&opts); free(buf); nft_ctx_free(nft); -- 2.11.0