Commit 543261907dc3c4e90845acfcd602ebdbfdfcb4f0

Authored by Jozsef Kadlecsik
Committed by Patrick McHardy
1 parent de76021a1b

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>

Showing 3 changed files with 530 additions and 0 deletions Side-by-side Diff

net/netfilter/ipset/Kconfig
... ... @@ -41,5 +41,14 @@
41 41  
42 42 To compile it as a module, choose M here. If unsure, say N.
43 43  
  44 +config 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 +
44 53 endif # IP_SET
net/netfilter/ipset/Makefile
... ... @@ -10,4 +10,5 @@
10 10 # bitmap types
11 11 obj-$(CONFIG_IP_SET_BITMAP_IP) += ip_set_bitmap_ip.o
12 12 obj-$(CONFIG_IP_SET_BITMAP_IPMAC) += ip_set_bitmap_ipmac.o
  13 +obj-$(CONFIG_IP_SET_BITMAP_PORT) += ip_set_bitmap_port.o
net/netfilter/ipset/ip_set_bitmap_port.c
  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 +
  30 +MODULE_LICENSE("GPL");
  31 +MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
  32 +MODULE_DESCRIPTION("bitmap:port type of IP sets");
  33 +MODULE_ALIAS("ip_set_bitmap:port");
  34 +
  35 +/* Type structure */
  36 +struct 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 +
  47 +static int
  48 +bitmap_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 +
  56 +static int
  57 +bitmap_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 +
  68 +static int
  69 +bitmap_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 +
  80 +static int
  81 +bitmap_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 +
  114 +nla_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 +
  126 +static int
  127 +bitmap_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 +
  136 +static int
  137 +bitmap_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 +
  151 +static int
  152 +bitmap_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 +
  166 +static int
  167 +bitmap_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 +
  204 +nla_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 +
  214 +static int
  215 +bitmap_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 +
  236 +static int
  237 +bitmap_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 +
  295 +static void
  296 +bitmap_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 +
  309 +static void
  310 +bitmap_port_flush(struct ip_set *set)
  311 +{
  312 + struct bitmap_port *map = set->data;
  313 +
  314 + memset(map->members, 0, map->memsize);
  315 +}
  316 +
  317 +static int
  318 +bitmap_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;
  337 +nla_put_failure:
  338 + return -EMSGSIZE;
  339 +}
  340 +
  341 +static bool
  342 +bitmap_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 +
  352 +static 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 +
  367 +static 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 +
  382 +static void
  383 +bitmap_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 +
  403 +static void
  404 +bitmap_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 +
  417 +static bool
  418 +init_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 +
  434 +static int
  435 +bitmap_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 +
  485 +static 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 +
  507 +static int __init
  508 +bitmap_port_init(void)
  509 +{
  510 + return ip_set_type_register(&bitmap_port_type);
  511 +}
  512 +
  513 +static void __exit
  514 +bitmap_port_fini(void)
  515 +{
  516 + ip_set_type_unregister(&bitmap_port_type);
  517 +}
  518 +
  519 +module_init(bitmap_port_init);
  520 +module_exit(bitmap_port_fini);