summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2013-08-14 15:41:20 +0200
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2013-08-14 15:41:20 +0200
commit2ad3a5bdb71e53ada2d19e2f13777e353cb6a4bc (patch)
tree4a1f933a454bfd9053faef3b08acf50d56af55ad /src
parent2f510b169b66e243681e2e3028a63375857c1b7d (diff)
Parse option "family" first, because other options may depend on it
Option like "netmask" depends on the INET family, so parse "family" first, then the rest of the options. Bug reported by Quentin Armitage, closed netfilter bugzilla #841.
Diffstat (limited to 'src')
-rw-r--r--src/ipset.c71
1 files changed, 47 insertions, 24 deletions
diff --git a/src/ipset.c b/src/ipset.c
index d5ecf7a..4f308da 100644
--- a/src/ipset.c
+++ b/src/ipset.c
@@ -235,58 +235,74 @@ restore(char *argv0)
return ret;
}
+static bool do_parse(const struct ipset_arg *arg, bool family)
+{
+ return !((family == true) ^ (arg->opt == IPSET_OPT_FAMILY));
+}
+
static int
-call_parser(int *argc, char *argv[], const struct ipset_arg *args)
+call_parser(int *argc, char *argv[], const struct ipset_arg *args, bool family)
{
- int ret = 0;
+ int ret = 0, i = 1;
const struct ipset_arg *arg;
const char *optstr;
/* Currently CREATE and ADT may have got additional arguments */
if (!args && *argc > 1)
goto err_unknown;
- while (*argc > 1) {
+ while (*argc > i) {
+ ret = -1;
for (arg = args; arg->opt; arg++) {
- D("argc: %u, %s vs %s", *argc, argv[1], arg->name[0]);
- if (!(ipset_match_option(argv[1], arg->name)))
+ D("argc: %u, %s vs %s", i, argv[i], arg->name[0]);
+ if (!(ipset_match_option(argv[i], arg->name)))
continue;
- optstr = argv[1];
- /* Shift off matched option */
- D("match %s", arg->name[0]);
- ipset_shift_argv(argc, argv, 1);
+ optstr = argv[i];
+ /* Matched option */
+ D("match %s, argc %u, i %u, %s",
+ arg->name[0], *argc, i + 1,
+ do_parse(arg, family) ? "parse" : "skip");
+ i++;
+ ret = 0;
switch (arg->has_arg) {
case IPSET_MANDATORY_ARG:
- if (*argc < 2)
+ if (*argc - i < 1)
return exit_error(PARAMETER_PROBLEM,
"Missing mandatory argument "
"of option `%s'",
arg->name[0]);
/* Fall through */
case IPSET_OPTIONAL_ARG:
- if (*argc >= 2) {
- ret = ipset_call_parser(session,
- arg, argv[1]);
- if (ret < 0)
- return ret;
- ipset_shift_argv(argc, argv, 1);
+ if (*argc - i >= 1) {
+ if (do_parse(arg, family)) {
+ ret = ipset_call_parser(
+ session, arg, argv[i]);
+ if (ret < 0)
+ return ret;
+ }
+ i++;
break;
}
/* Fall through */
default:
- ret = ipset_call_parser(session, arg, optstr);
- if (ret < 0)
- return ret;
+ if (do_parse(arg, family)) {
+ ret = ipset_call_parser(
+ session, arg, optstr);
+ if (ret < 0)
+ return ret;
+ }
}
break;
}
- if (!arg->opt)
+ if (ret < 0)
goto err_unknown;
}
+ if (!family)
+ *argc = 0;
return ret;
err_unknown:
- return exit_error(PARAMETER_PROBLEM, "Unknown argument: `%s'", argv[1]);
+ return exit_error(PARAMETER_PROBLEM, "Unknown argument: `%s'", argv[i]);
}
static enum ipset_adt
@@ -666,8 +682,15 @@ parse_commandline(int argc, char *argv[])
if (type == NULL)
return handle_error();
- /* Parse create options */
- ret = call_parser(&argc, argv, type->args[IPSET_CREATE]);
+ /* Parse create options: first check INET family */
+ ret = call_parser(&argc, argv, type->args[IPSET_CREATE], true);
+ if (ret < 0)
+ return handle_error();
+ else if (ret)
+ return ret;
+
+ /* Parse create options: then check all options */
+ ret = call_parser(&argc, argv, type->args[IPSET_CREATE], false);
if (ret < 0)
return handle_error();
else if (ret)
@@ -735,7 +758,7 @@ parse_commandline(int argc, char *argv[])
return handle_error();
/* Parse additional ADT options */
- ret = call_parser(&argc, argv, type->args[cmd2cmd(cmd)]);
+ ret = call_parser(&argc, argv, type->args[cmd2cmd(cmd)], false);
if (ret < 0)
return handle_error();
else if (ret)