]> granicus.if.org Git - ipset/commitdiff
Support range for IPv4 at adding/deleting elements for hash:*net* types
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Sun, 15 May 2011 10:04:19 +0000 (12:04 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Sun, 15 May 2011 10:04:19 +0000 (12:04 +0200)
The range internally is converted to the network(s) equal to the range.
Example:

# ipset new test hash:net
# ipset add test 10.2.0.0-10.2.1.12
# ipset list test
Name: test
Type: hash:net
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 16888
References: 0
Members:
10.2.1.12
10.2.1.0/29
10.2.0.0/24
10.2.1.8/30

27 files changed:
include/libipset/data.h
include/libipset/linux_ip_set.h
include/libipset/linux_ip_set_hash.h
include/libipset/parse.h
kernel/include/linux/netfilter/ipset/ip_set.h
kernel/include/linux/netfilter/ipset/ip_set_ahash.h
kernel/include/linux/netfilter/ipset/ip_set_hash.h
kernel/include/linux/netfilter/ipset/pfxlen.h
kernel/net/netfilter/ipset/ip_set_hash_ipportnet.c
kernel/net/netfilter/ipset/ip_set_hash_net.c
kernel/net/netfilter/ipset/ip_set_hash_netport.c
kernel/net/netfilter/ipset/pfxlen.c
lib/data.c
lib/parse.c
lib/session.c
src/errcode.c
src/ipset.8
src/ipset.c
src/ipset_hash_ipport.c
src/ipset_hash_ipportip.c
src/ipset_hash_ipportnet.c
src/ipset_hash_net.c
src/ipset_hash_netport.c
tests/hash:ip,port,net.t
tests/hash:net,port.t
tests/hash:net.t
tests/hash:net.t.list2 [new file with mode: 0644]

index 4710963d44455f1ac72f54a393e8d4c792e85b68..8902ddfcf15d2f342eb1f1ddf18877a1e0c1f762 100644 (file)
@@ -44,6 +44,7 @@ enum ipset_opt {
        IPSET_OPT_NAMEREF,
        IPSET_OPT_IP2,
        IPSET_OPT_CIDR2,
+       IPSET_OPT_IP2_TO,
        IPSET_OPT_PROTO,
        /* Swap/rename to */
        IPSET_OPT_SETNAME2,
index 00cf0c60c0dc06909034def17676a4708df633f3..e88f6d5350eed9b9149da48cf4adfcb028a03dbd 100644 (file)
@@ -104,6 +104,7 @@ enum {
        IPSET_ATTR_NAMEREF,
        IPSET_ATTR_IP2,
        IPSET_ATTR_CIDR2,
+       IPSET_ATTR_IP2_TO,
        __IPSET_ATTR_ADT_MAX,
 };
 #define IPSET_ATTR_ADT_MAX     (__IPSET_ATTR_ADT_MAX - 1)
@@ -145,7 +146,7 @@ enum ipset_cmd_flags {
        IPSET_FLAG_BIT_LIST_SETNAME = 1,
        IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
        IPSET_FLAG_BIT_LIST_HEADER = 2,
-       IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
+       IPSET_FLAG_LIST_HEADER  = (1 << IPSET_FLAG_BIT_LIST_HEADER),
 };
 
 /* Flags at CADT attribute level */
index 7c6336a2c7e26182b926d98c4df61ba66f5a7abf..7a9e5f7d21653d6378ec8282f0569da3c8f1a36b 100644 (file)
@@ -11,6 +11,10 @@ enum {
        IPSET_ERR_INVALID_PROTO,
        /* Protocol missing but must be specified */
        IPSET_ERR_MISSING_PROTO,
+       /* Range not supported */
+       IPSET_ERR_HASH_RANGE_UNSUPPORTED,
+       /* Invalid range */
+       IPSET_ERR_HASH_RANGE,
 };
 
 #endif /* __IP_SET_HASH_H */
index 760df49abce5cbf864a8928dffadfd9e39271851..bc96a6e6f98f4e16f99c5856d115d69aab77b3e1 100644 (file)
@@ -60,6 +60,8 @@ extern int ipset_parse_ipnet(struct ipset_session *session,
                             enum ipset_opt opt, const char *str);
 extern int ipset_parse_ip4_single6(struct ipset_session *session,
                                enum ipset_opt opt, const char *str);
+extern int ipset_parse_ip4_net6(struct ipset_session *session,
+                               enum ipset_opt opt, const char *str);
 extern int ipset_parse_name(struct ipset_session *session,
                             enum ipset_opt opt, const char *str);
 extern int ipset_parse_before(struct ipset_session *session,
index ac31e382472bdf4e60be21804125547b8779b1e3..fd83f4f436c3a6c642b324f0cb43ecc0eb3fba83 100644 (file)
@@ -104,6 +104,7 @@ enum {
        IPSET_ATTR_NAMEREF,
        IPSET_ATTR_IP2,
        IPSET_ATTR_CIDR2,
+       IPSET_ATTR_IP2_TO,
        __IPSET_ATTR_ADT_MAX,
 };
 #define IPSET_ATTR_ADT_MAX     (__IPSET_ATTR_ADT_MAX - 1)
index 6a4969dcbeb8b8069c9c75d55968f355bf3323d1..95f63195f5e3fdde0b67dfc58e77ed17588b50cd 100644 (file)
@@ -353,7 +353,7 @@ retry:
        return 0;
 }
 
-static inline void
+static void
 type_pf_data_next(struct ip_set_hash *h, const struct type_pf_elem *d);
 
 /* Add an element to a hash and update the internal counters when succeeded,
index b86f15c04524ee4783a1bfe48c8cf5011a0712c2..e2a9fae767f631ac9fbc406a5237bbf099ca6ef7 100644 (file)
@@ -11,6 +11,10 @@ enum {
        IPSET_ERR_INVALID_PROTO,
        /* Protocol missing but must be specified */
        IPSET_ERR_MISSING_PROTO,
+       /* Range not supported */
+       IPSET_ERR_HASH_RANGE_UNSUPPORTED,
+       /* Invalid range */
+       IPSET_ERR_HASH_RANGE,
 };
 
 #ifdef __KERNEL__
index 0e1fb50da562914a794d4cb9f02f32132b4f0e41..84efa3351e0e62896e05b3937c442fcf0ad2b2db 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <asm/byteorder.h>
 #include <linux/netfilter.h> 
+#include <net/tcp.h>
 
 /* Prefixlen maps, by Jan Engelhardt  */
 extern const union nf_inet_addr ip_set_netmask_map[];
@@ -32,4 +33,6 @@ ip_set_hostmask6(u8 pfxlen)
        return &ip_set_hostmask_map[pfxlen].ip6[0];
 }
 
+extern u32 ip_set_range_to_cidr(u32 from, u32 to, u8 *cidr);
+
 #endif /*_PFXLEN_H */
index 0b54fdea979431755ce07d1a042ce25168c43a07..ef068b03ec1a6e598ff5c760f410d8bacb0c407d 100644 (file)
@@ -146,6 +146,7 @@ hash_ipportnet4_data_next(struct ip_set_hash *h,
 {
        h->next.ip = ntohl(d->ip);
        h->next.port = ntohs(d->port);
+       h->next.ip2 = ntohl(d->ip2);
 }
 
 static int
@@ -181,6 +182,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
        u32 ip, ip_to, p = 0, port, port_to;
+       u32 ip2_from = 0, ip2_to, ip2_last, ip2;
        u32 timeout = h->timeout;
        bool with_ports = false;
        int ret;
@@ -194,21 +196,19 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
        if (tb[IPSET_ATTR_LINENO])
                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 
-       ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
+       ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
        if (ret)
                return ret;
 
-       ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &data.ip2);
+       ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from);
        if (ret)
                return ret;
 
-       if (tb[IPSET_ATTR_CIDR2])
+       if (tb[IPSET_ATTR_CIDR2]) {
                data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
-
-       if (!data.cidr)
-               return -IPSET_ERR_INVALID_CIDR;
-
-       data.ip2 &= ip_set_netmask(data.cidr);
+               if (!data.cidr)
+                       return -IPSET_ERR_INVALID_CIDR;
+       }
 
        if (tb[IPSET_ATTR_PORT])
                data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
@@ -233,14 +233,16 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
+       with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
        if (adt == IPSET_TEST ||
-           !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
-             tb[IPSET_ATTR_PORT_TO])) {
+           !(tb[IPSET_ATTR_CIDR] || tb[IPSET_ATTR_IP_TO] || with_ports ||
+             tb[IPSET_ATTR_IP2_TO])) {
+               data.ip = htonl(ip);
+               data.ip2 = htonl(ip2_from & ip_set_hostmask(data.cidr));
                ret = adtfn(set, &data, timeout, flags);
                return ip_set_eexist(ret, flags) ? 0 : ret;
        }
 
-       ip = ntohl(data.ip);
        if (tb[IPSET_ATTR_IP_TO]) {
                ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
                if (ret)
@@ -254,29 +256,48 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
                        return -IPSET_ERR_INVALID_CIDR;
                ip &= ip_set_hostmask(cidr);
                ip_to = ip | ~ip_set_hostmask(cidr);
-       } else
-               ip_to = ip;
+       }
 
        port_to = port = ntohs(data.port);
-       if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
+       if (tb[IPSET_ATTR_PORT_TO]) {
                port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
                if (port > port_to)
                        swap(port, port_to);
        }
+       if (tb[IPSET_ATTR_IP2_TO]) {
+               ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);
+               if (ret)
+                       return ret;
+               if (ip2_from > ip2_to)
+                       swap(ip2_from, ip2_to);
+               if (ip2_from + UINT_MAX == ip2_to)
+                       return -IPSET_ERR_HASH_RANGE;
+       } else {
+               ip2_from &= ip_set_hostmask(data.cidr);
+               ip2_to = ip2_from | ~ip_set_hostmask(data.cidr);
+       }
 
        if (retried)
                ip = h->next.ip;
        for (; !before(ip_to, ip); ip++) {
+               data.ip = htonl(ip);
                p = retried && ip == h->next.ip ? h->next.port : port;
                for (; p <= port_to; p++) {
-                       data.ip = htonl(ip);
                        data.port = htons(p);
-                       ret = adtfn(set, &data, timeout, flags);
-
-                       if (ret && !ip_set_eexist(ret, flags))
-                               return ret;
-                       else
-                               ret = 0;
+                       ip2 = retried && ip == h->next.ip && p == h->next.port
+                               ? h->next.ip2 : ip2_from;
+                       while (!after(ip2, ip2_to)) {
+                               data.ip2 = htonl(ip2);
+                               ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
+                                                               &data.cidr);
+                               ret = adtfn(set, &data, timeout, flags);
+
+                               if (ret && !ip_set_eexist(ret, flags))
+                                       return ret;
+                               else
+                                       ret = 0;
+                               ip2 = ip2_last + 1;
+                       }
                }
        }
        return ret;
@@ -451,6 +472,8 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
                     tb[IPSET_ATTR_IP_TO] ||
                     tb[IPSET_ATTR_CIDR]))
                return -IPSET_ERR_PROTOCOL;
+       if (unlikely(tb[IPSET_ATTR_IP_TO]))
+               return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
 
        if (tb[IPSET_ATTR_LINENO])
                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
@@ -596,7 +619,8 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
        .dimension      = IPSET_DIM_THREE,
        .family         = AF_UNSPEC,
        .revision_min   = 0,
-       .revision_max   = 1,    /* SCTP and UDPLITE support added */
+       /*                1        SCTP and UDPLITE support added */
+       .revision_max   = 2,    /* Range as input support for IPv4 added */
        .create         = hash_ipportnet_create,
        .create_policy  = {
                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
@@ -609,6 +633,7 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
                [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
                [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
                [IPSET_ATTR_IP2]        = { .type = NLA_NESTED },
+               [IPSET_ATTR_IP2_TO]     = { .type = NLA_NESTED },
                [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
                [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
                [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
index 360cf5b3ddf6e5d00d4236c448bad2adbce0cb87..8d3c3efbbf17d5822167e814fdcd672e9d0d10a1 100644 (file)
@@ -129,6 +129,7 @@ static inline void
 hash_net4_data_next(struct ip_set_hash *h,
                    const struct hash_net4_elem *d)
 {
+       h->next.ip = ntohl(d->ip);
 }
 
 static int
@@ -158,6 +159,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_net4_elem data = { .cidr = HOST_MASK };
        u32 timeout = h->timeout;
+       u32 ip = 0, ip_to, last;
        int ret;
 
        if (unlikely(!tb[IPSET_ATTR_IP] ||
@@ -167,27 +169,51 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
        if (tb[IPSET_ATTR_LINENO])
                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 
-       ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
+       ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
        if (ret)
                return ret;
 
-       if (tb[IPSET_ATTR_CIDR])
+       if (tb[IPSET_ATTR_CIDR]) {
                data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-
-       if (!data.cidr)
-               return -IPSET_ERR_INVALID_CIDR;
-
-       data.ip &= ip_set_netmask(data.cidr);
+               if (!data.cidr)
+                       return -IPSET_ERR_INVALID_CIDR;
+       }
 
        if (tb[IPSET_ATTR_TIMEOUT]) {
                if (!with_timeout(h->timeout))
                        return -IPSET_ERR_TIMEOUT;
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
+       
+       if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
+               data.ip = htonl(ip & ip_set_hostmask(data.cidr));
+               ret = adtfn(set, &data, timeout, flags);
+               return ip_set_eexist(ret, flags) ? 0 : ret;
+       }
 
-       ret = adtfn(set, &data, timeout, flags);
-
-       return ip_set_eexist(ret, flags) ? 0 : ret;
+       ip_to = ip;
+       if (tb[IPSET_ATTR_IP_TO]) {
+               ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
+               if (ret)
+                       return ret;
+               if (ip_to < ip)
+                       swap(ip, ip_to);
+               if (ip + UINT_MAX == ip_to)
+                       return -IPSET_ERR_HASH_RANGE;
+       }
+       if (retried)
+               ip = h->next.ip;                
+       while (!after(ip, ip_to)) {
+               data.ip = htonl(ip);
+               last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
+               ret = adtfn(set, &data, timeout, flags);
+               if (ret && !ip_set_eexist(ret, flags))
+                       return ret;
+               else
+                       ret = 0;
+               ip = last + 1;
+       }
+       return ret;
 }
 
 static bool
@@ -334,6 +360,8 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
        if (unlikely(!tb[IPSET_ATTR_IP] ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
                return -IPSET_ERR_PROTOCOL;
+       if (unlikely(tb[IPSET_ATTR_IP_TO]))
+               return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
 
        if (tb[IPSET_ATTR_LINENO])
                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
@@ -438,7 +466,7 @@ static struct ip_set_type hash_net_type __read_mostly = {
        .dimension      = IPSET_DIM_ONE,
        .family         = AF_UNSPEC,
        .revision_min   = 0,
-       .revision_max   = 0,
+       .revision_max   = 1,    /* Range as input support for IPv4 added */
        .create         = hash_net_create,
        .create_policy  = {
                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
@@ -449,6 +477,7 @@ static struct ip_set_type hash_net_type __read_mostly = {
        },
        .adt_policy     = {
                [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+               [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
                [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
        },
index 09f807fa24acffa2f6bbf66e1ecb3d5432f53f3c..300103096879fa826e91d0efa201e863e0f12042 100644 (file)
@@ -141,6 +141,7 @@ static inline void
 hash_netport4_data_next(struct ip_set_hash *h,
                        const struct hash_netport4_elem *d)
 {
+       h->next.ip = ntohl(d->ip);
        h->next.port = ntohs(d->port);
 }
 
@@ -175,7 +176,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_netport4_elem data = { .cidr = HOST_MASK };
-       u32 port, port_to;
+       u32 port, port_to, p = 0, ip = 0, ip_to, last;
        u32 timeout = h->timeout;
        bool with_ports = false;
        int ret;
@@ -189,15 +190,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
        if (tb[IPSET_ATTR_LINENO])
                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 
-       ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
+       ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
        if (ret)
                return ret;
 
-       if (tb[IPSET_ATTR_CIDR])
+       if (tb[IPSET_ATTR_CIDR]) {
                data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-       if (!data.cidr)
-               return -IPSET_ERR_INVALID_CIDR;
-       data.ip &= ip_set_netmask(data.cidr);
+               if (!data.cidr)
+                       return -IPSET_ERR_INVALID_CIDR; 
+       }
 
        if (tb[IPSET_ATTR_PORT])
                data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
@@ -222,26 +223,48 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
+       with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
+       if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) {
+               data.ip = htonl(ip & ip_set_hostmask(data.cidr));
                ret = adtfn(set, &data, timeout, flags);
                return ip_set_eexist(ret, flags) ? 0 : ret;
        }
 
-       port = ntohs(data.port);
-       port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
-       if (port > port_to)
-               swap(port, port_to);
+       port = port_to = ntohs(data.port);
+       if (tb[IPSET_ATTR_PORT_TO]) {
+               port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
+               if (port_to < port)
+                       swap(port, port_to);
+       }
+       if (tb[IPSET_ATTR_IP_TO]) {
+               ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
+               if (ret)
+                       return ret;
+               if (ip_to < ip)
+                       swap(ip, ip_to);
+               if (ip + UINT_MAX == ip_to)
+                       return -IPSET_ERR_HASH_RANGE;
+       } else {
+               ip &= ip_set_hostmask(data.cidr);
+               ip_to = ip | ~ip_set_hostmask(data.cidr);
+       }
 
        if (retried)
-               port = h->next.port;
-       for (; port <= port_to; port++) {
-               data.port = htons(port);
-               ret = adtfn(set, &data, timeout, flags);
-
-               if (ret && !ip_set_eexist(ret, flags))
-                       return ret;
-               else
-                       ret = 0;
+               ip = h->next.ip;
+       while (!after(ip, ip_to)) {
+               data.ip = htonl(ip);
+               last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
+               p = retried && ip == h->next.ip ? h->next.port : port;
+               for (; p <= port_to; p++) {
+                       data.port = htons(p);
+                       ret = adtfn(set, &data, timeout, flags);
+
+                       if (ret && !ip_set_eexist(ret, flags))
+                               return ret;
+                       else
+                               ret = 0;
+               }
+               ip = last + 1;
        }
        return ret;
 }
@@ -407,6 +430,8 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
                return -IPSET_ERR_PROTOCOL;
+       if (unlikely(tb[IPSET_ATTR_IP_TO]))
+               return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
 
        if (tb[IPSET_ATTR_LINENO])
                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
@@ -545,7 +570,8 @@ static struct ip_set_type hash_netport_type __read_mostly = {
        .dimension      = IPSET_DIM_TWO,
        .family         = AF_UNSPEC,
        .revision_min   = 0,
-       .revision_max   = 1,    /* SCTP and UDPLITE support added */
+       /*                1        SCTP and UDPLITE support added */
+       .revision_max   = 2,    /* Range as input support for IPv4 added */
        .create         = hash_netport_create,
        .create_policy  = {
                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
@@ -557,6 +583,7 @@ static struct ip_set_type hash_netport_type __read_mostly = {
        },
        .adt_policy     = {
                [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+               [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
                [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
                [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
                [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
index 23f8c81622140f8cbdc78c63fab1de4f0504fb8b..b57a85673de78a62e9fcb675ba9b614eccad64d1 100644 (file)
@@ -289,3 +289,24 @@ const union nf_inet_addr ip_set_hostmask_map[] = {
        E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF),
 };
 EXPORT_SYMBOL_GPL(ip_set_hostmask_map);
+
+/* Find the largest network which matches the range from left, in host order. */
+u32
+ip_set_range_to_cidr(u32 from, u32 to, u8 *cidr)
+{
+       u32 last;
+       u8 i;
+
+       for (i = 1; i < 32; i++) {
+               if ((from & ip_set_hostmask(i)) != from)
+                       continue;
+               last = from | ~ip_set_hostmask(i);
+               if (!after(last, to)) {
+                       *cidr = i;
+                       return last;
+               }
+       }
+       *cidr = 32;
+       return from;
+}
+EXPORT_SYMBOL_GPL(ip_set_range_to_cidr);
index 022e4b4effdf83330383a0ffe993a89c877903a2..1541728fecd5700b193035c5b62e25056801a0b8 100644 (file)
@@ -66,6 +66,7 @@ struct ipset_data {
                /* ADT/LIST/SAVE */
                struct {
                        union nf_inet_addr ip2;
+                       union nf_inet_addr ip2_to;
                        uint8_t cidr2;
                        uint8_t proto;
                        char ether[ETH_ALEN];
@@ -289,6 +290,11 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
                        return -1;
                copy_addr(data->family, &data->adt.ip2, value);
                break;
+       case IPSET_OPT_IP2_TO:
+               if (!(data->family == AF_INET || data->family == AF_INET6))
+                       return -1;
+               copy_addr(data->family, &data->adt.ip2_to, value);
+               break;
        case IPSET_OPT_CIDR2:
                data->adt.cidr2 = *(const uint8_t *) value;
                break;
@@ -401,6 +407,8 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
                return data->adt.nameref;
        case IPSET_OPT_IP2:
                return &data->adt.ip2;
+       case IPSET_OPT_IP2_TO:
+               return &data->adt.ip2_to;
        case IPSET_OPT_CIDR2:
                return &data->adt.cidr2;
        case IPSET_OPT_PROTO:
@@ -436,6 +444,7 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
        case IPSET_OPT_IP:
        case IPSET_OPT_IP_TO:
        case IPSET_OPT_IP2:
+       case IPSET_OPT_IP2_TO:
                return family == AF_INET ? sizeof(uint32_t)
                                         : sizeof(struct in6_addr);
        case IPSET_OPT_PORT:
index 0c152319ddfcaa1524b7f0245640ee4990900e9d..091fc6dfda613e0fb5218a7f055b55be64f05c4d 100644 (file)
@@ -667,8 +667,15 @@ parse_ipaddr(struct ipset_session *session,
         char *saved = strdup(str);
         char *a, *tmp = saved;
         struct addrinfo *info;
-        enum ipset_opt copt = opt == IPSET_OPT_IP ? IPSET_OPT_CIDR
-                               : IPSET_OPT_CIDR2;
+        enum ipset_opt copt, opt2;
+
+       if (opt == IPSET_OPT_IP) {
+               copt = IPSET_OPT_CIDR;
+               opt2 = IPSET_OPT_IP_TO;
+       } else {
+               copt = IPSET_OPT_CIDR2;
+               opt2 = IPSET_OPT_IP2_TO;
+       }
 
        if (tmp == NULL)
                return ipset_err(session,
@@ -691,7 +698,7 @@ parse_ipaddr(struct ipset_session *session,
            || !range)
                goto out;
        freeaddrinfo(info);
-       aerr = get_addrinfo(session, IPSET_OPT_IP_TO, a, &info, family);
+       aerr = get_addrinfo(session, opt2, a, &info, family);
 
 out:
        if (aerr != EINVAL)
@@ -973,6 +980,46 @@ ipset_parse_ip4_single6(struct ipset_session *session,
 
 }
 
+/**
+ * ipset_parse_ip4_net6 - parse IPv4|IPv6 address or address/cidr pattern
+ * @session: session structure
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Parse string as an IPv4|IPv6 address or address/cidr pattern. For IPv4,
+ * address range is valid too.
+ * If family is not set yet in the data blob, INET is assumed.
+ * The values are stored in the data blob of the session.
+ *
+ * FIXME: if the hostname resolves to multiple addresses,
+ * the first one is used only.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_parse_ip4_net6(struct ipset_session *session,
+                    enum ipset_opt opt, const char *str)
+{
+       struct ipset_data *data;
+       uint8_t family;
+
+       assert(session);
+       assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
+       assert(str);
+       
+       data = ipset_session_data(session);
+       family = ipset_data_family(data);
+       
+       if (family == AF_UNSPEC) {
+               family = AF_INET;
+               ipset_data_set(data, IPSET_OPT_FAMILY, &family);
+       }
+       
+       return family == AF_INET ? parse_ip(session, opt, str, IPADDR_ANY)
+                                : ipset_parse_ipnet(session, opt, str);
+
+}
+
 /**
  * ipset_parse_iptimeout - parse IPv4|IPv6 address and timeout
  * @session: session structure
index 59405d482b333307552f939d258fc2ea757a3a90..a9c7c33274b97059ebbd9e18fc323dcafe3f9958 100644 (file)
@@ -469,6 +469,10 @@ static const struct ipset_attr_policy adt_attrs[] = {
                .type = MNL_TYPE_U8,
                .opt = IPSET_OPT_CIDR2,
        },
+       [IPSET_ATTR_IP2_TO] = {
+               .type = MNL_TYPE_NESTED,
+               .opt = IPSET_OPT_IP2_TO,
+       },
 };
 
 static const struct ipset_attr_policy ipaddr_attrs[] = {
index 6370ec7f365cc919b43c4f096e2ebd40a64baa70..9d5f22693cec5d4d2b84f4b4ff09a972e24bc3ee 100644 (file)
@@ -113,6 +113,10 @@ static const struct ipset_errcode_table hash_errcode_table[] = {
          "Invalid protocol specified" },
        { IPSET_ERR_MISSING_PROTO, 0,
          "Protocol missing, but must be specified" },
+       { IPSET_ERR_HASH_RANGE_UNSUPPORTED, 0,
+         "Range is not supported in the \"net\" component of the element" },
+       { IPSET_ERR_HASH_RANGE, 0,
+         "Invalid range, covers the whole address space" },
        { },
 };
 
index 21750fab0558c555e542229be99535e3c8217f5c..90914f432ed67f3be54c47152877b258b2f32139 100644 (file)
@@ -214,7 +214,7 @@ command follows the syntax
 
 where the current list of the methods are
 \fBbitmap\fR, \fBhash\fR, and \fBlist\fR and the possible data types
-are \fBip\fR, \fBmac\fR and \fBport\fR. The dimension of a set
+are \fBip\fR, \fBnet\fR, \fBmac\fR and \fBport\fR. The dimension of a set
 is equal to the number of data types in its type name.
 
 When adding, deleting or testing entries in a set, the same comma separated
@@ -409,13 +409,16 @@ Network address with zero prefix size cannot be stored in this type of sets.
 .PP 
 \fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
 .PP 
-\fIADD\-ENTRY\fR := \fIip\fR[/\fIcidr\fR]
+\fIADD\-ENTRY\fR := \fInetaddr\fR
 .PP 
 \fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
 .PP 
-\fIDEL\-ENTRY\fR := \fIip\fR[/\fIcidr\fR]
+\fIDEL\-ENTRY\fR := \fInetaddr\fR
 .PP 
-\fITEST\-ENTRY\fR := \fIip\fR[/\fIcidr\fR]
+\fITEST\-ENTRY\fR := \fInetaddr\fR
+.PP 
+where
+\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
 .PP 
 Optional \fBcreate\fR options:
 .TP 
@@ -431,6 +434,11 @@ correct value.
 \fBmaxelem\fR \fIvalue\fR
 The maximal number of elements which can be stored in the set, default 65536.
 .PP 
+For the \fBinet\fR family one can add or delete multiple entries by specifying
+a range, which is converted internally to network(s) equal to the range:
+.PP 
+\fInetaddr\fR := { \fIip\fR[/\fIcidr\fR] | \fIfromaddr\fR\-\fItoaddr\fR }
+.PP 
 When adding/deleting/testing entries, if the cidr prefix parameter is not specified,
 then the host prefix value is assumed. When adding/deleting entries, the exact
 element is added/deleted and overlapping elements are not checked by the kernel.
@@ -539,13 +547,16 @@ address with zero prefix size is not accepted either.
 .PP 
 \fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
 .PP 
-\fIADD\-ENTRY\fR := \fIipaddr\fR[/\fIcidr\fR],[\fIproto\fR:]\fIport\fR
+\fIADD\-ENTRY\fR := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
 .PP 
 \fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
 .PP 
-\fIDEL\-ENTRY\fR := \fIipaddr\fR[/\fIcidr\fR],[\fIproto\fR:]\fIport\fR
+\fIDEL\-ENTRY\fR := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
 .PP 
-\fITEST\-ENTRY\fR := \fIipaddr\fR[/\fIcidr\fR],[\fIproto\fR:]\fIport\fR
+\fITEST\-ENTRY\fR := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
+.PP 
+where
+\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
 .PP 
 Optional \fBcreate\fR options:
 .TP 
@@ -561,7 +572,8 @@ correct value.
 \fBmaxelem\fR \fIvalue\fR
 The maximal number of elements which can be stored in the set, default 65536.
 .PP 
-For the
+For the \fInetaddr\fR part of the elements
+see the description at the \fBhash:net\fR set type. For the
 [\fIproto\fR:]\fIport\fR
 part of the elements see the description at the
 \fBhash:ip,port\fR set type.
@@ -645,18 +657,22 @@ address with zero prefix size cannot be stored either.
 .PP 
 \fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
 .PP 
-\fIADD\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIip\fR[/\fIcidr\fR]
+\fIADD\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fInetaddr\fR
 .PP 
 \fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
 .PP 
-\fIDEL\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIip\fR[/\fIcidr\fR]
+\fIDEL\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fInetaddr\fR
 .PP 
-\fITEST\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIip\fR[/\fIcidr\fR]
+\fITEST\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fInetaddr\fR
 .PP 
-For the first \fIipaddr\fR and
+where
+\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
+.PP 
+For the \fIipaddr\fR and
 [\fIproto\fR:]\fIport\fR
 parts of the elements see the descriptions at the
-\fBhash:ip,port\fR set type.
+\fBhash:ip,port\fR set type. For the \fInetaddr\fR part of the elements
+see the description at the \fBhash:net\fR set type.
 .PP 
 Optional \fBcreate\fR options:
 .TP 
index 05f8ef34672a12db6492bc7815c63e8ad11656a8..b3569ed63eac8ec1eccb52f9db662ebae1623591 100644 (file)
@@ -39,10 +39,13 @@ extern struct ipset_type ipset_bitmap_ipmac0;
 extern struct ipset_type ipset_bitmap_port0;
 extern struct ipset_type ipset_hash_ip0;
 extern struct ipset_type ipset_hash_net0;
-extern struct ipset_type ipset_hash_netport0;
-extern struct ipset_type ipset_hash_ipport0;
-extern struct ipset_type ipset_hash_ipportip0;
-extern struct ipset_type ipset_hash_ipportnet0;
+extern struct ipset_type ipset_hash_net1;
+extern struct ipset_type ipset_hash_netport1;
+extern struct ipset_type ipset_hash_netport2;
+extern struct ipset_type ipset_hash_ipport1;
+extern struct ipset_type ipset_hash_ipportip1;
+extern struct ipset_type ipset_hash_ipportnet1;
+extern struct ipset_type ipset_hash_ipportnet2;
 extern struct ipset_type ipset_list_set0;
 
 enum exittype {
@@ -721,10 +724,13 @@ main(int argc, char *argv[])
        ipset_type_add(&ipset_bitmap_port0);
        ipset_type_add(&ipset_hash_ip0);
        ipset_type_add(&ipset_hash_net0);
-       ipset_type_add(&ipset_hash_netport0);
-       ipset_type_add(&ipset_hash_ipport0);
-       ipset_type_add(&ipset_hash_ipportip0);
-       ipset_type_add(&ipset_hash_ipportnet0);
+       ipset_type_add(&ipset_hash_net1);
+       ipset_type_add(&ipset_hash_netport1);
+       ipset_type_add(&ipset_hash_netport2);
+       ipset_type_add(&ipset_hash_ipport1);
+       ipset_type_add(&ipset_hash_ipportip1);
+       ipset_type_add(&ipset_hash_ipportnet1);
+       ipset_type_add(&ipset_hash_ipportnet2);
        ipset_type_add(&ipset_list_set0);
 
        /* Initialize session */
index 3179805190bc64ae9ff941498fc685ff4c86ea9a..58ea76cb22611ce4654f7f3bb084d47916346c04 100644 (file)
@@ -70,7 +70,7 @@ static const struct ipset_arg hash_ipport_add_args[] = {
        { },
 }; 
 
-static const char hash_ipport_usage[] =
+static const char hash_ipport1_usage[] =
 "create SETNAME hash:ip,port\n"
 "              [family inet|inet6]\n"
 "               [hashsize VALUE] [maxelem VALUE]\n"
@@ -85,7 +85,7 @@ static const char hash_ipport_usage[] =
 "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
 "      port range is supported both for IPv4 and IPv6.\n";
 
-struct ipset_type ipset_hash_ipport0 = {
+struct ipset_type ipset_hash_ipport1 = {
        .name = "hash:ip,port",
        .alias = { "ipporthash", NULL },
        .revision = 1,
@@ -139,6 +139,6 @@ struct ipset_type ipset_hash_ipport0 = {
                        | IPSET_FLAG(IPSET_OPT_PROTO),
        },
 
-       .usage = hash_ipport_usage,
+       .usage = hash_ipport1_usage,
        .usagefn = ipset_port_usage,
 };
index 944ee81879b30f8d8548a0fd0943a160e53f984e..2f310ea4499166a54ac430ee1ee8c4209cdc59b1 100644 (file)
@@ -70,7 +70,7 @@ static const struct ipset_arg hash_ipportip_add_args[] = {
        { },
 }; 
 
-static const char hash_ipportip_usage[] =
+static const char hash_ipportip1_usage[] =
 "create SETNAME hash:ip,port,ip\n"
 "              [family inet|inet6]\n"
 "               [hashsize VALUE] [maxelem VALUE]\n"
@@ -85,7 +85,7 @@ static const char hash_ipportip_usage[] =
 "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
 "      port range is supported both for IPv4 and IPv6.\n";
 
-struct ipset_type ipset_hash_ipportip0 = {
+struct ipset_type ipset_hash_ipportip1 = {
        .name = "hash:ip,port,ip",
        .alias = { "ipportiphash", NULL },
        .revision = 1,
@@ -150,6 +150,6 @@ struct ipset_type ipset_hash_ipportip0 = {
                        | IPSET_FLAG(IPSET_OPT_IP2),
        },
 
-       .usage = hash_ipportip_usage,
+       .usage = hash_ipportip1_usage,
        .usagefn = ipset_port_usage,
 };
index bd94d12c7090ed135e1475cdf25cfd895d3b29d0..c2eece8193cbdbe4f8d96c5a9575bc4505c09412 100644 (file)
@@ -70,7 +70,7 @@ static const struct ipset_arg hash_ipportnet_add_args[] = {
        { },
 }; 
 
-static const char hash_ipportnet_usage[] =
+static const char hash_ipportnet1_usage[] =
 "create SETNAME hash:ip,port,net\n"
 "              [family inet|inet6]\n"
 "               [hashsize VALUE] [maxelem VALUE]\n"
@@ -86,7 +86,7 @@ static const char hash_ipportnet_usage[] =
 "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
 "      port range is supported both for IPv4 and IPv6.\n";
 
-struct ipset_type ipset_hash_ipportnet0 = {
+struct ipset_type ipset_hash_ipportnet1 = {
        .name = "hash:ip,port,net",
        .alias = { "ipportnethash", NULL },
        .revision = 1,
@@ -133,6 +133,7 @@ struct ipset_type ipset_hash_ipportnet0 = {
                        | IPSET_FLAG(IPSET_OPT_MAXELEM)
                        | IPSET_FLAG(IPSET_OPT_TIMEOUT),
                [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_CIDR)
                        | IPSET_FLAG(IPSET_OPT_IP_TO)
                        | IPSET_FLAG(IPSET_OPT_PORT)
                        | IPSET_FLAG(IPSET_OPT_PORT_TO)
@@ -141,6 +142,7 @@ struct ipset_type ipset_hash_ipportnet0 = {
                        | IPSET_FLAG(IPSET_OPT_CIDR2)
                        | IPSET_FLAG(IPSET_OPT_TIMEOUT),
                [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_CIDR)
                        | IPSET_FLAG(IPSET_OPT_IP_TO)
                        | IPSET_FLAG(IPSET_OPT_PORT)
                        | IPSET_FLAG(IPSET_OPT_PORT_TO)
@@ -154,6 +156,99 @@ struct ipset_type ipset_hash_ipportnet0 = {
                        | IPSET_FLAG(IPSET_OPT_CIDR2),
        },
 
-       .usage = hash_ipportnet_usage,
+       .usage = hash_ipportnet1_usage,
        .usagefn = ipset_port_usage,
 };
+
+static const char hash_ipportnet2_usage[] =
+"create SETNAME hash:ip,port,net\n"
+"              [family inet|inet6]\n"
+"               [hashsize VALUE] [maxelem VALUE]\n"
+"               [timeout VALUE]\n"
+"add    SETNAME IP,PROTO:PORT,IP[/CIDR] [timeout VALUE]\n"
+"del    SETNAME IP,PROTO:PORT,IP[/CIDR]\n"
+"test   SETNAME IP,PROTO:PORT,IP[/CIDR]\n\n"
+"where depending on the INET family\n"
+"      IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
+"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+"      Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+"      in both IP components are supported for IPv4.\n"
+"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+"      port range is supported both for IPv4 and IPv6.\n";
+
+struct ipset_type ipset_hash_ipportnet2 = {
+       .name = "hash:ip,port,net",
+       .alias = { "ipportnethash", NULL },
+       .revision = 2,
+       .family = AF_INET46,
+       .dimension = IPSET_DIM_THREE,
+       .elem = { 
+               [IPSET_DIM_ONE] = { 
+                       .parse = ipset_parse_ip4_single6,
+                       .print = ipset_print_ip,
+                       .opt = IPSET_OPT_IP
+               },
+               [IPSET_DIM_TWO] = { 
+                       .parse = ipset_parse_proto_port,
+                       .print = ipset_print_proto_port,
+                       .opt = IPSET_OPT_PORT
+               },
+               [IPSET_DIM_THREE] = { 
+                       .parse = ipset_parse_ip4_net6,
+                       .print = ipset_print_ip,
+                       .opt = IPSET_OPT_IP2
+               },
+       },
+       .args = {
+               [IPSET_CREATE] = hash_ipportnet_create_args,
+               [IPSET_ADD] = hash_ipportnet_add_args,
+       },
+       .mandatory = {
+               [IPSET_CREATE] = 0,
+               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_PORT)
+                       | IPSET_FLAG(IPSET_OPT_PROTO)
+                       | IPSET_FLAG(IPSET_OPT_IP2),
+               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_PORT)
+                       | IPSET_FLAG(IPSET_OPT_PROTO)
+                       | IPSET_FLAG(IPSET_OPT_IP2),
+               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_PORT)
+                       | IPSET_FLAG(IPSET_OPT_PROTO)
+                       | IPSET_FLAG(IPSET_OPT_IP2),
+       },
+       .full = {
+               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
+                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
+                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
+               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_CIDR)
+                       | IPSET_FLAG(IPSET_OPT_IP_TO)
+                       | IPSET_FLAG(IPSET_OPT_PORT)
+                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                       | IPSET_FLAG(IPSET_OPT_PROTO)
+                       | IPSET_FLAG(IPSET_OPT_IP2)
+                       | IPSET_FLAG(IPSET_OPT_CIDR2)
+                       | IPSET_FLAG(IPSET_OPT_IP2_TO)
+                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
+               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_CIDR)
+                       | IPSET_FLAG(IPSET_OPT_IP_TO)
+                       | IPSET_FLAG(IPSET_OPT_PORT)
+                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                       | IPSET_FLAG(IPSET_OPT_PROTO)
+                       | IPSET_FLAG(IPSET_OPT_IP2)
+                       | IPSET_FLAG(IPSET_OPT_CIDR2)
+                       | IPSET_FLAG(IPSET_OPT_IP2_TO),
+               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_PORT)
+                       | IPSET_FLAG(IPSET_OPT_PROTO)
+                       | IPSET_FLAG(IPSET_OPT_IP2)
+                       | IPSET_FLAG(IPSET_OPT_CIDR2),
+       },
+
+       .usage = hash_ipportnet2_usage,
+       .usagefn = ipset_port_usage,
+};
+
index e8891c1003e6cafe016a56b95e33389fb05d5039..9c0a6cabe3311d72ccf34aaca30edf54083ea523 100644 (file)
@@ -57,7 +57,7 @@ static const struct ipset_arg hash_net_add_args[] = {
        { },
 }; 
 
-static const char hash_net_usage[] =
+static const char hash_net0_usage[] =
 "create SETNAME hash:net\n"
 "              [family inet|inet6]\n"
 "               [hashsize VALUE] [maxelem VALUE]\n"
@@ -105,5 +105,60 @@ struct ipset_type ipset_hash_net0 = {
                        | IPSET_FLAG(IPSET_OPT_CIDR),
        },
 
-       .usage = hash_net_usage,
+       .usage = hash_net0_usage,
 };
+
+static const char hash_net1_usage[] =
+"create SETNAME hash:net\n"
+"              [family inet|inet6]\n"
+"               [hashsize VALUE] [maxelem VALUE]\n"
+"               [timeout VALUE]\n"
+"add    SETNAME IP[/CIDR]|FROM-TO [timeout VALUE]\n"
+"del    SETNAME IP[/CIDR]|FROM-TO\n"
+"test   SETNAME IP[/CIDR]\n\n"
+"where depending on the INET family\n"
+"      IP is an IPv4 or IPv6 address (or hostname),\n"
+"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+"      IP range is not supported with IPv6.\n";
+
+struct ipset_type ipset_hash_net1 = {
+       .name = "hash:net",
+       .alias = { "nethash", NULL },
+       .revision = 1,
+       .family = AF_INET46,
+       .dimension = IPSET_DIM_ONE,
+       .elem = { 
+               [IPSET_DIM_ONE] = { 
+                       .parse = ipset_parse_ip4_net6,
+                       .print = ipset_print_ip,
+                       .opt = IPSET_OPT_IP
+               },
+       },
+       .args = {
+               [IPSET_CREATE] = hash_net_create_args,
+               [IPSET_ADD] = hash_net_add_args,
+       },
+       .mandatory = {
+               [IPSET_CREATE] = 0,
+               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP),
+               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP),
+               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
+       },
+       .full = {
+               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
+                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
+                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
+               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_CIDR)
+                       | IPSET_FLAG(IPSET_OPT_IP_TO)
+                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
+               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_CIDR)
+                       | IPSET_FLAG(IPSET_OPT_IP_TO),
+               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_CIDR),
+       },
+
+       .usage = hash_net1_usage,
+};
+
index 8ca77df443580bf54b5cd9ef10a763e18ef0f98b..7964319535add9f8b7cbeb26dd0fb9483fc4af10 100644 (file)
@@ -49,7 +49,7 @@ static const struct ipset_arg hash_netport_add_args[] = {
        { },
 }; 
 
-static const char hash_netport_usage[] =
+static const char hash_netport1_usage[] =
 "create SETNAME hash:net,port\n"
 "              [family inet|inet6]\n"
 "               [hashsize VALUE] [maxelem VALUE]\n"
@@ -63,7 +63,7 @@ static const char hash_netport_usage[] =
 "      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
 "      port range is supported both for IPv4 and IPv6.\n";
 
-struct ipset_type ipset_hash_netport0 = {
+struct ipset_type ipset_hash_netport1 = {
        .name = "hash:net,port",
        .alias = { "netporthash", NULL },
        .revision = 1,
@@ -118,6 +118,82 @@ struct ipset_type ipset_hash_netport0 = {
                        | IPSET_FLAG(IPSET_OPT_CIDR),
        },
 
-       .usage = hash_netport_usage,
+       .usage = hash_netport1_usage,
+       .usagefn = ipset_port_usage,
+};
+
+static const char hash_netport2_usage[] =
+"create SETNAME hash:net,port\n"
+"              [family inet|inet6]\n"
+"               [hashsize VALUE] [maxelem VALUE]\n"
+"               [timeout VALUE]\n"
+"add    SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT [timeout VALUE]\n"
+"del    SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT\n"
+"test   SETNAME IP[/CIDR],PROTO:PORT\n\n"
+"where depending on the INET family\n"
+"      IP is a valid IPv4 or IPv6 address (or hostname),\n"
+"      CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+"      Adding/deleting multiple elements with IPv4 is supported.\n"
+"      Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+"      port range is supported both for IPv4 and IPv6.\n";
+
+struct ipset_type ipset_hash_netport2 = {
+       .name = "hash:net,port",
+       .alias = { "netporthash", NULL },
+       .revision = 2,
+       .family = AF_INET46,
+       .dimension = IPSET_DIM_TWO,
+       .elem = { 
+               [IPSET_DIM_ONE] = { 
+                       .parse = ipset_parse_ip4_net6,
+                       .print = ipset_print_ip,
+                       .opt = IPSET_OPT_IP
+               },
+               [IPSET_DIM_TWO] = { 
+                       .parse = ipset_parse_proto_port,
+                       .print = ipset_print_proto_port,
+                       .opt = IPSET_OPT_PORT
+               },
+       },
+       .args = {
+               [IPSET_CREATE] = hash_netport_create_args,
+               [IPSET_ADD] = hash_netport_add_args,
+       },
+       .mandatory = {
+               [IPSET_CREATE] = 0,
+               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_PROTO)
+                       | IPSET_FLAG(IPSET_OPT_PORT),
+               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_PROTO)
+                       | IPSET_FLAG(IPSET_OPT_PORT),
+               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_PROTO)
+                       | IPSET_FLAG(IPSET_OPT_PORT),
+       },
+       .full = {
+               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
+                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
+                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
+               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_CIDR)
+                       | IPSET_FLAG(IPSET_OPT_IP_TO)
+                       | IPSET_FLAG(IPSET_OPT_PORT)
+                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                       | IPSET_FLAG(IPSET_OPT_PROTO)
+                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
+               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_CIDR)
+                       | IPSET_FLAG(IPSET_OPT_IP_TO)
+                       | IPSET_FLAG(IPSET_OPT_PORT)
+                       | IPSET_FLAG(IPSET_OPT_PORT_TO)
+                       | IPSET_FLAG(IPSET_OPT_PROTO),
+               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_CIDR)
+                       | IPSET_FLAG(IPSET_OPT_PORT)
+                       | IPSET_FLAG(IPSET_OPT_PROTO),
+       },
+
+       .usage = hash_netport2_usage,
        .usagefn = ipset_port_usage,
 };
index 89b046c626902eb82bcf96a5a0ded8843b8a82f4..c13ccc43a058a32a389895c42cbd40f9c12fd7c4 100644 (file)
 0 n=`ipset list test|grep 10.0|wc -l` && test $n -eq 3072
 # Destroy set
 0 ipset -X test
+# Create set to add a range and with range notation in the network
+0 ipset new test hash:ip,port,net hashsize 64
+# Add a range which forces a resizing
+0 ipset add test 10.0.0.0-10.0.3.255,tcp:80-82,192.168.0.0-192.168.2.255
+# Check that correct number of elements are added
+0 n=`ipset list test|grep 10.0|wc -l` && test $n -eq 6144
+# Destroy set
+0 ipset -X test
 # eof
index d5f420ca364f8b3ee9aafabbdce7bd630e4085dd..519292c7ebb59e54b3ddb1cb1460daaaa0dce69f 100644 (file)
 0 n=`ipset list test|grep 10.0|wc -l` && test $n -eq 1026
 # Destroy set
 0 ipset -X test
+# Create set to add a range and with range notation in the network
+0 ipset new test hash:net,port hashsize 64
+# Add a range which forces a resizing
+0 ipset add test 10.0.0.0-10.0.2.255,tcp:80-1105
+# Check that correct number of elements are added
+0 n=`ipset list test|grep 10.0|wc -l` && test $n -eq 2052
+# Destroy set
+0 ipset -X test
 # eof
index 9947bf6810e22f8b1913f224bbdb4eea1dd09bc9..8ccc3f20cbe4a69e9858c3e0c0850fe55042d4ec 100644 (file)
 0 diff -u -I 'Size in memory.*' .foo hash:net.t.list0
 # Sleep 5s so that element can time out
 0 sleep 5
-# IP: List set
+# List set
 0 ipset -L test 2>/dev/null > .foo0 && ./sort.sh .foo0
-# IP: Check listing
+# Check listing
 0 diff -u -I 'Size in memory.*' .foo hash:net.t.list1
 # Flush test set
 0 ipset flush test
 # Delete test set
 0 ipset destroy test
+# Create test set
+0 ipset new test hash:net
+# Add networks in range notation
+0 ipset add test 10.2.0.0-10.2.1.12
+# List set
+0 ipset -L test 2>/dev/null > .foo0 && ./sort.sh .foo0
+# Check listing
+0 diff -u -I 'Size in memory.*' .foo hash:net.t.list2
+# Delete test set
+0 ipset destroy test
 # eof
diff --git a/tests/hash:net.t.list2 b/tests/hash:net.t.list2
new file mode 100644 (file)
index 0000000..dad3f22
--- /dev/null
@@ -0,0 +1,10 @@
+Name: test
+Type: hash:net
+Header: family inet hashsize 1024 maxelem 65536 
+Size in memory: 17016
+References: 0
+Members:
+10.2.0.0/24
+10.2.1.0/29
+10.2.1.12
+10.2.1.8/30