X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fnetfilter%2Fip_set.c;h=c7369cf9f7d5ccddcedb085cb35e59dbdbd218a6;hb=a2f44b27303a5353859d77a3e96a1d3f33f56ab7;hp=ff30f7ced1b2e270ed30ce7ffbba9998c0d419ed;hpb=134734d875a0a48d994ef20b9905209b4b8b6f75;p=linux-2.6.git diff --git a/net/ipv4/netfilter/ip_set.c b/net/ipv4/netfilter/ip_set.c index ff30f7ced..c7369cf9f 100644 --- a/net/ipv4/netfilter/ip_set.c +++ b/net/ipv4/netfilter/ip_set.c @@ -9,7 +9,10 @@ /* Kernel module for IP set management */ +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) #include +#endif #include #include #include @@ -25,9 +28,8 @@ #include #include -#define ASSERT_READ_LOCK(x) /* dont use that */ +#define ASSERT_READ_LOCK(x) #define ASSERT_WRITE_LOCK(x) -#include #include static struct list_head set_type_list; /* all registered sets */ @@ -69,11 +71,16 @@ __ip_set_put(ip_set_id_t index) * Binding routines */ -static inline int -ip_hash_cmp(const struct ip_set_hash *set_hash, - ip_set_id_t id, ip_set_ip_t ip) +static inline struct ip_set_hash * +__ip_set_find(u_int32_t key, ip_set_id_t id, ip_set_ip_t ip) { - return set_hash->id == id && set_hash->ip == ip; + struct ip_set_hash *set_hash; + + list_for_each_entry(set_hash, &ip_set_hash[key], list) + if (set_hash->id == id && set_hash->ip == ip) + return set_hash; + + return NULL; } static ip_set_id_t @@ -87,8 +94,7 @@ ip_set_find_in_hash(ip_set_id_t id, ip_set_ip_t ip) IP_SET_ASSERT(ip_set_list[id]); DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip)); - set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp, - struct ip_set_hash *, id, ip); + set_hash = __ip_set_find(key, id, ip); DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name, HIPQUAD(ip), @@ -118,8 +124,7 @@ ip_set_hash_del(ip_set_id_t id, ip_set_ip_t ip) IP_SET_ASSERT(ip_set_list[id]); DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip)); write_lock_bh(&ip_set_lock); - set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp, - struct ip_set_hash *, id, ip); + set_hash = __ip_set_find(key, id, ip); DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name, HIPQUAD(ip), set_hash != NULL ? ip_set_list[set_hash->binding]->name : ""); @@ -143,10 +148,9 @@ ip_set_hash_add(ip_set_id_t id, ip_set_ip_t ip, ip_set_id_t binding) DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name, HIPQUAD(ip), ip_set_list[binding]->name); write_lock_bh(&ip_set_lock); - set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp, - struct ip_set_hash *, id, ip); + set_hash = __ip_set_find(key, id, ip); if (!set_hash) { - set_hash = kmalloc(sizeof(struct ip_set_hash), GFP_KERNEL); + set_hash = kmalloc(sizeof(struct ip_set_hash), GFP_ATOMIC); if (!set_hash) { ret = -ENOMEM; goto unlock; @@ -154,7 +158,7 @@ ip_set_hash_add(ip_set_id_t id, ip_set_ip_t ip, ip_set_id_t binding) INIT_LIST_HEAD(&set_hash->list); set_hash->id = id; set_hash->ip = ip; - list_add(&ip_set_hash[key], &set_hash->list); + list_add(&set_hash->list, &ip_set_hash[key]); } else { IP_SET_ASSERT(ip_set_list[set_hash->binding]); DP("overwrite binding: %s", @@ -163,6 +167,9 @@ ip_set_hash_add(ip_set_id_t id, ip_set_ip_t ip, ip_set_id_t binding) } set_hash->binding = binding; __ip_set_get(set_hash->binding); + DP("stored: key %u, id %u (%s), ip %u.%u.%u.%u, binding %u (%s)", + key, id, ip_set_list[id]->name, + HIPQUAD(ip), binding, ip_set_list[binding]->name); unlock: write_unlock_bh(&ip_set_lock); return ret; @@ -285,19 +292,15 @@ ip_set_delip_kernel(ip_set_id_t index, /* Register and deregister settype */ -static inline int -set_type_equal(const struct ip_set_type *set_type, const char *str2) -{ - return !strncmp(set_type->typename, str2, IP_SET_MAXNAMELEN - 1); -} - static inline struct ip_set_type * find_set_type(const char *name) { - return LIST_FIND(&set_type_list, - set_type_equal, - struct ip_set_type *, - name); + struct ip_set_type *set_type; + + list_for_each_entry(set_type, &set_type_list, list) + if (!strncmp(set_type->typename, name, IP_SET_MAXNAMELEN - 1)) + return set_type; + return NULL; } int @@ -325,7 +328,7 @@ ip_set_register_set_type(struct ip_set_type *set_type) ret = -EFAULT; goto unlock; } - list_append(&set_type_list, set_type); + list_add(&set_type->list, &set_type_list); DP("'%s' registered.", set_type->typename); unlock: write_unlock_bh(&ip_set_lock); @@ -341,7 +344,7 @@ ip_set_unregister_set_type(struct ip_set_type *set_type) set_type->typename); goto unlock; } - LIST_DELETE(&set_type_list, set_type); + list_del(&set_type->list); module_put(THIS_MODULE); DP("'%s' unregistered.", set_type->typename); unlock: @@ -797,7 +800,7 @@ ip_set_create(const char *name, size_t size) { struct ip_set *set; - ip_set_id_t index, id; + ip_set_id_t index = 0, id; int res = 0; DP("setname: %s, typename: %s, id: %u", name, typename, restore); @@ -1161,8 +1164,8 @@ static int ip_set_save_set(ip_set_id_t index, set->type->list_header(set, data + *used); *used += set_save->header_size; - DP("set header filled: %s, used: %u %p %p", set->name, *used, - data, data + *used); + DP("set header filled: %s, used: %u(%u) %p %p", set->name, *used, + set_save->header_size, data, data + *used); /* Get and ensure set specific members size */ set_save->members_size = set->type->list_members_size(set); if (*used + set_save->members_size > len) @@ -1172,8 +1175,8 @@ static int ip_set_save_set(ip_set_id_t index, set->type->list_members(set, data + *used); *used += set_save->members_size; read_unlock_bh(&set->lock); - DP("set members filled: %s, used: %u %p %p", set->name, *used, - data, data + *used); + DP("set members filled: %s, used: %u(%u) %p %p", set->name, *used, + set_save->members_size, data, data + *used); return 0; unlock_set: @@ -1223,6 +1226,8 @@ static int ip_set_save_bindings(ip_set_id_t index, /* Marker */ set_save = (struct ip_set_save *) (data + *used); set_save->index = IP_SET_INVALID_ID; + set_save->header_size = 0; + set_save->members_size = 0; *used += sizeof(struct ip_set_save); DP("marker added used %u, len %u", *used, len); @@ -1329,7 +1334,10 @@ static int ip_set_restore(void *data, index, hash_save->id, hash_save->ip, hash_save->binding); if (index != hash_save->id) return line; - + if (ip_set_find_byindex(hash_save->binding) == IP_SET_INVALID_ID) { + DP("corrupt binding set index %u", hash_save->binding); + return line; + } set = ip_set_list[hash_save->id]; /* Null valued IP means default binding */ if (hash_save->ip) @@ -1413,8 +1421,8 @@ ip_set_sockfn_set(struct sock *sk, int optval, void *user, unsigned int len) struct ip_set_req_create *req_create = (struct ip_set_req_create *) data; - if (len <= sizeof(struct ip_set_req_create)) { - ip_set_printk("short CREATE data (want >%zu, got %u)", + if (len < sizeof(struct ip_set_req_create)) { + ip_set_printk("short CREATE data (want >=%zu, got %u)", sizeof(struct ip_set_req_create), len); res = -EINVAL; goto done; @@ -1768,8 +1776,9 @@ ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len) req_setnames->size += sizeof(struct ip_set_list) + set->type->header_size + set->type->list_members_size(set); + /* Sets are identified by id in the hash */ FOREACH_HASH_DO(__set_hash_bindings_size_list, - i, &req_setnames->size); + set->id, &req_setnames->size); break; } case IP_SET_OP_SAVE_SIZE: { @@ -1777,7 +1786,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len) + set->type->header_size + set->type->list_members_size(set); FOREACH_HASH_DO(__set_hash_bindings_size_save, - i, &req_setnames->size); + set->id, &req_setnames->size); break; } default: