]> git.ipfire.org Git - thirdparty/xtables-addons.git/commitdiff
ipset: update to 6.6a-genl
authorJan Engelhardt <jengelh@medozas.de>
Tue, 31 May 2011 14:14:44 +0000 (16:14 +0200)
committerJan Engelhardt <jengelh@medozas.de>
Tue, 31 May 2011 14:14:44 +0000 (16:14 +0200)
43 files changed:
README
extensions/ipset-6/include/libipset/data.h
extensions/ipset-6/include/libipset/linux_ip_set.h
extensions/ipset-6/include/libipset/linux_ip_set_hash.h
extensions/ipset-6/include/libipset/parse.h
extensions/ipset-6/include/libipset/session.h
extensions/ipset-6/ip_set.h
extensions/ipset-6/ip_set_ahash.h
extensions/ipset-6/ip_set_bitmap_ip.c
extensions/ipset-6/ip_set_bitmap_ipmac.c
extensions/ipset-6/ip_set_bitmap_port.c
extensions/ipset-6/ip_set_chash.h [deleted file]
extensions/ipset-6/ip_set_core.c
extensions/ipset-6/ip_set_hash.h
extensions/ipset-6/ip_set_hash_ip.c
extensions/ipset-6/ip_set_hash_ipport.c
extensions/ipset-6/ip_set_hash_ipportip.c
extensions/ipset-6/ip_set_hash_ipportnet.c
extensions/ipset-6/ip_set_hash_net.c
extensions/ipset-6/ip_set_hash_netport.c
extensions/ipset-6/ip_set_list_set.c
extensions/ipset-6/ip_set_timeout.h
extensions/ipset-6/libipset/data.c
extensions/ipset-6/libipset/debug.c [new file with mode: 0644]
extensions/ipset-6/libipset/mnl.c
extensions/ipset-6/libipset/parse.c
extensions/ipset-6/libipset/session.c
extensions/ipset-6/libipset/types.c
extensions/ipset-6/pfxlen.c
extensions/ipset-6/pfxlen.h
extensions/ipset-6/slist.h [deleted file]
extensions/ipset-6/src/errcode.c
extensions/ipset-6/src/ipset.8
extensions/ipset-6/src/ipset.c
extensions/ipset-6/src/ipset_hash_ip.c
extensions/ipset-6/src/ipset_hash_ipport.c
extensions/ipset-6/src/ipset_hash_ipportip.c
extensions/ipset-6/src/ipset_hash_ipportnet.c
extensions/ipset-6/src/ipset_hash_net.c
extensions/ipset-6/src/ipset_hash_netport.c
extensions/ipset-6/src/ui.c
extensions/ipset-6/xt_set.c
extensions/ipset-6/xt_set.h

diff --git a/README b/README
index e51ea2a1b98f2050f5ab11c3589c0906299bdfa3..d556c8af112f2a253b8a8d354545be201f808f4d 100644 (file)
--- a/README
+++ b/README
@@ -19,7 +19,7 @@ simplified, and sped up.
 Included in this package
 ========================
 - ipset 4.5
-- ipset 5.4.1
+- ipset 6.6a-genl
 - xt_ACCOUNT 1.16, libxt_ACCOUNT 1.3
 
 
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 d81a811cd0b5e53f3601305a163bc0601e74d5bc..0537fb852d7cae520e3373ffc36163bd509d73dd 100644 (file)
@@ -12,7 +12,7 @@
  */
 
 /* The protocol version */
-#define IPSET_PROTOCOL         6
+#define IPSET_PROTOCOL         0x60
 
 /* The max length of strings including NUL: set and type identifiers */
 #define IPSET_MAXNAMELEN       32
@@ -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)
@@ -142,6 +143,10 @@ enum ipset_errno {
 enum ipset_cmd_flags {
        IPSET_FLAG_BIT_EXIST    = 0,
        IPSET_FLAG_EXIST        = (1 << IPSET_FLAG_BIT_EXIST),
+       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),
 };
 
 /* 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 a06c79f20fbda1eeb20e567bfb4de2f3019c1ffc..9301ccd5aa770bbac690311ef6bfced8b6de729e 100644 (file)
@@ -65,6 +65,10 @@ enum ipset_envopt {
        IPSET_ENV_RESOLVE       = (1 << IPSET_ENV_BIT_RESOLVE),
        IPSET_ENV_BIT_EXIST     = 3,
        IPSET_ENV_EXIST         = (1 << IPSET_ENV_BIT_EXIST),
+       IPSET_ENV_BIT_LIST_SETNAME = 4,
+       IPSET_ENV_LIST_SETNAME  = (1 << IPSET_ENV_BIT_LIST_SETNAME),
+       IPSET_ENV_BIT_LIST_HEADER = 5,
+       IPSET_ENV_LIST_HEADER   = (1 << IPSET_ENV_BIT_LIST_HEADER),
 };
 
 extern int ipset_envopt_parse(struct ipset_session *session,
@@ -92,4 +96,6 @@ typedef int (*ipset_outfn)(const char *fmt, ...)
 extern struct ipset_session * ipset_session_init(ipset_outfn outfn);
 extern int ipset_session_fini(struct ipset_session *session);
 
+extern void ipset_debug_msg(const char *dir, void *buffer, int len);
+
 #endif /* LIBIPSET_SESSION_H */
index 08f59eb106cb90dbba66e58b575ecc09491fcca1..ff8d39a9066fd2d118e10ef71cac14324ec0efec 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/netlink.h>
 
 /* The protocol version */
-#define IPSET_PROTOCOL         6
+#define IPSET_PROTOCOL         0x60
 
 /* The max length of strings including NUL: set and type identifiers */
 #define IPSET_MAXNAMELEN       32
@@ -106,6 +106,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)
@@ -144,6 +145,10 @@ enum ipset_errno {
 enum ipset_cmd_flags {
        IPSET_FLAG_BIT_EXIST    = 0,
        IPSET_FLAG_EXIST        = (1 << IPSET_FLAG_BIT_EXIST),
+       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),
 };
 
 /* Flags at CADT attribute level */
@@ -167,6 +172,7 @@ enum ipset_adt {
 #include <linux/ipv6.h>
 #include <linux/netlink.h>
 #include <linux/netfilter.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/vmalloc.h>
 #include <net/netlink.h>
 
@@ -219,6 +225,15 @@ struct ip_set;
 typedef int (*ipset_adtfn)(struct ip_set *set, void *value,
                           u32 timeout, u32 flags);
 
+/* Kernel API function options */
+struct ip_set_adt_opt {
+       u8 family;              /* Actual protocol family */
+       u8 dim;                 /* Dimension of match/target */
+       u8 flags;               /* Direction and negation flags */
+       u32 cmdflags;           /* Command-like flags */
+       u32 timeout;            /* Timeout value */
+};
+
 /* Set type, variant-specific part */
 struct ip_set_type_variant {
        /* Kernelspace: test/add/del entries
@@ -226,14 +241,15 @@ struct ip_set_type_variant {
         *                      zero for no match/success to add/delete
         *                      positive for matching element */
        int (*kadt)(struct ip_set *set, const struct sk_buff * skb,
-                   enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
+                   const struct xt_action_param *par,
+                   enum ipset_adt adt, const struct ip_set_adt_opt *opt);
 
        /* Userspace: test/add/del entries
         *              returns negative error code,
         *                      zero for no match/success to add/delete
         *                      positive for matching element */
        int (*uadt)(struct ip_set *set, struct nlattr *tb[],
-                   enum ipset_adt adt, u32 *lineno, u32 flags);
+                   enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);
 
        /* Low level add/del/test functions */
        ipset_adtfn adt[IPSET_ADT_MAX];
@@ -271,8 +287,8 @@ struct ip_set_type {
        u8 dimension;
        /* Supported family: may be AF_UNSPEC for both AF_INET/AF_INET6 */
        u8 family;
-       /* Type revision */
-       u8 revision;
+       /* Type revisions */
+       u8 revision_min, revision_max;
 
        /* Create set */
        int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags);
@@ -303,6 +319,8 @@ struct ip_set {
        const struct ip_set_type_variant *variant;
        /* The actual INET family of the set */
        u8 family;
+       /* The type revision */
+       u8 revision;
        /* The type specific data */
        void *data;
 };
@@ -316,12 +334,16 @@ extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index);
 extern void ip_set_nfnl_put(ip_set_id_t index);
 
 /* API for iptables set match, and SET target */
+
 extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb,
-                     u8 family, u8 dim, u8 flags);
+                     const struct xt_action_param *par,
+                     const struct ip_set_adt_opt *opt);
 extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb,
-                     u8 family, u8 dim, u8 flags);
+                     const struct xt_action_param *par,
+                     const struct ip_set_adt_opt *opt);
 extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb,
-                      u8 family, u8 dim, u8 flags);
+                      const struct xt_action_param *par,
+                      const struct ip_set_adt_opt *opt);
 
 /* Utility functions */
 extern void * ip_set_alloc(size_t size);
index 36a5b00b99510bc0890757130be19f1974576535..e4acbd486b0af5ce0b95cc7ef6d80dac679ebfa5 100644 (file)
@@ -5,6 +5,11 @@
 #include "jhash.h"
 #include "ip_set_timeout.h"
 
+#define CONCAT(a, b, c)                a##b##c
+#define TOKEN(a, b, c)         CONCAT(a, b, c)
+
+#define type_pf_next           TOKEN(TYPE, PF, _elem)
+
 /* Hashing which uses arrays to resolve clashing. The hash table is resized
  * (doubled) when searching becomes too long.
  * Internally jhash is used with the assumption that the size of the
@@ -54,6 +59,7 @@ struct ip_set_hash {
        u32 initval;            /* random jhash init value */
        u32 timeout;            /* timeout value, if enabled */
        struct timer_list gc;   /* garbage collection when timeout enabled */
+       struct type_pf_next next; /* temporary storage for uadd */
 #ifdef IP_SET_HASH_WITH_NETMASK
        u8 netmask;             /* netmask value for subnets to store */
 #endif
@@ -217,6 +223,7 @@ ip_set_hash_destroy(struct ip_set *set)
 #define type_pf_data_netmask   TOKEN(TYPE, PF, _data_netmask)
 #define type_pf_data_list      TOKEN(TYPE, PF, _data_list)
 #define type_pf_data_tlist     TOKEN(TYPE, PF, _data_tlist)
+#define type_pf_data_next      TOKEN(TYPE, PF, _data_next)
 
 #define type_pf_elem           TOKEN(TYPE, PF, _elem)
 #define type_pf_telem          TOKEN(TYPE, PF, _telem)
@@ -346,6 +353,9 @@ retry:
        return 0;
 }
 
+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,
  * otherwise report the proper error code. */
 static int
@@ -372,8 +382,11 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
                }
 
        ret = type_pf_elem_add(n, value);
-       if (ret != 0)
+       if (ret != 0) {
+               if (ret == -EAGAIN)
+                       type_pf_data_next(h, d);
                goto out;
+       }
 
 #ifdef IP_SET_HASH_WITH_NETS
        add_cidr(h, d->cidr, HOST_MASK);
@@ -586,10 +599,11 @@ nla_put_failure:
 
 static int
 type_pf_kadt(struct ip_set *set, const struct sk_buff * skb,
-            enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
+            const struct xt_action_param *par,
+            enum ipset_adt adt, const struct ip_set_adt_opt *opt);
 static int
 type_pf_uadt(struct ip_set *set, struct nlattr *tb[],
-            enum ipset_adt adt, u32 *lineno, u32 flags);
+            enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);
 
 static const struct ip_set_type_variant type_pf_variant = {
        .kadt   = type_pf_kadt,
@@ -821,8 +835,11 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
                goto out;
        }
        ret = type_pf_elem_tadd(n, d, timeout);
-       if (ret != 0)
+       if (ret != 0) {
+               if (ret == -EAGAIN)
+                       type_pf_data_next(h, d);
                goto out;
+       }
 
 #ifdef IP_SET_HASH_WITH_NETS
        add_cidr(h, d->cidr, HOST_MASK);
@@ -840,7 +857,7 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
        struct htable *t = h->table;
        const struct type_pf_elem *d = value;
        struct hbucket *n;
-       int i, ret = 0;
+       int i;
        struct type_pf_elem *data;
        u32 key;
 
@@ -851,7 +868,7 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
                if (!type_pf_data_equal(data, d))
                        continue;
                if (type_pf_data_expired(data))
-                       ret = -IPSET_ERR_EXIST;
+                       return -IPSET_ERR_EXIST;
                if (i != n->pos - 1)
                        /* Not last one */
                        type_pf_data_copy(data, ahash_tdata(n, n->pos - 1));
index cceac52c14dae5c1c18e3d3486a06d22ce712f1c..bae805af496fbadb66fd7cf999f339c5cf061907 100644 (file)
@@ -219,24 +219,25 @@ nla_put_failure:
 
 static int
 bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
-              enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+              const struct xt_action_param *par,
+              enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        struct bitmap_ip *map = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        u32 ip;
 
-       ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
+       ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
        if (ip < map->first_ip || ip > map->last_ip)
                return -IPSET_ERR_BITMAP_RANGE;
 
        ip = ip_to_id(map, ip);
 
-       return adtfn(set, &ip, map->timeout, flags);
+       return adtfn(set, &ip, opt_timeout(opt, map), opt->cmdflags);
 }
 
 static int
 bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
-              enum ipset_adt adt, u32 *lineno, u32 flags)
+              enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        struct bitmap_ip *map = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
@@ -283,8 +284,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
 
                if (cidr > 32)
                        return -IPSET_ERR_INVALID_CIDR;
-               ip &= ip_set_hostmask(cidr);
-               ip_to = ip | ~ip_set_hostmask(cidr);
+               ip_set_mask_from_to(ip, ip_to, cidr);
        } else
                ip_to = ip;
 
@@ -478,7 +478,7 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 
                if (cidr >= 32)
                        return -IPSET_ERR_INVALID_CIDR;
-               last_ip = first_ip | ~ip_set_hostmask(cidr);
+               ip_set_mask_from_to(first_ip, last_ip, cidr);
        } else
                return -IPSET_ERR_PROTOCOL;
 
@@ -551,7 +551,8 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
        .features       = IPSET_TYPE_IP,
        .dimension      = IPSET_DIM_ONE,
        .family         = AF_INET,
-       .revision       = 0,
+       .revision_min   = 0,
+       .revision_max   = 0,
        .create         = bitmap_ip_create,
        .create_policy  = {
                [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
index 175d8719f6f750e564270fb4f7c8bd61d9042db9..9dd9bfe0a7cfbad9087d1b65a522cf3c1c6c559f 100644 (file)
@@ -338,17 +338,18 @@ nla_put_failure:
 
 static int
 bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
-                 enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+                 const struct xt_action_param *par,
+                 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        struct bitmap_ipmac *map = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct ipmac data;
 
        /* MAC can be src only */
-       if (!(flags & IPSET_DIM_TWO_SRC))
+       if (!(opt->flags & IPSET_DIM_TWO_SRC))
                return 0;
 
-       data.id = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
+       data.id = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
        if (data.id < map->first_ip || data.id > map->last_ip)
                return -IPSET_ERR_BITMAP_RANGE;
 
@@ -360,12 +361,12 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
        data.id -= map->first_ip;
        data.ether = eth_hdr(skb)->h_source;
 
-       return adtfn(set, &data, map->timeout, flags);
+       return adtfn(set, &data, opt_timeout(opt, map), opt->cmdflags);
 }
 
 static int
 bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
-                 enum ipset_adt adt, u32 *lineno, u32 flags)
+                 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        const struct bitmap_ipmac *map = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
@@ -578,7 +579,7 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
 
                if (cidr >= 32)
                        return -IPSET_ERR_INVALID_CIDR;
-               last_ip = first_ip | ~ip_set_hostmask(cidr);
+               ip_set_mask_from_to(first_ip, last_ip, cidr);
        } else
                return -IPSET_ERR_PROTOCOL;
 
@@ -623,7 +624,8 @@ static struct ip_set_type bitmap_ipmac_type = {
        .features       = IPSET_TYPE_IP | IPSET_TYPE_MAC,
        .dimension      = IPSET_DIM_TWO,
        .family         = AF_INET,
-       .revision       = 0,
+       .revision_min   = 0,
+       .revision_max   = 0,
        .create         = bitmap_ipmac_create,
        .create_policy  = {
                [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
index 6512542d4cefb43ce701d1d4d094a3645ead6cde..4c6b26ccda2579de06d0c1da65643055359f8532 100644 (file)
@@ -208,14 +208,16 @@ nla_put_failure:
 
 static int
 bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
-                enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+                const struct xt_action_param *par,
+                enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        struct bitmap_port *map = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        __be16 __port;
        u16 port = 0;
 
-       if (!ip_set_get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port))
+       if (!ip_set_get_ip_port(skb, opt->family,
+                               opt->flags & IPSET_DIM_ONE_SRC, &__port))
                return -EINVAL;
 
        port = ntohs(__port);
@@ -225,12 +227,12 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
 
        port -= map->first_port;
 
-       return adtfn(set, &port, map->timeout, flags);
+       return adtfn(set, &port, opt_timeout(opt, map), opt->cmdflags);
 }
 
 static int
 bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
-                enum ipset_adt adt, u32 *lineno, u32 flags)
+                enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        struct bitmap_port *map = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
@@ -482,7 +484,8 @@ static struct ip_set_type bitmap_port_type = {
        .features       = IPSET_TYPE_PORT,
        .dimension      = IPSET_DIM_ONE,
        .family         = AF_UNSPEC,
-       .revision       = 0,
+       .revision_min   = 0,
+       .revision_max   = 0,
        .create         = bitmap_port_create,
        .create_policy  = {
                [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
diff --git a/extensions/ipset-6/ip_set_chash.h b/extensions/ipset-6/ip_set_chash.h
deleted file mode 100644 (file)
index dc8a9ab..0000000
+++ /dev/null
@@ -1,1164 +0,0 @@
-#ifndef _IP_SET_CHASH_H
-#define _IP_SET_CHASH_H
-
-#include "jhash.h"
-#include "slist.h"
-#include "ip_set_timeout.h"
-
-/* Cacheline friendly hash with resizing when linear searching becomes too
- * long. Internally jhash is used with the assumption that the size of the
- * stored data is a multiple of sizeof(u32). If storage supports timeout,
- * the timeout field must be the last one in the data structure - that field
- * is ignored when computing the hash key.
- */
-
-/* Number of elements to store in an array block */
-#define CHASH_DEFAULT_ARRAY_SIZE        4
-/* Number of arrays: max ARRAY_SIZE * CHAIN_LIMIT "long" chains */
-#define CHASH_DEFAULT_CHAIN_LIMIT       3
-
-/* Book-keeping of the prefixes added to the set */
-struct chash_nets {
-       u8 cidr;                /* the different cidr values in the set */
-       u32 nets;               /* number of elements per cidr */
-};
-
-struct htable {
-       u8 htable_bits;         /* size of hash table == 2^htable_bits */
-       struct slist htable[0]; /* hashtable of single linked lists */
-};
-
-struct chash {
-       struct htable *table;   /* the hash table */
-       u32 maxelem;            /* max elements in the hash */
-       u32 elements;           /* current element (vs timeout) */
-       u32 initval;            /* random jhash init value */
-       u32 timeout;            /* timeout value, if enabled */
-       struct timer_list gc;   /* garbage collection when timeout enabled */
-       u8 array_size;          /* number of elements in an array */
-       u8 chain_limit;         /* max number of arrays */
-#ifdef IP_SET_HASH_WITH_NETMASK
-       u8 netmask;             /* netmask value for subnets to store */
-#endif
-#ifdef IP_SET_HASH_WITH_NETS
-       struct chash_nets nets[0]; /* book-keeping of prefixes */
-#endif
-};
-
-/* Compute htable_bits from the user input parameter hashsize */
-static inline u8
-htable_bits(u32 hashsize)
-{
-       /* Assume that hashsize == 2^htable_bits */
-       u8 bits = fls(hashsize - 1);
-       if (jhash_size(bits) != hashsize)
-               /* Round up to the first 2^n value */
-               bits = fls(hashsize);
-
-       return bits;
-}
-
-#ifdef IP_SET_HASH_WITH_NETS
-
-#define SET_HOST_MASK(family)  (family == AF_INET ? 32 : 128)
-
-/* Network cidr size book keeping when the hash stores different
- * sized networks */
-static inline void
-add_cidr(struct chash *h, u8 cidr, u8 host_mask)
-{
-       u8 i;
-
-       ++h->nets[cidr-1].nets;
-
-       pr_debug("add_cidr added %u: %u", cidr, h->nets[cidr-1].nets);
-
-       if (h->nets[cidr-1].nets > 1)
-               return;
-
-       /* New cidr size */
-       for (i = 0; i < host_mask && h->nets[i].cidr; i++) {
-               /* Add in increasing prefix order, so larger cidr first */
-               if (h->nets[i].cidr < cidr)
-                       swap(h->nets[i].cidr, cidr);
-       }
-       if (i < host_mask)
-               h->nets[i].cidr = cidr;
-}
-
-static inline void
-del_cidr(struct chash *h, u8 cidr, u8 host_mask)
-{
-       u8 i;
-
-       --h->nets[cidr-1].nets;
-
-       pr_debug("del_cidr deleted %u: %u", cidr, h->nets[cidr-1].nets);
-
-       if (h->nets[cidr-1].nets != 0)
-               return;
-
-       /* All entries with this cidr size deleted, so cleanup h->cidr[] */
-       for (i = 0; i < host_mask - 1 && h->nets[i].cidr; i++) {
-               if (h->nets[i].cidr == cidr)
-                       h->nets[i].cidr = cidr = h->nets[i+1].cidr;
-       }
-       h->nets[i - 1].cidr = 0;
-}
-#endif
-
-/* Destroy the hashtable part of the set */
-static void
-chash_destroy(struct htable *ht)
-{
-       struct slist *n, *tmp;
-       u32 i;
-
-       for (i = 0; i < jhash_size(ht->htable_bits); i++)
-               slist_for_each_safe(n, tmp, &ht->htable[i])
-                       /* FIXME: use slab cache */
-                       kfree(n);
-
-       ip_set_free(ht);
-}
-
-/* Calculate the actual memory size of the set data */
-static size_t
-chash_memsize(const struct chash *h, size_t dsize, u8 host_mask)
-{
-       struct slist *n;
-       u32 i;
-       struct htable *ht = h->table;
-       size_t memsize = sizeof(*h)
-#ifdef IP_SET_HASH_WITH_NETS
-                        + sizeof(struct chash_nets) * host_mask
-#endif
-                        + jhash_size(ht->htable_bits) * sizeof(struct slist);
-
-       for (i = 0; i < jhash_size(ht->htable_bits); i++)
-               slist_for_each(n, &ht->htable[i])
-                       memsize += sizeof(struct slist)
-                               + h->array_size * dsize;
-
-       return memsize;
-}
-
-/* Flush a hash type of set: destroy all elements */
-static void
-ip_set_hash_flush(struct ip_set *set)
-{
-       struct chash *h = set->data;
-       struct htable *ht = h->table;
-       struct slist *n, *tmp;
-       u32 i;
-
-       for (i = 0; i < jhash_size(ht->htable_bits); i++) {
-               slist_for_each_safe(n, tmp, &ht->htable[i])
-                       /* FIXME: slab cache */
-                       kfree(n);
-               ht->htable[i].next = NULL;
-       }
-#ifdef IP_SET_HASH_WITH_NETS
-       memset(h->nets, 0, sizeof(struct chash_nets)
-                          * SET_HOST_MASK(set->family));
-#endif
-       h->elements = 0;
-}
-
-/* Destroy a hash type of set */
-static void
-ip_set_hash_destroy(struct ip_set *set)
-{
-       struct chash *h = set->data;
-
-       if (with_timeout(h->timeout))
-               del_timer_sync(&h->gc);
-
-       chash_destroy(h->table);
-       kfree(h);
-
-       set->data = NULL;
-}
-
-#define JHASH2(data, initval, htable_bits)                              \
-(jhash2((u32 *)(data), sizeof(struct type_pf_elem)/sizeof(u32), initval) \
-       & jhash_mask(htable_bits))
-
-#endif /* _IP_SET_CHASH_H */
-
-#define CONCAT(a, b, c)                a##b##c
-#define TOKEN(a, b, c)         CONCAT(a, b, c)
-
-/* Type/family dependent function prototypes */
-
-#define type_pf_data_equal     TOKEN(TYPE, PF, _data_equal)
-#define type_pf_data_isnull    TOKEN(TYPE, PF, _data_isnull)
-#define type_pf_data_copy      TOKEN(TYPE, PF, _data_copy)
-#define type_pf_data_swap      TOKEN(TYPE, PF, _data_swap)
-#define type_pf_data_zero_out  TOKEN(TYPE, PF, _data_zero_out)
-#define type_pf_data_netmask   TOKEN(TYPE, PF, _data_netmask)
-#define type_pf_data_list      TOKEN(TYPE, PF, _data_list)
-#define type_pf_data_tlist     TOKEN(TYPE, PF, _data_tlist)
-
-#define type_pf_elem           TOKEN(TYPE, PF, _elem)
-#define type_pf_telem          TOKEN(TYPE, PF, _telem)
-#define type_pf_data_timeout   TOKEN(TYPE, PF, _data_timeout)
-#define type_pf_data_expired   TOKEN(TYPE, PF, _data_expired)
-#define type_pf_data_swap_timeout TOKEN(TYPE, PF, _data_swap_timeout)
-#define type_pf_data_timeout_set TOKEN(TYPE, PF, _data_timeout_set)
-
-#define type_pf_chash_readd    TOKEN(TYPE, PF, _chash_readd)
-#define type_pf_chash_del_elem TOKEN(TYPE, PF, _chash_del_elem)
-#define type_pf_chash_add      TOKEN(TYPE, PF, _chash_add)
-#define type_pf_chash_del      TOKEN(TYPE, PF, _chash_del)
-#define type_pf_chash_test_cidrs TOKEN(TYPE, PF, _chash_test_cidrs)
-#define type_pf_chash_test     TOKEN(TYPE, PF, _chash_test)
-
-#define type_pf_chash_treadd   TOKEN(TYPE, PF, _chash_treadd)
-#define type_pf_chash_del_telem        TOKEN(TYPE, PF, _chash_del_telem)
-#define type_pf_chash_expire   TOKEN(TYPE, PF, _chash_expire)
-#define type_pf_chash_tadd     TOKEN(TYPE, PF, _chash_tadd)
-#define type_pf_chash_tdel     TOKEN(TYPE, PF, _chash_tdel)
-#define type_pf_chash_ttest_cidrs TOKEN(TYPE, PF, _chash_ttest_cidrs)
-#define type_pf_chash_ttest    TOKEN(TYPE, PF, _chash_ttest)
-
-#define type_pf_resize         TOKEN(TYPE, PF, _resize)
-#define type_pf_tresize                TOKEN(TYPE, PF, _tresize)
-#define type_pf_flush          ip_set_hash_flush
-#define type_pf_destroy                ip_set_hash_destroy
-#define type_pf_head           TOKEN(TYPE, PF, _head)
-#define type_pf_list           TOKEN(TYPE, PF, _list)
-#define type_pf_tlist          TOKEN(TYPE, PF, _tlist)
-#define type_pf_same_set       TOKEN(TYPE, PF, _same_set)
-#define type_pf_kadt           TOKEN(TYPE, PF, _kadt)
-#define type_pf_uadt           TOKEN(TYPE, PF, _uadt)
-#define type_pf_gc             TOKEN(TYPE, PF, _gc)
-#define type_pf_gc_init                TOKEN(TYPE, PF, _gc_init)
-#define type_pf_variant                TOKEN(TYPE, PF, _variant)
-#define type_pf_tvariant       TOKEN(TYPE, PF, _tvariant)
-
-/* Flavour without timeout */
-
-/* Get the ith element from the array block n */
-#define chash_data(n, i)                                       \
-(struct type_pf_elem *)((char *)(n) + sizeof(struct slist)     \
-                       + (i)*sizeof(struct type_pf_elem))
-
-/* Add an element to the hash table when resizing the set:
- * we spare the maintenance of the internal counters. */
-static int
-type_pf_chash_readd(struct chash *h, struct htable *ht,
-                   const struct type_pf_elem *value,
-                   gfp_t gfp_flags)
-{
-       struct slist *n, *prev;
-       struct type_pf_elem *data;
-       void *tmp;
-       int i = 0, j = 0;
-       u32 hash = JHASH2(value, h->initval, ht->htable_bits);
-
-       slist_for_each_prev(prev, n, &ht->htable[hash]) {
-               for (i = 0; i < h->array_size; i++) {
-                       data = chash_data(n, i);
-                       if (type_pf_data_isnull(data)) {
-                               tmp = n;
-                               goto found;
-                       }
-               }
-               j++;
-       }
-       if (j < h->chain_limit) {
-               tmp = kzalloc(h->array_size * sizeof(struct type_pf_elem)
-                             + sizeof(struct slist), gfp_flags);
-               if (!tmp)
-                       return -ENOMEM;
-               prev->next = (struct slist *) tmp;
-               data = chash_data(tmp, 0);
-       } else {
-               /* Trigger rehashing */
-               return -EAGAIN;
-       }
-found:
-       type_pf_data_copy(data, value);
-       return 0;
-}
-
-/* Delete an element from the hash table: swap it with the last
- * element in the hash bucket and free up the array if it was
- * completely emptied */
-static void
-type_pf_chash_del_elem(struct chash *h, struct slist *prev,
-                      struct slist *n, int i)
-{
-       struct type_pf_elem *data = chash_data(n, i);
-       struct slist *tmp;
-       int j;                  /* Index in array */
-
-       if (n->next != NULL) {
-               for (prev = n, tmp = n->next;
-                    tmp->next != NULL;
-                    prev = tmp, tmp = tmp->next)
-                       /* Find last array */;
-               j = 0;
-       } else {
-               /* Already at last array */
-               tmp = n;
-               j = i;
-       }
-       /* Find last non-empty element */
-       for (; j < h->array_size - 1; j++)
-               if (type_pf_data_isnull(chash_data(tmp, j + 1)))
-                       break;
-
-       if (!(tmp == n && i == j))
-               type_pf_data_swap(data, chash_data(tmp, j));
-
-#ifdef IP_SET_HASH_WITH_NETS
-       del_cidr(h, data->cidr, HOST_MASK);
-#endif
-       if (j == 0) {
-               prev->next = NULL;
-               kfree(tmp);
-       } else
-               type_pf_data_zero_out(chash_data(tmp, j));
-
-       h->elements--;
-}
-
-/* Resize a hash: create a new hash table with doubling the hashsize
- * and inserting the elements to it. Repeat until we succeed or
- * fail due to memory pressures. */
-static int
-type_pf_resize(struct ip_set *set, gfp_t gfp_flags, bool retried)
-{
-       struct chash *h = set->data;
-       struct htable *ht, *orig = h->table;
-       u8 htable_bits = orig->htable_bits;
-       struct slist *n;
-       const struct type_pf_elem *data;
-       u32 i, j;
-       int ret;
-
-retry:
-       ret = i = 0;
-       htable_bits++;
-       if (!htable_bits)
-               /* In case we have plenty of memory :-) */
-               return -IPSET_ERR_HASH_FULL;
-       ht = ip_set_alloc(sizeof(*ht)
-                         + jhash_size(htable_bits) * sizeof(struct slist),
-                         GFP_KERNEL);
-       if (!ht)
-               return -ENOMEM;
-       ht->htable_bits = htable_bits;
-
-       read_lock_bh(&set->lock);
-next_slot:
-       for (; i < jhash_size(orig->htable_bits); i++) {
-               slist_for_each(n, &orig->htable[i]) {
-                       for (j = 0; j < h->array_size; j++) {
-                               data = chash_data(n, j);
-                               if (type_pf_data_isnull(data)) {
-                                       i++;
-                                       goto next_slot;
-                               }
-                               ret = type_pf_chash_readd(h, ht,
-                                                         data, gfp_flags);
-                               if (ret < 0) {
-                                       read_unlock_bh(&set->lock);
-                                       chash_destroy(ht);
-                                       if (ret == -EAGAIN)
-                                               goto retry;
-                                       return ret;
-                               }
-                       }
-               }
-       }
-
-       h->table = ht;
-       read_unlock_bh(&set->lock);
-
-       /* Give time to other users of the set */
-       synchronize_net();
-
-       chash_destroy(orig);
-
-       return 0;
-}
-
-/* Add an element to a hash and update the internal counters when succeeded,
- * otherwise report the proper error code. */
-static int
-type_pf_chash_add(struct ip_set *set, void *value,
-                 gfp_t gfp_flags, u32 timeout)
-{
-       struct chash *h = set->data;
-       const struct type_pf_elem *d = value;
-       struct slist *n, *prev;
-       struct htable *ht = h->table;
-       struct type_pf_elem *data;
-       void *tmp;
-       int i = 0, j = 0;
-       u32 hash;
-
-       if (h->elements >= h->maxelem)
-               return -IPSET_ERR_HASH_FULL;
-
-       hash = JHASH2(value, h->initval, ht->htable_bits);
-       slist_for_each_prev(prev, n, &ht->htable[hash]) {
-               for (i = 0; i < h->array_size; i++) {
-                       data = chash_data(n, i);
-                       if (type_pf_data_isnull(data)) {
-                               tmp = n;
-                               goto found;
-                       }
-                       if (type_pf_data_equal(data, d))
-                               return -IPSET_ERR_EXIST;
-               }
-               j++;
-       }
-       if (j < h->chain_limit) {
-               tmp = kzalloc(h->array_size * sizeof(struct type_pf_elem)
-                             + sizeof(struct slist), gfp_flags);
-               if (!tmp)
-                       return -ENOMEM;
-               prev->next = (struct slist *) tmp;
-               data = chash_data(tmp, 0);
-       } else {
-               /* Rehashing */
-               return -EAGAIN;
-       }
-found:
-       type_pf_data_copy(data, d);
-#ifdef IP_SET_HASH_WITH_NETS
-       add_cidr(h, d->cidr, HOST_MASK);
-#endif
-       h->elements++;
-       return 0;
-}
-
-/* Delete an element from the hash */
-static int
-type_pf_chash_del(struct ip_set *set, void *value,
-                 gfp_t gfp_flags, u32 timeout)
-{
-       struct chash *h = set->data;
-       const struct type_pf_elem *d = value;
-       struct htable *ht = h->table;
-       struct slist *n, *prev;
-       int i;
-       struct type_pf_elem *data;
-       u32 hash = JHASH2(value, h->initval, ht->htable_bits);
-
-       slist_for_each_prev(prev, n, &ht->htable[hash])
-               for (i = 0; i < h->array_size; i++) {
-                       data = chash_data(n, i);
-                       if (type_pf_data_isnull(data))
-                               return -IPSET_ERR_EXIST;
-                       if (type_pf_data_equal(data, d)) {
-                               type_pf_chash_del_elem(h, prev, n, i);
-                               return 0;
-                       }
-               }
-
-       return -IPSET_ERR_EXIST;
-}
-
-#ifdef IP_SET_HASH_WITH_NETS
-
-/* Special test function which takes into account the different network
- * sizes added to the set */
-static inline int
-type_pf_chash_test_cidrs(struct ip_set *set,
-                        struct type_pf_elem *d,
-                        gfp_t gfp_flags, u32 timeout)
-{
-       struct chash *h = set->data;
-       struct htable *ht = h->table;
-       struct slist *n;
-       const struct type_pf_elem *data;
-       int i, j = 0;
-       u32 hash;
-       u8 host_mask = SET_HOST_MASK(set->family);
-
-retry:
-       pr_debug("test by nets");
-       for (; j < host_mask && h->nets[j].cidr; j++) {
-               type_pf_data_netmask(d, h->nets[j].cidr);
-               hash = JHASH2(d, h->initval, ht->htable_bits);
-               slist_for_each(n, &ht->htable[hash])
-                       for (i = 0; i < h->array_size; i++) {
-                               data = chash_data(n, i);
-                               if (type_pf_data_isnull(data)) {
-                                       j++;
-                                       goto retry;
-                               }
-                               if (type_pf_data_equal(data, d))
-                                       return 1;
-                       }
-       }
-       return 0;
-}
-#endif
-
-/* Test whether the element is added to the set */
-static inline int
-type_pf_chash_test(struct ip_set *set, void *value,
-                  gfp_t gfp_flags, u32 timeout)
-{
-       struct chash *h = set->data;
-       struct htable *ht = h->table;
-       struct type_pf_elem *d = value;
-       struct slist *n;
-       const struct type_pf_elem *data;
-       int i;
-       u32 hash;
-
-#ifdef IP_SET_HASH_WITH_NETS
-       /* If we test an IP address and not a network address,
-        * try all possible network sizes */
-       if (d->cidr == SET_HOST_MASK(set->family))
-               return type_pf_chash_test_cidrs(set, d, gfp_flags, timeout);
-#endif
-
-       hash = JHASH2(d, h->initval, ht->htable_bits);
-       slist_for_each(n, &ht->htable[hash])
-               for (i = 0; i < h->array_size; i++) {
-                       data = chash_data(n, i);
-                       if (type_pf_data_isnull(data))
-                               return 0;
-                       if (type_pf_data_equal(data, d))
-                               return 1;
-               }
-       return 0;
-}
-
-/* Reply a HEADER request: fill out the header part of the set */
-static int
-type_pf_head(struct ip_set *set, struct sk_buff *skb)
-{
-       const struct chash *h = set->data;
-       struct nlattr *nested;
-       size_t memsize;
-
-       read_lock_bh(&set->lock);
-       memsize = chash_memsize(h, with_timeout(h->timeout)
-                                       ? sizeof(struct type_pf_telem)
-                                       : sizeof(struct type_pf_elem),
-                               set->family == AF_INET ? 32 : 128);
-       read_unlock_bh(&set->lock);
-
-       nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
-       if (!nested)
-               goto nla_put_failure;
-       NLA_PUT_NET32(skb, IPSET_ATTR_HASHSIZE,
-                     htonl(jhash_size(h->table->htable_bits)));
-       NLA_PUT_NET32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem));
-#ifdef IP_SET_HASH_WITH_NETMASK
-       if (h->netmask != HOST_MASK)
-               NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, h->netmask);
-#endif
-       NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
-                     htonl(atomic_read(&set->ref) - 1));
-       NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize));
-       if (with_timeout(h->timeout))
-               NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout));
-       ipset_nest_end(skb, nested);
-
-       return 0;
-nla_put_failure:
-       return -EFAULT;
-}
-
-/* Reply a LIST/SAVE request: dump the elements of the specified set */
-static int
-type_pf_list(struct ip_set *set,
-            struct sk_buff *skb, struct netlink_callback *cb)
-{
-       const struct chash *h = set->data;
-       const struct htable *ht = h->table;
-       struct nlattr *atd, *nested;
-       struct slist *n;
-       const struct type_pf_elem *data;
-       u32 first = cb->args[2];
-       /* We assume that one hash bucket fills into one page */
-       void *incomplete;
-       int i;
-
-       atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
-       if (!atd)
-               return -EFAULT;
-       pr_debug("list hash set %s", set->name);
-       for (; cb->args[2] < jhash_size(ht->htable_bits); cb->args[2]++) {
-               incomplete = skb_tail_pointer(skb);
-               slist_for_each(n, &ht->htable[cb->args[2]]) {
-                       for (i = 0; i < h->array_size; i++) {
-                               data = chash_data(n, i);
-                               if (type_pf_data_isnull(data))
-                                       break;
-                               pr_debug("list hash %lu slist %p i %u",
-                                        cb->args[2], n, i);
-                               nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
-                               if (!nested) {
-                                       if (cb->args[2] == first) {
-                                               nla_nest_cancel(skb, atd);
-                                               return -EFAULT;
-                                       } else
-                                               goto nla_put_failure;
-                               }
-                               if (type_pf_data_list(skb, data))
-                                       goto nla_put_failure;
-                               ipset_nest_end(skb, nested);
-                       }
-               }
-       }
-       ipset_nest_end(skb, atd);
-       /* Set listing finished */
-       cb->args[2] = 0;
-
-       return 0;
-
-nla_put_failure:
-       nlmsg_trim(skb, incomplete);
-       ipset_nest_end(skb, atd);
-       if (unlikely(first == cb->args[2])) {
-               pr_warn("Can't list set %s: one bucket does not fit into "
-                       "a message. Please report it!\n", set->name);
-               cb->args[2] = 0;
-       }
-       return 0;
-}
-
-static int
-type_pf_kadt(struct ip_set *set, const struct sk_buff * skb,
-            enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
-static int
-type_pf_uadt(struct ip_set *set, struct nlattr *head, int len,
-            enum ipset_adt adt, u32 *lineno, u32 flags);
-
-static const struct ip_set_type_variant type_pf_variant = {
-       .kadt   = type_pf_kadt,
-       .uadt   = type_pf_uadt,
-       .adt    = {
-               [IPSET_ADD] = type_pf_chash_add,
-               [IPSET_DEL] = type_pf_chash_del,
-               [IPSET_TEST] = type_pf_chash_test,
-       },
-       .destroy = type_pf_destroy,
-       .flush  = type_pf_flush,
-       .head   = type_pf_head,
-       .list   = type_pf_list,
-       .resize = type_pf_resize,
-       .same_set = type_pf_same_set,
-};
-
-/* Flavour with timeout support */
-
-#define chash_tdata(n, i) \
-(struct type_pf_elem *)((char *)(n) + sizeof(struct slist) \
-                                   + (i)*sizeof(struct type_pf_telem))
-
-static inline u32
-type_pf_data_timeout(const struct type_pf_elem *data)
-{
-       const struct type_pf_telem *tdata =
-               (const struct type_pf_telem *) data;
-
-       return tdata->timeout;
-}
-
-static inline bool
-type_pf_data_expired(const struct type_pf_elem *data)
-{
-       const struct type_pf_telem *tdata =
-               (const struct type_pf_telem *) data;
-
-       return ip_set_timeout_expired(tdata->timeout);
-}
-
-static inline void
-type_pf_data_swap_timeout(struct type_pf_elem *src,
-                         struct type_pf_elem *dst)
-{
-       struct type_pf_telem *x = (struct type_pf_telem *) src;
-       struct type_pf_telem *y = (struct type_pf_telem *) dst;
-
-       swap(x->timeout, y->timeout);
-}
-
-static inline void
-type_pf_data_timeout_set(struct type_pf_elem *data, u32 timeout)
-{
-       struct type_pf_telem *tdata = (struct type_pf_telem *) data;
-
-       tdata->timeout = ip_set_timeout_set(timeout);
-}
-
-static int
-type_pf_chash_treadd(struct chash *h, struct htable *ht,
-                    const struct type_pf_elem *value,
-                    gfp_t gfp_flags, u32 timeout)
-{
-       struct slist *n, *prev;
-       struct type_pf_elem *data;
-       void *tmp;
-       int i = 0, j = 0;
-       u32 hash = JHASH2(value, h->initval, ht->htable_bits);
-
-       slist_for_each_prev(prev, n, &ht->htable[hash]) {
-               for (i = 0; i < h->array_size; i++) {
-                       data = chash_tdata(n, i);
-                       if (type_pf_data_isnull(data)) {
-                               tmp = n;
-                               goto found;
-                       }
-               }
-               j++;
-       }
-       if (j < h->chain_limit) {
-               tmp = kzalloc(h->array_size * sizeof(struct type_pf_telem)
-                             + sizeof(struct slist), gfp_flags);
-               if (!tmp)
-                       return -ENOMEM;
-               prev->next = (struct slist *) tmp;
-               data = chash_tdata(tmp, 0);
-       } else {
-               /* Trigger rehashing */
-               return -EAGAIN;
-       }
-found:
-       type_pf_data_copy(data, value);
-       type_pf_data_timeout_set(data, timeout);
-       return 0;
-}
-
-static void
-type_pf_chash_del_telem(struct chash *h, struct slist *prev,
-                       struct slist *n, int i)
-{
-       struct type_pf_elem *d, *data = chash_tdata(n, i);
-       struct slist *tmp;
-       int j;          /* Index in array */
-
-       pr_debug("del %u", i);
-       if (n->next != NULL) {
-               for (prev = n, tmp = n->next;
-                    tmp->next != NULL;
-                    prev = tmp, tmp = tmp->next)
-                       /* Find last array */;
-               j = 0;
-       } else {
-               /* Already at last array */
-               tmp = n;
-               j = i;
-       }
-       /* Find last non-empty element */
-       for (; j < h->array_size - 1; j++)
-               if (type_pf_data_isnull(chash_tdata(tmp, j + 1)))
-                       break;
-
-       d = chash_tdata(tmp, j);
-       if (!(tmp == n && i == j)) {
-               type_pf_data_swap(data, d);
-               type_pf_data_swap_timeout(data, d);
-       }
-#ifdef IP_SET_HASH_WITH_NETS
-       del_cidr(h, data->cidr, HOST_MASK);
-#endif
-       if (j == 0) {
-               prev->next = NULL;
-               kfree(tmp);
-       } else
-               type_pf_data_zero_out(d);
-
-       h->elements--;
-}
-
-/* Delete expired elements from the hashtable */
-static void
-type_pf_chash_expire(struct chash *h)
-{
-       struct htable *ht = h->table;
-       struct slist *n, *prev;
-       struct type_pf_elem *data;
-       u32 i;
-       int j;
-
-       for (i = 0; i < jhash_size(ht->htable_bits); i++)
-               slist_for_each_prev(prev, n, &ht->htable[i])
-                       for (j = 0; j < h->array_size; j++) {
-                               data = chash_tdata(n, j);
-                               if (type_pf_data_isnull(data))
-                                       break;
-                               if (type_pf_data_expired(data)) {
-                                       pr_debug("expire %u/%u", i, j);
-                                       type_pf_chash_del_telem(h, prev, n, j);
-                               }
-                       }
-}
-
-static int
-type_pf_tresize(struct ip_set *set, gfp_t gfp_flags, bool retried)
-{
-       struct chash *h = set->data;
-       struct htable *ht, *orig = h->table;
-       u8 htable_bits = orig->htable_bits;
-       struct slist *n;
-       const struct type_pf_elem *data;
-       u32 i, j;
-       int ret;
-
-       /* Try to cleanup once */
-       if (!retried) {
-               i = h->elements;
-               write_lock_bh(&set->lock);
-               type_pf_chash_expire(set->data);
-               write_unlock_bh(&set->lock);
-               if (h->elements <  i)
-                       return 0;
-       }
-
-retry:
-       ret = i = 0;
-       htable_bits++;
-       if (!htable_bits)
-               /* In case we have plenty of memory :-) */
-               return -IPSET_ERR_HASH_FULL;
-       ht = ip_set_alloc(sizeof(*ht)
-                        + jhash_size(htable_bits) * sizeof(struct slist),
-                        GFP_KERNEL);
-       if (!ht)
-               return -ENOMEM;
-       ht->htable_bits = htable_bits;
-
-       read_lock_bh(&set->lock);
-next_slot:
-       for (; i < jhash_size(orig->htable_bits); i++) {
-               slist_for_each(n, &orig->htable[i]) {
-                       for (j = 0; j < h->array_size; j++) {
-                               data = chash_tdata(n, j);
-                               if (type_pf_data_isnull(data)) {
-                                       i++;
-                                       goto next_slot;
-                               }
-                               ret = type_pf_chash_treadd(h, ht,
-                                               data, gfp_flags,
-                                               type_pf_data_timeout(data));
-                               if (ret < 0) {
-                                       read_unlock_bh(&set->lock);
-                                       chash_destroy(ht);
-                                       if (ret == -EAGAIN)
-                                               goto retry;
-                                       return ret;
-                               }
-                       }
-               }
-       }
-
-       h->table = ht;
-       read_unlock_bh(&set->lock);
-
-       /* Give time to other users of the set */
-       synchronize_net();
-
-       chash_destroy(orig);
-
-       return 0;
-}
-
-static int
-type_pf_chash_tadd(struct ip_set *set, void *value,
-                  gfp_t gfp_flags, u32 timeout)
-{
-       struct chash *h = set->data;
-       const struct type_pf_elem *d = value;
-       struct slist *n, *prev;
-       struct htable *ht = h->table;
-       struct type_pf_elem *data;
-       void *tmp;
-       int i = 0, j = 0;
-       u32 hash;
-
-       if (h->elements >= h->maxelem)
-               /* FIXME: when set is full, we slow down here */
-               type_pf_chash_expire(h);
-       if (h->elements >= h->maxelem)
-               return -IPSET_ERR_HASH_FULL;
-
-       hash = JHASH2(d, h->initval, ht->htable_bits);
-       slist_for_each_prev(prev, n, &ht->htable[hash]) {
-               for (i = 0; i < h->array_size; i++) {
-                       data = chash_tdata(n, i);
-                       if (type_pf_data_isnull(data)
-                           || type_pf_data_expired(data)) {
-                               tmp = n;
-                               goto found;
-                       }
-                       if (type_pf_data_equal(data, d))
-                               return -IPSET_ERR_EXIST;
-               }
-               j++;
-       }
-       if (j < h->chain_limit) {
-               tmp = kzalloc(h->array_size * sizeof(struct type_pf_telem)
-                             + sizeof(struct slist), gfp_flags);
-               if (!tmp)
-                       return -ENOMEM;
-               prev->next = (struct slist *) tmp;
-               data = chash_tdata(tmp, 0);
-       } else {
-               /* Rehashing */
-               return -EAGAIN;
-       }
-found:
-       if (type_pf_data_isnull(data))
-               h->elements++;
-#ifdef IP_SET_HASH_WITH_NETS
-       else
-               del_cidr(h, data->cidr, HOST_MASK);
-
-       add_cidr(h, d->cidr, HOST_MASK);
-#endif
-       type_pf_data_copy(data, d);
-       type_pf_data_timeout_set(data, timeout);
-       return 0;
-}
-
-static int
-type_pf_chash_tdel(struct ip_set *set, void *value,
-                  gfp_t gfp_flags, u32 timeout)
-{
-       struct chash *h = set->data;
-       struct htable *ht = h->table;
-       const struct type_pf_elem *d = value;
-       struct slist *n, *prev;
-       int i, ret = 0;
-       struct type_pf_elem *data;
-       u32 hash = JHASH2(value, h->initval, ht->htable_bits);
-
-       slist_for_each_prev(prev, n, &ht->htable[hash])
-               for (i = 0; i < h->array_size; i++) {
-                       data = chash_tdata(n, i);
-                       if (type_pf_data_isnull(data))
-                               return -IPSET_ERR_EXIST;
-                       if (type_pf_data_equal(data, d)) {
-                               if (type_pf_data_expired(data))
-                                       ret = -IPSET_ERR_EXIST;
-                               type_pf_chash_del_telem(h, prev, n, i);
-                               return ret;
-                       }
-               }
-
-       return -IPSET_ERR_EXIST;
-}
-
-#ifdef IP_SET_HASH_WITH_NETS
-static inline int
-type_pf_chash_ttest_cidrs(struct ip_set *set,
-                         struct type_pf_elem *d,
-                         gfp_t gfp_flags, u32 timeout)
-{
-       struct chash *h = set->data;
-       struct htable *ht = h->table;
-       struct type_pf_elem *data;
-       struct slist *n;
-       int i, j = 0;
-       u32 hash;
-       u8 host_mask = SET_HOST_MASK(set->family);
-
-retry:
-       for (; j < host_mask && h->nets[j].cidr; j++) {
-               type_pf_data_netmask(d, h->nets[j].cidr);
-               hash = JHASH2(d, h->initval, ht->htable_bits);
-               slist_for_each(n, &ht->htable[hash])
-                       for (i = 0; i < h->array_size; i++) {
-                               data = chash_tdata(n, i);
-                               if (type_pf_data_isnull(data)) {
-                                       j++;
-                                       goto retry;
-                               }
-                               if (type_pf_data_equal(data, d))
-                                       return !type_pf_data_expired(data);
-                       }
-       }
-       return 0;
-}
-#endif
-
-static inline int
-type_pf_chash_ttest(struct ip_set *set, void *value,
-                   gfp_t gfp_flags, u32 timeout)
-{
-       struct chash *h = set->data;
-       struct htable *ht = h->table;
-       struct type_pf_elem *data, *d = value;
-       struct slist *n;
-       int i;
-       u32 hash;
-
-#ifdef IP_SET_HASH_WITH_NETS
-       if (d->cidr == SET_HOST_MASK(set->family))
-               return type_pf_chash_ttest_cidrs(set, d, gfp_flags,
-                                                timeout);
-#endif
-       hash = JHASH2(d, h->initval, ht->htable_bits);
-       slist_for_each(n, &ht->htable[hash])
-               for (i = 0; i < h->array_size; i++) {
-                       data = chash_tdata(n, i);
-                       if (type_pf_data_isnull(data))
-                               return 0;
-                       if (type_pf_data_equal(data, d))
-                               return !type_pf_data_expired(data);
-               }
-       return 0;
-}
-
-static int
-type_pf_tlist(struct ip_set *set,
-             struct sk_buff *skb, struct netlink_callback *cb)
-{
-       const struct chash *h = set->data;
-       const struct htable *ht = h->table;
-       struct nlattr *atd, *nested;
-       struct slist *n;
-       const struct type_pf_elem *data;
-       u32 first = cb->args[2];
-       /* We assume that one hash bucket fills into one page */
-       void *incomplete;
-       int i;
-
-       atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
-       if (!atd)
-               return -EFAULT;
-       for (; cb->args[2] < jhash_size(ht->htable_bits); cb->args[2]++) {
-               incomplete = skb_tail_pointer(skb);
-               slist_for_each(n, &ht->htable[cb->args[2]]) {
-                       for (i = 0; i < h->array_size; i++) {
-                               data = chash_tdata(n, i);
-                               pr_debug("list %p %u", n, i);
-                               if (type_pf_data_isnull(data))
-                                       break;
-                               if (type_pf_data_expired(data))
-                                       continue;
-                               pr_debug("do list %p %u", n, i);
-                               nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
-                               if (!nested) {
-                                       if (cb->args[2] == first) {
-                                               nla_nest_cancel(skb, atd);
-                                               return -EFAULT;
-                                       } else
-                                               goto nla_put_failure;
-                               }
-                               if (type_pf_data_tlist(skb, data))
-                                       goto nla_put_failure;
-                               ipset_nest_end(skb, nested);
-                       }
-               }
-       }
-       ipset_nest_end(skb, atd);
-       /* Set listing finished */
-       cb->args[2] = 0;
-
-       return 0;
-
-nla_put_failure:
-       nlmsg_trim(skb, incomplete);
-       ipset_nest_end(skb, atd);
-       if (unlikely(first == cb->args[2])) {
-               pr_warn("Can't list set %s: one bucket does not fit into "
-                       "a message. Please report it!\n", set->name);
-               cb->args[2] = 0;
-       }
-       return 0;
-}
-
-static const struct ip_set_type_variant type_pf_tvariant = {
-       .kadt   = type_pf_kadt,
-       .uadt   = type_pf_uadt,
-       .adt    = {
-               [IPSET_ADD] = type_pf_chash_tadd,
-               [IPSET_DEL] = type_pf_chash_tdel,
-               [IPSET_TEST] = type_pf_chash_ttest,
-       },
-       .destroy = type_pf_destroy,
-       .flush  = type_pf_flush,
-       .head   = type_pf_head,
-       .list   = type_pf_tlist,
-       .resize = type_pf_tresize,
-       .same_set = type_pf_same_set,
-};
-
-static void
-type_pf_gc(unsigned long ul_set)
-{
-       struct ip_set *set = (struct ip_set *) ul_set;
-       struct chash *h = set->data;
-
-       pr_debug("called");
-       write_lock_bh(&set->lock);
-       type_pf_chash_expire(h);
-       write_unlock_bh(&set->lock);
-
-       h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
-       add_timer(&h->gc);
-}
-
-static inline void
-type_pf_gc_init(struct ip_set *set)
-{
-       struct chash *h = set->data;
-
-       init_timer(&h->gc);
-       h->gc.data = (unsigned long) set;
-       h->gc.function = type_pf_gc;
-       h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
-       add_timer(&h->gc);
-       pr_debug("gc initialized, run in every %u",
-                IPSET_GC_PERIOD(h->timeout));
-}
-
-#undef type_pf_data_equal
-#undef type_pf_data_isnull
-#undef type_pf_data_copy
-#undef type_pf_data_swap
-#undef type_pf_data_zero_out
-#undef type_pf_data_list
-#undef type_pf_data_tlist
-
-#undef type_pf_elem
-#undef type_pf_telem
-#undef type_pf_data_timeout
-#undef type_pf_data_expired
-#undef type_pf_data_swap_timeout
-#undef type_pf_data_netmask
-#undef type_pf_data_timeout_set
-
-#undef type_pf_chash_readd
-#undef type_pf_chash_del_elem
-#undef type_pf_chash_add
-#undef type_pf_chash_del
-#undef type_pf_chash_test_cidrs
-#undef type_pf_chash_test
-
-#undef type_pf_chash_treadd
-#undef type_pf_chash_del_telem
-#undef type_pf_chash_expire
-#undef type_pf_chash_tadd
-#undef type_pf_chash_tdel
-#undef type_pf_chash_ttest_cidrs
-#undef type_pf_chash_ttest
-
-#undef type_pf_resize
-#undef type_pf_tresize
-#undef type_pf_flush
-#undef type_pf_destroy
-#undef type_pf_head
-#undef type_pf_list
-#undef type_pf_tlist
-#undef type_pf_same_set
-#undef type_pf_kadt
-#undef type_pf_uadt
-#undef type_pf_gc
-#undef type_pf_gc_init
-#undef type_pf_variant
-#undef type_pf_tvariant
index 509a87cbdc323df843f372a15273193f83a07478..43ad97345203a496d02019b77904ec0cb9d399cf 100644 (file)
@@ -21,6 +21,7 @@
 #include <net/netlink.h>
 
 #include <linux/netfilter.h>
+#include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/nfnetlink.h>
 #include "ip_set.h"
 #include <net/genetlink.h>
@@ -75,7 +76,8 @@ find_set_type(const char *name, u8 family, u8 revision)
        list_for_each_entry_rcu(type, &ip_set_type_list, list)
                if (STREQ(type->name, name) &&
                    (type->family == family || type->family == AF_UNSPEC) &&
-                   type->revision == revision)
+                   revision >= type->revision_min &&
+                   revision <= type->revision_max)
                        return type;
        return NULL;
 }
@@ -148,10 +150,10 @@ retry:
                if (STREQ(type->name, name) &&
                    (type->family == family || type->family == AF_UNSPEC)) {
                        found = true;
-                       if (type->revision < *min)
-                               *min = type->revision;
-                       if (type->revision > *max)
-                               *max = type->revision;
+                       if (type->revision_min < *min)
+                               *min = type->revision_min;
+                       if (type->revision_max > *max)
+                               *max = type->revision_max;
                }
        rcu_read_unlock();
        if (found)
@@ -175,25 +177,27 @@ ip_set_type_register(struct ip_set_type *type)
        int ret = 0;
 
        if (type->protocol != IPSET_PROTOCOL) {
-               pr_warning("ip_set type %s, family %s, revision %u uses "
+               pr_warning("ip_set type %s, family %s, revision %u:%u uses "
                           "wrong protocol version %u (want %u)\n",
                           type->name, family_name(type->family),
-                          type->revision, type->protocol, IPSET_PROTOCOL);
+                          type->revision_min, type->revision_max,
+                          type->protocol, IPSET_PROTOCOL);
                return -EINVAL;
        }
 
        ip_set_type_lock();
-       if (find_set_type(type->name, type->family, type->revision)) {
+       if (find_set_type(type->name, type->family, type->revision_min)) {
                /* Duplicate! */
-               pr_warning("ip_set type %s, family %s, revision %u "
+               pr_warning("ip_set type %s, family %s with revision min %u "
                           "already registered!\n", type->name,
-                          family_name(type->family), type->revision);
+                          family_name(type->family), type->revision_min);
                ret = -EINVAL;
                goto unlock;
        }
        list_add_rcu(&type->list, &ip_set_type_list);
-       pr_debug("type %s, family %s, revision %u registered.\n",
-                type->name, family_name(type->family), type->revision);
+       pr_debug("type %s, family %s, revision %u:%u registered.\n",
+                type->name, family_name(type->family),
+                type->revision_min, type->revision_max);
 unlock:
        ip_set_type_unlock();
        return ret;
@@ -205,15 +209,15 @@ void
 ip_set_type_unregister(struct ip_set_type *type)
 {
        ip_set_type_lock();
-       if (!find_set_type(type->name, type->family, type->revision)) {
-               pr_warning("ip_set type %s, family %s, revision %u "
+       if (!find_set_type(type->name, type->family, type->revision_min)) {
+               pr_warning("ip_set type %s, family %s with revision min %u "
                           "not registered\n", type->name,
-                          family_name(type->family), type->revision);
+                          family_name(type->family), type->revision_min);
                goto unlock;
        }
        list_del_rcu(&type->list);
-       pr_debug("type %s, family %s, revision %u unregistered.\n",
-                type->name, family_name(type->family), type->revision);
+       pr_debug("type %s, family %s with revision min %u unregistered.\n",
+                type->name, family_name(type->family), type->revision_min);
 unlock:
        ip_set_type_unlock();
 
@@ -346,7 +350,8 @@ __ip_set_put(ip_set_id_t index)
 
 int
 ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
-           u8 family, u8 dim, u8 flags)
+           const struct xt_action_param *par,
+           const struct ip_set_adt_opt *opt)
 {
        struct ip_set *set = ip_set_list[index];
        int ret = 0;
@@ -354,19 +359,19 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
        BUG_ON(set == NULL);
        pr_debug("set %s, index %u\n", set->name, index);
 
-       if (dim < set->type->dimension ||
-           !(family == set->family || set->family == AF_UNSPEC))
+       if (opt->dim < set->type->dimension ||
+           !(opt->family == set->family || set->family == AF_UNSPEC))
                return 0;
 
        read_lock_bh(&set->lock);
-       ret = set->variant->kadt(set, skb, IPSET_TEST, family, dim, flags);
+       ret = set->variant->kadt(set, skb, par, IPSET_TEST, opt);
        read_unlock_bh(&set->lock);
 
        if (ret == -EAGAIN) {
                /* Type requests element to be completed */
                pr_debug("element must be competed, ADD is triggered\n");
                write_lock_bh(&set->lock);
-               set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags);
+               set->variant->kadt(set, skb, par, IPSET_ADD, opt);
                write_unlock_bh(&set->lock);
                ret = 1;
        }
@@ -378,7 +383,8 @@ EXPORT_SYMBOL_GPL(ip_set_test);
 
 int
 ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
-          u8 family, u8 dim, u8 flags)
+          const struct xt_action_param *par,
+          const struct ip_set_adt_opt *opt)
 {
        struct ip_set *set = ip_set_list[index];
        int ret;
@@ -386,12 +392,12 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
        BUG_ON(set == NULL);
        pr_debug("set %s, index %u\n", set->name, index);
 
-       if (dim < set->type->dimension ||
-           !(family == set->family || set->family == AF_UNSPEC))
+       if (opt->dim < set->type->dimension ||
+           !(opt->family == set->family || set->family == AF_UNSPEC))
                return 0;
 
        write_lock_bh(&set->lock);
-       ret = set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags);
+       ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);
        write_unlock_bh(&set->lock);
 
        return ret;
@@ -400,7 +406,8 @@ EXPORT_SYMBOL_GPL(ip_set_add);
 
 int
 ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
-          u8 family, u8 dim, u8 flags)
+          const struct xt_action_param *par,
+          const struct ip_set_adt_opt *opt)
 {
        struct ip_set *set = ip_set_list[index];
        int ret = 0;
@@ -408,12 +415,12 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
        BUG_ON(set == NULL);
        pr_debug("set %s, index %u\n", set->name, index);
 
-       if (dim < set->type->dimension ||
-           !(family == set->family || set->family == AF_UNSPEC))
+       if (opt->dim < set->type->dimension ||
+           !(opt->family == set->family || set->family == AF_UNSPEC))
                return 0;
 
        write_lock_bh(&set->lock);
-       ret = set->variant->kadt(set, skb, IPSET_DEL, family, dim, flags);
+       ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);
        write_unlock_bh(&set->lock);
 
        return ret;
@@ -668,6 +675,7 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
        rwlock_init(&set->lock);
        strlcpy(set->name, name, IPSET_MAXNAMELEN);
        set->family = family;
+       set->revision = revision;
 
        /*
         * Next, check that we know the type, and take
@@ -708,7 +716,8 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
                    (flags & IPSET_FLAG_EXIST) &&
                    STREQ(set->type->name, clash->type->name) &&
                    set->type->family == clash->type->family &&
-                   set->type->revision == clash->type->revision &&
+                   set->type->revision_min == clash->type->revision_min &&
+                   set->type->revision_max == clash->type->revision_max &&
                    set->variant->same_set(set, clash))
                        ret = 0;
                goto cleanup;
@@ -778,7 +787,7 @@ ip_set_destroy(struct sk_buff *skb, struct genl_info *info)
        if (!attr[IPSET_ATTR_SETNAME]) {
                for (i = 0; i < ip_set_max; i++) {
                        if (ip_set_list[i] != NULL && ip_set_list[i]->ref) {
-                               ret = IPSET_ERR_BUSY;
+                               ret = -IPSET_ERR_BUSY;
                                goto out;
                        }
                }
@@ -825,7 +834,7 @@ ip_set_flush(struct sk_buff *skb, struct genl_info *info)
        ip_set_id_t i;
 
        if (unlikely(protocol_failed(attr)))
-               return -EPROTO;
+               return -IPSET_ERR_PROTOCOL;
 
        if (!attr[IPSET_ATTR_SETNAME]) {
                for (i = 0; i < ip_set_max; i++)
@@ -947,10 +956,13 @@ ip_set_swap(struct sk_buff *skb, struct genl_info *info)
 
 /* List/save set data */
 
-#define DUMP_INIT      0L
-#define DUMP_ALL       1L
-#define DUMP_ONE       2L
-#define DUMP_LAST      3L
+#define DUMP_INIT      0
+#define DUMP_ALL       1
+#define DUMP_ONE       2
+#define DUMP_LAST      3
+
+#define DUMP_TYPE(arg)         (((u32)(arg)) & 0x0000FFFF)
+#define DUMP_FLAGS(arg)                (((u32)(arg)) >> 16)
 
 static int
 ip_set_dump_done(struct netlink_callback *cb)
@@ -983,6 +995,7 @@ dump_init(struct netlink_callback *cb)
        int min_len = NLMSG_SPACE(sizeof(struct genlmsghdr));
        struct nlattr *cda[IPSET_ATTR_CMD_MAX+1];
        struct nlattr *attr = (void *)nlh + min_len;
+       u32 dump_type;
        ip_set_id_t index;
 
        /* Second pass, so parser can't fail */
@@ -994,17 +1007,22 @@ dump_init(struct netlink_callback *cb)
         *         [..]: type specific
         */
 
-       if (!cda[IPSET_ATTR_SETNAME]) {
-               cb->args[0] = DUMP_ALL;
-               return 0;
-       }
+       if (cda[IPSET_ATTR_SETNAME]) {
+               index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
+               if (index == IPSET_INVALID_ID)
+                       return -ENOENT;
 
-       index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
-       if (index == IPSET_INVALID_ID)
-               return -ENOENT;
+               dump_type = DUMP_ONE;
+               cb->args[1] = index;
+       } else
+               dump_type = DUMP_ALL;
+
+       if (cda[IPSET_ATTR_FLAGS]) {
+               u32 f = ip_set_get_h32(cda[IPSET_ATTR_FLAGS]);
+               dump_type |= (f << 16);
+       }
+       cb->args[0] = dump_type;
 
-       cb->args[0] = DUMP_ONE;
-       cb->args[1] = index;
        return 0;
 }
 
@@ -1015,9 +1033,10 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
        struct ip_set *set = NULL;
        struct genlmsg_buf *nlh = NULL;
        unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0;
+       u32 dump_type, dump_flags;
        int ret = 0;
 
-       if (cb->args[0] == DUMP_INIT) {
+       if (!cb->args[0]) {
                ret = dump_init(cb);
                if (ret < 0) {
                        struct nlmsghdr *nlh = nlmsg_hdr(cb->skb);
@@ -1032,13 +1051,17 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
        if (cb->args[1] >= ip_set_max)
                goto out;
 
-       pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]);
-       max = cb->args[0] == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
+       dump_type = DUMP_TYPE(cb->args[0]);
+       dump_flags = DUMP_FLAGS(cb->args[0]);
+       max = dump_type == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
+dump_last:
+       pr_debug("args[0]: %u %u args[1]: %ld\n",
+                dump_type, dump_flags, cb->args[1]);
        for (; cb->args[1] < max; cb->args[1]++) {
                index = (ip_set_id_t) cb->args[1];
                set = ip_set_list[index];
                if (set == NULL) {
-                       if (cb->args[0] == DUMP_ONE) {
+                       if (dump_type == DUMP_ONE) {
                                ret = -ENOENT;
                                goto out;
                        }
@@ -1047,9 +1070,9 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
                /* When dumping all sets, we must dump "sorted"
                 * so that lists (unions of sets) are dumped last.
                 */
-               if (cb->args[0] != DUMP_ONE &&
-                   !((cb->args[0] == DUMP_ALL) ^
-                     (set->type->features & IPSET_DUMP_LAST)))
+               if (dump_type != DUMP_ONE &&
+                   ((dump_type == DUMP_ALL) ==
+                    !!(set->type->features & IPSET_DUMP_LAST)))
                        continue;
                pr_debug("List set: %s\n", set->name);
                if (!cb->args[2]) {
@@ -1066,6 +1089,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
                }
                NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
                NLA_PUT_STRING(skb, IPSET_ATTR_SETNAME, set->name);
+               if (dump_flags & IPSET_FLAG_LIST_SETNAME)
+                       goto next_set;
                switch (cb->args[2]) {
                case 0:
                        /* Core header data */
@@ -1074,40 +1099,45 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
                        NLA_PUT_U8(skb, IPSET_ATTR_FAMILY,
                                   set->family);
                        NLA_PUT_U8(skb, IPSET_ATTR_REVISION,
-                                  set->type->revision);
+                                  set->revision);
                        ret = set->variant->head(set, skb);
                        if (ret < 0)
                                goto release_refcount;
+                       if (dump_flags & IPSET_FLAG_LIST_HEADER)
+                               goto next_set;
                        /* Fall through and add elements */
                default:
                        read_lock_bh(&set->lock);
                        ret = set->variant->list(set, skb, cb);
                        read_unlock_bh(&set->lock);
-                       if (!cb->args[2]) {
+                       if (!cb->args[2])
                                /* Set is done, proceed with next one */
-                               if (cb->args[0] == DUMP_ONE)
-                                       cb->args[1] = IPSET_INVALID_ID;
-                               else
-                                       cb->args[1]++;
-                       }
+                               goto next_set;
                        goto release_refcount;
                }
        }
+       /* If we dump all sets, continue with dumping last ones */
+       if (dump_type == DUMP_ALL) {
+               dump_type = DUMP_LAST;
+               cb->args[0] = dump_type | (dump_flags << 16);
+               cb->args[1] = 0;
+               goto dump_last;
+       }
        goto out;
 
 nla_put_failure:
        ret = -EFAULT;
+next_set:
+       if (dump_type == DUMP_ONE)
+               cb->args[1] = IPSET_INVALID_ID;
+       else
+               cb->args[1]++;
 release_refcount:
        /* If there was an error or set is done, release set */
        if (ret || !cb->args[2]) {
                pr_debug("release set %s\n", ip_set_list[index]->name);
                ip_set_put_byindex(index);
        }
-
-       /* If we dump all sets, continue with dumping last ones */
-       if (cb->args[0] == DUMP_ALL && cb->args[1] >= max && !cb->args[2])
-               cb->args[0] = DUMP_LAST;
-
 out:
        if (nlh) {
                genlmsg_end(skb, nlh);
@@ -1153,17 +1183,18 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
        struct nlattr *tb[], enum ipset_adt adt,
        u32 flags, bool use_lineno)
 {
-       int ret, retried = 0;
+       int ret;
        u32 lineno = 0;
-       bool eexist = flags & IPSET_FLAG_EXIST;
+       bool eexist = flags & IPSET_FLAG_EXIST, retried = false;
 
        do {
                write_lock_bh(&set->lock);
-               ret = set->variant->uadt(set, tb, adt, &lineno, flags);
+               ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
                write_unlock_bh(&set->lock);
+               retried = true;
        } while (ret == -EAGAIN &&
                 set->variant->resize &&
-                (ret = set->variant->resize(set, retried++)) == 0);
+                (ret = set->variant->resize(set, retried)) == 0);
 
        if (!ret || (ret == -IPSET_ERR_EXIST && eexist))
                return 0;
@@ -1338,7 +1369,7 @@ ip_set_utest(struct sk_buff *skb, struct genl_info *info)
                return -IPSET_ERR_PROTOCOL;
 
        read_lock_bh(&set->lock);
-       ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0);
+       ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0, 0);
        read_unlock_bh(&set->lock);
        /* Userspace can't trigger element to be re-added */
        if (ret == -EAGAIN)
@@ -1381,7 +1412,7 @@ ip_set_header(struct sk_buff *skb, struct genl_info *info)
        NLA_PUT_STRING(skb2, IPSET_ATTR_SETNAME, set->name);
        NLA_PUT_STRING(skb2, IPSET_ATTR_TYPENAME, set->type->name);
        NLA_PUT_U8(skb2, IPSET_ATTR_FAMILY, set->family);
-       NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->type->revision);
+       NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->revision);
        genlmsg_end(skb2, nlh2);
 
        ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid);
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 94092f39066e8313278891c72c117efe0a4e110f..084d606e7adb556504510ee14e1291a13196272b 100644 (file)
@@ -108,25 +108,32 @@ nla_put_failure:
 #define HOST_MASK      32
 #include "ip_set_ahash.h"
 
+static inline void
+hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d)
+{
+       h->next.ip = ntohl(d->ip);
+}
+
 static int
 hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
-             enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+             const struct xt_action_param *par,
+             enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        __be32 ip;
 
-       ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &ip);
+       ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
        ip &= ip_set_netmask(h->netmask);
        if (ip == 0)
                return -EINVAL;
 
-       return adtfn(set, &ip, h->timeout, flags);
+       return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
 }
 
 static int
 hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
-             enum ipset_adt adt, u32 *lineno, u32 flags)
+             enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
@@ -171,13 +178,14 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
 
                if (cidr > 32)
                        return -IPSET_ERR_INVALID_CIDR;
-               ip &= ip_set_hostmask(cidr);
-               ip_to = ip | ~ip_set_hostmask(cidr);
+               ip_set_mask_from_to(ip, ip_to, cidr);
        } else
                ip_to = ip;
 
        hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
 
+       if (retried)
+               ip = h->next.ip;
        for (; !before(ip_to, ip); ip += hosts) {
                nip = htonl(ip);
                if (nip == 0)
@@ -281,20 +289,26 @@ nla_put_failure:
 #define HOST_MASK      128
 #include "ip_set_ahash.h"
 
+static inline void
+hash_ip6_data_next(struct ip_set_hash *h, const struct hash_ip6_elem *d)
+{
+}
+
 static int
 hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
-             enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+             const struct xt_action_param *par,
+             enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        union nf_inet_addr ip;
 
-       ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &ip.in6);
+       ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip.in6);
        ip6_netmask(&ip, h->netmask);
        if (ipv6_addr_any(&ip.in6))
                return -EINVAL;
 
-       return adtfn(set, &ip, h->timeout, flags);
+       return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
 }
 
 static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
@@ -305,7 +319,7 @@ static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
 
 static int
 hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
-             enum ipset_adt adt, u32 *lineno, u32 flags)
+             enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
@@ -428,7 +442,8 @@ static struct ip_set_type hash_ip_type __read_mostly = {
        .features       = IPSET_TYPE_IP,
        .dimension      = IPSET_DIM_ONE,
        .family         = AF_UNSPEC,
-       .revision       = 0,
+       .revision_min   = 0,
+       .revision_max   = 0,
        .create         = hash_ip_create,
        .create_policy  = {
                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
index e8b506a5e3050cb2864d3827457b4131904e14cf..c450a31854b79617e7d3e259ea161b1b2a04fa2d 100644 (file)
@@ -124,31 +124,40 @@ nla_put_failure:
 #define HOST_MASK      32
 #include "ip_set_ahash.h"
 
+static inline void
+hash_ipport4_data_next(struct ip_set_hash *h,
+                      const struct hash_ipport4_elem *d)
+{
+       h->next.ip = ntohl(d->ip);
+       h->next.port = ntohs(d->port);
+}
+
 static int
 hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
-                 enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+                 const struct xt_action_param *par,
+                 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipport4_elem data = { };
 
-       if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
+       if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
                                 &data.port, &data.proto))
                return -EINVAL;
 
-       ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
+       ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
 
-       return adtfn(set, &data, h->timeout, flags);
+       return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
 
 static int
 hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
-                 enum ipset_adt adt, u32 *lineno, u32 flags)
+                 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipport4_elem data = { };
-       u32 ip, ip_to, p, port, port_to;
+       u32 ip, ip_to, p = 0, port, port_to;
        u32 timeout = h->timeout;
        bool with_ports = false;
        int ret;
@@ -208,8 +217,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
 
                if (cidr > 32)
                        return -IPSET_ERR_INVALID_CIDR;
-               ip &= ip_set_hostmask(cidr);
-               ip_to = ip | ~ip_set_hostmask(cidr);
+               ip_set_mask_from_to(ip, ip_to, cidr);
        } else
                ip_to = ip;
 
@@ -220,8 +228,11 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
                        swap(port, port_to);
        }
 
-       for (; !before(ip_to, ip); ip++)
-               for (p = port; p <= port_to; p++) {
+       if (retried)
+               ip = h->next.ip;
+       for (; !before(ip_to, ip); 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);
@@ -231,6 +242,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
                        else
                                ret = 0;
                }
+       }
        return ret;
 }
 
@@ -328,26 +340,34 @@ nla_put_failure:
 #define HOST_MASK      128
 #include "ip_set_ahash.h"
 
+static inline void
+hash_ipport6_data_next(struct ip_set_hash *h,
+                      const struct hash_ipport6_elem *d)
+{
+       h->next.port = ntohs(d->port);
+}
+
 static int
 hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
-                 enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+                 const struct xt_action_param *par,
+                 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipport6_elem data = { };
 
-       if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
+       if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
                                 &data.port, &data.proto))
                return -EINVAL;
 
-       ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
+       ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
 
-       return adtfn(set, &data, h->timeout, flags);
+       return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
 
 static int
 hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
-                 enum ipset_adt adt, u32 *lineno, u32 flags)
+                 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
@@ -405,6 +425,8 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
        if (port > port_to)
                swap(port, port_to);
 
+       if (retried)
+               port = h->next.port;
        for (; port <= port_to; port++) {
                data.port = htons(port);
                ret = adtfn(set, &data, timeout, flags);
@@ -491,7 +513,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
        .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT,
        .dimension      = IPSET_DIM_TWO,
        .family         = AF_UNSPEC,
-       .revision       = 1,
+       .revision_min   = 0,
+       .revision_max   = 1,    /* SCTP and UDPLITE support added */
        .create         = hash_ipport_create,
        .create_policy  = {
                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
index f7726b3d5d61189983b54254301c2e7bf23011bc..b608bd3e7c0ae6f392bf10890093e70355223814 100644 (file)
@@ -127,32 +127,41 @@ nla_put_failure:
 #define HOST_MASK      32
 #include "ip_set_ahash.h"
 
+static inline void
+hash_ipportip4_data_next(struct ip_set_hash *h,
+                        const struct hash_ipportip4_elem *d)
+{
+       h->next.ip = ntohl(d->ip);
+       h->next.port = ntohs(d->port);
+}
+
 static int
 hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
-                   enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+                   const struct xt_action_param *par,
+                   enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipportip4_elem data = { };
 
-       if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
+       if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
                                 &data.port, &data.proto))
                return -EINVAL;
 
-       ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
-       ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
+       ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
+       ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2);
 
-       return adtfn(set, &data, h->timeout, flags);
+       return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
 
 static int
 hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
-                   enum ipset_adt adt, u32 *lineno, u32 flags)
+                   enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipportip4_elem data = { };
-       u32 ip, ip_to, p, port, port_to;
+       u32 ip, ip_to, p = 0, port, port_to;
        u32 timeout = h->timeout;
        bool with_ports = false;
        int ret;
@@ -216,8 +225,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
 
                if (cidr > 32)
                        return -IPSET_ERR_INVALID_CIDR;
-               ip &= ip_set_hostmask(cidr);
-               ip_to = ip | ~ip_set_hostmask(cidr);
+               ip_set_mask_from_to(ip, ip_to, cidr);
        } else
                ip_to = ip;
 
@@ -228,8 +236,11 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
                        swap(port, port_to);
        }
 
-       for (; !before(ip_to, ip); ip++)
-               for (p = port; p <= port_to; p++) {
+       if (retried)
+               ip = h->next.ip;
+       for (; !before(ip_to, ip); 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);
@@ -239,6 +250,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
                        else
                                ret = 0;
                }
+       }
        return ret;
 }
 
@@ -341,27 +353,35 @@ nla_put_failure:
 #define HOST_MASK      128
 #include "ip_set_ahash.h"
 
+static inline void
+hash_ipportip6_data_next(struct ip_set_hash *h,
+                        const struct hash_ipportip6_elem *d)
+{
+       h->next.port = ntohs(d->port);
+}
+
 static int
 hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
-                   enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+                   const struct xt_action_param *par,
+                   enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipportip6_elem data = { };
 
-       if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
+       if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
                                 &data.port, &data.proto))
                return -EINVAL;
 
-       ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
-       ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
+       ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
+       ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
 
-       return adtfn(set, &data, h->timeout, flags);
+       return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
 
 static int
 hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
-                   enum ipset_adt adt, u32 *lineno, u32 flags)
+                   enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
@@ -423,6 +443,8 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
        if (port > port_to)
                swap(port, port_to);
 
+       if (retried)
+               port = h->next.port;
        for (; port <= port_to; port++) {
                data.port = htons(port);
                ret = adtfn(set, &data, timeout, flags);
@@ -509,7 +531,8 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
        .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
        .dimension      = IPSET_DIM_THREE,
        .family         = AF_UNSPEC,
-       .revision       = 1,
+       .revision_min   = 0,
+       .revision_max   = 1,    /* SCTP and UDPLITE support added */
        .create         = hash_ipportip_create,
        .create_policy  = {
                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
index 52d53531157e1c6c9663e7262fdc69fc192a59b6..0babe3de714b9e2ee4a2b17eceb41440e09232bf 100644 (file)
@@ -140,39 +140,51 @@ nla_put_failure:
 #define HOST_MASK      32
 #include "ip_set_ahash.h"
 
+static inline void
+hash_ipportnet4_data_next(struct ip_set_hash *h,
+                         const struct hash_ipportnet4_elem *d)
+{
+       h->next.ip = ntohl(d->ip);
+       h->next.port = ntohs(d->port);
+       h->next.ip2 = ntohl(d->ip2);
+}
+
 static int
 hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
-                    enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+                    const struct xt_action_param *par,
+                    enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
-       struct hash_ipportnet4_elem data =
-               { .cidr = h->nets[0].cidr || HOST_MASK };
+       struct hash_ipportnet4_elem data = {
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+       };
 
        if (data.cidr == 0)
                return -EINVAL;
        if (adt == IPSET_TEST)
                data.cidr = HOST_MASK;
 
-       if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
+       if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
                                 &data.port, &data.proto))
                return -EINVAL;
 
-       ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
-       ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
+       ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
+       ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2);
        data.ip2 &= ip_set_netmask(data.cidr);
 
-       return adtfn(set, &data, h->timeout, flags);
+       return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
 
 static int
 hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
-                    enum ipset_adt adt, u32 *lineno, u32 flags)
+                    enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
-       u32 ip, ip_to, p, port, port_to;
+       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;
@@ -186,21 +198,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]);
@@ -225,14 +235,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)
@@ -244,29 +256,50 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
 
                if (cidr > 32)
                        return -IPSET_ERR_INVALID_CIDR;
-               ip &= ip_set_hostmask(cidr);
-               ip_to = ip | ~ip_set_hostmask(cidr);
-       } else
-               ip_to = ip;
+               ip_set_mask_from_to(ip, ip_to, cidr);
+       }
 
        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 {
+               ip_set_mask_from_to(ip2_from, ip2_to, data.cidr);
+       }
 
-       for (; !before(ip_to, ip); ip++)
-               for (p = port; p <= port_to; p++) {
-                       data.ip = htonl(ip);
+       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.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;
 }
 
@@ -388,34 +421,43 @@ nla_put_failure:
 #define HOST_MASK      128
 #include "ip_set_ahash.h"
 
+static inline void
+hash_ipportnet6_data_next(struct ip_set_hash *h,
+                         const struct hash_ipportnet6_elem *d)
+{
+       h->next.port = ntohs(d->port);
+}
+
 static int
 hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
-                    enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+                    const struct xt_action_param *par,
+                    enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
-       struct hash_ipportnet6_elem data =
-               { .cidr = h->nets[0].cidr || HOST_MASK };
+       struct hash_ipportnet6_elem data = {
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+       };
 
        if (data.cidr == 0)
                return -EINVAL;
        if (adt == IPSET_TEST)
                data.cidr = HOST_MASK;
 
-       if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
+       if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
                                 &data.port, &data.proto))
                return -EINVAL;
 
-       ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
-       ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
+       ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
+       ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
        ip6_netmask(&data.ip2, data.cidr);
 
-       return adtfn(set, &data, h->timeout, flags);
+       return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
 
 static int
 hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
-                    enum ipset_adt adt, u32 *lineno, u32 flags)
+                    enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
@@ -432,6 +474,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]);
@@ -485,6 +529,8 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
        if (port > port_to)
                swap(port, port_to);
 
+       if (retried)
+               port = h->next.port;
        for (; port <= port_to; port++) {
                data.port = htons(port);
                ret = adtfn(set, &data, timeout, flags);
@@ -574,7 +620,9 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
        .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
        .dimension      = IPSET_DIM_THREE,
        .family         = AF_UNSPEC,
-       .revision       = 1,
+       .revision_min   = 0,
+       /*                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 },
@@ -587,6 +635,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 9f1b14efed1b3f0752952895d9f76206ac9fcb4b..60cdb50736fb8566f486db21cac89ba35e2f94e6 100644 (file)
@@ -125,33 +125,44 @@ nla_put_failure:
 #define HOST_MASK      32
 #include "ip_set_ahash.h"
 
+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
 hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
-              enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+              const struct xt_action_param *par,
+              enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
-       struct hash_net4_elem data = { .cidr = h->nets[0].cidr || HOST_MASK };
+       struct hash_net4_elem data = {
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+       };
 
        if (data.cidr == 0)
                return -EINVAL;
        if (adt == IPSET_TEST)
                data.cidr = HOST_MASK;
 
-       ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
+       ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
        data.ip &= ip_set_netmask(data.cidr);
 
-       return adtfn(set, &data, h->timeout, flags);
+       return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
 
 static int
 hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
-              enum ipset_adt adt, u32 *lineno, u32 flags)
+              enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        const struct ip_set_hash *h = set->data;
        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] ||
@@ -161,27 +172,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
@@ -290,28 +325,37 @@ nla_put_failure:
 #define HOST_MASK      128
 #include "ip_set_ahash.h"
 
+static inline void
+hash_net6_data_next(struct ip_set_hash *h,
+                   const struct hash_net6_elem *d)
+{
+}
+
 static int
 hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
-              enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+              const struct xt_action_param *par,
+              enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
-       struct hash_net6_elem data = { .cidr = h->nets[0].cidr || HOST_MASK };
+       struct hash_net6_elem data = {
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+       };
 
        if (data.cidr == 0)
                return -EINVAL;
        if (adt == IPSET_TEST)
                data.cidr = HOST_MASK;
 
-       ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
+       ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
        ip6_netmask(&data.ip, data.cidr);
 
-       return adtfn(set, &data, h->timeout, flags);
+       return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
 
 static int
 hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
-              enum ipset_adt adt, u32 *lineno, u32 flags)
+              enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
@@ -322,6 +366,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]);
@@ -425,7 +471,8 @@ static struct ip_set_type hash_net_type __read_mostly = {
        .features       = IPSET_TYPE_IP,
        .dimension      = IPSET_DIM_ONE,
        .family         = AF_UNSPEC,
-       .revision       = 0,
+       .revision_min   = 0,
+       .revision_max   = 1,    /* Range as input support for IPv4 added */
        .create         = hash_net_create,
        .create_policy  = {
                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
@@ -436,6 +483,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 989d266a5833690cbfb79663a4933bc6fe51c48f..5d141456d2d6999b7eeb099b2edef249c5718f1f 100644 (file)
@@ -137,38 +137,48 @@ nla_put_failure:
 #define HOST_MASK      32
 #include "ip_set_ahash.h"
 
+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);
+}
+
 static int
 hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
-                  enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+                  const struct xt_action_param *par,
+                  enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_netport4_elem data = {
-               .cidr = h->nets[0].cidr || HOST_MASK };
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+       };
 
        if (data.cidr == 0)
                return -EINVAL;
        if (adt == IPSET_TEST)
                data.cidr = HOST_MASK;
 
-       if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
+       if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
                                 &data.port, &data.proto))
                return -EINVAL;
 
-       ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
+       ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
        data.ip &= ip_set_netmask(data.cidr);
 
-       return adtfn(set, &data, h->timeout, flags);
+       return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
 
 static int
 hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
-                  enum ipset_adt adt, u32 *lineno, u32 flags)
+                  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        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;
@@ -182,15 +192,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]);
@@ -215,24 +225,47 @@ 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);
-
-       for (; port <= port_to; port++) {
-               data.port = htons(port);
-               ret = adtfn(set, &data, timeout, flags);
-
-               if (ret && !ip_set_eexist(ret, flags))
+       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;
-               else
-                       ret = 0;
+               if (ip_to < ip)
+                       swap(ip, ip_to);
+               if (ip + UINT_MAX == ip_to)
+                       return -IPSET_ERR_HASH_RANGE;
+       } else {
+               ip_set_mask_from_to(ip, ip_to, data.cidr);
+       }
+
+       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);
+               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;
 }
@@ -350,33 +383,42 @@ nla_put_failure:
 #define HOST_MASK      128
 #include "ip_set_ahash.h"
 
+static inline void
+hash_netport6_data_next(struct ip_set_hash *h,
+                       const struct hash_netport6_elem *d)
+{
+       h->next.port = ntohs(d->port);
+}
+
 static int
 hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
-                  enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+                  const struct xt_action_param *par,
+                  enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_netport6_elem data = {
-               .cidr = h->nets[0].cidr || HOST_MASK };
+               .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
+       };
 
        if (data.cidr == 0)
                return -EINVAL;
        if (adt == IPSET_TEST)
                data.cidr = HOST_MASK;
 
-       if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
+       if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
                                 &data.port, &data.proto))
                return -EINVAL;
 
-       ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
+       ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
        ip6_netmask(&data.ip, data.cidr);
 
-       return adtfn(set, &data, h->timeout, flags);
+       return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 }
 
 static int
 hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
-                  enum ipset_adt adt, u32 *lineno, u32 flags)
+                  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        const struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
@@ -391,6 +433,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]);
@@ -438,6 +482,8 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
        if (port > port_to)
                swap(port, port_to);
 
+       if (retried)
+               port = h->next.port;
        for (; port <= port_to; port++) {
                data.port = htons(port);
                ret = adtfn(set, &data, timeout, flags);
@@ -526,7 +572,9 @@ static struct ip_set_type hash_netport_type __read_mostly = {
        .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT,
        .dimension      = IPSET_DIM_TWO,
        .family         = AF_UNSPEC,
-       .revision       = 1,
+       .revision_min   = 0,
+       /*                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 },
@@ -538,6 +586,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 e15f819049e5bebe687c3499b14355f51a8e0a90..5253a529d06039a048756cfdfbc1f3995891771e 100644 (file)
@@ -72,7 +72,8 @@ list_set_expired(const struct list_set *map, u32 id)
 
 static int
 list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
-             enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+             const struct xt_action_param *par,
+             enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 {
        struct list_set *map = set->data;
        struct set_elem *elem;
@@ -87,17 +88,17 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
                        continue;
                switch (adt) {
                case IPSET_TEST:
-                       ret = ip_set_test(elem->id, skb, pf, dim, flags);
+                       ret = ip_set_test(elem->id, skb, par, opt);
                        if (ret > 0)
                                return ret;
                        break;
                case IPSET_ADD:
-                       ret = ip_set_add(elem->id, skb, pf, dim, flags);
+                       ret = ip_set_add(elem->id, skb, par, opt);
                        if (ret == 0)
                                return ret;
                        break;
                case IPSET_DEL:
-                       ret = ip_set_del(elem->id, skb, pf, dim, flags);
+                       ret = ip_set_del(elem->id, skb, par, opt);
                        if (ret == 0)
                                return ret;
                        break;
@@ -218,7 +219,7 @@ cleanup_entries(struct list_set *map)
 
 static int
 list_set_uadt(struct ip_set *set, struct nlattr *tb[],
-             enum ipset_adt adt, u32 *lineno, u32 flags)
+             enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 {
        struct list_set *map = set->data;
        bool with_timeout = with_timeout(map->timeout);
@@ -575,7 +576,8 @@ static struct ip_set_type list_set_type __read_mostly = {
        .features       = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
        .dimension      = IPSET_DIM_ONE,
        .family         = AF_UNSPEC,
-       .revision       = 0,
+       .revision_min   = 0,
+       .revision_max   = 0,
        .create         = list_set_create,
        .create_policy  = {
                [IPSET_ATTR_SIZE]       = { .type = NLA_U32 },
index 9f30c5f2ec1cfcd6f02bb3d76413f4e223402827..bae086af0e44b2c77572881c207df3079081a814 100644 (file)
@@ -22,6 +22,9 @@
 
 #define with_timeout(timeout)  ((timeout) != IPSET_NO_TIMEOUT)
 
+#define opt_timeout(opt, map)  \
+       (with_timeout((opt)->timeout) ? (opt)->timeout : (map)->timeout)
+
 static inline unsigned int
 ip_set_timeout_uget(struct nlattr *tb)
 {
@@ -45,7 +48,7 @@ ip_set_timeout_test(unsigned long timeout)
 {
        return timeout != IPSET_ELEM_UNSET &&
               (timeout == IPSET_ELEM_PERMANENT ||
-               time_after(timeout, jiffies));
+               time_is_after_jiffies(timeout));
 }
 
 static inline bool
@@ -53,7 +56,7 @@ ip_set_timeout_expired(unsigned long timeout)
 {
        return timeout != IPSET_ELEM_UNSET &&
               timeout != IPSET_ELEM_PERMANENT &&
-              time_before(timeout, jiffies);
+              time_is_before_jiffies(timeout);
 }
 
 static inline unsigned long
@@ -64,7 +67,7 @@ ip_set_timeout_set(u32 timeout)
        if (!timeout)
                return IPSET_ELEM_PERMANENT;
 
-       t = timeout * HZ + jiffies;
+       t = msecs_to_jiffies(timeout * 1000) + jiffies;
        if (t == IPSET_ELEM_UNSET || t == IPSET_ELEM_PERMANENT)
                /* Bingo! */
                t++;
@@ -75,7 +78,8 @@ ip_set_timeout_set(u32 timeout)
 static inline u32
 ip_set_timeout_get(unsigned long timeout)
 {
-       return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ;
+       return timeout == IPSET_ELEM_PERMANENT ? 0 : 
+               jiffies_to_msecs(timeout - jiffies)/1000;
 }
 
 #else
@@ -89,14 +93,14 @@ static inline bool
 ip_set_timeout_test(unsigned long timeout)
 {
        return timeout == IPSET_ELEM_PERMANENT ||
-              time_after(timeout, jiffies);
+              time_is_after_jiffies(timeout);
 }
 
 static inline bool
 ip_set_timeout_expired(unsigned long timeout)
 {
        return timeout != IPSET_ELEM_PERMANENT &&
-              time_before(timeout, jiffies);
+              time_is_before_jiffies(timeout);
 }
 
 static inline unsigned long
@@ -107,7 +111,7 @@ ip_set_timeout_set(u32 timeout)
        if (!timeout)
                return IPSET_ELEM_PERMANENT;
 
-       t = timeout * HZ + jiffies;
+       t = msecs_to_jiffies(timeout * 1000) + jiffies;
        if (t == IPSET_ELEM_PERMANENT)
                /* Bingo! :-) */
                t++;
@@ -118,7 +122,8 @@ ip_set_timeout_set(u32 timeout)
 static inline u32
 ip_set_timeout_get(unsigned long timeout)
 {
-       return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ;
+       return timeout == IPSET_ELEM_PERMANENT ? 0 :
+               jiffies_to_msecs(timeout - jiffies)/1000;
 }
 #endif /* ! IP_SET_BITMAP_TIMEOUT */
 
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:
diff --git a/extensions/ipset-6/libipset/debug.c b/extensions/ipset-6/libipset/debug.c
new file mode 100644 (file)
index 0000000..174567d
--- /dev/null
@@ -0,0 +1,268 @@
+/* Copyright 2011 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
+ *
+ * This program is free software; you can redistribute it and/or modify   
+ * it under the terms of the GNU General Public License version 2 as 
+ * published by the Free Software Foundation.
+ */
+
+#include <arpa/inet.h>                                 /* inet_ntop */
+#include <libmnl/libmnl.h>                             /* libmnl backend */
+
+struct ipset_attrname {
+       const char *name;
+};
+
+static const struct ipset_attrname cmdattr2name[] = {
+       [IPSET_ATTR_PROTOCOL]   = { .name = "PROTOCOL" },
+       [IPSET_ATTR_SETNAME]    = { .name = "SETNAME" },
+       [IPSET_ATTR_TYPENAME]   = { .name = "TYPENAME" },
+       [IPSET_ATTR_REVISION]   = { .name = "REVISION" },
+       [IPSET_ATTR_FAMILY]     = { .name = "FAMILY" },
+       [IPSET_ATTR_FLAGS]      = { .name = "FLAGS" },
+       [IPSET_ATTR_DATA]       = { .name = "DATA" },
+       [IPSET_ATTR_ADT]        = { .name = "ADT" },
+       [IPSET_ATTR_LINENO]     = { .name = "LINENO" },
+       [IPSET_ATTR_PROTOCOL_MIN] = { .name = "PROTO_MIN" },
+};
+
+static const struct ipset_attrname createattr2name[] = {
+       [IPSET_ATTR_IP]         = { .name = "IP" },
+       [IPSET_ATTR_IP_TO]      = { .name = "IP_TO" },
+       [IPSET_ATTR_CIDR]       = { .name = "CIDR" },
+       [IPSET_ATTR_PORT]       = { .name = "PORT" },
+       [IPSET_ATTR_PORT_TO]    = { .name = "PORT_TO" },
+       [IPSET_ATTR_TIMEOUT]    = { .name = "TIMEOUT" },
+       [IPSET_ATTR_PROTO]      = { .name = "PROTO" },
+       [IPSET_ATTR_CADT_FLAGS] = { .name = "CADT_FLAGS" },
+       [IPSET_ATTR_CADT_LINENO] = { .name = "CADT_LINENO" },
+       [IPSET_ATTR_GC]         = { .name = "GC" },
+       [IPSET_ATTR_HASHSIZE]   = { .name = "HASHSIZE" },
+       [IPSET_ATTR_MAXELEM]    = { .name = "MAXELEM" },
+       [IPSET_ATTR_NETMASK]    = { .name = "NETMASK" },
+       [IPSET_ATTR_PROBES]     = { .name = "PROBES" },
+       [IPSET_ATTR_RESIZE]     = { .name = "RESIZE" },
+       [IPSET_ATTR_SIZE]       = { .name = "SIZE" },
+       [IPSET_ATTR_ELEMENTS]   = { .name = "ELEMENTS" },
+       [IPSET_ATTR_REFERENCES] = { .name = "REFERENCES" },
+       [IPSET_ATTR_MEMSIZE]    = { .name = "MEMSIZE" },
+};
+
+static const struct ipset_attrname adtattr2name[] = {
+       [IPSET_ATTR_IP]         = { .name = "IP" },
+       [IPSET_ATTR_IP_TO]      = { .name = "IP_TO" },
+       [IPSET_ATTR_CIDR]       = { .name = "CIDR" },
+       [IPSET_ATTR_PORT]       = { .name = "PORT" },
+       [IPSET_ATTR_PORT_TO]    = { .name = "PORT_TO" },
+       [IPSET_ATTR_TIMEOUT]    = { .name = "TIMEOUT" },
+       [IPSET_ATTR_PROTO]      = { .name = "PROTO" },
+       [IPSET_ATTR_CADT_FLAGS] = { .name = "CADT_FLAGS" },
+       [IPSET_ATTR_CADT_LINENO] = { .name = "CADT_LINENO" },
+       [IPSET_ATTR_ETHER]      = { .name = "ETHER" },
+       [IPSET_ATTR_NAME]       = { .name = "NAME" },
+       [IPSET_ATTR_NAMEREF]    = { .name = "NAMEREF" },
+       [IPSET_ATTR_IP2]        = { .name = "IP2" },
+       [IPSET_ATTR_CIDR2]      = { .name = "CIDR2" },
+       [IPSET_ATTR_IP2_TO]     = { .name = "IP2_TO" },
+};
+
+static void
+debug_cadt_attrs(int max, const struct ipset_attr_policy *policy,
+                const struct ipset_attrname attr2name[],
+                struct nlattr *nla[])
+{
+       uint32_t v;
+       int i;
+
+       fprintf(stderr,"\t\t%s attributes:\n", policy == create_attrs ? "CREATE" : "ADT");
+       for (i = IPSET_ATTR_UNSPEC + 1; i <= max; i++) {
+               if (!nla[i])
+                       continue;
+               switch (policy[i].type) {
+               case MNL_TYPE_U8:
+                       v = * (uint8_t *) mnl_attr_get_payload(nla[i]);
+                       fprintf(stderr, "\t\t%s: %u\n",
+                               attr2name[i].name, v);
+                       break;
+               case MNL_TYPE_U16:
+                       v = * (uint16_t *) mnl_attr_get_payload(nla[i]);
+                       fprintf(stderr, "\t\t%s: %u\n",
+                               attr2name[i].name, ntohs(v));
+                       break;
+               case MNL_TYPE_U32:
+                       v = * (uint32_t *) mnl_attr_get_payload(nla[i]);
+                       fprintf(stderr, "\t\t%s: %u\n",
+                               attr2name[i].name, ntohl(v));
+                       break;
+               case MNL_TYPE_NUL_STRING:
+                       fprintf(stderr, "\t\t%s: %s\n",
+                               attr2name[i].name,
+                               (const char *) mnl_attr_get_payload(nla[i]));
+                       break;
+               case MNL_TYPE_NESTED: {
+                       struct nlattr *ipattr[IPSET_ATTR_IPADDR_MAX+1] = {};
+                       char addr[INET6_ADDRSTRLEN];
+                       void *d;
+
+                       if (mnl_attr_parse_nested(nla[i], ipaddr_attr_cb, ipattr) < 0) {
+                               fprintf(stderr, "\t\tIPADDR: cannot validate and parse attributes\n");
+                               continue;
+                       }
+                       if (ipattr[IPSET_ATTR_IPADDR_IPV4]) {
+                               d = mnl_attr_get_payload(ipattr[IPSET_ATTR_IPADDR_IPV4]);
+
+                               inet_ntop(AF_INET, d, addr, INET6_ADDRSTRLEN);
+                               fprintf(stderr, "\t\t%s: %s\n",
+                                       attr2name[i].name, addr);
+                       } else if (ipattr[IPSET_ATTR_IPADDR_IPV6]) {
+                               d = mnl_attr_get_payload(ipattr[IPSET_ATTR_IPADDR_IPV6]);
+
+                               inet_ntop(AF_INET6, d, addr, INET6_ADDRSTRLEN);
+                               fprintf(stderr, "\t\t%s: %s\n",
+                                       attr2name[i].name, addr);
+                       }
+                       break;
+               }
+               default:
+                       fprintf(stderr, "\t\t%s: unresolved!\n",
+                               attr2name[i].name);
+               }
+       }
+}
+
+static void
+debug_cmd_attrs(int cmd, struct nlattr *nla[])
+{
+       struct nlattr *adt[IPSET_ATTR_ADT_MAX+1] = {};
+       struct nlattr *cattr[IPSET_ATTR_CREATE_MAX+1] = {};
+       uint32_t v;
+       int i;
+
+       fprintf(stderr,"\tCommand attributes:\n");
+       for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_CMD_MAX; i++) {
+               if (!nla[i])
+                       continue;
+               switch (cmd_attrs[i].type) {
+               case MNL_TYPE_U8:
+                       v = * (uint8_t *) mnl_attr_get_payload(nla[i]);
+                       fprintf(stderr, "\t%s: %u\n",
+                               cmdattr2name[i].name, v);
+                       break;
+               case MNL_TYPE_U16:
+                       v = * (uint16_t *) mnl_attr_get_payload(nla[i]);
+                       fprintf(stderr, "\t%s: %u\n",
+                               cmdattr2name[i].name, ntohs(v));
+                       break;
+               case MNL_TYPE_U32:
+                       v = * (uint32_t *) mnl_attr_get_payload(nla[i]);
+                       fprintf(stderr, "\t%s: %u\n",
+                               cmdattr2name[i].name, ntohl(v));
+                       break;
+               case MNL_TYPE_NUL_STRING:
+                       fprintf(stderr, "\t%s: %s\n",
+                               cmdattr2name[i].name,
+                               (const char *) mnl_attr_get_payload(nla[i]));
+                       break;
+               case MNL_TYPE_NESTED:
+                       if (i == IPSET_ATTR_DATA) {
+                               switch (cmd) {
+                               case IPSET_CMD_ADD:
+                               case IPSET_CMD_DEL:
+                               case IPSET_CMD_TEST:
+                                       if (mnl_attr_parse_nested(nla[i], adt_attr_cb, adt) < 0) {
+                                               fprintf(stderr, "\tADT: cannot validate and parse attributes\n");
+                                               continue;
+                                       }
+                                       debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
+                                                        adt_attrs,
+                                                        adtattr2name,
+                                                        adt);
+                                       break;
+                               default:
+                                       if (mnl_attr_parse_nested(nla[i], create_attr_cb, cattr) < 0) {
+                                               fprintf(stderr, "\tCREATE: cannot validate and parse attributes\n");
+                                               continue;
+                                       }
+                                       debug_cadt_attrs(IPSET_ATTR_CREATE_MAX,
+                                                        create_attrs,
+                                                        createattr2name,
+                                                        cattr);
+                               }
+                       } else {
+                               struct nlattr *tb;
+                               mnl_attr_for_each_nested(tb, nla[i]) {
+                                       memset(adt, 0, sizeof(adt));
+                                       if (mnl_attr_parse_nested(tb, adt_attr_cb, adt) < 0) {
+                                               fprintf(stderr, "\tADT: cannot validate and parse attributes\n");
+                                               continue;
+                                       }
+                                       debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
+                                                        adt_attrs,
+                                                        adtattr2name,
+                                                        adt);
+                               }               
+                       }
+                       break;
+               default:
+                       fprintf(stderr, "\t%s: unresolved!\n",
+                               cmdattr2name[i].name);
+               }
+       }
+}
+
+void
+ipset_debug_msg(const char *dir, void *buffer, int len)
+{
+       const struct nlmsghdr *nlh = buffer;
+       struct nlattr *nla[IPSET_ATTR_CMD_MAX+1] = {};
+       int cmd, nfmsglen = MNL_ALIGN(sizeof(struct nfgenmsg));
+
+       debug = 0;
+       while (mnl_nlmsg_ok(nlh, len)) {
+               switch (nlh->nlmsg_type) {
+               case NLMSG_NOOP:
+               case NLMSG_DONE:
+               case NLMSG_OVERRUN:
+                       fprintf(stderr, "Message header: %s msg %s\n"
+                                       "\tlen %d\n"
+                                       "\tseq  %u\n",
+                               dir,
+                               nlh->nlmsg_type == NLMSG_NOOP ? "NOOP" : 
+                               nlh->nlmsg_type == NLMSG_DONE ? "DONE" : "OVERRUN",
+                               len, nlh->nlmsg_seq);
+                       goto next_msg;
+               case NLMSG_ERROR: {
+                       const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
+                       fprintf(stderr, "Message header: %s msg ERROR\n"
+                                       "\tlen %d\n"
+                                       "\terrcode %d\n"
+                                       "\tseq %u\n",
+                               dir, len, err->error, nlh->nlmsg_seq);
+                       goto next_msg;
+                       }
+               default:
+                       ;
+               }
+               cmd = ipset_get_nlmsg_type(nlh);
+               fprintf(stderr, "Message header: %s cmd  %s (%d)\n"
+                               "\tlen %d\n"
+                               "\tflag %s\n"
+                               "\tseq %u\n",
+                       dir,
+                       cmd <= IPSET_CMD_NONE ? "NONE!" :
+                       cmd >= IPSET_CMD_MAX ? "MAX!" : cmd2name[cmd], cmd,
+                       len,
+                       !(nlh->nlmsg_flags & NLM_F_EXCL) ? "EXIST" : "none",
+                       nlh->nlmsg_seq);
+               if (cmd <= IPSET_CMD_NONE || cmd >= IPSET_CMD_MAX)
+                       goto next_msg;
+               memset(nla, 0, sizeof(nla));
+               if (mnl_attr_parse(nlh, nfmsglen, cmd_attr_cb, nla) < MNL_CB_STOP) {
+                       fprintf(stderr, "\tcannot validate and parse attributes\n");
+                       goto next_msg;
+               }
+               debug_cmd_attrs(cmd, nla);
+next_msg:
+               nlh = mnl_nlmsg_next(nlh, &len);
+       }
+       debug = 1;
+}
index 91a5ee406bd295f2424b08147dc7aa8fcd2558ca..646a5cd334b374a2b562923043fcd7f909f1aa76 100644 (file)
@@ -83,7 +83,6 @@ ipset_mnl_fill_hdr(struct ipset_handle *handle, enum ipset_cmd cmd,
        nlh->nlmsg_flags = NLM_F_REQUEST;
        if (cmdflags[cmd-1] & NLM_F_ACK)
                nlh->nlmsg_flags |= NLM_F_ACK;
-       nlh->nlmsg_seq = ++handle->seq;
 
        ghdr = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
        ghdr->cmd = cmd;
@@ -102,19 +101,24 @@ ipset_mnl_query(struct ipset_handle *handle, void *buffer, size_t len)
        assert(handle);
        assert(buffer);
 
+       nlh->nlmsg_seq = ++handle->seq;
+#ifdef IPSET_DEBUG
+       ipset_debug_msg("sent", nlh, nlh->nlmsg_len);
+#endif
        if (mnl_socket_sendto(handle->h, nlh, nlh->nlmsg_len) < 0)
                return -ECOMM;
 
-       D("message sent");
        ret = mnl_socket_recvfrom(handle->h, buffer, len);
-       D("message received, ret: %d", ret);
+#ifdef IPSET_DEBUG
+       ipset_debug_msg("received", buffer, ret);
+#endif
        while (ret > 0) {
                ret = mnl_cb_run2(buffer, ret,
                                  handle->seq, handle->portid,
                                  handle->cb_ctl[NLMSG_MIN_TYPE],
                                  handle->data,
                                  handle->cb_ctl, NLMSG_MIN_TYPE);
-               D("nfln_cb_run2, ret: %d", ret);
+               D("nfln_cb_run2, ret: %d, errno %d", ret, errno);
                if (ret <= 0)
                        break;
                ret = mnl_socket_recvfrom(handle->h, buffer, len);
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 5b5eca9ba49e52647eeaf231a47b35c9253e7a34..3a53e596f16d22992d7c4b1b894adb09c9464b30 100644 (file)
@@ -37,6 +37,7 @@ struct ipset_session {
        /* Command state */
        enum ipset_cmd cmd;                     /* Current command */
        uint32_t lineno;                        /* Current lineno in restore mode */
+       uint32_t printed_set;                   /* Printed sets so far */
        char saved_setname[IPSET_MAXNAMELEN];   /* Saved setname */
        const struct ipset_type *saved_type;    /* Saved type */
        struct nlattr *nested[IPSET_NEST_MAX];  /* Pointer to nest levels */
@@ -138,6 +139,8 @@ ipset_envopt_parse(struct ipset_session *session, int opt,
        case IPSET_ENV_QUIET:
        case IPSET_ENV_RESOLVE:
        case IPSET_ENV_EXIST:
+       case IPSET_ENV_LIST_SETNAME:
+       case IPSET_ENV_LIST_HEADER:
                session->envopts |= opt;
                return 0;
        default:
@@ -468,6 +471,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[] = {
@@ -480,6 +487,10 @@ static const struct ipset_attr_policy ipaddr_attrs[] = {
        },
 };
 
+#ifdef IPSET_DEBUG
+static int debug = 1;
+#endif
+
 static int
 generic_data_attr_cb(const struct nlattr *attr, void *data,
                     int attr_max, const struct ipset_attr_policy *policy)
@@ -487,14 +498,14 @@ generic_data_attr_cb(const struct nlattr *attr, void *data,
        const struct nlattr **tb = data;
        int type = mnl_attr_get_type(attr);
        
-       D("attr type: %u, len %u", type, attr->nla_len);
+       IF_D(debug, "attr type: %u, len %u", type, attr->nla_len);
        if (mnl_attr_type_valid(attr, attr_max) < 0) {
-               D("attr type: %u INVALID", type);
+               IF_D(debug, "attr type: %u INVALID", type);
                return MNL_CB_ERROR;
        }
        if (mnl_attr_validate(attr, policy[type].type) < 0) {
-               D("attr type: %u POLICY, attrlen %u", type,
-                 mnl_attr_get_payload_len(attr));
+               IF_D(debug, "attr type: %u POLICY, attrlen %u", type,
+                    mnl_attr_get_payload_len(attr));
                return MNL_CB_ERROR;
        }
        if (policy[type].type == MNL_TYPE_NUL_STRING
@@ -829,8 +840,9 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
                              type->name);
                break;
        case IPSET_LIST_PLAIN:
-               safe_snprintf(session, "Name: %s\n"
+               safe_snprintf(session, "%sName: %s\n"
                              "Type: %s\nHeader: ",
+                             session->printed_set ? "\n" : "",
                              ipset_data_setname(data),
                              type->name);
                break;
@@ -887,18 +899,24 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
                safe_dprintf(session, ipset_print_number, IPSET_OPT_MEMSIZE);
                safe_snprintf(session, "\nReferences: ");
                safe_dprintf(session, ipset_print_number, IPSET_OPT_REFERENCES);
-               safe_snprintf(session, "\nMembers:\n");
+               safe_snprintf(session,
+                       session->envopts & IPSET_ENV_LIST_HEADER ?
+                       "\n" : "\nMembers:\n");
                break;
        case IPSET_LIST_XML:
-               safe_snprintf(session, "</elements>\n    <memsize>");
+               safe_snprintf(session, "    <memsize>");
                safe_dprintf(session, ipset_print_number, IPSET_OPT_MEMSIZE);
                safe_snprintf(session, "</memsize>\n    <references>");
                safe_dprintf(session, ipset_print_number, IPSET_OPT_REFERENCES);
-               safe_snprintf(session, "</references>\n  </header>\n  <members>\n");
+               safe_snprintf(session,
+                       session->envopts & IPSET_ENV_LIST_HEADER ?
+                       "</references>\n  </header>\n" :
+                       "</references>\n  </header>\n  <members>\n");
                break;
        default:
                break;
        }
+       session->printed_set++;
 
        return MNL_CB_OK;
 }
@@ -910,16 +928,17 @@ print_set_done(struct ipset_session *session)
                ? "NONE" : session->saved_setname);
        switch (session->mode) {
        case IPSET_LIST_XML:
-               if (session->saved_setname[0] == '\0')
-                       safe_snprintf(session, "\n");
-               else
+               if (session->envopts & IPSET_ENV_LIST_SETNAME)
+                       break;
+               if (session->envopts & IPSET_ENV_LIST_HEADER) {
+                       if (session->saved_setname[0] != '\0')
+                               safe_snprintf(session, "</ipset>\n");
+                       break;
+               }
+               if (session->saved_setname[0] != '\0')
                        safe_snprintf(session, "  </members>\n</ipset>\n");
                break;
-       case IPSET_LIST_SAVE:
-               /* No empty lines between the sets */
-               break;
        default:
-               safe_snprintf(session, "\n");
                break;
        }
        return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_STOP;
@@ -931,8 +950,11 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
 {
        struct ipset_data *data = session->data;
 
-       if (setjmp(printf_failure))
+       if (setjmp(printf_failure)) {
+               session->saved_setname[0] = '\0';
+               session->printed_set = 0;
                return MNL_CB_ERROR;
+       }
 
        if (!nla[IPSET_ATTR_SETNAME])
                FAILURE("Broken %s kernel message: missing setname!",
@@ -940,6 +962,17 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
 
        ATTR2DATA(session, nla, IPSET_ATTR_SETNAME, cmd_attrs);
        D("setname %s", ipset_data_setname(data));
+       if (session->envopts & IPSET_ENV_LIST_SETNAME &&
+           session->mode != IPSET_LIST_SAVE) {
+               if (session->mode == IPSET_LIST_XML)
+                       safe_snprintf(session, "<ipset name=\"%s\"/>\n",
+                                     ipset_data_setname(data));
+               else
+                       safe_snprintf(session, "%s\n",
+                                     ipset_data_setname(data));
+               return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_OK;
+       }
+
        if (STREQ(ipset_data_setname(data), session->saved_setname)) {
                /* Header part already seen */
                if (ipset_data_test(data, IPSET_OPT_TYPE)
@@ -1422,6 +1455,9 @@ rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
                return 1;
 
        switch (attr->type) {
+       case MNL_TYPE_NUL_STRING:
+               alen = strlen((const char *)d) + 1;
+               break;
        case MNL_TYPE_U32: {
                uint32_t value = htonl(*(const uint32_t *)d);
                
@@ -1497,7 +1533,7 @@ addattr_adt(struct ipset_session *session,
 static int
 build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
 {
-       char buffer[PRIVATE_MSG_BUFLEN] __attribute__ ((aligned));
+       char buffer[PRIVATE_MSG_BUFLEN] __attribute__ ((aligned)) = {};
        struct nlmsghdr *nlh = (void *)buffer;
        struct ipset_data *data = session->data;
        int len = PRIVATE_MSG_BUFLEN, ret;
@@ -1592,7 +1628,12 @@ build_msg(struct ipset_session *session, bool aggregate)
                            IPSET_ATTR_REVISION, cmd_attrs);
                D("family: %u, type family %u",
                  ipset_data_family(data), type->family);
-               ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY, AF_INET, cmd_attrs);
+               if (ipset_data_test(data, IPSET_OPT_FAMILY))
+                       ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY,
+                               AF_INET, cmd_attrs);
+               else
+                       /* bitmap:port and list:set types */
+                       mnl_attr_put_u8(nlh, IPSET_ATTR_FAMILY, AF_UNSPEC);
 
                /* Type-specific create attributes */
                D("call open_nested");
@@ -1604,11 +1645,26 @@ build_msg(struct ipset_session *session, bool aggregate)
        }
        case IPSET_CMD_DESTROY:
        case IPSET_CMD_FLUSH:
-       case IPSET_CMD_LIST:
        case IPSET_CMD_SAVE:
                if (ipset_data_test(data, IPSET_SETNAME))
                        ADDATTR_SETNAME(session, nlh, data);
                break;
+       case IPSET_CMD_LIST: {
+               uint32_t flags = 0;
+               
+               if (session->envopts & IPSET_ENV_LIST_SETNAME)
+                       flags |= IPSET_FLAG_LIST_SETNAME;
+               if (session->envopts & IPSET_ENV_LIST_HEADER)
+                       flags |= IPSET_FLAG_LIST_HEADER;
+               if (ipset_data_test(data, IPSET_SETNAME))
+                       ADDATTR_SETNAME(session, nlh, data);
+               if (flags && session->mode != IPSET_LIST_SAVE) {
+                       ipset_data_set(data, IPSET_OPT_FLAGS, &flags);
+                       ADDATTR(session, nlh, data, IPSET_ATTR_FLAGS, AF_INET,
+                               cmd_attrs);
+               }
+               break;
+       }
        case IPSET_CMD_RENAME:
        case IPSET_CMD_SWAP:
                if (!ipset_data_test(data, IPSET_SETNAME))
@@ -1729,6 +1785,7 @@ ipset_commit(struct ipset_session *session)
 
        /* Reset saved data and nested state */
        session->saved_setname[0] = '\0';
+       session->printed_set = 0;
        for (i = session->nestid - 1; i >= 0; i--)
                session->nested[i] = NULL;
        session->nestid = 0;
@@ -1926,3 +1983,7 @@ ipset_session_fini(struct ipset_session *session)
        free(session);
        return 0;
 }
+
+#ifdef IPSET_DEBUG
+#include "debug.c"
+#endif
index 402e726def09cdd53e868f21061cf6c57dfa8461..c440993408124a770d67cb3c808c5b0fe3304d9a 100644 (file)
@@ -267,6 +267,19 @@ create_type_get(struct ipset_session *session)
                                kmax, tmin);
        }
        
+       /* Disable unsupported revisions */
+       for (match = NULL, t = typelist; t != NULL; t = t->next) {
+               /* Skip revisions which are unsupported by the kernel */
+               if (t->kernel_check == IPSET_KERNEL_MISMATCH)
+                       continue;
+               if (ipset_match_typename(typename, t)
+                   && MATCH_FAMILY(t, family)) {
+                       if (t->revision < kmin || t->revision > kmax)
+                               t->kernel_check = IPSET_KERNEL_MISMATCH;
+                       else if (match == NULL)
+                               match = t;
+               }       
+       }
        match->kernel_check = IPSET_KERNEL_OK;
 found:
        ipset_data_set(data, IPSET_OPT_TYPE, match);
index e9c0764df9ee9d06dabe2e18017b43d06ef73e63..5750cf5bf324d5a69f0e50edbe5736731f924011 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 0e1fb50da562914a794d4cb9f02f32132b4f0e41..d55a6ccf662e0b20441e9c04bb6efe04a8d63917 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,12 @@ 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);
+
+#define ip_set_mask_from_to(from, to, cidr)    \
+do {                                           \
+       from &= ip_set_hostmask(cidr);          \
+       to = from | ~ip_set_hostmask(cidr);     \
+} while (0)
+
 #endif /*_PFXLEN_H */
diff --git a/extensions/ipset-6/slist.h b/extensions/ipset-6/slist.h
deleted file mode 100644 (file)
index e472e43..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef _IP_SET_SLIST_H
-#define _IP_SET_SLIST_H
-
-#include <linux/stddef.h>
-#include <linux/prefetch.h>
-#include <asm/system.h>
-
-/*
- * Single linked lists with a single pointer.
- * Mostly useful for hash tables where the two pointer list head
- * and list node is too wasteful.
- */
-
-struct slist {
-       struct slist *next;
-};
-
-#define SLIST(name) struct slist name = {  .next = NULL }
-#define INIT_SLIST(ptr) ((ptr)->next = NULL)
-
-#define slist_entry(ptr, type, member) container_of(ptr, type, member)
-
-#define slist_for_each(pos, head) \
-       for (pos = (head)->next; pos && ({ prefetch(pos->next); 1; }); \
-            pos = pos->next)
-
-#define slist_for_each_prev(prev, pos, head) \
-       for (prev = head, pos = (head)->next; \
-            pos && ({ prefetch(pos->next); 1; }); \
-            prev = pos, pos = pos->next)
-
-#define slist_for_each_safe(pos, n, head) \
-       for (pos = (head)->next; pos && ({ n = pos->next; 1; }); \
-            pos = n)
-
-/**
- * slist_for_each_entry        - iterate over list of given type
- * @tpos:      the type * to use as a loop cursor.
- * @pos:       the &struct slist to use as a loop cursor.
- * @head:      the head for your list.
- * @member:    the name of the slist within the struct.
- */
-#define slist_for_each_entry(tpos, pos, head, member)                   \
-       for (pos = (head)->next;                                         \
-            pos && ({ prefetch(pos->next); 1; }) &&                     \
-               ({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
-            pos = pos->next)
-
-/**
- * slist_for_each_entry_continue - iterate over a hlist continuing
- *                                after current point
- * @tpos:      the type * to use as a loop cursor.
- * @pos:       the &struct slist to use as a loop cursor.
- * @member:    the name of the slist within the struct.
- */
-#define slist_for_each_entry_continue(tpos, pos, member)                \
-       for (pos = (pos)->next;                                          \
-            pos && ({ prefetch(pos->next); 1; }) &&                     \
-               ({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
-            pos = pos->next)
-
-/**
- * slist_for_each_entry_from - iterate over a hlist continuing
- *                            from current point
- * @tpos:      the type * to use as a loop cursor.
- * @pos:       the &struct slist to use as a loop cursor.
- * @member:    the name of the slist within the struct.
- */
-#define slist_for_each_entry_from(tpos, pos, member)                    \
-       for (; pos && ({ prefetch(pos->next); 1; }) &&                   \
-               ({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
-            pos = pos->next)
-
-/**
- * slist_for_each_entry_safe - iterate over list of given type safe against
- *                            removal of list entry
- * @tpos:      the type * to use as a loop cursor.
- * @pos:       the &struct slist to use as a loop cursor.
- * @n:         another &struct slist to use as temporary storage
- * @head:      the head for your list.
- * @member:    the name of the slist within the struct.
- */
-#define slist_for_each_entry_safe(tpos, pos, n, head, member)          \
-       for (pos = (head)->next;                                        \
-            pos && ({ n = pos->next; 1; }) &&                          \
-               ({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
-            pos = n)
-
-#endif /* _IP_SET_SLIST_H */
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 d9e5ff8e902f8e4e2b722456101a2f71e2456e17..90914f432ed67f3be54c47152877b258b2f32139 100644 (file)
@@ -21,7 +21,7 @@ ipset \(em administration tool for IP sets
 .PP 
 COMMANDS := { \fBcreate\fR | \fBadd\fR | \fBdel\fR | \fBtest\fR | \fBdestroy\fR | \fBlist\fR | \fBsave\fR | \fBrestore\fR | \fBflush\fR | \fBrename\fR | \fBswap\fR | \fBhelp\fR | \fBversion\fR | \fB\-\fR }
 .PP 
-\fIOPTIONS\fR := { \fB\-exist\fR | \fB\-output\fR { \fBplain\fR | \fBsave\fR | \fBxml\fR } | \fB\-quiet\fR | \fB\-resolve\fR | \fB\-sorted\fR }
+\fIOPTIONS\fR := { \fB\-exist\fR | \fB\-output\fR { \fBplain\fR | \fBsave\fR | \fBxml\fR } | \fB\-quiet\fR | \fB\-resolve\fR | \fB\-sorted\fR | \fB\-name\fR | \fB\-terse\fR }
 .PP 
 \fBipset\fR \fBcreate\fR \fISETNAME\fR \fITYPENAME\fR [ \fICREATE\-OPTIONS\fR ]
 .PP 
@@ -109,7 +109,7 @@ Destroy the specified set or all the sets if none is given.
 
 If the set has got reference(s), nothing is done and no set destroyed.
 .TP 
-\fBlist\fP [ \fISETNAME\fP ]
+\fBlist\fP [ \fISETNAME\fP ] [ \fIOPTIONS\fP ]
 List the header data and the entries for the specified set, or for
 all sets if none is given. The
 \fB\-resolve\fP
@@ -120,8 +120,13 @@ type supports the operation). The option
 \fB\-output\fR
 can be used to control the format of the listing:
 \fBplain\fR, \fBsave\fR or \fBxml\fR.
-The default is
-\fBplain\fR. 
+(The default is
+\fBplain\fR.)
+If the option
+\fB\-name\fR
+is specified, just the names of the existing sets are listed. If the option
+\fB\-terse\fR
+is specified, just the set names and headers are listed. 
 .TP 
 \fBsave\fP [ \fISETNAME\fP ]
 Save the given set, or all sets if none is given
@@ -190,6 +195,13 @@ DNS lookups.
 .TP 
 \fB\-s\fP, \fB\-sorted\fP
 Sorted output. When listing sets entries are listed sorted. Not supported yet.
+.TP 
+\fB\-n\fP, \fB\-name\fP
+List just the names of the existing sets, i.e. suppress listing of set headers and members.
+.TP 
+\fB\-t\fP, \fB\-terse\fP
+List the set names and headers, i.e. suppress listing of set members.
+
 .SH "SET TYPES"
 A set type comprises of the storage method by which the data is stored and
 the data type(s) which are stored in the set. Therefore the
@@ -202,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
@@ -397,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 
@@ -419,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.
@@ -527,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 := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
 .PP 
-\fITEST\-ENTRY\fR := \fIipaddr\fR[/\fIcidr\fR],[\fIproto\fR:]\fIport\fR
+where
+\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
 .PP 
 Optional \fBcreate\fR options:
 .TP 
@@ -549,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.
@@ -633,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..371d8515b06ac28e2cbdc6e28ba888e255271b7b 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 {
@@ -145,9 +148,9 @@ build_argv(char *buffer)
                newargv[i] = NULL;
        newargc = 1;
 
-       ptr = strtok(buffer, " \t\n");
+       ptr = strtok(buffer, " \t\r\n");
        newargv[newargc++] = ptr;
-       while ((ptr = strtok(NULL, " \t\n")) != NULL) {
+       while ((ptr = strtok(NULL, " \t\r\n")) != NULL) {
                if ((newargc + 1) < (int)(sizeof(newargv)/sizeof(char *)))
                        newargv[newargc++] = ptr;
                else {
@@ -181,7 +184,7 @@ restore(char *argv0)
                        c++;
                if (c[0] == '\0' || c[0] == '#')
                        continue;
-               else if (strcmp(c, "COMMIT\n") == 0) {
+               else if (STREQ(c, "COMMIT\n") || STREQ(c, "COMMIT\r\n")) {
                        ret = ipset_commit(session);
                        if (ret < 0)
                                handle_error();
@@ -715,16 +718,21 @@ parse_commandline(int argc, char *argv[])
 int
 main(int argc, char *argv[])
 {
+       int ret;
+
        /* Register types */
        ipset_type_add(&ipset_bitmap_ip0);
        ipset_type_add(&ipset_bitmap_ipmac0);
        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 */
@@ -733,5 +741,9 @@ main(int argc, char *argv[])
                return exit_error(OTHER_PROBLEM,
                        "Cannot initialize ipset session, aborting.");
 
-       return parse_commandline(argc, argv);
+       ret = parse_commandline(argc, argv);
+       
+       ipset_session_fini(session);
+       
+       return ret;
 }
index 0af65b7b5e74a216382d632c2eb07a0352300923..6926644f98fc9aec268bf4277c471c000cb477f1 100644 (file)
@@ -81,7 +81,7 @@ static const char hash_ip_usage[] =
 
 struct ipset_type ipset_hash_ip0 = {
        .name = "hash:ip",
-       .alias = { "iphash", "iptree", "iptreemap", NULL },
+       .alias = { "iphash", NULL },
        .revision = 0,
        .family = AF_INET46,
        .dimension = IPSET_DIM_ONE,
@@ -92,7 +92,6 @@ struct ipset_type ipset_hash_ip0 = {
                        .opt = IPSET_OPT_IP
                },
        },
-       .compat_parse_elem = ipset_parse_iptimeout,
        .args = {
                [IPSET_CREATE] = hash_ip_create_args,
                [IPSET_ADD] = hash_ip_add_args,
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 3601c65b2285175ad986c8b454d86da67ea4eff1..c603c53b367ade32d361e8764e6b67b883c55963 100644 (file)
@@ -188,6 +188,19 @@ const struct ipset_envopts ipset_envopts[] = {
                  "        when adding already existing elements\n"
                  "        or when deleting non-existing elements.",
        },
+       { .name = { "-n", "-name" },
+         .parse = ipset_envopt_parse,
+         .has_arg = IPSET_NO_ARG,      .flag = IPSET_ENV_LIST_SETNAME,
+         .help = "\n"
+                 "        When listing, list just setnames from kernel.\n",
+       },
+       { .name = { "-t", "-terse" },
+         .parse = ipset_envopt_parse,
+         .has_arg = IPSET_NO_ARG,      .flag = IPSET_ENV_LIST_HEADER,
+         .help = "\n"
+                 "        When listing, list setnames and set headers\n"
+                 "        from kernel only.",
+       },
        { },
 };
 
@@ -256,9 +269,9 @@ ipset_port_usage(void)
        const char *name;
 
        printf("      [PROTO:]PORT is a valid pattern of the following:\n"
-              "           PORTNAME         port name from /etc/services\n"
-              "           PORTNUMBER       port number identifier\n"
-              "           tcp|udp:PORTNAME|PORTNUMBER\n"
+              "           PORTNAME         TCP port name from /etc/services\n"
+              "           PORTNUMBER       TCP port number identifier\n"
+              "           tcp|sctp|udp|udplite:PORTNAME|PORTNUMBER\n"
               "           icmp:CODENAME    supported ICMP codename\n"
               "           icmp:TYPE/CODE   ICMP type/code value\n"
               "           icmpv6:CODENAME  supported ICMPv6 codename\n"
index 93de81d2b97a382b7373e42b060da0c0563533bd..0e8e90aa24dbe465d09d07676948df2be14484a3 100644 (file)
@@ -29,52 +29,33 @@ MODULE_ALIAS("ip6t_SET");
 
 static inline int
 match_set(ip_set_id_t index, const struct sk_buff *skb,
-         u8 pf, u8 dim, u8 flags, int inv)
+         const struct xt_action_param *par,
+         const struct ip_set_adt_opt *opt, int inv)
 {
-       if (ip_set_test(index, skb, pf, dim, flags))
+       if (ip_set_test(index, skb, par, opt))
                inv = !inv;
        return inv;
 }
 
-/* Revision 0 interface: backward compatible with netfilter/iptables */
-
-/* Backward compatibility constrains (incomplete):
- *  2.6.24: [NETLINK]: Introduce nested and byteorder flag to netlink attribute
- *  2.6.25: is_vmalloc_addr(): Check if an address is within the vmalloc
- *         boundaries
- *  2.6.27: rcu: split list.h and move rcu-protected lists into rculist.h
- *  2.6.28: netfilter: ctnetlink: remove bogus module dependency between
- *         ctnetlink and nf_nat (nfnl_lock/nfnl_unlock)
- *  2.6.29: generic swap(): introduce global macro swap(a, b)
- *  2.6.31: netfilter: passive OS fingerprint xtables match
- *  2.6.34: rcu: Add lockdep-enabled variants of rcu_dereference()
- */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
-#error "Linux kernel version too old: must be >= 2.6.34"
-#endif
+#define ADT_OPT(n, f, d, fs, cfs, t)   \
+const struct ip_set_adt_opt n = {      \
+       .family = f,                    \
+       .dim = d,                       \
+       .flags = fs,                    \
+       .cmdflags = cfs,                \
+       .timeout = t,                   \
+}
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-#define CHECK_OK       1
-#define CHECK_FAIL(err)        0
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
-#define        CHECK_OK        0
-#define CHECK_FAIL(err)        (err)
-#endif
+/* Revision 0 interface: backward compatible with netfilter/iptables */
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-static bool
-set_match_v0(const struct sk_buff *skb, const struct xt_match_param *par)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
 static bool
 set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
-#endif
 {
        const struct xt_set_info_match_v0 *info = par->matchinfo;
+       ADT_OPT(opt, par->family, info->match_set.u.compat.dim,
+               info->match_set.u.compat.flags, 0, UINT_MAX);
 
-       return match_set(info->match_set.index, skb, par->family,
-                        info->match_set.u.compat.dim,
-                        info->match_set.u.compat.flags,
+       return match_set(info->match_set.index, skb, par, &opt,
                         info->match_set.u.compat.flags & IPSET_INV_MATCH);
 }
 
@@ -94,13 +75,8 @@ compat_flags(struct xt_set_info_v0 *info)
        }
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-static bool
-set_match_v0_checkentry(const struct xt_mtchk_param *par)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
 static int
 set_match_v0_checkentry(const struct xt_mtchk_param *par)
-#endif
 {
        struct xt_set_info_match_v0 *info = par->matchinfo;
        ip_set_id_t index;
@@ -110,19 +86,19 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
        if (index == IPSET_INVALID_ID) {
                pr_warning("Cannot find set indentified by id %u to match\n",
                           info->match_set.index);
-               return CHECK_FAIL(-ENOENT);     /* error */
+               return -ENOENT;
        }
        if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
                pr_warning("Protocol error: set match dimension "
                           "is over the limit!\n");
                ip_set_nfnl_put(info->match_set.index);
-               return CHECK_FAIL(-ERANGE);     /* error */
+               return -ERANGE;
        }
 
        /* Fill out compatibility data */
        compat_flags(&info->match_set);
 
-       return CHECK_OK;
+       return 0;
 }
 
 static void
@@ -133,35 +109,25 @@ set_match_v0_destroy(const struct xt_mtdtor_param *par)
        ip_set_nfnl_put(info->match_set.index);
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-static unsigned int
-set_target_v0(struct sk_buff *skb, const struct xt_target_param *par)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
 static unsigned int
 set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
-#endif
 {
        const struct xt_set_info_target_v0 *info = par->targinfo;
+       ADT_OPT(add_opt, par->family, info->add_set.u.compat.dim,
+               info->add_set.u.compat.flags, 0, UINT_MAX);
+       ADT_OPT(del_opt, par->family, info->del_set.u.compat.dim,
+               info->del_set.u.compat.flags, 0, UINT_MAX);
 
        if (info->add_set.index != IPSET_INVALID_ID)
-               ip_set_add(info->add_set.index, skb, par->family,
-                          info->add_set.u.compat.dim,
-                          info->add_set.u.compat.flags);
+               ip_set_add(info->add_set.index, skb, par, &add_opt);
        if (info->del_set.index != IPSET_INVALID_ID)
-               ip_set_del(info->del_set.index, skb, par->family,
-                          info->del_set.u.compat.dim,
-                          info->del_set.u.compat.flags);
+               ip_set_del(info->del_set.index, skb, par, &del_opt);
 
        return XT_CONTINUE;
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-static bool
-set_target_v0_checkentry(const struct xt_tgchk_param *par)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
 static int
 set_target_v0_checkentry(const struct xt_tgchk_param *par)
-#endif
 {
        struct xt_set_info_target_v0 *info = par->targinfo;
        ip_set_id_t index;
@@ -171,7 +137,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
                if (index == IPSET_INVALID_ID) {
                        pr_warning("Cannot find add_set index %u as target\n",
                                   info->add_set.index);
-                       return CHECK_FAIL(-ENOENT);     /* error */
+                       return -ENOENT;
                }
        }
 
@@ -182,7 +148,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
                                   info->del_set.index);
                        if (info->add_set.index != IPSET_INVALID_ID)
                                ip_set_nfnl_put(info->add_set.index);
-                       return CHECK_FAIL(-ENOENT);     /* error */
+                       return -ENOENT;
                }
        }
        if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
@@ -193,14 +159,14 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
                        ip_set_nfnl_put(info->add_set.index);
                if (info->del_set.index != IPSET_INVALID_ID)
                        ip_set_nfnl_put(info->del_set.index);
-               return CHECK_FAIL(-ERANGE);     /* error */
+               return -ERANGE;
        }
 
        /* Fill out compatibility data */
        compat_flags(&info->add_set);
        compat_flags(&info->del_set);
 
-       return CHECK_OK;
+       return 0;
 }
 
 static void
@@ -214,33 +180,23 @@ set_target_v0_destroy(const struct xt_tgdtor_param *par)
                ip_set_nfnl_put(info->del_set.index);
 }
 
-/* Revision 1: current interface to netfilter/iptables */
+/* Revision 1 match and target */
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-static bool
-set_match(const struct sk_buff *skb, const struct xt_match_param *par)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
 static bool
-set_match(const struct sk_buff *skb, struct xt_action_param *par)
-#endif
+set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
 {
-       const struct xt_set_info_match *info = par->matchinfo;
+       const struct xt_set_info_match_v1 *info = par->matchinfo;
+       ADT_OPT(opt, par->family, info->match_set.dim,
+               info->match_set.flags, 0, UINT_MAX);
 
-       return match_set(info->match_set.index, skb, par->family,
-                        info->match_set.dim,
-                        info->match_set.flags,
+       return match_set(info->match_set.index, skb, par, &opt,
                         info->match_set.flags & IPSET_INV_MATCH);
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-static bool
-set_match_checkentry(const struct xt_mtchk_param *par)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
 static int
-set_match_checkentry(const struct xt_mtchk_param *par)
-#endif
+set_match_v1_checkentry(const struct xt_mtchk_param *par)
 {
-       struct xt_set_info_match *info = par->matchinfo;
+       struct xt_set_info_match_v1 *info = par->matchinfo;
        ip_set_id_t index;
 
        index = ip_set_nfnl_get_byindex(info->match_set.index);
@@ -248,59 +204,47 @@ set_match_checkentry(const struct xt_mtchk_param *par)
        if (index == IPSET_INVALID_ID) {
                pr_warning("Cannot find set indentified by id %u to match\n",
                           info->match_set.index);
-               return CHECK_FAIL(-ENOENT);     /* error */
+               return -ENOENT;
        }
        if (info->match_set.dim > IPSET_DIM_MAX) {
                pr_warning("Protocol error: set match dimension "
                           "is over the limit!\n");
                ip_set_nfnl_put(info->match_set.index);
-               return CHECK_FAIL(-ERANGE);     /* error */
+               return -ERANGE;
        }
 
-       return CHECK_OK;
+       return 0;
 }
 
 static void
-set_match_destroy(const struct xt_mtdtor_param *par)
+set_match_v1_destroy(const struct xt_mtdtor_param *par)
 {
-       struct xt_set_info_match *info = par->matchinfo;
+       struct xt_set_info_match_v1 *info = par->matchinfo;
 
        ip_set_nfnl_put(info->match_set.index);
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-static unsigned int
-set_target(struct sk_buff *skb, const struct xt_target_param *par)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
 static unsigned int
-set_target(struct sk_buff *skb, const struct xt_action_param *par)
-#endif
+set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
 {
-       const struct xt_set_info_target *info = par->targinfo;
+       const struct xt_set_info_target_v1 *info = par->targinfo;
+       ADT_OPT(add_opt, par->family, info->add_set.dim,
+               info->add_set.flags, 0, UINT_MAX);
+       ADT_OPT(del_opt, par->family, info->del_set.dim,
+               info->del_set.flags, 0, UINT_MAX);
 
        if (info->add_set.index != IPSET_INVALID_ID)
-               ip_set_add(info->add_set.index,
-                          skb, par->family,
-                          info->add_set.dim,
-                          info->add_set.flags);
+               ip_set_add(info->add_set.index, skb, par, &add_opt);
        if (info->del_set.index != IPSET_INVALID_ID)
-               ip_set_del(info->del_set.index,
-                          skb, par->family,
-                          info->del_set.dim,
-                          info->del_set.flags);
+               ip_set_del(info->del_set.index, skb, par, &del_opt);
 
        return XT_CONTINUE;
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
-static bool
-set_target_checkentry(const struct xt_tgchk_param *par)
-#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
 static int
-set_target_checkentry(const struct xt_tgchk_param *par)
-#endif
+set_target_v1_checkentry(const struct xt_tgchk_param *par)
 {
-       const struct xt_set_info_target *info = par->targinfo;
+       const struct xt_set_info_target_v1 *info = par->targinfo;
        ip_set_id_t index;
 
        if (info->add_set.index != IPSET_INVALID_ID) {
@@ -308,7 +252,7 @@ set_target_checkentry(const struct xt_tgchk_param *par)
                if (index == IPSET_INVALID_ID) {
                        pr_warning("Cannot find add_set index %u as target\n",
                                   info->add_set.index);
-                       return CHECK_FAIL(-ENOENT);     /* error */
+                       return -ENOENT;
                }
        }
 
@@ -319,7 +263,7 @@ set_target_checkentry(const struct xt_tgchk_param *par)
                                   info->del_set.index);
                        if (info->add_set.index != IPSET_INVALID_ID)
                                ip_set_nfnl_put(info->add_set.index);
-                       return CHECK_FAIL(-ENOENT);     /* error */
+                       return -ENOENT;
                }
        }
        if (info->add_set.dim > IPSET_DIM_MAX ||
@@ -330,16 +274,16 @@ set_target_checkentry(const struct xt_tgchk_param *par)
                        ip_set_nfnl_put(info->add_set.index);
                if (info->del_set.index != IPSET_INVALID_ID)
                        ip_set_nfnl_put(info->del_set.index);
-               return CHECK_FAIL(-ERANGE);     /* error */
+               return -ERANGE;
        }
 
-       return CHECK_OK;
+       return 0;
 }
 
 static void
-set_target_destroy(const struct xt_tgdtor_param *par)
+set_target_v1_destroy(const struct xt_tgdtor_param *par)
 {
-       const struct xt_set_info_target *info = par->targinfo;
+       const struct xt_set_info_target_v1 *info = par->targinfo;
 
        if (info->add_set.index != IPSET_INVALID_ID)
                ip_set_nfnl_put(info->add_set.index);
@@ -347,6 +291,28 @@ set_target_destroy(const struct xt_tgdtor_param *par)
                ip_set_nfnl_put(info->del_set.index);
 }
 
+/* Revision 2 target */
+
+static unsigned int
+set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
+{
+       const struct xt_set_info_target_v2 *info = par->targinfo;
+       ADT_OPT(add_opt, par->family, info->add_set.dim,
+               info->add_set.flags, info->flags, info->timeout);
+       ADT_OPT(del_opt, par->family, info->del_set.dim,
+               info->del_set.flags, 0, UINT_MAX);
+
+       if (info->add_set.index != IPSET_INVALID_ID)
+               ip_set_add(info->add_set.index, skb, par, &add_opt);
+       if (info->del_set.index != IPSET_INVALID_ID)
+               ip_set_del(info->del_set.index, skb, par, &del_opt);
+
+       return XT_CONTINUE;
+}
+
+#define set_target_v2_checkentry       set_target_v1_checkentry
+#define set_target_v2_destroy          set_target_v1_destroy
+
 static struct xt_match set_matches[] __read_mostly = {
        {
                .name           = "set",
@@ -362,20 +328,20 @@ static struct xt_match set_matches[] __read_mostly = {
                .name           = "set",
                .family         = NFPROTO_IPV4,
                .revision       = 1,
-               .match          = set_match,
-               .matchsize      = sizeof(struct xt_set_info_match),
-               .checkentry     = set_match_checkentry,
-               .destroy        = set_match_destroy,
+               .match          = set_match_v1,
+               .matchsize      = sizeof(struct xt_set_info_match_v1),
+               .checkentry     = set_match_v1_checkentry,
+               .destroy        = set_match_v1_destroy,
                .me             = THIS_MODULE
        },
        {
                .name           = "set",
                .family         = NFPROTO_IPV6,
                .revision       = 1,
-               .match          = set_match,
-               .matchsize      = sizeof(struct xt_set_info_match),
-               .checkentry     = set_match_checkentry,
-               .destroy        = set_match_destroy,
+               .match          = set_match_v1,
+               .matchsize      = sizeof(struct xt_set_info_match_v1),
+               .checkentry     = set_match_v1_checkentry,
+               .destroy        = set_match_v1_destroy,
                .me             = THIS_MODULE
        },
 };
@@ -395,20 +361,40 @@ static struct xt_target set_targets[] __read_mostly = {
                .name           = "SET",
                .revision       = 1,
                .family         = NFPROTO_IPV4,
-               .target         = set_target,
-               .targetsize     = sizeof(struct xt_set_info_target),
-               .checkentry     = set_target_checkentry,
-               .destroy        = set_target_destroy,
+               .target         = set_target_v1,
+               .targetsize     = sizeof(struct xt_set_info_target_v1),
+               .checkentry     = set_target_v1_checkentry,
+               .destroy        = set_target_v1_destroy,
                .me             = THIS_MODULE
        },
        {
                .name           = "SET",
                .revision       = 1,
                .family         = NFPROTO_IPV6,
-               .target         = set_target,
-               .targetsize     = sizeof(struct xt_set_info_target),
-               .checkentry     = set_target_checkentry,
-               .destroy        = set_target_destroy,
+               .target         = set_target_v1,
+               .targetsize     = sizeof(struct xt_set_info_target_v1),
+               .checkentry     = set_target_v1_checkentry,
+               .destroy        = set_target_v1_destroy,
+               .me             = THIS_MODULE
+       },
+       {
+               .name           = "SET",
+               .revision       = 2,
+               .family         = NFPROTO_IPV4,
+               .target         = set_target_v2,
+               .targetsize     = sizeof(struct xt_set_info_target_v2),
+               .checkentry     = set_target_v2_checkentry,
+               .destroy        = set_target_v2_destroy,
+               .me             = THIS_MODULE
+       },
+       {
+               .name           = "SET",
+               .revision       = 2,
+               .family         = NFPROTO_IPV6,
+               .target         = set_target_v2,
+               .targetsize     = sizeof(struct xt_set_info_target_v2),
+               .checkentry     = set_target_v2_checkentry,
+               .destroy        = set_target_v2_destroy,
                .me             = THIS_MODULE
        },
 };
index 6d6e04ff40f733f12acbbf5f2bbc5705529c5060..c46eaeedf24b05f071717b0e19bebff90d096ce3 100644 (file)
@@ -35,7 +35,7 @@ struct xt_set_info_target_v0 {
        struct xt_set_info_v0 del_set;
 };
 
-/* Revision 1: current interface to netfilter/iptables */
+/* Revision 1  match and target */
 
 struct xt_set_info {
        ip_set_id_t index;
@@ -44,13 +44,22 @@ struct xt_set_info {
 };
 
 /* match and target infos */
-struct xt_set_info_match {
+struct xt_set_info_match_v1 {
        struct xt_set_info match_set;
 };
 
-struct xt_set_info_target {
+struct xt_set_info_target_v1 {
        struct xt_set_info add_set;
        struct xt_set_info del_set;
 };
 
+/* Revision 2 target */
+
+struct xt_set_info_target_v2 {
+       struct xt_set_info add_set;
+       struct xt_set_info del_set;
+       u32 flags;
+       u32 timeout;
+};
+
 #endif /*_XT_SET_H*/