aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2011-02-01 09:37:04 -0500
committerPatrick McHardy <kaber@trash.net>2011-02-01 09:37:04 -0500
commit543261907dc3c4e90845acfcd602ebdbfdfcb4f0 (patch)
treea8f233fa9532347b4d795d5d8021c36df7c60471 /net
parentde76021a1bb35e3560afccf741d1119a872aea49 (diff)
netfilter: ipset; bitmap:port set type support
The module implements the bitmap:port type in two flavours, without and with timeout support to store TCP/UDP ports from a range. Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/ipset/Kconfig9
-rw-r--r--net/netfilter/ipset/Makefile1
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_port.c520
3 files changed, 530 insertions, 0 deletions
diff --git a/net/netfilter/ipset/Kconfig b/net/netfilter/ipset/Kconfig
index f18654c73af2..f401e9112703 100644
--- a/net/netfilter/ipset/Kconfig
+++ b/net/netfilter/ipset/Kconfig
@@ -41,4 +41,13 @@ config IP_SET_BITMAP_IPMAC
41 41
42 To compile it as a module, choose M here. If unsure, say N. 42 To compile it as a module, choose M here. If unsure, say N.
43 43
44config IP_SET_BITMAP_PORT
45 tristate "bitmap:port set support"
46 depends on IP_SET
47 help
48 This option adds the bitmap:port set type support, by which one
49 can store TCP/UDP port numbers from a range.
50
51 To compile it as a module, choose M here. If unsure, say N.
52
44endif # IP_SET 53endif # IP_SET
diff --git a/net/netfilter/ipset/Makefile b/net/netfilter/ipset/Makefile
index f7a099f40d0b..40866e267752 100644
--- a/net/netfilter/ipset/Makefile
+++ b/net/netfilter/ipset/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_IP_SET) += ip_set.o
10# bitmap types 10# bitmap types
11obj-$(CONFIG_IP_SET_BITMAP_IP) += ip_set_bitmap_ip.o 11obj-$(CONFIG_IP_SET_BITMAP_IP) += ip_set_bitmap_ip.o
12obj-$(CONFIG_IP_SET_BITMAP_IPMAC) += ip_set_bitmap_ipmac.o 12obj-$(CONFIG_IP_SET_BITMAP_IPMAC) += ip_set_bitmap_ipmac.o
13obj-$(CONFIG_IP_SET_BITMAP_PORT) += ip_set_bitmap_port.o
diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c
new file mode 100644
index 000000000000..92074bb64134
--- /dev/null
+++ b/net/netfilter/ipset/ip_set_bitmap_port.c
@@ -0,0 +1,520 @@
1/* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
2 *
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.
6 */
7
8/* Kernel module implementing an IP set type: the bitmap:port type */
9
10#include <linux/module.h>
11#include <linux/ip.h>
12#include <linux/tcp.h>
13#include <linux/udp.h>
14#include <linux/skbuff.h>
15#include <linux/errno.h>
16#include <linux/uaccess.h>
17#include <linux/bitops.h>
18#include <linux/spinlock.h>
19#include <linux/netlink.h>
20#include <linux/jiffies.h>
21#include <linux/timer.h>
22#include <net/netlink.h>
23
24#include <linux/netfilter/ipset/ip_set.h>
25#include <linux/netfilter/ipset/ip_set_bitmap.h>
26#include <linux/netfilter/ipset/ip_set_getport.h>
27#define IP_SET_BITMAP_TIMEOUT
28#include <linux/netfilter/ipset/ip_set_timeout.h>
29
30MODULE_LICENSE("GPL");
31MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
32MODULE_DESCRIPTION("bitmap:port type of IP sets");
33MODULE_ALIAS("ip_set_bitmap:port");
34
35/* Type structure */
36struct bitmap_port {
37 void *members; /* the set members */
38 u16 first_port; /* host byte order, included in range */
39 u16 last_port; /* host byte order, included in range */
40 size_t memsize; /* members size */
41 u32 timeout; /* timeout parameter */
42 struct timer_list gc; /* garbage collection */
43};
44
45/* Base variant */
46
47static int
48bitmap_port_test(struct ip_set *set, void *value, u32 timeout)
49{
50 const struct bitmap_port *map = set->data;
51 u16 id = *(u16 *)value;
52
53 return !!test_bit(id, map->members);
54}
55
56static int
57bitmap_port_add(struct ip_set *set, void *value, u32 timeout)
58{
59 struct bitmap_port *map = set->data;
60 u16 id = *(u16 *)value;
61
62 if (test_and_set_bit(id, map->members))
63 return -IPSET_ERR_EXIST;
64
65 return 0;
66}
67
68static int
69bitmap_port_del(struct ip_set *set, void *value, u32 timeout)
70{
71 struct bitmap_port *map = set->data;
72 u16 id = *(u16 *)value;
73
74 if (!test_and_clear_bit(id, map->members))
75 return -IPSET_ERR_EXIST;
76
77 return 0;
78}
79
80static int
81bitmap_port_list(const struct ip_set *set,
82 struct sk_buff *skb, struct netlink_callback *cb)
83{
84 const struct bitmap_port *map = set->data;
85 struct nlattr *atd, *nested;
86 u16 id, first = cb->args[2];
87 u16 last = map->last_port - map->first_port;
88
89 atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
90 if (!atd)
91 return -EMSGSIZE;
92 for (; cb->args[2] <= last; cb->args[2]++) {
93 id = cb->args[2];
94 if (!test_bit(id, map->members))
95 continue;
96 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
97 if (!nested) {
98 if (id == first) {
99 nla_nest_cancel(skb, atd);
100 return -EMSGSIZE;
101 } else
102 goto nla_put_failure;
103 }
104 NLA_PUT_NET16(skb, IPSET_ATTR_PORT,
105 htons(map->first_port + id));
106 ipset_nest_end(skb, nested);
107 }
108 ipset_nest_end(skb, atd);
109 /* Set listing finished */
110 cb->args[2] = 0;
111
112 return 0;
113
114nla_put_failure:
115 nla_nest_cancel(skb, nested);
116 ipset_nest_end(skb, atd);
117 if (unlikely(id == first)) {
118 cb->args[2] = 0;
119 return -EMSGSIZE;
120 }
121 return 0;
122}
123
124/* Timeout variant */
125
126static int
127bitmap_port_ttest(struct ip_set *set, void *value, u32 timeout)
128{
129 const struct bitmap_port *map = set->data;
130 const unsigned long *members = map->members;
131 u16 id = *(u16 *)value;
132
133 return ip_set_timeout_test(members[id]);
134}
135
136static int
137bitmap_port_tadd(struct ip_set *set, void *value, u32 timeout)
138{
139 struct bitmap_port *map = set->data;
140 unsigned long *members = map->members;
141 u16 id = *(u16 *)value;
142
143 if (ip_set_timeout_test(members[id]))
144 return -IPSET_ERR_EXIST;
145
146 members[id] = ip_set_timeout_set(timeout);
147
148 return 0;
149}
150
151static int
152bitmap_port_tdel(struct ip_set *set, void *value, u32 timeout)
153{
154 struct bitmap_port *map = set->data;
155 unsigned long *members = map->members;
156 u16 id = *(u16 *)value;
157 int ret = -IPSET_ERR_EXIST;
158
159 if (ip_set_timeout_test(members[id]))
160 ret = 0;
161
162 members[id] = IPSET_ELEM_UNSET;
163 return ret;
164}
165
166static int
167bitmap_port_tlist(const struct ip_set *set,
168 struct sk_buff *skb, struct netlink_callback *cb)
169{
170 const struct bitmap_port *map = set->data;
171 struct nlattr *adt, *nested;
172 u16 id, first = cb->args[2];
173 u16 last = map->last_port - map->first_port;
174 const unsigned long *members = map->members;
175
176 adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
177 if (!adt)
178 return -EMSGSIZE;
179 for (; cb->args[2] <= last; cb->args[2]++) {
180 id = cb->args[2];
181 if (!ip_set_timeout_test(members[id]))
182 continue;
183 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
184 if (!nested) {
185 if (id == first) {
186 nla_nest_cancel(skb, adt);
187 return -EMSGSIZE;
188 } else
189 goto nla_put_failure;
190 }
191 NLA_PUT_NET16(skb, IPSET_ATTR_PORT,
192 htons(map->first_port + id));
193 NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
194 htonl(ip_set_timeout_get(members[id])));
195 ipset_nest_end(skb, nested);
196 }
197 ipset_nest_end(skb, adt);
198
199 /* Set listing finished */
200 cb->args[2] = 0;
201
202 return 0;
203
204nla_put_failure:
205 nla_nest_cancel(skb, nested);
206 ipset_nest_end(skb, adt);
207 if (unlikely(id == first)) {
208 cb->args[2] = 0;
209 return -EMSGSIZE;
210 }
211 return 0;
212}
213
214static int
215bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
216 enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
217{
218 struct bitmap_port *map = set->data;
219 ipset_adtfn adtfn = set->variant->adt[adt];
220 __be16 __port;
221 u16 port = 0;
222
223 if (!ip_set_get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port))
224 return -EINVAL;
225
226 port = ntohs(__port);
227
228 if (port < map->first_port || port > map->last_port)
229 return -IPSET_ERR_BITMAP_RANGE;
230
231 port -= map->first_port;
232
233 return adtfn(set, &port, map->timeout);
234}
235
236static int
237bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
238 enum ipset_adt adt, u32 *lineno, u32 flags)
239{
240 struct bitmap_port *map = set->data;
241 ipset_adtfn adtfn = set->variant->adt[adt];
242 u32 timeout = map->timeout;
243 u32 port; /* wraparound */
244 u16 id, port_to;
245 int ret = 0;
246
247 if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
248 !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
249 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
250 return -IPSET_ERR_PROTOCOL;
251
252 if (tb[IPSET_ATTR_LINENO])
253 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
254
255 port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
256 if (port < map->first_port || port > map->last_port)
257 return -IPSET_ERR_BITMAP_RANGE;
258
259 if (tb[IPSET_ATTR_TIMEOUT]) {
260 if (!with_timeout(map->timeout))
261 return -IPSET_ERR_TIMEOUT;
262 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
263 }
264
265 if (adt == IPSET_TEST) {
266 id = port - map->first_port;
267 return adtfn(set, &id, timeout);
268 }
269
270 if (tb[IPSET_ATTR_PORT_TO]) {
271 port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
272 if (port > port_to) {
273 swap(port, port_to);
274 if (port < map->first_port)
275 return -IPSET_ERR_BITMAP_RANGE;
276 }
277 } else
278 port_to = port;
279
280 if (port_to > map->last_port)
281 return -IPSET_ERR_BITMAP_RANGE;
282
283 for (; port <= port_to; port++) {
284 id = port - map->first_port;
285 ret = adtfn(set, &id, timeout);
286
287 if (ret && !ip_set_eexist(ret, flags))
288 return ret;
289 else
290 ret = 0;
291 }
292 return ret;
293}
294
295static void
296bitmap_port_destroy(struct ip_set *set)
297{
298 struct bitmap_port *map = set->data;
299
300 if (with_timeout(map->timeout))
301 del_timer_sync(&map->gc);
302
303 ip_set_free(map->members);
304 kfree(map);
305
306 set->data = NULL;
307}
308
309static void
310bitmap_port_flush(struct ip_set *set)
311{
312 struct bitmap_port *map = set->data;
313
314 memset(map->members, 0, map->memsize);
315}
316
317static int
318bitmap_port_head(struct ip_set *set, struct sk_buff *skb)
319{
320 const struct bitmap_port *map = set->data;
321 struct nlattr *nested;
322
323 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
324 if (!nested)
325 goto nla_put_failure;
326 NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port));
327 NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port));
328 NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
329 htonl(atomic_read(&set->ref) - 1));
330 NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
331 htonl(sizeof(*map) + map->memsize));
332 if (with_timeout(map->timeout))
333 NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
334 ipset_nest_end(skb, nested);
335
336 return 0;
337nla_put_failure:
338 return -EMSGSIZE;
339}
340
341static bool
342bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
343{
344 const struct bitmap_port *x = a->data;
345 const struct bitmap_port *y = b->data;
346
347 return x->first_port == y->first_port &&
348 x->last_port == y->last_port &&
349 x->timeout == y->timeout;
350}
351
352static const struct ip_set_type_variant bitmap_port = {
353 .kadt = bitmap_port_kadt,
354 .uadt = bitmap_port_uadt,
355 .adt = {
356 [IPSET_ADD] = bitmap_port_add,
357 [IPSET_DEL] = bitmap_port_del,
358 [IPSET_TEST] = bitmap_port_test,
359 },
360 .destroy = bitmap_port_destroy,
361 .flush = bitmap_port_flush,
362 .head = bitmap_port_head,
363 .list = bitmap_port_list,
364 .same_set = bitmap_port_same_set,
365};
366
367static const struct ip_set_type_variant bitmap_tport = {
368 .kadt = bitmap_port_kadt,
369 .uadt = bitmap_port_uadt,
370 .adt = {
371 [IPSET_ADD] = bitmap_port_tadd,
372 [IPSET_DEL] = bitmap_port_tdel,
373 [IPSET_TEST] = bitmap_port_ttest,
374 },
375 .destroy = bitmap_port_destroy,
376 .flush = bitmap_port_flush,
377 .head = bitmap_port_head,
378 .list = bitmap_port_tlist,
379 .same_set = bitmap_port_same_set,
380};
381
382static void
383bitmap_port_gc(unsigned long ul_set)
384{
385 struct ip_set *set = (struct ip_set *) ul_set;
386 struct bitmap_port *map = set->data;
387 unsigned long *table = map->members;
388 u32 id; /* wraparound */
389 u16 last = map->last_port - map->first_port;
390
391 /* We run parallel with other readers (test element)
392 * but adding/deleting new entries is locked out */
393 read_lock_bh(&set->lock);
394 for (id = 0; id <= last; id++)
395 if (ip_set_timeout_expired(table[id]))
396 table[id] = IPSET_ELEM_UNSET;
397 read_unlock_bh(&set->lock);
398
399 map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
400 add_timer(&map->gc);
401}
402
403static void
404bitmap_port_gc_init(struct ip_set *set)
405{
406 struct bitmap_port *map = set->data;
407
408 init_timer(&map->gc);
409 map->gc.data = (unsigned long) set;
410 map->gc.function = bitmap_port_gc;
411 map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
412 add_timer(&map->gc);
413}
414
415/* Create bitmap:ip type of sets */
416
417static bool
418init_map_port(struct ip_set *set, struct bitmap_port *map,
419 u16 first_port, u16 last_port)
420{
421 map->members = ip_set_alloc(map->memsize);
422 if (!map->members)
423 return false;
424 map->first_port = first_port;
425 map->last_port = last_port;
426 map->timeout = IPSET_NO_TIMEOUT;
427
428 set->data = map;
429 set->family = AF_UNSPEC;
430
431 return true;
432}
433
434static int
435bitmap_port_create(struct ip_set *set, struct nlattr *tb[],
436 u32 flags)
437{
438 struct bitmap_port *map;
439 u16 first_port, last_port;
440
441 if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
442 !ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) ||
443 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
444 return -IPSET_ERR_PROTOCOL;
445
446 first_port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
447 last_port = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
448 if (first_port > last_port) {
449 u16 tmp = first_port;
450
451 first_port = last_port;
452 last_port = tmp;
453 }
454
455 map = kzalloc(sizeof(*map), GFP_KERNEL);
456 if (!map)
457 return -ENOMEM;
458
459 if (tb[IPSET_ATTR_TIMEOUT]) {
460 map->memsize = (last_port - first_port + 1)
461 * sizeof(unsigned long);
462
463 if (!init_map_port(set, map, first_port, last_port)) {
464 kfree(map);
465 return -ENOMEM;
466 }
467
468 map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
469 set->variant = &bitmap_tport;
470
471 bitmap_port_gc_init(set);
472 } else {
473 map->memsize = bitmap_bytes(0, last_port - first_port);
474 pr_debug("memsize: %zu\n", map->memsize);
475 if (!init_map_port(set, map, first_port, last_port)) {
476 kfree(map);
477 return -ENOMEM;
478 }
479
480 set->variant = &bitmap_port;
481 }
482 return 0;
483}
484
485static struct ip_set_type bitmap_port_type = {
486 .name = "bitmap:port",
487 .protocol = IPSET_PROTOCOL,
488 .features = IPSET_TYPE_PORT,
489 .dimension = IPSET_DIM_ONE,
490 .family = AF_UNSPEC,
491 .revision = 0,
492 .create = bitmap_port_create,
493 .create_policy = {
494 [IPSET_ATTR_PORT] = { .type = NLA_U16 },
495 [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
496 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
497 },
498 .adt_policy = {
499 [IPSET_ATTR_PORT] = { .type = NLA_U16 },
500 [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
501 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
502 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
503 },
504 .me = THIS_MODULE,
505};
506
507static int __init
508bitmap_port_init(void)
509{
510 return ip_set_type_register(&bitmap_port_type);
511}
512
513static void __exit
514bitmap_port_fini(void)
515{
516 ip_set_type_unregister(&bitmap_port_type);
517}
518
519module_init(bitmap_port_init);
520module_exit(bitmap_port_fini);