summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Make_global.am2
-rw-r--r--include/libipset/types.h2
-rw-r--r--lib/types.c24
-rw-r--r--src/ipset.c33
4 files changed, 54 insertions, 7 deletions
diff --git a/Make_global.am b/Make_global.am
index 7f4e263..f9d8dca 100644
--- a/Make_global.am
+++ b/Make_global.am
@@ -69,7 +69,7 @@
# interface.
# curr:rev:age
-LIBVERSION = 9:0:6
+LIBVERSION = 10:0:7
AM_CPPFLAGS = $(kinclude_CFLAGS) $(all_includes) -I$(top_srcdir)/include
diff --git a/include/libipset/types.h b/include/libipset/types.h
index 7f41afc..137d7ec 100644
--- a/include/libipset/types.h
+++ b/include/libipset/types.h
@@ -103,6 +103,8 @@ extern const struct ipset_type *
ipset_type_get(struct ipset_session *session, enum ipset_cmd cmd);
extern const struct ipset_type *
ipset_type_check(struct ipset_session *session);
+extern const struct ipset_type *
+ ipset_type_higher_rev(const struct ipset_type *type);
extern int ipset_type_add(struct ipset_type *type);
extern const struct ipset_type *ipset_types(void);
diff --git a/lib/types.c b/lib/types.c
index f303ea6..0fe8a7c 100644
--- a/lib/types.c
+++ b/lib/types.c
@@ -416,6 +416,30 @@ ipset_type_get(struct ipset_session *session, enum ipset_cmd cmd)
}
/**
+ * ipset_type_higher_rev - find the next higher userspace revision
+ * @type: set type
+ *
+ * Find the next higher revision of the set type for the input
+ * set type. Higher revision numbers come first on typelist.
+ *
+ * Returns the found or original set type, cannot fail.
+ */
+const struct ipset_type *
+ipset_type_higher_rev(const struct ipset_type *type)
+{
+ const struct ipset_type *t;
+
+ /* Check all registered types in userspace */
+ for (t = typelist; t != NULL; t = t->next) {
+ if (STREQ(type->name, t->name)
+ && type->family == t->family
+ && type == t->next)
+ return t;
+ }
+ return type;
+}
+
+/**
* ipset_type_check - check the set type received from kernel
* @session: session structure
*
diff --git a/src/ipset.c b/src/ipset.c
index 2c4fa10..79f56b8 100644
--- a/src/ipset.c
+++ b/src/ipset.c
@@ -275,15 +275,21 @@ static bool do_parse(const struct ipset_arg *arg, bool family)
}
static int
-call_parser(int *argc, char *argv[], const struct ipset_arg *args, bool family)
+call_parser(int *argc, char *argv[], const struct ipset_type *type,
+ enum ipset_adt cmd, bool family)
{
- int ret = 0, i = 1;
+ const struct ipset_arg *args = type->args[cmd];
const struct ipset_arg *arg;
const char *optstr;
+ const struct ipset_type *t = type;
+ u_int8_t revision = type->revision;
+ int ret = 0, i = 1;
/* Currently CREATE and ADT may have got additional arguments */
if (!args && *argc > 1)
- goto err_unknown;
+ return exit_error(PARAMETER_PROBLEM, "Unknown argument: `%s'",
+ argv[i]);
+
while (*argc > i) {
ret = -1;
for (arg = args; arg->opt; arg++) {
@@ -336,6 +342,21 @@ call_parser(int *argc, char *argv[], const struct ipset_arg *args, bool family)
return ret;
err_unknown:
+ while ((type = ipset_type_higher_rev(t)) != t) {
+ args = type->args[cmd];
+ for (arg = args; arg->opt; arg++) {
+ D("argc: %u, %s vs %s", i, argv[i], arg->name[0]);
+ if (ipset_match_option(argv[i], arg->name))
+ return exit_error(PARAMETER_PROBLEM,
+ "Argument `%s' is supported in the kernel module "
+ "of the set type %s starting from the revision %u "
+ "and you have installed revision %u only. "
+ "Your kernel is behind your ipset utility.",
+ argv[i], type->name,
+ type->revision, revision);
+ }
+ t = type;
+ }
return exit_error(PARAMETER_PROBLEM, "Unknown argument: `%s'", argv[i]);
}
@@ -717,14 +738,14 @@ parse_commandline(int argc, char *argv[])
return handle_error();
/* Parse create options: first check INET family */
- ret = call_parser(&argc, argv, type->args[IPSET_CREATE], true);
+ ret = call_parser(&argc, argv, type, 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);
+ ret = call_parser(&argc, argv, type, IPSET_CREATE, false);
if (ret < 0)
return handle_error();
else if (ret)
@@ -792,7 +813,7 @@ parse_commandline(int argc, char *argv[])
return handle_error();
/* Parse additional ADT options */
- ret = call_parser(&argc, argv, type->args[cmd2cmd(cmd)], false);
+ ret = call_parser(&argc, argv, type, cmd2cmd(cmd), false);
if (ret < 0)
return handle_error();
else if (ret)