]> Pileus Git - ~andy/linux/blobdiff - net/netfilter/ipset/ip_set_hash_net.c
netfilter: ipset: add xt_action_param to the variant level kadt functions, ipset...
[~andy/linux] / net / netfilter / ipset / ip_set_hash_net.c
index c4db202b7da4bcaefc22e9c637e3a242233c5c9e..dcbb5d4c636c1dcbcaa426663ad14f8b474b974a 100644 (file)
@@ -125,9 +125,17 @@ nla_put_failure:
 #define HOST_MASK      32
 #include <linux/netfilter/ipset/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];
@@ -138,20 +146,21 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
        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);
+       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 +170,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);
-
-       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,9 +323,16 @@ nla_put_failure:
 #define HOST_MASK      128
 #include <linux/netfilter/ipset/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];
@@ -303,15 +343,15 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
        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);
+       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 +362,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]);
@@ -344,7 +386,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       ret = adtfn(set, &data, timeout);
+       ret = adtfn(set, &data, timeout, flags);
 
        return ip_set_eexist(ret, flags) ? 0 : ret;
 }
@@ -425,7 +467,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 +479,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 },
        },