linux/net/netfilter/ipset/ip_set_bitmap_port.c
<<
>>
Prefs
   1/* Copyright (C) 2003-2013 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/skbuff.h>
  13#include <linux/errno.h>
  14#include <linux/netlink.h>
  15#include <linux/jiffies.h>
  16#include <linux/timer.h>
  17#include <net/netlink.h>
  18
  19#include <linux/netfilter/ipset/ip_set.h>
  20#include <linux/netfilter/ipset/ip_set_bitmap.h>
  21#include <linux/netfilter/ipset/ip_set_getport.h>
  22
  23#define REVISION_MIN    0
  24#define REVISION_MAX    1       /* Counter support added */
  25
  26MODULE_LICENSE("GPL");
  27MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
  28IP_SET_MODULE_DESC("bitmap:port", REVISION_MIN, REVISION_MAX);
  29MODULE_ALIAS("ip_set_bitmap:port");
  30
  31#define MTYPE           bitmap_port
  32
  33/* Type structure */
  34struct bitmap_port {
  35        void *members;          /* the set members */
  36        void *extensions;       /* data extensions */
  37        u16 first_port;         /* host byte order, included in range */
  38        u16 last_port;          /* host byte order, included in range */
  39        u32 elements;           /* number of max elements in the set */
  40        size_t memsize;         /* members size */
  41        size_t dsize;           /* extensions struct size */
  42        size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
  43        u32 timeout;            /* timeout parameter */
  44        struct timer_list gc;   /* garbage collection */
  45};
  46
  47/* ADT structure for generic function args */
  48struct bitmap_port_adt_elem {
  49        u16 id;
  50};
  51
  52static inline u16
  53port_to_id(const struct bitmap_port *m, u16 port)
  54{
  55        return port - m->first_port;
  56}
  57
  58/* Common functions */
  59
  60static inline int
  61bitmap_port_do_test(const struct bitmap_port_adt_elem *e,
  62                    const struct bitmap_port *map)
  63{
  64        return !!test_bit(e->id, map->members);
  65}
  66
  67static inline int
  68bitmap_port_gc_test(u16 id, const struct bitmap_port *map)
  69{
  70        return !!test_bit(id, map->members);
  71}
  72
  73static inline int
  74bitmap_port_do_add(const struct bitmap_port_adt_elem *e,
  75                   struct bitmap_port *map, u32 flags)
  76{
  77        return !!test_and_set_bit(e->id, map->members);
  78}
  79
  80static inline int
  81bitmap_port_do_del(const struct bitmap_port_adt_elem *e,
  82                   struct bitmap_port *map)
  83{
  84        return !test_and_clear_bit(e->id, map->members);
  85}
  86
  87static inline int
  88bitmap_port_do_list(struct sk_buff *skb, const struct bitmap_port *map, u32 id)
  89{
  90        return nla_put_net16(skb, IPSET_ATTR_PORT,
  91                             htons(map->first_port + id));
  92}
  93
  94static inline int
  95bitmap_port_do_head(struct sk_buff *skb, const struct bitmap_port *map)
  96{
  97        return nla_put_net16(skb, IPSET_ATTR_PORT, htons(map->first_port)) ||
  98               nla_put_net16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port));
  99}
 100
 101static int
 102bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
 103                 const struct xt_action_param *par,
 104                 enum ipset_adt adt, struct ip_set_adt_opt *opt)
 105{
 106        struct bitmap_port *map = set->data;
 107        ipset_adtfn adtfn = set->variant->adt[adt];
 108        struct bitmap_port_adt_elem e = {};
 109        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
 110        __be16 __port;
 111        u16 port = 0;
 112
 113        if (!ip_set_get_ip_port(skb, opt->family,
 114                                opt->flags & IPSET_DIM_ONE_SRC, &__port))
 115                return -EINVAL;
 116
 117        port = ntohs(__port);
 118
 119        if (port < map->first_port || port > map->last_port)
 120                return -IPSET_ERR_BITMAP_RANGE;
 121
 122        e.id = port_to_id(map, port);
 123
 124        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 125}
 126
 127static int
 128bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
 129                 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 130{
 131        struct bitmap_port *map = set->data;
 132        ipset_adtfn adtfn = set->variant->adt[adt];
 133        struct bitmap_port_adt_elem e = {};
 134        struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
 135        u32 port;       /* wraparound */
 136        u16 port_to;
 137        int ret = 0;
 138
 139        if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
 140                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
 141                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
 142                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
 143                     !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
 144                return -IPSET_ERR_PROTOCOL;
 145
 146        if (tb[IPSET_ATTR_LINENO])
 147                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 148
 149        port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
 150        if (port < map->first_port || port > map->last_port)
 151                return -IPSET_ERR_BITMAP_RANGE;
 152        ret = ip_set_get_extensions(set, tb, &ext);
 153        if (ret)
 154                return ret;
 155
 156        if (adt == IPSET_TEST) {
 157                e.id = port_to_id(map, port);
 158                return adtfn(set, &e, &ext, &ext, flags);
 159        }
 160
 161        if (tb[IPSET_ATTR_PORT_TO]) {
 162                port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
 163                if (port > port_to) {
 164                        swap(port, port_to);
 165                        if (port < map->first_port)
 166                                return -IPSET_ERR_BITMAP_RANGE;
 167                }
 168        } else
 169                port_to = port;
 170
 171        if (port_to > map->last_port)
 172                return -IPSET_ERR_BITMAP_RANGE;
 173
 174        for (; port <= port_to; port++) {
 175                e.id = port_to_id(map, port);
 176                ret = adtfn(set, &e, &ext, &ext, flags);
 177
 178                if (ret && !ip_set_eexist(ret, flags))
 179                        return ret;
 180                else
 181                        ret = 0;
 182        }
 183        return ret;
 184}
 185
 186static bool
 187bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
 188{
 189        const struct bitmap_port *x = a->data;
 190        const struct bitmap_port *y = b->data;
 191
 192        return x->first_port == y->first_port &&
 193               x->last_port == y->last_port &&
 194               x->timeout == y->timeout &&
 195               a->extensions == b->extensions;
 196}
 197
 198/* Plain variant */
 199
 200struct bitmap_port_elem {
 201};
 202
 203/* Timeout variant */
 204
 205struct bitmap_portt_elem {
 206        unsigned long timeout;
 207};
 208
 209/* Plain variant with counter */
 210
 211struct bitmap_portc_elem {
 212        struct ip_set_counter counter;
 213};
 214
 215/* Timeout variant with counter */
 216
 217struct bitmap_portct_elem {
 218        unsigned long timeout;
 219        struct ip_set_counter counter;
 220};
 221
 222#include "ip_set_bitmap_gen.h"
 223
 224/* Create bitmap:ip type of sets */
 225
 226static bool
 227init_map_port(struct ip_set *set, struct bitmap_port *map,
 228              u16 first_port, u16 last_port)
 229{
 230        map->members = ip_set_alloc(map->memsize);
 231        if (!map->members)
 232                return false;
 233        if (map->dsize) {
 234                map->extensions = ip_set_alloc(map->dsize * map->elements);
 235                if (!map->extensions) {
 236                        kfree(map->members);
 237                        return false;
 238                }
 239        }
 240        map->first_port = first_port;
 241        map->last_port = last_port;
 242        map->timeout = IPSET_NO_TIMEOUT;
 243
 244        set->data = map;
 245        set->family = NFPROTO_UNSPEC;
 246
 247        return true;
 248}
 249
 250static int
 251bitmap_port_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 252{
 253        struct bitmap_port *map;
 254        u16 first_port, last_port;
 255        u32 cadt_flags = 0;
 256
 257        if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
 258                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) ||
 259                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
 260                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
 261                return -IPSET_ERR_PROTOCOL;
 262
 263        first_port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
 264        last_port = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
 265        if (first_port > last_port) {
 266                u16 tmp = first_port;
 267
 268                first_port = last_port;
 269                last_port = tmp;
 270        }
 271
 272        map = kzalloc(sizeof(*map), GFP_KERNEL);
 273        if (!map)
 274                return -ENOMEM;
 275
 276        map->elements = last_port - first_port + 1;
 277        map->memsize = map->elements * sizeof(unsigned long);
 278        set->variant = &bitmap_port;
 279        if (tb[IPSET_ATTR_CADT_FLAGS])
 280                cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
 281        if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
 282                set->extensions |= IPSET_EXT_COUNTER;
 283                if (tb[IPSET_ATTR_TIMEOUT]) {
 284                        map->dsize = sizeof(struct bitmap_portct_elem);
 285                        map->offset[IPSET_OFFSET_TIMEOUT] =
 286                                offsetof(struct bitmap_portct_elem, timeout);
 287                        map->offset[IPSET_OFFSET_COUNTER] =
 288                                offsetof(struct bitmap_portct_elem, counter);
 289                        if (!init_map_port(set, map, first_port, last_port)) {
 290                                kfree(map);
 291                                return -ENOMEM;
 292                        }
 293
 294                        map->timeout =
 295                                ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 296                        set->extensions |= IPSET_EXT_TIMEOUT;
 297                        bitmap_port_gc_init(set, bitmap_port_gc);
 298                } else {
 299                        map->dsize = sizeof(struct bitmap_portc_elem);
 300                        map->offset[IPSET_OFFSET_COUNTER] =
 301                                offsetof(struct bitmap_portc_elem, counter);
 302                        if (!init_map_port(set, map, first_port, last_port)) {
 303                                kfree(map);
 304                                return -ENOMEM;
 305                        }
 306                }
 307        } else if (tb[IPSET_ATTR_TIMEOUT]) {
 308                map->dsize = sizeof(struct bitmap_portt_elem);
 309                map->offset[IPSET_OFFSET_TIMEOUT] =
 310                        offsetof(struct bitmap_portt_elem, timeout);
 311                if (!init_map_port(set, map, first_port, last_port)) {
 312                        kfree(map);
 313                        return -ENOMEM;
 314                }
 315
 316                map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 317                set->extensions |= IPSET_EXT_TIMEOUT;
 318                bitmap_port_gc_init(set, bitmap_port_gc);
 319        } else {
 320                map->dsize = 0;
 321                if (!init_map_port(set, map, first_port, last_port)) {
 322                        kfree(map);
 323                        return -ENOMEM;
 324                }
 325
 326        }
 327        return 0;
 328}
 329
 330static struct ip_set_type bitmap_port_type = {
 331        .name           = "bitmap:port",
 332        .protocol       = IPSET_PROTOCOL,
 333        .features       = IPSET_TYPE_PORT,
 334        .dimension      = IPSET_DIM_ONE,
 335        .family         = NFPROTO_UNSPEC,
 336        .revision_min   = REVISION_MIN,
 337        .revision_max   = REVISION_MAX,
 338        .create         = bitmap_port_create,
 339        .create_policy  = {
 340                [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
 341                [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
 342                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 343                [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 344        },
 345        .adt_policy     = {
 346                [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
 347                [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
 348                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 349                [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
 350                [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
 351                [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
 352        },
 353        .me             = THIS_MODULE,
 354};
 355
 356static int __init
 357bitmap_port_init(void)
 358{
 359        return ip_set_type_register(&bitmap_port_type);
 360}
 361
 362static void __exit
 363bitmap_port_fini(void)
 364{
 365        ip_set_type_unregister(&bitmap_port_type);
 366}
 367
 368module_init(bitmap_port_init);
 369module_exit(bitmap_port_fini);
 370