summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libipset/data.h1
-rw-r--r--lib/data.c18
-rw-r--r--lib/libipset.map1
-rw-r--r--lib/parse.c10
-rw-r--r--lib/types.c14
5 files changed, 39 insertions, 5 deletions
diff --git a/include/libipset/data.h b/include/libipset/data.h
index 525cc6a..5d80185 100644
--- a/include/libipset/data.h
+++ b/include/libipset/data.h
@@ -113,6 +113,7 @@ extern bool ipset_data_flags_test(const struct ipset_data *data,
extern void ipset_data_flags_set(struct ipset_data *data, uint64_t flags);
extern void ipset_data_flags_unset(struct ipset_data *data, uint64_t flags);
extern bool ipset_data_ignored(struct ipset_data *data, enum ipset_opt opt);
+extern bool ipset_data_test_ignored(struct ipset_data *data, enum ipset_opt opt);
extern int ipset_data_set(struct ipset_data *data, enum ipset_opt opt,
const void *value);
diff --git a/lib/data.c b/lib/data.c
index 3bbb75b..d74be4d 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -166,7 +166,7 @@ do { \
* @data: data blob
* @flags: the option flag to be ignored
*
- * Returns true if the option was not already ignored.
+ * Returns true if the option was already ignored.
*/
bool
ipset_data_ignored(struct ipset_data *data, enum ipset_opt opt)
@@ -181,6 +181,21 @@ ipset_data_ignored(struct ipset_data *data, enum ipset_opt opt)
}
/**
+ * ipset_data_test_ignored - test ignored bits in the data blob
+ * @data: data blob
+ * @flags: the option flag to be tested
+ *
+ * Returns true if the option is ignored.
+ */
+bool
+ipset_data_test_ignored(struct ipset_data *data, enum ipset_opt opt)
+{
+ assert(data);
+
+ return data->ignored & IPSET_FLAG(opt);
+}
+
+/**
* ipset_data_set - put data into the data blob
* @data: data blob
* @opt: the option kind of the data
@@ -208,6 +223,7 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
break;
case IPSET_OPT_FAMILY:
data->family = *(const uint8_t *) value;
+ data->ignored &= ~IPSET_FLAG(IPSET_OPT_FAMILY);
D("family set to %u", data->family);
break;
/* CADT options */
diff --git a/lib/libipset.map b/lib/libipset.map
index 0eb7fad..fd6b8c0 100644
--- a/lib/libipset.map
+++ b/lib/libipset.map
@@ -115,4 +115,5 @@ global:
ipset_load_types;
ipset_port_usage;
ipset_parse_timeout;
+ ipset_data_test_ignored;
} LIBIPSET_1.0;
diff --git a/lib/parse.c b/lib/parse.c
index 45937f0..afbbbf9 100644
--- a/lib/parse.c
+++ b/lib/parse.c
@@ -651,7 +651,8 @@ ipset_parse_family(struct ipset_session *session,
assert(str);
data = ipset_session_data(session);
- if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_FAMILY)))
+ if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_FAMILY))
+ && !ipset_data_test_ignored(data, IPSET_OPT_FAMILY))
syntax_err("protocol family may not be specified "
"multiple times");
@@ -1637,8 +1638,11 @@ ipset_call_parser(struct ipset_session *session,
const struct ipset_arg *arg,
const char *str)
{
- if (ipset_data_flags_test(ipset_session_data(session),
- IPSET_FLAG(arg->opt)))
+ struct ipset_data *data = ipset_session_data(session);
+
+ if (ipset_data_flags_test(data, IPSET_FLAG(arg->opt))
+ && !(arg->opt == IPSET_OPT_FAMILY
+ && ipset_data_test_ignored(data, IPSET_OPT_FAMILY)))
syntax_err("%s already specified", arg->name[0]);
return arg->parse(session, arg->opt, str);
diff --git a/lib/types.c b/lib/types.c
index 64c9c84..5721705 100644
--- a/lib/types.c
+++ b/lib/types.c
@@ -207,6 +207,7 @@ create_type_get(struct ipset_session *session)
uint8_t family, tmin = 0, tmax = 0;
uint8_t kmin, kmax;
int ret;
+ bool ignore_family = false;
data = ipset_session_data(session);
assert(data);
@@ -238,6 +239,8 @@ create_type_get(struct ipset_session *session)
family = match->family == NFPROTO_IPSET_IPV46 ?
NFPROTO_IPV4 : match->family;
ipset_data_set(data, IPSET_OPT_FAMILY, &family);
+ if (match->family == NFPROTO_IPSET_IPV46)
+ ignore_family = true;
}
if (match->kernel_check == IPSET_KERNEL_OK)
@@ -294,6 +297,11 @@ create_type_get(struct ipset_session *session)
found:
ipset_data_set(data, IPSET_OPT_TYPE, match);
+ if (ignore_family) {
+ /* Overload ignored flag */
+ D("set ignored flag to FAMILY");
+ ipset_data_ignored(data, IPSET_OPT_FAMILY);
+ }
return match;
}
@@ -390,7 +398,11 @@ ipset_type_get(struct ipset_session *session, enum ipset_cmd cmd)
switch (cmd) {
case IPSET_CMD_CREATE:
- return create_type_get(session);
+ return ipset_data_test(ipset_session_data(session),
+ IPSET_OPT_TYPE)
+ ? ipset_data_get(ipset_session_data(session),
+ IPSET_OPT_TYPE)
+ : create_type_get(session);
case IPSET_CMD_ADD:
case IPSET_CMD_DEL:
case IPSET_CMD_TEST: