summaryrefslogtreecommitdiffstats
path: root/kernel/ip_set_portmap.c
diff options
context:
space:
mode:
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
commita96e4fca10506462df4ee4035f0f86f09bd9dc34 (patch)
tree103bed0a7ae3608675f371d2ac91f3fa7f3a58cc /kernel/ip_set_portmap.c
parentbc2ddd2d8da1252e78a1f25bd91c1e3cd8016ead (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.c293
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)