linux/net/netfilter/ipset/ip_set_hash_ip.c
<<
>>
Prefs
   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 hash:ip 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#include <net/tcp.h>
  20
  21#include <linux/netfilter.h>
  22#include <linux/netfilter/ipset/pfxlen.h>
  23#include <linux/netfilter/ipset/ip_set.h>
  24#include <linux/netfilter/ipset/ip_set_timeout.h>
  25#include <linux/netfilter/ipset/ip_set_hash.h>
  26
  27MODULE_LICENSE("GPL");
  28MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
  29MODULE_DESCRIPTION("hash:ip type of IP sets");
  30MODULE_ALIAS("ip_set_hash:ip");
  31
  32/* Type specific function prefix */
  33#define TYPE            hash_ip
  34
  35static bool
  36hash_ip_same_set(const struct ip_set *a, const struct ip_set *b);
  37
  38#define hash_ip4_same_set       hash_ip_same_set
  39#define hash_ip6_same_set       hash_ip_same_set
  40
  41/* The type variant functions: IPv4 */
  42
  43/* Member elements without timeout */
  44struct hash_ip4_elem {
  45        __be32 ip;
  46};
  47
  48/* Member elements with timeout support */
  49struct hash_ip4_telem {
  50        __be32 ip;
  51        unsigned long timeout;
  52};
  53
  54static inline bool
  55hash_ip4_data_equal(const struct hash_ip4_elem *ip1,
  56                    const struct hash_ip4_elem *ip2,
  57                    u32 *multi)
  58{
  59        return ip1->ip == ip2->ip;
  60}
  61
  62static inline bool
  63hash_ip4_data_isnull(const struct hash_ip4_elem *elem)
  64{
  65        return elem->ip == 0;
  66}
  67
  68static inline void
  69hash_ip4_data_copy(struct hash_ip4_elem *dst, const struct hash_ip4_elem *src)
  70{
  71        dst->ip = src->ip;
  72}
  73
  74/* Zero valued IP addresses cannot be stored */
  75static inline void
  76hash_ip4_data_zero_out(struct hash_ip4_elem *elem)
  77{
  78        elem->ip = 0;
  79}
  80
  81static inline bool
  82hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *data)
  83{
  84        NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
  85        return 0;
  86
  87nla_put_failure:
  88        return 1;
  89}
  90
  91static bool
  92hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data)
  93{
  94        const struct hash_ip4_telem *tdata =
  95                (const struct hash_ip4_telem *)data;
  96
  97        NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
  98        NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
  99                      htonl(ip_set_timeout_get(tdata->timeout)));
 100
 101        return 0;
 102
 103nla_put_failure:
 104        return 1;
 105}
 106
 107#define IP_SET_HASH_WITH_NETMASK
 108#define PF              4
 109#define HOST_MASK       32
 110#include <linux/netfilter/ipset/ip_set_ahash.h>
 111
 112static inline void
 113hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d)
 114{
 115        h->next.ip = ntohl(d->ip);
 116}
 117
 118static int
 119hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
 120              const struct xt_action_param *par,
 121              enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 122{
 123        const struct ip_set_hash *h = set->data;
 124        ipset_adtfn adtfn = set->variant->adt[adt];
 125        __be32 ip;
 126
 127        ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
 128        ip &= ip_set_netmask(h->netmask);
 129        if (ip == 0)
 130                return -EINVAL;
 131
 132        return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
 133}
 134
 135static int
 136hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
 137              enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 138{
 139        const struct ip_set_hash *h = set->data;
 140        ipset_adtfn adtfn = set->variant->adt[adt];
 141        u32 ip, ip_to, hosts, timeout = h->timeout;
 142        __be32 nip;
 143        int ret = 0;
 144
 145        if (unlikely(!tb[IPSET_ATTR_IP] ||
 146                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
 147                return -IPSET_ERR_PROTOCOL;
 148
 149        if (tb[IPSET_ATTR_LINENO])
 150                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 151
 152        ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
 153        if (ret)
 154                return ret;
 155
 156        ip &= ip_set_hostmask(h->netmask);
 157
 158        if (tb[IPSET_ATTR_TIMEOUT]) {
 159                if (!with_timeout(h->timeout))
 160                        return -IPSET_ERR_TIMEOUT;
 161                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 162        }
 163
 164        if (adt == IPSET_TEST) {
 165                nip = htonl(ip);
 166                if (nip == 0)
 167                        return -IPSET_ERR_HASH_ELEM;
 168                return adtfn(set, &nip, timeout, flags);
 169        }
 170
 171        if (tb[IPSET_ATTR_IP_TO]) {
 172                ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
 173                if (ret)
 174                        return ret;
 175                if (ip > ip_to)
 176                        swap(ip, ip_to);
 177        } else if (tb[IPSET_ATTR_CIDR]) {
 178                u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 179
 180                if (cidr > 32)
 181                        return -IPSET_ERR_INVALID_CIDR;
 182                ip_set_mask_from_to(ip, ip_to, cidr);
 183        } else
 184                ip_to = ip;
 185
 186        hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
 187
 188        if (retried)
 189                ip = h->next.ip;
 190        for (; !before(ip_to, ip); ip += hosts) {
 191                nip = htonl(ip);
 192                if (nip == 0)
 193                        return -IPSET_ERR_HASH_ELEM;
 194                ret = adtfn(set, &nip, timeout, flags);
 195
 196                if (ret && !ip_set_eexist(ret, flags))
 197                        return ret;
 198                else
 199                        ret = 0;
 200        }
 201        return ret;
 202}
 203
 204static bool
 205hash_ip_same_set(const struct ip_set *a, const struct ip_set *b)
 206{
 207        const struct ip_set_hash *x = a->data;
 208        const struct ip_set_hash *y = b->data;
 209
 210        /* Resizing changes htable_bits, so we ignore it */
 211        return x->maxelem == y->maxelem &&
 212               x->timeout == y->timeout &&
 213               x->netmask == y->netmask;
 214}
 215
 216/* The type variant functions: IPv6 */
 217
 218struct hash_ip6_elem {
 219        union nf_inet_addr ip;
 220};
 221
 222struct hash_ip6_telem {
 223        union nf_inet_addr ip;
 224        unsigned long timeout;
 225};
 226
 227static inline bool
 228hash_ip6_data_equal(const struct hash_ip6_elem *ip1,
 229                    const struct hash_ip6_elem *ip2,
 230                    u32 *multi)
 231{
 232        return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0;
 233}
 234
 235static inline bool
 236hash_ip6_data_isnull(const struct hash_ip6_elem *elem)
 237{
 238        return ipv6_addr_any(&elem->ip.in6);
 239}
 240
 241static inline void
 242hash_ip6_data_copy(struct hash_ip6_elem *dst, const struct hash_ip6_elem *src)
 243{
 244        dst->ip.in6 = src->ip.in6;
 245}
 246
 247static inline void
 248hash_ip6_data_zero_out(struct hash_ip6_elem *elem)
 249{
 250        ipv6_addr_set(&elem->ip.in6, 0, 0, 0, 0);
 251}
 252
 253static inline void
 254ip6_netmask(union nf_inet_addr *ip, u8 prefix)
 255{
 256        ip->ip6[0] &= ip_set_netmask6(prefix)[0];
 257        ip->ip6[1] &= ip_set_netmask6(prefix)[1];
 258        ip->ip6[2] &= ip_set_netmask6(prefix)[2];
 259        ip->ip6[3] &= ip_set_netmask6(prefix)[3];
 260}
 261
 262static bool
 263hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data)
 264{
 265        NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
 266        return 0;
 267
 268nla_put_failure:
 269        return 1;
 270}
 271
 272static bool
 273hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data)
 274{
 275        const struct hash_ip6_telem *e =
 276                (const struct hash_ip6_telem *)data;
 277
 278        NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
 279        NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
 280                      htonl(ip_set_timeout_get(e->timeout)));
 281        return 0;
 282
 283nla_put_failure:
 284        return 1;
 285}
 286
 287#undef PF
 288#undef HOST_MASK
 289
 290#define PF              6
 291#define HOST_MASK       128
 292#include <linux/netfilter/ipset/ip_set_ahash.h>
 293
 294static inline void
 295hash_ip6_data_next(struct ip_set_hash *h, const struct hash_ip6_elem *d)
 296{
 297}
 298
 299static int
 300hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
 301              const struct xt_action_param *par,
 302              enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 303{
 304        const struct ip_set_hash *h = set->data;
 305        ipset_adtfn adtfn = set->variant->adt[adt];
 306        union nf_inet_addr ip;
 307
 308        ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip.in6);
 309        ip6_netmask(&ip, h->netmask);
 310        if (ipv6_addr_any(&ip.in6))
 311                return -EINVAL;
 312
 313        return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
 314}
 315
 316static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
 317        [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
 318        [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 319        [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
 320};
 321
 322static int
 323hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
 324              enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 325{
 326        const struct ip_set_hash *h = set->data;
 327        ipset_adtfn adtfn = set->variant->adt[adt];
 328        union nf_inet_addr ip;
 329        u32 timeout = h->timeout;
 330        int ret;
 331
 332        if (unlikely(!tb[IPSET_ATTR_IP] ||
 333                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
 334                     tb[IPSET_ATTR_IP_TO] ||
 335                     tb[IPSET_ATTR_CIDR]))
 336                return -IPSET_ERR_PROTOCOL;
 337
 338        if (tb[IPSET_ATTR_LINENO])
 339                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 340
 341        ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &ip);
 342        if (ret)
 343                return ret;
 344
 345        ip6_netmask(&ip, h->netmask);
 346        if (ipv6_addr_any(&ip.in6))
 347                return -IPSET_ERR_HASH_ELEM;
 348
 349        if (tb[IPSET_ATTR_TIMEOUT]) {
 350                if (!with_timeout(h->timeout))
 351                        return -IPSET_ERR_TIMEOUT;
 352                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 353        }
 354
 355        ret = adtfn(set, &ip, timeout, flags);
 356
 357        return ip_set_eexist(ret, flags) ? 0 : ret;
 358}
 359
 360/* Create hash:ip type of sets */
 361
 362static int
 363hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 364{
 365        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
 366        u8 netmask, hbits;
 367        struct ip_set_hash *h;
 368
 369        if (!(set->family == AF_INET || set->family == AF_INET6))
 370                return -IPSET_ERR_INVALID_FAMILY;
 371        netmask = set->family == AF_INET ? 32 : 128;
 372        pr_debug("Create set %s with family %s\n",
 373                 set->name, set->family == AF_INET ? "inet" : "inet6");
 374
 375        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
 376                     !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
 377                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
 378                return -IPSET_ERR_PROTOCOL;
 379
 380        if (tb[IPSET_ATTR_HASHSIZE]) {
 381                hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
 382                if (hashsize < IPSET_MIMINAL_HASHSIZE)
 383                        hashsize = IPSET_MIMINAL_HASHSIZE;
 384        }
 385
 386        if (tb[IPSET_ATTR_MAXELEM])
 387                maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
 388
 389        if (tb[IPSET_ATTR_NETMASK]) {
 390                netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
 391
 392                if ((set->family == AF_INET && netmask > 32) ||
 393                    (set->family == AF_INET6 && netmask > 128) ||
 394                    netmask == 0)
 395                        return -IPSET_ERR_INVALID_NETMASK;
 396        }
 397
 398        h = kzalloc(sizeof(*h), GFP_KERNEL);
 399        if (!h)
 400                return -ENOMEM;
 401
 402        h->maxelem = maxelem;
 403        h->netmask = netmask;
 404        get_random_bytes(&h->initval, sizeof(h->initval));
 405        h->timeout = IPSET_NO_TIMEOUT;
 406
 407        hbits = htable_bits(hashsize);
 408        h->table = ip_set_alloc(
 409                        sizeof(struct htable)
 410                        + jhash_size(hbits) * sizeof(struct hbucket));
 411        if (!h->table) {
 412                kfree(h);
 413                return -ENOMEM;
 414        }
 415        h->table->htable_bits = hbits;
 416
 417        set->data = h;
 418
 419        if (tb[IPSET_ATTR_TIMEOUT]) {
 420                h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 421
 422                set->variant = set->family == AF_INET
 423                        ? &hash_ip4_tvariant : &hash_ip6_tvariant;
 424
 425                if (set->family == AF_INET)
 426                        hash_ip4_gc_init(set);
 427                else
 428                        hash_ip6_gc_init(set);
 429        } else {
 430                set->variant = set->family == AF_INET
 431                        ? &hash_ip4_variant : &hash_ip6_variant;
 432        }
 433
 434        pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
 435                 set->name, jhash_size(h->table->htable_bits),
 436                 h->table->htable_bits, h->maxelem, set->data, h->table);
 437
 438        return 0;
 439}
 440
 441static struct ip_set_type hash_ip_type __read_mostly = {
 442        .name           = "hash:ip",
 443        .protocol       = IPSET_PROTOCOL,
 444        .features       = IPSET_TYPE_IP,
 445        .dimension      = IPSET_DIM_ONE,
 446        .family         = AF_UNSPEC,
 447        .revision_min   = 0,
 448        .revision_max   = 0,
 449        .create         = hash_ip_create,
 450        .create_policy  = {
 451                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
 452                [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
 453                [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
 454                [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
 455                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 456                [IPSET_ATTR_NETMASK]    = { .type = NLA_U8  },
 457        },
 458        .adt_policy     = {
 459                [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
 460                [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
 461                [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
 462                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 463                [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
 464        },
 465        .me             = THIS_MODULE,
 466};
 467
 468static int __init
 469hash_ip_init(void)
 470{
 471        return ip_set_type_register(&hash_ip_type);
 472}
 473
 474static void __exit
 475hash_ip_fini(void)
 476{
 477        ip_set_type_unregister(&hash_ip_type);
 478}
 479
 480module_init(hash_ip_init);
 481module_exit(hash_ip_fini);
 482
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.