Merge to Fedora kernel-2.6.18-1.2260_FC5 patched with stable patch-2.6.18.5-vs2.0...
[linux-2.6.git] / net / ipv4 / netfilter / ip_set_nethash.c
index b78988f..8d5e9f6 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/netfilter_ipv4/ip_set_nethash.h>
 #include <linux/netfilter_ipv4/ip_set_jhash.h>
 
+static int limit = MAX_RANGE;
+
 static inline __u32
 jhash_ip(const struct ip_set_nethash *map, uint16_t i, ip_set_ip_t ip)
 {
@@ -74,13 +76,13 @@ __testip_cidr(struct ip_set *set, ip_set_ip_t ip, unsigned char cidr,
 {
        struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
 
-       return (hash_id_cidr(map, ip, cidr, hash_ip) != UINT_MAX);
+       return (ip && hash_id_cidr(map, ip, cidr, hash_ip) != UINT_MAX);
 }
 
 static inline int
 __testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
 {
-       return (hash_id(set, ip, hash_ip) != UINT_MAX);
+       return (ip && hash_id(set, ip, hash_ip) != UINT_MAX);
 }
 
 static int
@@ -128,6 +130,7 @@ __addip_base(struct ip_set_nethash *map, ip_set_ip_t ip)
                        return -EEXIST;
                if (!*elem) {
                        *elem = ip;
+                       map->elements++;
                        return 0;
                }
        }
@@ -139,6 +142,9 @@ static inline int
 __addip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
        ip_set_ip_t *hash_ip)
 {
+       if (!ip || map->elements > limit)
+               return -ERANGE;
+       
        *hash_ip = pack(ip, cidr);
        DP("%u.%u.%u.%u/%u, %u.%u.%u.%u", HIPQUAD(ip), cidr, HIPQUAD(*hash_ip));
        
@@ -246,6 +252,7 @@ static int retry(struct ip_set *set)
                return -ENOMEM;
        }
        tmp->hashsize = hashsize;
+       tmp->elements = 0;
        tmp->probes = map->probes;
        tmp->resize = map->resize;
        memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
@@ -283,14 +290,18 @@ static inline int
 __delip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
        ip_set_ip_t *hash_ip)
 {
-       ip_set_ip_t id = hash_id_cidr(map, ip, cidr, hash_ip);
-       ip_set_ip_t *elem;
+       ip_set_ip_t id, *elem;
 
+       if (!ip)
+               return -ERANGE;
+       
+       id = hash_id_cidr(map, ip, cidr, hash_ip);
        if (id == UINT_MAX)
                return -EEXIST;
                
        elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
        *elem = 0;
+       map->elements--;
        return 0;
 }
 
@@ -364,6 +375,7 @@ static int create(struct ip_set *set, const void *data, size_t size)
        }
        for (i = 0; i < req->probes; i++)
                get_random_bytes(((uint32_t *) map->initval)+i, 4);
+       map->elements = 0;
        map->hashsize = req->hashsize;
        map->probes = req->probes;
        map->resize = req->resize;
@@ -394,6 +406,7 @@ static void flush(struct ip_set *set)
        struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
        harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
        memset(map->cidr, 0, 30 * sizeof(unsigned char));
+       map->elements = 0;
 }
 
 static void list_header(const struct ip_set *set, void *data)
@@ -450,6 +463,8 @@ static struct ip_set_type ip_set_nethash = {
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
 MODULE_DESCRIPTION("nethash type of IP sets");
+module_param(limit, int, 0600);
+MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
 
 static int __init init(void)
 {