linux/net/netfilter/ipset/ip_set_bitmap_port.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
   3
   4/* Kernel module implementing an IP set type: the bitmap:port type */
   5
   6#include <linux/module.h>
   7#include <linux/ip.h>
   8#include <linux/skbuff.h>
   9#include <linux/errno.h>
  10#include <linux/netlink.h>
  11#include <linux/jiffies.h>
  12#include <linux/timer.h>
  13#include <net/netlink.h>
  14
  15#include <linux/netfilter/ipset/ip_set.h>
  16#include <linux/netfilter/ipset/ip_set_bitmap.h>
  17#include <linux/netfilter/ipset/ip_set_getport.h>
  18
  19#define IPSET_TYPE_REV_MIN      0
  20/*                              1          Counter support added */
  21/*                              2          Comment support added */
  22#define IPSET_TYPE_REV_MAX      3       /* skbinfo support added */
  23
  24MODULE_LICENSE("GPL");
  25MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
  26IP_SET_MODULE_DESC("bitmap:port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
  27MODULE_ALIAS("ip_set_bitmap:port");
  28
  29#define MTYPE           bitmap_port
  30
  31/* Type structure */
  32struct bitmap_port {
  33        void *members;          /* the set members */
  34        u16 first_port;         /* host byte order, included in range */
  35        u16 last_port;          /* host byte order, included in range */
  36        u32 elements;           /* number of max elements in the set */
  37        size_t memsize;         /* members size */
  38        struct timer_list gc;   /* garbage collection */
  39        struct ip_set *set;     /* attached to this ip_set */
  40        unsigned char extensions[0]     /* data extensions */
  41                __aligned(__alignof__(u64));
  42};
  43
  44/* ADT structure for generic function args */
  45struct bitmap_port_adt_elem {
  46        u16 id;
  47};
  48
  49static inline u16
  50port_to_id(const struct bitmap_port *m, u16 port)
  51{
  52        return port - m->first_port;
  53}
  54
  55/* Common functions */
  56
  57static inline int
  58bitmap_port_do_test(const struct bitmap_port_adt_elem *e,
  59                    const struct bitmap_port *map, size_t dsize)
  60{
  61        return !!test_bit(e->id, map->members);
  62}
  63
  64static inline int
  65bitmap_port_gc_test(u16 id, const struct bitmap_port *map, size_t dsize)
  66{
  67        return !!test_bit(id, map->members);
  68}
  69
  70static inline int
  71bitmap_port_do_add(const struct bitmap_port_adt_elem *e,
  72                   struct bitmap_port *map, u32 flags, size_t dsize)
  73{
  74        return !!test_bit(e->id, map->members);
  75}
  76
  77static inline int
  78bitmap_port_do_del(const struct bitmap_port_adt_elem *e,
  79                   struct bitmap_port *map)
  80{
  81        return !test_and_clear_bit(e->id, map->members);
  82}
  83
  84static inline int
  85bitmap_port_do_list(struct sk_buff *skb, const struct bitmap_port *map, u32 id,
  86                    size_t dsize)
  87{
  88        return nla_put_net16(skb, IPSET_ATTR_PORT,
  89                             htons(map->first_port + id));
  90}
  91
  92static inline int
  93bitmap_port_do_head(struct sk_buff *skb, const struct bitmap_port *map)
  94{
  95        return nla_put_net16(skb, IPSET_ATTR_PORT, htons(map->first_port)) ||
  96               nla_put_net16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port));
  97}
  98
  99static int
 100bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
 101                 const struct xt_action_param *par,
 102                 enum ipset_adt adt, struct ip_set_adt_opt *opt)
 103{
 104        struct bitmap_port *map = set->data;
 105        ipset_adtfn adtfn = set->variant->adt[adt];
 106        struct bitmap_port_adt_elem e = { .id = 0 };
 107        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
 108        __be16 __port;
 109        u16 port = 0;
 110
 111        if (!ip_set_get_ip_port(skb, opt->family,
 112                                opt->flags & IPSET_DIM_ONE_SRC, &__port))
 113                return -EINVAL;
 114
 115        port = ntohs(__port);
 116
 117        if (port < map->first_port || port > map->last_port)
 118                return -IPSET_ERR_BITMAP_RANGE;
 119
 120        e.id = port_to_id(map, port);
 121
 122        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 123}
 124
 125static int
 126bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
 127                 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 128{
 129        struct bitmap_port *map = set->data;
 130        ipset_adtfn adtfn = set->variant->adt[adt];
 131        struct bitmap_port_adt_elem e = { .id = 0 };
 132        struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
 133        u32 port;       /* wraparound */
 134        u16 port_to;
 135        int ret = 0;
 136
 137        if (tb[IPSET_ATTR_LINENO])
 138                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 139
 140        if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
 141                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO)))
 142                return -IPSET_ERR_PROTOCOL;
 143
 144        port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
 145        if (port < map->first_port || port > map->last_port)
 146                return -IPSET_ERR_BITMAP_RANGE;
 147        ret = ip_set_get_extensions(set, tb, &ext);
 148        if (ret)
 149                return ret;
 150
 151        if (adt == IPSET_TEST) {
 152                e.id = port_to_id(map, port);
 153                return adtfn(set, &e, &ext, &ext, flags);
 154        }
 155
 156        if (tb[IPSET_ATTR_PORT_TO]) {
 157                port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
 158                if (port > port_to) {
 159                        swap(port, port_to);
 160                        if (port < map->first_port)
 161                                return -IPSET_ERR_BITMAP_RANGE;
 162                }
 163        } else {
 164                port_to = port;
 165        }
 166
 167        if (port_to > map->last_port)
 168                return -IPSET_ERR_BITMAP_RANGE;
 169
 170        for (; port <= port_to; port++) {
 171                e.id = port_to_id(map, port);
 172                ret = adtfn(set, &e, &ext, &ext, flags);
 173
 174                if (ret && !ip_set_eexist(ret, flags))
 175                        return ret;
 176
 177                ret = 0;
 178        }
 179        return ret;
 180}
 181
 182static bool
 183bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
 184{
 185        const struct bitmap_port *x = a->data;
 186        const struct bitmap_port *y = b->data;
 187
 188        return x->first_port == y->first_port &&
 189               x->last_port == y->last_port &&
 190               a->timeout == b->timeout &&
 191               a->extensions == b->extensions;
 192}
 193
 194/* Plain variant */
 195
 196struct bitmap_port_elem {
 197};
 198
 199#include "ip_set_bitmap_gen.h"
 200
 201/* Create bitmap:ip type of sets */
 202
 203static bool
 204init_map_port(struct ip_set *set, struct bitmap_port *map,
 205              u16 first_port, u16 last_port)
 206{
 207        map->members = ip_set_alloc(map->memsize);
 208        if (!map->members)
 209                return false;
 210        map->first_port = first_port;
 211        map->last_port = last_port;
 212        set->timeout = IPSET_NO_TIMEOUT;
 213
 214        map->set = set;
 215        set->data = map;
 216        set->family = NFPROTO_UNSPEC;
 217
 218        return true;
 219}
 220
 221static int
 222bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
 223                   u32 flags)
 224{
 225        struct bitmap_port *map;
 226        u16 first_port, last_port;
 227        u32 elements;
 228
 229        if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
 230                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) ||
 231                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
 232                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
 233                return -IPSET_ERR_PROTOCOL;
 234
 235        first_port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
 236        last_port = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
 237        if (first_port > last_port)
 238                swap(first_port, last_port);
 239
 240        elements = last_port - first_port + 1;
 241        set->dsize = ip_set_elem_len(set, tb, 0, 0);
 242        map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
 243        if (!map)
 244                return -ENOMEM;
 245
 246        map->elements = elements;
 247        map->memsize = bitmap_bytes(0, map->elements);
 248        set->variant = &bitmap_port;
 249        if (!init_map_port(set, map, first_port, last_port)) {
 250                kfree(map);
 251                return -ENOMEM;
 252        }
 253        if (tb[IPSET_ATTR_TIMEOUT]) {
 254                set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 255                bitmap_port_gc_init(set, bitmap_port_gc);
 256        }
 257        return 0;
 258}
 259
 260static struct ip_set_type bitmap_port_type = {
 261        .name           = "bitmap:port",
 262        .protocol       = IPSET_PROTOCOL,
 263        .features       = IPSET_TYPE_PORT,
 264        .dimension      = IPSET_DIM_ONE,
 265        .family         = NFPROTO_UNSPEC,
 266        .revision_min   = IPSET_TYPE_REV_MIN,
 267        .revision_max   = IPSET_TYPE_REV_MAX,
 268        .create         = bitmap_port_create,
 269        .create_policy  = {
 270                [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
 271                [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
 272                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 273                [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 274        },
 275        .adt_policy     = {
 276                [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
 277                [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
 278                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 279                [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
 280                [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
 281                [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
 282                [IPSET_ATTR_COMMENT]    = { .type = NLA_NUL_STRING,
 283                                            .len  = IPSET_MAX_COMMENT_SIZE },
 284                [IPSET_ATTR_SKBMARK]    = { .type = NLA_U64 },
 285                [IPSET_ATTR_SKBPRIO]    = { .type = NLA_U32 },
 286                [IPSET_ATTR_SKBQUEUE]   = { .type = NLA_U16 },
 287        },
 288        .me             = THIS_MODULE,
 289};
 290
 291static int __init
 292bitmap_port_init(void)
 293{
 294        return ip_set_type_register(&bitmap_port_type);
 295}
 296
 297static void __exit
 298bitmap_port_fini(void)
 299{
 300        rcu_barrier();
 301        ip_set_type_unregister(&bitmap_port_type);
 302}
 303
 304module_init(bitmap_port_init);
 305module_exit(bitmap_port_fini);
 306