diff options
author | /C=EU/ST=EU/CN=Jozsef Kadlecsik/emailAddress=kadlec@blackhole.kfki.hu </C=EU/ST=EU/CN=Jozsef Kadlecsik/emailAddress=kadlec@blackhole.kfki.hu> | 2008-10-20 10:00:26 +0000 |
---|---|---|
committer | /C=EU/ST=EU/CN=Jozsef Kadlecsik/emailAddress=kadlec@blackhole.kfki.hu </C=EU/ST=EU/CN=Jozsef Kadlecsik/emailAddress=kadlec@blackhole.kfki.hu> | 2008-10-20 10:00:26 +0000 |
commit | a96e4fca10506462df4ee4035f0f86f09bd9dc34 (patch) | |
tree | 103bed0a7ae3608675f371d2ac91f3fa7f3a58cc /kernel/ip_set_portmap.c | |
parent | bc2ddd2d8da1252e78a1f25bd91c1e3cd8016ead (diff) |
ipset 2.4 release
userspace changes:
- Added KBUILD_OUTPUT support (Sven Wegener)
- Fix memory leak in ipset_iptreemap (Sven Wegener)
- Fix multiple compiler warnings (Sven Wegener)
- ipportiphash, ipportnethash and setlist types added
- binding marked as deprecated functionality
- element separator token changed to ',' in anticipating
IPv6 addresses, old separator tokens are still supported
- unnecessary includes removed
- ipset does not try to resolve IP addresses when listing
the content of sets (default changed)
- manpage updated
- ChangeLog forked for kernel part
kernel part changes:
- ipportiphash, ipportnethash and setlist types added
- set type modules reworked to avoid code duplication
as much as possible, code unification macros
- expand_macros Makefile target added to help debugging
code unification macros
- ip_set_addip_kernel and ip_set_delip_kernel
changed from void to int, __ip_set_get_byname and
__ip_set_put_byid added for the sake of setlist type
- unnecessary includes removed
- compatibility fix for kernels >= 2.6.27:
semaphore.h was moved from asm/ to linux/ (James King)
- ChangeLog forked for kernel part
Diffstat (limited to 'kernel/ip_set_portmap.c')
-rw-r--r-- | kernel/ip_set_portmap.c | 293 |
1 files changed, 40 insertions, 253 deletions
diff --git a/kernel/ip_set_portmap.c b/kernel/ip_set_portmap.c index aeaabcd..79cc511 100644 --- a/kernel/ip_set_portmap.c +++ b/kernel/ip_set_portmap.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> +/* Copyright (C) 2003-2008 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 @@ -12,9 +12,6 @@ #include <linux/tcp.h> #include <linux/udp.h> #include <linux/skbuff.h> -#include <linux/version.h> -#include <linux/netfilter_ipv4/ip_tables.h> -#include <linux/netfilter_ipv4/ip_set.h> #include <linux/errno.h> #include <asm/uaccess.h> #include <asm/bitops.h> @@ -22,102 +19,40 @@ #include <net/ip.h> +#include <linux/netfilter_ipv4/ip_set.h> +#include <linux/netfilter_ipv4/ip_set_bitmaps.h> #include <linux/netfilter_ipv4/ip_set_portmap.h> - -/* We must handle non-linear skbs */ -static inline ip_set_ip_t -get_port(const struct sk_buff *skb, u_int32_t flags) -{ - struct iphdr *iph = ip_hdr(skb); - u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET; - switch (iph->protocol) { - case IPPROTO_TCP: { - struct tcphdr tcph; - - /* See comments at tcp_match in ip_tables.c */ - if (offset) - return INVALID_PORT; - - if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &tcph, sizeof(tcph)) < 0) - /* No choice either */ - return INVALID_PORT; - - return ntohs(flags & IPSET_SRC ? - tcph.source : tcph.dest); - } - case IPPROTO_UDP: { - struct udphdr udph; - - if (offset) - return INVALID_PORT; - - if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &udph, sizeof(udph)) < 0) - /* No choice either */ - return INVALID_PORT; - - return ntohs(flags & IPSET_SRC ? - udph.source : udph.dest); - } - default: - return INVALID_PORT; - } -} +#include <linux/netfilter_ipv4/ip_set_getport.h> static inline int -__testport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port) +portmap_test(const struct ip_set *set, ip_set_ip_t *hash_port, + ip_set_ip_t port) { - struct ip_set_portmap *map = set->data; + const struct ip_set_portmap *map = set->data; - if (port < map->first_port || port > map->last_port) + if (port < map->first_ip || port > map->last_ip) return -ERANGE; *hash_port = port; DP("set: %s, port:%u, %u", set->name, port, *hash_port); - return !!test_bit(port - map->first_port, map->members); + return !!test_bit(port - map->first_ip, map->members); } -static int -testport(struct ip_set *set, const void *data, size_t size, - ip_set_ip_t *hash_port) -{ - const struct ip_set_req_portmap *req = data; - - if (size != sizeof(struct ip_set_req_portmap)) { - ip_set_printk("data length wrong (want %zu, have %zu)", - sizeof(struct ip_set_req_portmap), - size); - return -EINVAL; - } - return __testport(set, req->port, hash_port); -} - -static int -testport_kernel(struct ip_set *set, - const struct sk_buff *skb, - ip_set_ip_t *hash_port, - const u_int32_t *flags, - unsigned char index) -{ - int res; - ip_set_ip_t port = get_port(skb, flags[index]); - - DP("flag %s port %u", flags[index] & IPSET_SRC ? "SRC" : "DST", port); - if (port == INVALID_PORT) +#define KADT_CONDITION \ + if (ip == INVALID_PORT) \ return 0; - res = __testport(set, port, hash_port); - - return (res < 0 ? 0 : res); -} +UADT(portmap, test) +KADT(portmap, test, get_port) static inline int -__addport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port) +portmap_add(struct ip_set *set, ip_set_ip_t *hash_port, ip_set_ip_t port) { struct ip_set_portmap *map = set->data; - if (port < map->first_port || port > map->last_port) + if (port < map->first_ip || port > map->last_ip) return -ERANGE; - if (test_and_set_bit(port - map->first_port, map->members)) + if (test_and_set_bit(port - map->first_ip, map->members)) return -EEXIST; *hash_port = port; @@ -125,44 +60,17 @@ __addport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port) return 0; } -static int -addport(struct ip_set *set, const void *data, size_t size, - ip_set_ip_t *hash_port) -{ - const struct ip_set_req_portmap *req = data; - - if (size != sizeof(struct ip_set_req_portmap)) { - ip_set_printk("data length wrong (want %zu, have %zu)", - sizeof(struct ip_set_req_portmap), - size); - return -EINVAL; - } - return __addport(set, req->port, hash_port); -} - -static int -addport_kernel(struct ip_set *set, - const struct sk_buff *skb, - ip_set_ip_t *hash_port, - const u_int32_t *flags, - unsigned char index) -{ - ip_set_ip_t port = get_port(skb, flags[index]); - - if (port == INVALID_PORT) - return -EINVAL; - - return __addport(set, port, hash_port); -} +UADT(portmap, add) +KADT(portmap, add, get_port) static inline int -__delport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port) +portmap_del(struct ip_set *set, ip_set_ip_t *hash_port, ip_set_ip_t port) { struct ip_set_portmap *map = set->data; - if (port < map->first_port || port > map->last_port) + if (port < map->first_ip || port > map->last_ip) return -ERANGE; - if (!test_and_clear_bit(port - map->first_port, map->members)) + if (!test_and_clear_bit(port - map->first_ip, map->members)) return -EEXIST; *hash_port = port; @@ -170,160 +78,39 @@ __delport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port) return 0; } -static int -delport(struct ip_set *set, const void *data, size_t size, - ip_set_ip_t *hash_port) -{ - const struct ip_set_req_portmap *req = data; +UADT(portmap, del) +KADT(portmap, del, get_port) - if (size != sizeof(struct ip_set_req_portmap)) { - ip_set_printk("data length wrong (want %zu, have %zu)", - sizeof(struct ip_set_req_portmap), - size); - return -EINVAL; - } - return __delport(set, req->port, hash_port); -} - -static int -delport_kernel(struct ip_set *set, - const struct sk_buff *skb, - ip_set_ip_t *hash_port, - const u_int32_t *flags, - unsigned char index) -{ - ip_set_ip_t port = get_port(skb, flags[index]); - - if (port == INVALID_PORT) - return -EINVAL; - - return __delport(set, port, hash_port); -} - -static int create(struct ip_set *set, const void *data, size_t size) +static inline int +__portmap_create(const struct ip_set_req_portmap_create *req, + struct ip_set_portmap *map) { - int newbytes; - const struct ip_set_req_portmap_create *req = data; - struct ip_set_portmap *map; - - if (size != sizeof(struct ip_set_req_portmap_create)) { - ip_set_printk("data length wrong (want %zu, have %zu)", - sizeof(struct ip_set_req_portmap_create), - size); - return -EINVAL; - } - - DP("from %u to %u", req->from, req->to); - - if (req->from > req->to) { - DP("bad port range"); - return -ENOEXEC; - } - if (req->to - req->from > MAX_RANGE) { - ip_set_printk("range too big (max %d ports)", - MAX_RANGE+1); + ip_set_printk("range too big, %d elements (max %d)", + req->to - req->from + 1, MAX_RANGE+1); return -ENOEXEC; } - - map = kmalloc(sizeof(struct ip_set_portmap), GFP_KERNEL); - if (!map) { - DP("out of memory for %d bytes", - sizeof(struct ip_set_portmap)); - return -ENOMEM; - } - map->first_port = req->from; - map->last_port = req->to; - newbytes = bitmap_bytes(req->from, req->to); - map->members = kmalloc(newbytes, GFP_KERNEL); - if (!map->members) { - DP("out of memory for %d bytes", newbytes); - kfree(map); - return -ENOMEM; - } - memset(map->members, 0, newbytes); - - set->data = map; - return 0; -} - -static void destroy(struct ip_set *set) -{ - struct ip_set_portmap *map = set->data; - - kfree(map->members); - kfree(map); - - set->data = NULL; -} - -static void flush(struct ip_set *set) -{ - struct ip_set_portmap *map = set->data; - memset(map->members, 0, bitmap_bytes(map->first_port, map->last_port)); + return bitmap_bytes(req->from, req->to); } -static void list_header(const struct ip_set *set, void *data) -{ - const struct ip_set_portmap *map = set->data; - struct ip_set_req_portmap_create *header = data; - - DP("list_header %u %u", map->first_port, map->last_port); +BITMAP_CREATE(portmap) +BITMAP_DESTROY(portmap) +BITMAP_FLUSH(portmap) - header->from = map->first_port; - header->to = map->last_port; -} - -static int list_members_size(const struct ip_set *set) +static inline void +__portmap_list_header(const struct ip_set_portmap *map, + struct ip_set_req_portmap_create *header) { - const struct ip_set_portmap *map = set->data; - - return bitmap_bytes(map->first_port, map->last_port); } -static void list_members(const struct ip_set *set, void *data) -{ - const struct ip_set_portmap *map = set->data; - int bytes = bitmap_bytes(map->first_port, map->last_port); - - memcpy(data, map->members, bytes); -} +BITMAP_LIST_HEADER(portmap) +BITMAP_LIST_MEMBERS_SIZE(portmap) +BITMAP_LIST_MEMBERS(portmap) -static struct ip_set_type ip_set_portmap = { - .typename = SETTYPE_NAME, - .features = IPSET_TYPE_PORT | IPSET_DATA_SINGLE, - .protocol_version = IP_SET_PROTOCOL_VERSION, - .create = &create, - .destroy = &destroy, - .flush = &flush, - .reqsize = sizeof(struct ip_set_req_portmap), - .addip = &addport, - .addip_kernel = &addport_kernel, - .delip = &delport, - .delip_kernel = &delport_kernel, - .testip = &testport, - .testip_kernel = &testport_kernel, - .header_size = sizeof(struct ip_set_req_portmap_create), - .list_header = &list_header, - .list_members_size = &list_members_size, - .list_members = &list_members, - .me = THIS_MODULE, -}; +IP_SET_TYPE(portmap, IPSET_TYPE_PORT | IPSET_DATA_SINGLE) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_DESCRIPTION("portmap type of IP sets"); -static int __init ip_set_portmap_init(void) -{ - return ip_set_register_set_type(&ip_set_portmap); -} - -static void __exit ip_set_portmap_fini(void) -{ - /* FIXME: possible race with ip_set_create() */ - ip_set_unregister_set_type(&ip_set_portmap); -} - -module_init(ip_set_portmap_init); -module_exit(ip_set_portmap_fini); +REGISTER_MODULE(portmap) |