linux/net/netfilter/ipset/ip_set_hash_net.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 hash:net type */
   9
  10#include <linux/jhash.h>
  11#include <linux/module.h>
  12#include <linux/ip.h>
  13#include <linux/skbuff.h>
  14#include <linux/errno.h>
  15#include <linux/random.h>
  16#include <net/ip.h>
  17#include <net/ipv6.h>
  18#include <net/netlink.h>
  19
  20#include <linux/netfilter.h>
  21#include <linux/netfilter/ipset/pfxlen.h>
  22#include <linux/netfilter/ipset/ip_set.h>
  23#include <linux/netfilter/ipset/ip_set_hash.h>
  24
  25#define IPSET_TYPE_REV_MIN      0
  26/*                              1    Range as input support for IPv4 added */
  27/*                              2    nomatch flag support added */
  28/*                              3    Counters support added */
  29/*                              4    Comments support added */
  30/*                              5    Forceadd support added */
  31#define IPSET_TYPE_REV_MAX      6 /* skbinfo mapping support added */
  32
  33MODULE_LICENSE("GPL");
  34MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
  35IP_SET_MODULE_DESC("hash:net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
  36MODULE_ALIAS("ip_set_hash:net");
  37
  38/* Type specific function prefix */
  39#define HTYPE           hash_net
  40#define IP_SET_HASH_WITH_NETS
  41
  42/* IPv4 variant */
  43
  44/* Member elements  */
  45struct hash_net4_elem {
  46        __be32 ip;
  47        u16 padding0;
  48        u8 nomatch;
  49        u8 cidr;
  50};
  51
  52/* Common functions */
  53
  54static inline bool
  55hash_net4_data_equal(const struct hash_net4_elem *ip1,
  56                     const struct hash_net4_elem *ip2,
  57                     u32 *multi)
  58{
  59        return ip1->ip == ip2->ip &&
  60               ip1->cidr == ip2->cidr;
  61}
  62
  63static inline int
  64hash_net4_do_data_match(const struct hash_net4_elem *elem)
  65{
  66        return elem->nomatch ? -ENOTEMPTY : 1;
  67}
  68
  69static inline void
  70hash_net4_data_set_flags(struct hash_net4_elem *elem, u32 flags)
  71{
  72        elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
  73}
  74
  75static inline void
  76hash_net4_data_reset_flags(struct hash_net4_elem *elem, u8 *flags)
  77{
  78        swap(*flags, elem->nomatch);
  79}
  80
  81static inline void
  82hash_net4_data_netmask(struct hash_net4_elem *elem, u8 cidr)
  83{
  84        elem->ip &= ip_set_netmask(cidr);
  85        elem->cidr = cidr;
  86}
  87
  88static bool
  89hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
  90{
  91        u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
  92
  93        if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
  94            nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
  95            (flags &&
  96             nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
  97                goto nla_put_failure;
  98        return false;
  99
 100nla_put_failure:
 101        return true;
 102}
 103
 104static inline void
 105hash_net4_data_next(struct hash_net4_elem *next,
 106                    const struct hash_net4_elem *d)
 107{
 108        next->ip = d->ip;
 109}
 110
 111#define MTYPE           hash_net4
 112#define HOST_MASK       32
 113#include "ip_set_hash_gen.h"
 114
 115static int
 116hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
 117               const struct xt_action_param *par,
 118               enum ipset_adt adt, struct ip_set_adt_opt *opt)
 119{
 120        const struct hash_net4 *h = set->data;
 121        ipset_adtfn adtfn = set->variant->adt[adt];
 122        struct hash_net4_elem e = {
 123                .cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
 124        };
 125        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
 126
 127        if (e.cidr == 0)
 128                return -EINVAL;
 129        if (adt == IPSET_TEST)
 130                e.cidr = HOST_MASK;
 131
 132        ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
 133        e.ip &= ip_set_netmask(e.cidr);
 134
 135        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 136}
 137
 138static int
 139hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
 140               enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 141{
 142        const struct hash_net4 *h = set->data;
 143        ipset_adtfn adtfn = set->variant->adt[adt];
 144        struct hash_net4_elem e = { .cidr = HOST_MASK };
 145        struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
 146        u32 ip = 0, ip_to = 0, last;
 147        int ret;
 148
 149        if (tb[IPSET_ATTR_LINENO])
 150                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 151
 152        if (unlikely(!tb[IPSET_ATTR_IP] ||
 153                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
 154                return -IPSET_ERR_PROTOCOL;
 155
 156        ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
 157        if (ret)
 158                return ret;
 159
 160        ret = ip_set_get_extensions(set, tb, &ext);
 161        if (ret)
 162                return ret;
 163
 164        if (tb[IPSET_ATTR_CIDR]) {
 165                e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 166                if (!e.cidr || e.cidr > HOST_MASK)
 167                        return -IPSET_ERR_INVALID_CIDR;
 168        }
 169
 170        if (tb[IPSET_ATTR_CADT_FLAGS]) {
 171                u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
 172
 173                if (cadt_flags & IPSET_FLAG_NOMATCH)
 174                        flags |= (IPSET_FLAG_NOMATCH << 16);
 175        }
 176
 177        if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
 178                e.ip = htonl(ip & ip_set_hostmask(e.cidr));
 179                ret = adtfn(set, &e, &ext, &ext, flags);
 180                return ip_set_enomatch(ret, flags, adt, set) ? -ret :
 181                       ip_set_eexist(ret, flags) ? 0 : ret;
 182        }
 183
 184        ip_to = ip;
 185        if (tb[IPSET_ATTR_IP_TO]) {
 186                ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
 187                if (ret)
 188                        return ret;
 189                if (ip_to < ip)
 190                        swap(ip, ip_to);
 191                if (ip + UINT_MAX == ip_to)
 192                        return -IPSET_ERR_HASH_RANGE;
 193        }
 194        if (retried)
 195                ip = ntohl(h->next.ip);
 196        while (!after(ip, ip_to)) {
 197                e.ip = htonl(ip);
 198                last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
 199                ret = adtfn(set, &e, &ext, &ext, flags);
 200                if (ret && !ip_set_eexist(ret, flags))
 201                        return ret;
 202
 203                ret = 0;
 204                ip = last + 1;
 205        }
 206        return ret;
 207}
 208
 209/* IPv6 variant */
 210
 211struct hash_net6_elem {
 212        union nf_inet_addr ip;
 213        u16 padding0;
 214        u8 nomatch;
 215        u8 cidr;
 216};
 217
 218/* Common functions */
 219
 220static inline bool
 221hash_net6_data_equal(const struct hash_net6_elem *ip1,
 222                     const struct hash_net6_elem *ip2,
 223                     u32 *multi)
 224{
 225        return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
 226               ip1->cidr == ip2->cidr;
 227}
 228
 229static inline int
 230hash_net6_do_data_match(const struct hash_net6_elem *elem)
 231{
 232        return elem->nomatch ? -ENOTEMPTY : 1;
 233}
 234
 235static inline void
 236hash_net6_data_set_flags(struct hash_net6_elem *elem, u32 flags)
 237{
 238        elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
 239}
 240
 241static inline void
 242hash_net6_data_reset_flags(struct hash_net6_elem *elem, u8 *flags)
 243{
 244        swap(*flags, elem->nomatch);
 245}
 246
 247static inline void
 248hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr)
 249{
 250        ip6_netmask(&elem->ip, cidr);
 251        elem->cidr = cidr;
 252}
 253
 254static bool
 255hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
 256{
 257        u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 258
 259        if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
 260            nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
 261            (flags &&
 262             nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
 263                goto nla_put_failure;
 264        return false;
 265
 266nla_put_failure:
 267        return true;
 268}
 269
 270static inline void
 271hash_net6_data_next(struct hash_net6_elem *next,
 272                    const struct hash_net6_elem *d)
 273{
 274}
 275
 276#undef MTYPE
 277#undef HOST_MASK
 278
 279#define MTYPE           hash_net6
 280#define HOST_MASK       128
 281#define IP_SET_EMIT_CREATE
 282#include "ip_set_hash_gen.h"
 283
 284static int
 285hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
 286               const struct xt_action_param *par,
 287               enum ipset_adt adt, struct ip_set_adt_opt *opt)
 288{
 289        const struct hash_net6 *h = set->data;
 290        ipset_adtfn adtfn = set->variant->adt[adt];
 291        struct hash_net6_elem e = {
 292                .cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
 293        };
 294        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
 295
 296        if (e.cidr == 0)
 297                return -EINVAL;
 298        if (adt == IPSET_TEST)
 299                e.cidr = HOST_MASK;
 300
 301        ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
 302        ip6_netmask(&e.ip, e.cidr);
 303
 304        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 305}
 306
 307static int
 308hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
 309               enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 310{
 311        ipset_adtfn adtfn = set->variant->adt[adt];
 312        struct hash_net6_elem e = { .cidr = HOST_MASK };
 313        struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
 314        int ret;
 315
 316        if (tb[IPSET_ATTR_LINENO])
 317                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 318
 319        if (unlikely(!tb[IPSET_ATTR_IP] ||
 320                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
 321                return -IPSET_ERR_PROTOCOL;
 322        if (unlikely(tb[IPSET_ATTR_IP_TO]))
 323                return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
 324
 325        ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip);
 326        if (ret)
 327                return ret;
 328
 329        ret = ip_set_get_extensions(set, tb, &ext);
 330        if (ret)
 331                return ret;
 332
 333        if (tb[IPSET_ATTR_CIDR]) {
 334                e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 335                if (!e.cidr || e.cidr > HOST_MASK)
 336                        return -IPSET_ERR_INVALID_CIDR;
 337        }
 338
 339        ip6_netmask(&e.ip, e.cidr);
 340
 341        if (tb[IPSET_ATTR_CADT_FLAGS]) {
 342                u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
 343
 344                if (cadt_flags & IPSET_FLAG_NOMATCH)
 345                        flags |= (IPSET_FLAG_NOMATCH << 16);
 346        }
 347
 348        ret = adtfn(set, &e, &ext, &ext, flags);
 349
 350        return ip_set_enomatch(ret, flags, adt, set) ? -ret :
 351               ip_set_eexist(ret, flags) ? 0 : ret;
 352}
 353
 354static struct ip_set_type hash_net_type __read_mostly = {
 355        .name           = "hash:net",
 356        .protocol       = IPSET_PROTOCOL,
 357        .features       = IPSET_TYPE_IP | IPSET_TYPE_NOMATCH,
 358        .dimension      = IPSET_DIM_ONE,
 359        .family         = NFPROTO_UNSPEC,
 360        .revision_min   = IPSET_TYPE_REV_MIN,
 361        .revision_max   = IPSET_TYPE_REV_MAX,
 362        .create         = hash_net_create,
 363        .create_policy  = {
 364                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
 365                [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
 366                [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
 367                [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
 368                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 369                [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 370        },
 371        .adt_policy     = {
 372                [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
 373                [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
 374                [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
 375                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 376                [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 377                [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
 378                [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
 379                [IPSET_ATTR_COMMENT]    = { .type = NLA_NUL_STRING,
 380                                            .len  = IPSET_MAX_COMMENT_SIZE },
 381                [IPSET_ATTR_SKBMARK]    = { .type = NLA_U64 },
 382                [IPSET_ATTR_SKBPRIO]    = { .type = NLA_U32 },
 383                [IPSET_ATTR_SKBQUEUE]   = { .type = NLA_U16 },
 384        },
 385        .me             = THIS_MODULE,
 386};
 387
 388static int __init
 389hash_net_init(void)
 390{
 391        return ip_set_type_register(&hash_net_type);
 392}
 393
 394static void __exit
 395hash_net_fini(void)
 396{
 397        rcu_barrier();
 398        ip_set_type_unregister(&hash_net_type);
 399}
 400
 401module_init(hash_net_init);
 402module_exit(hash_net_fini);
 403