1 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
2 * Patrick Schaaf <bof@bof.de>
3 * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
10 /* Kernel module implementing an IP set type: the single bitmap type */
12 #include <linux/module.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>
22 #include <linux/netfilter_ipv4/ip_set_ipmap.h>
24 static inline ip_set_ip_t
25 ip_to_id(const struct ip_set_ipmap *map, ip_set_ip_t ip)
27 return (ip - map->first_ip)/map->hosts;
31 __testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
33 struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
35 if (ip < map->first_ip || ip > map->last_ip)
38 *hash_ip = ip & map->netmask;
39 DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
40 set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
41 return !!test_bit(ip_to_id(map, *hash_ip), map->members);
45 testip(struct ip_set *set, const void *data, size_t size,
48 struct ip_set_req_ipmap *req =
49 (struct ip_set_req_ipmap *) data;
51 if (size != sizeof(struct ip_set_req_ipmap)) {
52 ip_set_printk("data length wrong (want %zu, have %zu)",
53 sizeof(struct ip_set_req_ipmap),
57 return __testip(set, req->ip, hash_ip);
61 testip_kernel(struct ip_set *set,
62 const struct sk_buff *skb,
64 const u_int32_t *flags,
69 DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
70 flags[index] & IPSET_SRC ? "SRC" : "DST",
71 NIPQUAD(skb->nh.iph->saddr),
72 NIPQUAD(skb->nh.iph->daddr));
75 ntohl(flags[index] & IPSET_SRC
77 : skb->nh.iph->daddr),
79 return (res < 0 ? 0 : res);
83 __addip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
85 struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
87 if (ip < map->first_ip || ip > map->last_ip)
90 *hash_ip = ip & map->netmask;
91 DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
92 if (test_and_set_bit(ip_to_id(map, *hash_ip), map->members))
99 addip(struct ip_set *set, const void *data, size_t size,
100 ip_set_ip_t *hash_ip)
102 struct ip_set_req_ipmap *req =
103 (struct ip_set_req_ipmap *) data;
105 if (size != sizeof(struct ip_set_req_ipmap)) {
106 ip_set_printk("data length wrong (want %zu, have %zu)",
107 sizeof(struct ip_set_req_ipmap),
111 DP("%u.%u.%u.%u", HIPQUAD(req->ip));
112 return __addip(set, req->ip, hash_ip);
116 addip_kernel(struct ip_set *set,
117 const struct sk_buff *skb,
118 ip_set_ip_t *hash_ip,
119 const u_int32_t *flags,
123 ntohl(flags[index] & IPSET_SRC
125 : skb->nh.iph->daddr),
130 __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
132 struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
134 if (ip < map->first_ip || ip > map->last_ip)
137 *hash_ip = ip & map->netmask;
138 DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
139 if (!test_and_clear_bit(ip_to_id(map, *hash_ip), map->members))
146 delip(struct ip_set *set, const void *data, size_t size,
147 ip_set_ip_t *hash_ip)
149 struct ip_set_req_ipmap *req =
150 (struct ip_set_req_ipmap *) data;
152 if (size != sizeof(struct ip_set_req_ipmap)) {
153 ip_set_printk("data length wrong (want %zu, have %zu)",
154 sizeof(struct ip_set_req_ipmap),
158 return __delip(set, req->ip, hash_ip);
162 delip_kernel(struct ip_set *set,
163 const struct sk_buff *skb,
164 ip_set_ip_t *hash_ip,
165 const u_int32_t *flags,
169 ntohl(flags[index] & IPSET_SRC
171 : skb->nh.iph->daddr),
175 static int create(struct ip_set *set, const void *data, size_t size)
178 struct ip_set_req_ipmap_create *req =
179 (struct ip_set_req_ipmap_create *) data;
180 struct ip_set_ipmap *map;
182 if (size != sizeof(struct ip_set_req_ipmap_create)) {
183 ip_set_printk("data length wrong (want %zu, have %zu)",
184 sizeof(struct ip_set_req_ipmap_create),
189 DP("from %u.%u.%u.%u to %u.%u.%u.%u",
190 HIPQUAD(req->from), HIPQUAD(req->to));
192 if (req->from > req->to) {
197 map = kmalloc(sizeof(struct ip_set_ipmap), GFP_KERNEL);
199 DP("out of memory for %d bytes",
200 sizeof(struct ip_set_ipmap));
203 map->first_ip = req->from;
204 map->last_ip = req->to;
205 map->netmask = req->netmask;
207 if (req->netmask == 0xFFFFFFFF) {
209 map->sizeid = map->last_ip - map->first_ip + 1;
211 unsigned int mask_bits, netmask_bits;
214 map->first_ip &= map->netmask; /* Should we better bark? */
216 mask = range_to_mask(map->first_ip, map->last_ip, &mask_bits);
217 netmask_bits = mask_to_bits(map->netmask);
219 if ((!mask && (map->first_ip || map->last_ip != 0xFFFFFFFF))
220 || netmask_bits <= mask_bits)
223 DP("mask_bits %u, netmask_bits %u",
224 mask_bits, netmask_bits);
225 map->hosts = 2 << (32 - netmask_bits - 1);
226 map->sizeid = 2 << (netmask_bits - mask_bits - 1);
228 if (map->sizeid > MAX_RANGE + 1) {
229 ip_set_printk("range too big (max %d addresses)",
234 DP("hosts %u, sizeid %u", map->hosts, map->sizeid);
235 newbytes = bitmap_bytes(0, map->sizeid - 1);
236 map->members = kmalloc(newbytes, GFP_KERNEL);
238 DP("out of memory for %d bytes", newbytes);
242 memset(map->members, 0, newbytes);
248 static void destroy(struct ip_set *set)
250 struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
258 static void flush(struct ip_set *set)
260 struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
261 memset(map->members, 0, bitmap_bytes(0, map->sizeid - 1));
264 static void list_header(const struct ip_set *set, void *data)
266 struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
267 struct ip_set_req_ipmap_create *header =
268 (struct ip_set_req_ipmap_create *) data;
270 header->from = map->first_ip;
271 header->to = map->last_ip;
272 header->netmask = map->netmask;
275 static int list_members_size(const struct ip_set *set)
277 struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
279 return bitmap_bytes(0, map->sizeid - 1);
282 static void list_members(const struct ip_set *set, void *data)
284 struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
285 int bytes = bitmap_bytes(0, map->sizeid - 1);
287 memcpy(data, map->members, bytes);
290 static struct ip_set_type ip_set_ipmap = {
291 .typename = SETTYPE_NAME,
292 .features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
293 .protocol_version = IP_SET_PROTOCOL_VERSION,
297 .reqsize = sizeof(struct ip_set_req_ipmap),
299 .addip_kernel = &addip_kernel,
301 .delip_kernel = &delip_kernel,
303 .testip_kernel = &testip_kernel,
304 .header_size = sizeof(struct ip_set_req_ipmap_create),
305 .list_header = &list_header,
306 .list_members_size = &list_members_size,
307 .list_members = &list_members,
311 MODULE_LICENSE("GPL");
312 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
313 MODULE_DESCRIPTION("ipmap type of IP sets");
315 static int __init init(void)
317 return ip_set_register_set_type(&ip_set_ipmap);
320 static void __exit fini(void)
322 /* FIXME: possible race with ip_set_create() */
323 ip_set_unregister_set_type(&ip_set_ipmap);