summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/args.c8
-rw-r--r--lib/data.c10
-rw-r--r--lib/debug.c1
-rw-r--r--lib/errcode.c2
-rw-r--r--lib/parse.c43
-rw-r--r--lib/print.c3
-rw-r--r--lib/session.c8
7 files changed, 74 insertions, 1 deletions
diff --git a/lib/args.c b/lib/args.c
index bab3b13..e47105c 100644
--- a/lib/args.c
+++ b/lib/args.c
@@ -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 *
diff --git a/lib/data.c b/lib/data.c
index 7720178..72f1330 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -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;