1 /* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation.
8 /* Kernel module implementing a port set type as a bitmap */
10 #include <linux/module.h>
12 #include <linux/tcp.h>
13 #include <linux/udp.h>
14 #include <linux/skbuff.h>
15 #include <linux/netfilter_ipv4/ip_tables.h>
16 #include <linux/netfilter_ipv4/ip_set.h>
17 #include <linux/errno.h>
18 #include <asm/uaccess.h>
19 #include <asm/bitops.h>
20 #include <linux/spinlock.h>
24 #include <linux/netfilter_ipv4/ip_set_portmap.h>
26 /* We must handle non-linear skbs */
27 static inline ip_set_ip_t
28 get_port(const struct sk_buff *skb, u_int32_t flags)
30 struct iphdr *iph = skb->nh.iph;
31 u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET;
33 switch (iph->protocol) {
37 /* See comments at tcp_match in ip_tables.c */
41 if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0)
42 /* No choice either */
45 return ntohs(flags & IPSET_SRC ?
46 tcph.source : tcph.dest);
54 if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &udph, sizeof(udph)) < 0)
55 /* No choice either */
58 return ntohs(flags & IPSET_SRC ?
59 udph.source : udph.dest);
67 __testport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
69 struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
71 if (port < map->first_port || port > map->last_port)
75 DP("set: %s, port:%u, %u", set->name, port, *hash_port);
76 return !!test_bit(port - map->first_port, map->members);
80 testport(struct ip_set *set, const void *data, size_t size,
81 ip_set_ip_t *hash_port)
83 struct ip_set_req_portmap *req =
84 (struct ip_set_req_portmap *) data;
86 if (size != sizeof(struct ip_set_req_portmap)) {
87 ip_set_printk("data length wrong (want %zu, have %zu)",
88 sizeof(struct ip_set_req_portmap),
92 return __testport(set, req->port, hash_port);
96 testport_kernel(struct ip_set *set,
97 const struct sk_buff *skb,
98 ip_set_ip_t *hash_port,
99 const u_int32_t *flags,
103 ip_set_ip_t port = get_port(skb, flags[index]);
105 DP("flag %s port %u", flags[index] & IPSET_SRC ? "SRC" : "DST", port);
106 if (port == INVALID_PORT)
109 res = __testport(set, port, hash_port);
111 return (res < 0 ? 0 : res);
115 __addport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
117 struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
119 if (port < map->first_port || port > map->last_port)
121 if (test_and_set_bit(port - map->first_port, map->members))
130 addport(struct ip_set *set, const void *data, size_t size,
131 ip_set_ip_t *hash_port)
133 struct ip_set_req_portmap *req =
134 (struct ip_set_req_portmap *) data;
136 if (size != sizeof(struct ip_set_req_portmap)) {
137 ip_set_printk("data length wrong (want %zu, have %zu)",
138 sizeof(struct ip_set_req_portmap),
142 return __addport(set, req->port, hash_port);
146 addport_kernel(struct ip_set *set,
147 const struct sk_buff *skb,
148 ip_set_ip_t *hash_port,
149 const u_int32_t *flags,
152 ip_set_ip_t port = get_port(skb, flags[index]);
154 if (port == INVALID_PORT)
157 return __addport(set, port, hash_port);
161 __delport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
163 struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
165 if (port < map->first_port || port > map->last_port)
167 if (!test_and_clear_bit(port - map->first_port, map->members))
176 delport(struct ip_set *set, const void *data, size_t size,
177 ip_set_ip_t *hash_port)
179 struct ip_set_req_portmap *req =
180 (struct ip_set_req_portmap *) data;
182 if (size != sizeof(struct ip_set_req_portmap)) {
183 ip_set_printk("data length wrong (want %zu, have %zu)",
184 sizeof(struct ip_set_req_portmap),
188 return __delport(set, req->port, hash_port);
192 delport_kernel(struct ip_set *set,
193 const struct sk_buff *skb,
194 ip_set_ip_t *hash_port,
195 const u_int32_t *flags,
198 ip_set_ip_t port = get_port(skb, flags[index]);
200 if (port == INVALID_PORT)
203 return __delport(set, port, hash_port);
206 static int create(struct ip_set *set, const void *data, size_t size)
209 struct ip_set_req_portmap_create *req =
210 (struct ip_set_req_portmap_create *) data;
211 struct ip_set_portmap *map;
213 if (size != sizeof(struct ip_set_req_portmap_create)) {
214 ip_set_printk("data length wrong (want %zu, have %zu)",
215 sizeof(struct ip_set_req_portmap_create),
220 DP("from %u to %u", req->from, req->to);
222 if (req->from > req->to) {
223 DP("bad port range");
227 if (req->to - req->from > MAX_RANGE) {
228 ip_set_printk("range too big (max %d ports)",
233 map = kmalloc(sizeof(struct ip_set_portmap), GFP_KERNEL);
235 DP("out of memory for %d bytes",
236 sizeof(struct ip_set_portmap));
239 map->first_port = req->from;
240 map->last_port = req->to;
241 newbytes = bitmap_bytes(req->from, req->to);
242 map->members = kmalloc(newbytes, GFP_KERNEL);
244 DP("out of memory for %d bytes", newbytes);
248 memset(map->members, 0, newbytes);
254 static void destroy(struct ip_set *set)
256 struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
264 static void flush(struct ip_set *set)
266 struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
267 memset(map->members, 0, bitmap_bytes(map->first_port, map->last_port));
270 static void list_header(const struct ip_set *set, void *data)
272 struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
273 struct ip_set_req_portmap_create *header =
274 (struct ip_set_req_portmap_create *) data;
276 DP("list_header %u %u", map->first_port, map->last_port);
278 header->from = map->first_port;
279 header->to = map->last_port;
282 static int list_members_size(const struct ip_set *set)
284 struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
286 return bitmap_bytes(map->first_port, map->last_port);
289 static void list_members(const struct ip_set *set, void *data)
291 struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
292 int bytes = bitmap_bytes(map->first_port, map->last_port);
294 memcpy(data, map->members, bytes);
297 static struct ip_set_type ip_set_portmap = {
298 .typename = SETTYPE_NAME,
299 .features = IPSET_TYPE_PORT | IPSET_DATA_SINGLE,
300 .protocol_version = IP_SET_PROTOCOL_VERSION,
304 .reqsize = sizeof(struct ip_set_req_portmap),
306 .addip_kernel = &addport_kernel,
308 .delip_kernel = &delport_kernel,
310 .testip_kernel = &testport_kernel,
311 .header_size = sizeof(struct ip_set_req_portmap_create),
312 .list_header = &list_header,
313 .list_members_size = &list_members_size,
314 .list_members = &list_members,
318 MODULE_LICENSE("GPL");
319 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
320 MODULE_DESCRIPTION("portmap type of IP sets");
322 static int __init init(void)
324 return ip_set_register_set_type(&ip_set_portmap);
327 static void __exit fini(void)
329 /* FIXME: possible race with ip_set_create() */
330 ip_set_unregister_set_type(&ip_set_portmap);