[PATCH nft] main: allow for getopt parser from top-level scope only

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Netfitler Users]     [Berkeley Packet Filter]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux