From patchwork Sun Dec 16 21:30:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Smith X-Patchwork-Id: 1014204 X-Patchwork-Delegate: kadlec@blackhole.kfki.hu Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=quarantine dis=none) header.from=uptheinter.net Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=uptheinter.net header.i=@uptheinter.net header.b="Vx4OLJsD"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43HyKV54pHz9sBQ for ; Mon, 17 Dec 2018 08:36:46 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730932AbeLPVgf (ORCPT ); Sun, 16 Dec 2018 16:36:35 -0500 Received: from mail.uptheinter.net ([77.74.193.35]:39822 "EHLO mail.uptheinter.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730917AbeLPVgf (ORCPT ); Sun, 16 Dec 2018 16:36:35 -0500 Received: from localhost (localhost [127.0.0.1]) by mail.uptheinter.net (Postfix) with ESMTP id DFC65A26E4 for ; Sun, 16 Dec 2018 21:30:47 +0000 (GMT) X-DKIM: Sendmail DKIM Filter v2.7.2 mail.uptheinter.net DFC65A26E4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=uptheinter.net; s=default; t=1544995847; bh=xmnMDI+7dTMHcb24ei7smoVUVR+Mjq+J0p4eRMq Mx5k=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding; b=Vx4OLJsD9zOhgoXqfpAVI2ei 3HeEjmAlEVKAxv9eQ+bP2zIYf2hEx2gfhJLD2feyq5ZemgcSyOJq5KXg0uvEJCWlmEx ZIGd2IX095GD38pQiIs/QQMSKicC10ZcsjGhevUXghkq6gHU2EMF7+J3BFjx5ogXB/D 1xKJ7H667hFOw= X-Virus-Scanned: amavisd-new at example.com Received: from mail.uptheinter.net ([127.0.0.1]) by localhost (mail.uptheinter.net [127.0.0.1]) (amavisd-new, port 10024) with LMTP id ifD0S9SuB1RL for ; Sun, 16 Dec 2018 21:30:42 +0000 (GMT) From: Oliver Smith To: netfilter-devel@vger.kernel.org Subject: [PATCH 1/5] ipset: Support sets with 4 individual elements and an extra port Date: Sun, 16 Dec 2018 21:30:35 +0000 Message-Id: <20181216213039.399-2-oliver@uptheinter.net> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181216213039.399-1-oliver@uptheinter.net> References: <20181216213039.399-1-oliver@uptheinter.net> MIME-Version: 1.0 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org 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 --- 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(-) diff --git a/include/libipset/data.h b/include/libipset/data.h index 744b010..55cf42f 100644 --- a/include/libipset/data.h +++ b/include/libipset/data.h @@ -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) \ diff --git a/include/libipset/linux_ip_set.h b/include/libipset/linux_ip_set.h index 68a2087..4ea0c6d 100644 --- a/include/libipset/linux_ip_set.h +++ b/include/libipset/linux_ip_set.h @@ -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), }; diff --git a/include/libipset/types.h b/include/libipset/types.h index bb71d88..a0b0d48 100644 --- a/include/libipset/types.h +++ b/include/libipset/types.h @@ -29,7 +29,7 @@ enum { }; /* The maximal type dimension userspace supports */ -#define IPSET_DIM_UMAX 3 +#define IPSET_DIM_UMAX 4 /* Parser options */ enum { diff --git a/kernel/include/linux/netfilter/ipset/ip_set.h b/kernel/include/linux/netfilter/ipset/ip_set.h index f2b946f..62ec898 100644 --- a/kernel/include/linux/netfilter/ipset/ip_set.h +++ b/kernel/include/linux/netfilter/ipset/ip_set.h @@ -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), }; diff --git a/kernel/include/uapi/linux/netfilter/ipset/ip_set.h b/kernel/include/uapi/linux/netfilter/ipset/ip_set.h index c83497f..7fce287 100644 --- a/kernel/include/uapi/linux/netfilter/ipset/ip_set.h +++ b/kernel/include/uapi/linux/netfilter/ipset/ip_set.h @@ -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), }; diff --git a/kernel/net/netfilter/ipset/Kconfig b/kernel/net/netfilter/ipset/Kconfig index 861659f..4083a80 100644 --- a/kernel/net/netfilter/ipset/Kconfig +++ b/kernel/net/netfilter/ipset/Kconfig @@ -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 diff --git a/lib/data.c b/lib/data.c index 9a7c861..94080f7 100644 --- a/lib/data.c +++ b/lib/data.c @@ -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); diff --git a/lib/debug.c b/lib/debug.c index 44d0f04..eed1731 100644 --- a/lib/debug.c +++ b/lib/debug.c @@ -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" }, diff --git a/lib/parse.c b/lib/parse.c index 5943f05..b10432f 100644 --- a/lib/parse.c +++ b/lib/parse.c @@ -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; diff --git a/lib/print.c b/lib/print.c index 02ffe41..70b4396 100644 --- a/lib/print.c +++ b/lib/print.c @@ -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; } diff --git a/lib/session.c b/lib/session.c index 9e1d7dd..ed82ca9 100644 --- a/lib/session.c +++ b/lib/session.c @@ -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,