@@ -66,6 +66,10 @@ enum ipset_opt {
IPSET_OPT_SKBMARK,
IPSET_OPT_SKBPRIO,
IPSET_OPT_SKBQUEUE,
+ /* New second port ADT options */
+ IPSET_OPT_PORT2,
+ IPSET_OPT_PORT2_FROM = IPSET_OPT_PORT2,
+ IPSET_OPT_PORT2_TO,
/* Internal options */
IPSET_OPT_FLAGS = 48, /* IPSET_FLAG_EXIST| */
IPSET_OPT_CADT_FLAGS, /* IPSET_FLAG_BEFORE| */
@@ -111,6 +115,8 @@ enum ipset_opt {
| IPSET_FLAG(IPSET_OPT_MARK) \
| IPSET_FLAG(IPSET_OPT_PORT) \
| IPSET_FLAG(IPSET_OPT_PORT_TO) \
+ | IPSET_FLAG(IPSET_OPT_PORT2) \
+ | IPSET_FLAG(IPSET_OPT_PORT2_TO)\
| IPSET_FLAG(IPSET_OPT_TIMEOUT) \
| IPSET_FLAG(IPSET_OPT_ETHER) \
| IPSET_FLAG(IPSET_OPT_NAME) \
@@ -122,6 +122,9 @@ enum {
IPSET_ATTR_SKBMARK,
IPSET_ATTR_SKBPRIO,
IPSET_ATTR_SKBQUEUE,
+ IPSET_ATTR_PORT2,
+ IPSET_ATTR_PORT2_FROM = IPSET_ATTR_PORT2,
+ IPSET_ATTR_PORT2_TO,
IPSET_ATTR_PAD,
__IPSET_ATTR_ADT_MAX,
};
@@ -237,6 +240,7 @@ enum ip_set_dim {
IPSET_DIM_ONE,
IPSET_DIM_TWO,
IPSET_DIM_THREE,
+ IPSET_DIM_FOUR,
/* Max dimension in elements.
* If changed, new revision of iptables match/target is required.
*/
@@ -251,6 +255,7 @@ enum ip_set_kopt {
IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE),
IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO),
IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE),
+ IPSET_DIM_FOUR_SRC = (1 << IPSET_DIM_FOUR),
IPSET_RETURN_NOMATCH = (1 << IPSET_BIT_RETURN_NOMATCH),
};
@@ -29,7 +29,7 @@ enum {
};
/* The maximal type dimension userspace supports */
-#define IPSET_DIM_UMAX 3
+#define IPSET_DIM_UMAX 4
/* Parser options */
enum {
@@ -44,9 +44,11 @@ enum ip_set_feature {
IPSET_TYPE_MARK = (1 << IPSET_TYPE_MARK_FLAG),
IPSET_TYPE_NOMATCH_FLAG = 7,
IPSET_TYPE_NOMATCH = (1 << IPSET_TYPE_NOMATCH_FLAG),
+ IPSET_TYPE_PORT2_FLAG = 8,
+ IPSET_TYPE_PORT2 = (1 << IPSET_TYPE_PORT2_FLAG),
/* Strictly speaking not a feature, but a flag for dumping:
* this settype must be dumped last */
- IPSET_DUMP_LAST_FLAG = 8,
+ IPSET_DUMP_LAST_FLAG = 9,
IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG),
};
@@ -122,6 +122,9 @@ enum {
IPSET_ATTR_SKBMARK,
IPSET_ATTR_SKBPRIO,
IPSET_ATTR_SKBQUEUE,
+ IPSET_ATTR_PORT2,
+ IPSET_ATTR_PORT2_FROM = IPSET_ATTR_PORT2,
+ IPSET_ATTR_PORT2_TO,
IPSET_ATTR_PAD,
__IPSET_ATTR_ADT_MAX,
};
@@ -237,6 +240,7 @@ enum ip_set_dim {
IPSET_DIM_ONE,
IPSET_DIM_TWO,
IPSET_DIM_THREE,
+ IPSET_DIM_FOUR,
/* Max dimension in elements.
* If changed, new revision of iptables match/target is required.
*/
@@ -251,6 +255,7 @@ enum ip_set_kopt {
IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE),
IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO),
IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE),
+ IPSET_DIM_FOUR_SRC = (1 << IPSET_DIM_FOUR),
IPSET_RETURN_NOMATCH = (1 << IPSET_BIT_RETURN_NOMATCH),
};
@@ -21,7 +21,7 @@ config IP_SET_MAX
You can define here default value of the maximum number
of IP sets for the kernel.
- The value can be overriden by the 'max_sets' module
+ The value can be overridden by the 'max_sets' module
parameter of the 'ip_set' module.
config IP_SET_BITMAP_IP
@@ -44,6 +44,8 @@ struct ipset_data {
uint32_t mark;
uint16_t port;
uint16_t port_to;
+ uint16_t port2;
+ uint16_t port2_to;
uint16_t index;
union {
/* RENAME/SWAP */
@@ -365,6 +367,12 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
return -1;
copy_addr(data->family, &data->adt.ip2_to, value);
break;
+ case IPSET_OPT_PORT2:
+ data->port2 = *(const uint16_t *) value;
+ break;
+ case IPSET_OPT_PORT2_TO:
+ data->port2_to = *(const uint16_t *) value;
+ break;
case IPSET_OPT_CIDR2:
data->adt.cidr2 = *(const uint8_t *) value;
break;
@@ -531,6 +539,10 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
return &data->adt.ip2;
case IPSET_OPT_IP2_TO:
return &data->adt.ip2_to;
+ case IPSET_OPT_PORT2:
+ return &data->port2;
+ case IPSET_OPT_PORT2_TO:
+ return &data->port2_to;
case IPSET_OPT_CIDR2:
return &data->adt.cidr2;
case IPSET_OPT_PROTO:
@@ -593,6 +605,8 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
return sizeof(uint32_t);
case IPSET_OPT_PORT:
case IPSET_OPT_PORT_TO:
+ case IPSET_OPT_PORT2:
+ case IPSET_OPT_PORT2_TO:
case IPSET_OPT_SKBQUEUE:
case IPSET_OPT_INDEX:
return sizeof(uint16_t);
@@ -55,6 +55,8 @@ static const struct ipset_attrname adtattr2name[] = {
[IPSET_ATTR_MARK] = { .name = "MARK" },
[IPSET_ATTR_PORT] = { .name = "PORT" },
[IPSET_ATTR_PORT_TO] = { .name = "PORT_TO" },
+ [IPSET_ATTR_PORT2] = { .name = "PORT2" },
+ [IPSET_ATTR_PORT2_TO] = { .name = "PORT2_TO" },
[IPSET_ATTR_TIMEOUT] = { .name = "TIMEOUT" },
[IPSET_ATTR_PROTO] = { .name = "PROTO" },
[IPSET_ATTR_CADT_FLAGS] = { .name = "CADT_FLAGS" },
@@ -316,7 +316,8 @@ ipset_parse_port(struct ipset_session *session,
uint16_t port;
assert(session);
- assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT_TO);
+ assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT_TO ||
+ opt == IPSET_OPT_PORT2 || opt == IPSET_OPT_PORT2_TO);
assert(str);
if (parse_portname(session, str, &port, proto) == 0) {
@@ -383,7 +384,7 @@ ipset_parse_tcpudp_port(struct ipset_session *session,
int err = 0;
assert(session);
- assert(opt == IPSET_OPT_PORT);
+ assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT2);
assert(str);
saved = tmp = ipset_strdup(session, str);
@@ -399,7 +400,10 @@ ipset_parse_tcpudp_port(struct ipset_session *session,
if (a != NULL) {
/* port-port */
*a++ = '\0';
- err = ipset_parse_port(session, IPSET_OPT_PORT_TO, a, proto);
+ err = ipset_parse_port(session,
+ opt == IPSET_OPT_PORT ? IPSET_OPT_PORT_TO
+ : IPSET_OPT_PORT2_TO,
+ a, proto);
if (err)
goto error;
}
@@ -446,7 +450,8 @@ ipset_parse_single_tcp_port(struct ipset_session *session,
enum ipset_opt opt, const char *str)
{
assert(session);
- assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT_TO);
+ assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT_TO ||
+ opt == IPSET_OPT_PORT2 || opt == IPSET_OPT_PORT2_TO);
assert(str);
return ipset_parse_port(session, opt, str, "tcp");
@@ -603,7 +608,7 @@ ipset_parse_proto_port(struct ipset_session *session,
int err = 0;
assert(session);
- assert(opt == IPSET_OPT_PORT);
+ assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT2);
assert(str);
data = ipset_session_data(session);
@@ -1962,7 +1967,7 @@ ipset_parse_elem(struct ipset_session *session,
bool optional, const char *str)
{
const struct ipset_type *type;
- char *a = NULL, *b = NULL, *tmp, *saved;
+ char *a = NULL, *b = NULL, *c = NULL, *tmp, *saved;
int ret;
assert(session);
@@ -2010,9 +2015,22 @@ ipset_parse_elem(struct ipset_session *session,
elem_syntax_err("Two elem separators in %s, "
"but settype %s supports one.",
str, type->name);
- if (b != NULL && elem_separator(b))
- elem_syntax_err("Three elem separators in %s, "
- "but settype %s supports two.",
+ if (b)
+ c = elem_separator(b);
+ if (type->dimension > IPSET_DIM_THREE) {
+ if (c != NULL) {
+ /* elem,elem,elem,elem */
+ *c++ = '\0';
+ } else if (!optional)
+ elem_syntax_err("Fourth element is missing from %s.",
+ str);
+ } else if (c != NULL)
+ elem_syntax_err("Four elem separators in %s, "
+ "but settype %s supports three.",
+ str, type->name);
+ if (c != NULL && elem_separator(c))
+ elem_syntax_err("Five elem separators in %s, "
+ "but settype %s supports four.",
str, type->name);
D("parse elem part one: %s", tmp);
@@ -2026,6 +2044,10 @@ ipset_parse_elem(struct ipset_session *session,
D("parse elem part three: %s", b);
parse_elem(session, type, IPSET_DIM_THREE, b);
}
+ if (type->dimension > IPSET_DIM_THREE && c != NULL) {
+ D("parse elem part four: %s", c);
+ parse_elem(session, type, IPSET_DIM_FOUR, c);
+ }
goto out;
@@ -470,12 +470,12 @@ ipset_print_port(char *buf, unsigned int len,
assert(buf);
assert(len > 0);
assert(data);
- assert(opt == IPSET_OPT_PORT);
+ assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT2);
if (len < 2*strlen("65535") + 2)
return -1;
- port = ipset_data_get(data, IPSET_OPT_PORT);
+ port = ipset_data_get(data, opt);
assert(port);
size = snprintf(buf, len, "%u", *port);
SNPRINTF_FAILURE(size, len, offset);
@@ -486,6 +486,12 @@ ipset_print_port(char *buf, unsigned int len,
"%s%u",
IPSET_RANGE_SEPARATOR, *port);
SNPRINTF_FAILURE(size, len, offset);
+ } else if (ipset_data_test(data, IPSET_OPT_PORT2_TO)) {
+ port = ipset_data_get(data, IPSET_OPT_PORT2_TO);
+ size = snprintf(buf + offset, len,
+ "%s%u",
+ IPSET_RANGE_SEPARATOR, *port);
+ SNPRINTF_FAILURE(size, len, offset);
}
return offset;
@@ -775,7 +781,7 @@ ipset_print_proto_port(char *buf, unsigned int len,
assert(buf);
assert(len > 0);
assert(data);
- assert(opt == IPSET_OPT_PORT);
+ assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT2);
if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_PROTO))) {
uint8_t proto = *(const uint8_t *) ipset_data_get(data,
@@ -795,17 +801,17 @@ ipset_print_proto_port(char *buf, unsigned int len,
break;
case IPPROTO_ICMP:
size = ipset_print_icmp(buf + offset, len, data,
- IPSET_OPT_PORT, env);
+ opt, env);
goto out;
case IPPROTO_ICMPV6:
size = ipset_print_icmpv6(buf + offset, len, data,
- IPSET_OPT_PORT, env);
+ opt, env);
goto out;
default:
break;
}
}
- size = ipset_print_port(buf + offset, len, data, IPSET_OPT_PORT, env);
+ size = ipset_print_port(buf + offset, len, data, opt, env);
out:
SNPRINTF_FAILURE(size, len, offset);
return offset;
@@ -871,6 +877,16 @@ ipset_print_elem(char *buf, unsigned int len,
size = type->elem[IPSET_DIM_THREE - 1].print(buf + offset, len, data,
type->elem[IPSET_DIM_THREE - 1].opt, env);
SNPRINTF_FAILURE(size, len, offset);
+ if (type->dimension == IPSET_DIM_THREE ||
+ (type->last_elem_optional &&
+ !ipset_data_test(data, type->elem[IPSET_DIM_FOUR - 1].opt)))
+ return offset;
+
+ size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR);
+ SNPRINTF_FAILURE(size, len, offset);
+ size = type->elem[IPSET_DIM_FOUR - 1].print(buf + offset, len, data,
+ type->elem[IPSET_DIM_FOUR - 1].opt, env);
+ SNPRINTF_FAILURE(size, len, offset);
return offset;
}
@@ -488,6 +488,14 @@ static const struct ipset_attr_policy adt_attrs[] = {
.type = MNL_TYPE_U16,
.opt = IPSET_OPT_PORT_TO,
},
+ [IPSET_ATTR_PORT2] = {
+ .type = MNL_TYPE_U16,
+ .opt = IPSET_OPT_PORT2,
+ },
+ [IPSET_ATTR_PORT2_TO] = {
+ .type = MNL_TYPE_U16,
+ .opt = IPSET_OPT_PORT2_TO,
+ },
[IPSET_ATTR_PROTO] = {
.type = MNL_TYPE_U8,
.opt = IPSET_OPT_PROTO,
This patch prepares ipset for supporting sets which contain 4 elements. A definition for a "PORT2" element type has also been added which is akin to the existing "IP2" type. not related, but a typo in the Kconfig was file was also corrected - purely to bring it into sync with the kernel sources. Signed-off-by: Oliver Smith <oliver@uptheinter.net> --- include/libipset/data.h | 6 +++ include/libipset/linux_ip_set.h | 5 +++ include/libipset/types.h | 2 +- kernel/include/linux/netfilter/ipset/ip_set.h | 4 +- .../uapi/linux/netfilter/ipset/ip_set.h | 5 +++ kernel/net/netfilter/ipset/Kconfig | 2 +- lib/data.c | 14 +++++++ lib/debug.c | 2 + lib/parse.c | 40 ++++++++++++++----- lib/print.c | 28 ++++++++++--- lib/session.c | 8 ++++ 11 files changed, 98 insertions(+), 18 deletions(-)