diff options
-rw-r--r-- | include/libipset/data.h | 1 | ||||
-rw-r--r-- | lib/data.c | 18 | ||||
-rw-r--r-- | lib/libipset.map | 1 | ||||
-rw-r--r-- | lib/parse.c | 10 | ||||
-rw-r--r-- | lib/types.c | 14 |
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); @@ -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: |