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