diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/args.c | 8 | ||||
-rw-r--r-- | lib/data.c | 10 | ||||
-rw-r--r-- | lib/debug.c | 1 | ||||
-rw-r--r-- | lib/errcode.c | 2 | ||||
-rw-r--r-- | lib/parse.c | 43 | ||||
-rw-r--r-- | lib/print.c | 3 | ||||
-rw-r--r-- | lib/session.c | 8 |
7 files changed, 74 insertions, 1 deletions
@@ -300,6 +300,14 @@ static const struct ipset_arg ipset_args[] = { .print = ipset_print_hexnumber, .help = "[initval VALUE]", }, + [IPSET_ARG_BITMASK] = { + .name = { "bitmask", NULL }, + .has_arg = IPSET_MANDATORY_ARG, + .opt = IPSET_OPT_BITMASK, + .parse = ipset_parse_bitmask, + .print = ipset_print_ip, + .help = "[bitmask bitmask]", + }, }; const struct ipset_arg * @@ -53,6 +53,7 @@ struct ipset_data { uint8_t bucketsize; uint8_t resize; uint8_t netmask; + union nf_inet_addr bitmask; uint32_t hashsize; uint32_t maxelem; uint32_t markmask; @@ -301,6 +302,12 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value) case IPSET_OPT_NETMASK: data->create.netmask = *(const uint8_t *) value; break; + case IPSET_OPT_BITMASK: + if (!(data->family == NFPROTO_IPV4 || + data->family == NFPROTO_IPV6)) + return -1; + copy_addr(data->family, &data->create.bitmask, value); + break; case IPSET_OPT_BUCKETSIZE: data->create.bucketsize = *(const uint8_t *) value; break; @@ -508,6 +515,8 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt) return &data->create.markmask; case IPSET_OPT_NETMASK: return &data->create.netmask; + case IPSET_OPT_BITMASK: + return &data->create.bitmask; case IPSET_OPT_BUCKETSIZE: return &data->create.bucketsize; case IPSET_OPT_RESIZE: @@ -594,6 +603,7 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family) case IPSET_OPT_IP_TO: case IPSET_OPT_IP2: case IPSET_OPT_IP2_TO: + case IPSET_OPT_BITMASK: return family == NFPROTO_IPV4 ? sizeof(uint32_t) : sizeof(struct in6_addr); case IPSET_OPT_MARK: diff --git a/lib/debug.c b/lib/debug.c index bf57a41..dbc5cfb 100644 --- a/lib/debug.c +++ b/lib/debug.c @@ -40,6 +40,7 @@ static const struct ipset_attrname createattr2name[] = { [IPSET_ATTR_MAXELEM] = { .name = "MAXELEM" }, [IPSET_ATTR_MARKMASK] = { .name = "MARKMASK" }, [IPSET_ATTR_NETMASK] = { .name = "NETMASK" }, + [IPSET_ATTR_BITMASK] = { .name = "BITMASK" }, [IPSET_ATTR_BUCKETSIZE] = { .name = "BUCKETSIZE" }, [IPSET_ATTR_RESIZE] = { .name = "RESIZE" }, [IPSET_ATTR_SIZE] = { .name = "SIZE" }, diff --git a/lib/errcode.c b/lib/errcode.c index 76bab74..49c97a1 100644 --- a/lib/errcode.c +++ b/lib/errcode.c @@ -44,6 +44,8 @@ static const struct ipset_errcode_table core_errcode_table[] = { "The value of the markmask parameter is invalid" }, { IPSET_ERR_INVALID_FAMILY, 0, "Protocol family not supported by the set type" }, + { IPSET_ERR_BITMASK_NETMASK_EXCL, 0, + "netmask and bitmask options are mutually exclusive, provide only one" }, /* DESTROY specific error codes */ { IPSET_ERR_BUSY, IPSET_CMD_DESTROY, diff --git a/lib/parse.c b/lib/parse.c index 974eaf8..48d71be 100644 --- a/lib/parse.c +++ b/lib/parse.c @@ -1703,6 +1703,9 @@ ipset_parse_netmask(struct ipset_session *session, assert(str); data = ipset_session_data(session); + if (ipset_data_test(data, IPSET_OPT_BITMASK)) + return syntax_err("bitmask and netmask are mutually exclusive, provide only one"); + family = ipset_data_family(data); if (family == NFPROTO_UNSPEC) { family = NFPROTO_IPV4; @@ -1722,6 +1725,46 @@ ipset_parse_netmask(struct ipset_session *session, } /** + * ipset_parse_bitmask - parse string as a bitmask + * @session: session structure + * @opt: option kind of the data + * @str: string to parse + * + * Parse string as a bitmask value, depending on family type. + * If family is not set yet, INET is assumed. + * The value is stored in the data blob of the session. + * + * Returns 0 on success or a negative error code. + */ +int +ipset_parse_bitmask(struct ipset_session *session, + enum ipset_opt opt, const char *str) +{ + uint8_t family; + struct ipset_data *data; + + assert(session); + assert(opt == IPSET_OPT_BITMASK); + assert(str); + + data = ipset_session_data(session); + if (ipset_data_test(data, IPSET_OPT_NETMASK)) + return syntax_err("bitmask and netmask are mutually exclusive, provide only one"); + + family = ipset_data_family(data); + if (family == NFPROTO_UNSPEC) { + family = NFPROTO_IPV4; + ipset_data_set(data, IPSET_OPT_FAMILY, &family); + } + + if (parse_ipaddr(session, opt, str, family)) + return syntax_err("bitmask is not valid for family = %s", + family == NFPROTO_IPV4 ? "inet" : "inet6"); + + return 0; +} + +/** * ipset_parse_flag - "parse" option flags * @session: session structure * @opt: option kind of the data diff --git a/lib/print.c b/lib/print.c index a7ffd81..50f0ad6 100644 --- a/lib/print.c +++ b/lib/print.c @@ -265,7 +265,7 @@ ipset_print_ip(char *buf, unsigned int len, assert(buf); assert(len > 0); assert(data); - assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2); + assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2 || opt == IPSET_OPT_BITMASK); D("len: %u", len); family = ipset_data_family(data); @@ -976,6 +976,7 @@ ipset_print_data(char *buf, unsigned int len, size = ipset_print_elem(buf, len, data, opt, env); break; case IPSET_OPT_IP: + case IPSET_OPT_BITMASK: size = ipset_print_ip(buf, len, data, opt, env); break; case IPSET_OPT_PORT: diff --git a/lib/session.c b/lib/session.c index 1ca26ff..cdc59e0 100644 --- a/lib/session.c +++ b/lib/session.c @@ -462,6 +462,10 @@ static const struct ipset_attr_policy create_attrs[] = { .type = MNL_TYPE_U32, .opt = IPSET_OPT_MEMSIZE, }, + [IPSET_ATTR_BITMASK] = { + .type = MNL_TYPE_NESTED, + .opt = IPSET_OPT_BITMASK, + }, }; static const struct ipset_attr_policy adt_attrs[] = { @@ -1721,6 +1725,10 @@ rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh, if (attr->type == MNL_TYPE_NESTED) { /* IP addresses */ struct nlattr *nested; + + if (type == IPSET_ATTR_BITMASK) + family = ipset_data_family(session->data); + int atype = family == NFPROTO_IPV4 ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6; |