linux/net/netfilter/ipset/ip_set_hash_ipport.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,port 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_getport.h>
  26#include <linux/netfilter/ipset/ip_set_hash.h>
  27
  28#define REVISION_MIN    0
  29#define REVISION_MAX    1 /* SCTP and UDPLITE support added */
  30
  31MODULE_LICENSE("GPL");
  32MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
  33IP_SET_MODULE_DESC("hash:ip,port", REVISION_MIN, REVISION_MAX);
  34MODULE_ALIAS("ip_set_hash:ip,port");
  35
  36/* Type specific function prefix */
  37#define TYPE            hash_ipport
  38
  39static bool
  40hash_ipport_same_set(const struct ip_set *a, const struct ip_set *b);
  41
  42#define hash_ipport4_same_set   hash_ipport_same_set
  43#define hash_ipport6_same_set   hash_ipport_same_set
  44
  45/* The type variant functions: IPv4 */
  46
  47/* Member elements without timeout */
  48struct hash_ipport4_elem {
  49        __be32 ip;
  50        __be16 port;
  51        u8 proto;
  52        u8 padding;
  53};
  54
  55/* Member elements with timeout support */
  56struct hash_ipport4_telem {
  57        __be32 ip;
  58        __be16 port;
  59        u8 proto;
  60        u8 padding;
  61        unsigned long timeout;
  62};
  63
  64static inline bool
  65hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1,
  66                        const struct hash_ipport4_elem *ip2,
  67                        u32 *multi)
  68{
  69        return ip1->ip == ip2->ip &&
  70               ip1->port == ip2->port &&
  71               ip1->proto == ip2->proto;
  72}
  73
  74static inline bool
  75hash_ipport4_data_isnull(const struct hash_ipport4_elem *elem)
  76{
  77        return elem->proto == 0;
  78}
  79
  80static inline void
  81hash_ipport4_data_copy(struct hash_ipport4_elem *dst,
  82                       const struct hash_ipport4_elem *src)
  83{
  84        dst->ip = src->ip;
  85        dst->port = src->port;
  86        dst->proto = src->proto;
  87}
  88
  89static inline void
  90hash_ipport4_data_zero_out(struct hash_ipport4_elem *elem)
  91{
  92        elem->proto = 0;
  93}
  94
  95static bool
  96hash_ipport4_data_list(struct sk_buff *skb,
  97                       const struct hash_ipport4_elem *data)
  98{
  99        if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
 100            nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
 101            nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto))
 102                goto nla_put_failure;
 103        return 0;
 104
 105nla_put_failure:
 106        return 1;
 107}
 108
 109static bool
 110hash_ipport4_data_tlist(struct sk_buff *skb,
 111                        const struct hash_ipport4_elem *data)
 112{
 113        const struct hash_ipport4_telem *tdata =
 114                (const struct hash_ipport4_telem *)data;
 115
 116        if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, tdata->ip) ||
 117            nla_put_net16(skb, IPSET_ATTR_PORT, tdata->port) ||
 118            nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
 119            nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
 120                          htonl(ip_set_timeout_get(tdata->timeout))))
 121                goto nla_put_failure;
 122        return 0;
 123
 124nla_put_failure:
 125        return 1;
 126}
 127
 128#define PF              4
 129#define HOST_MASK       32
 130#include <linux/netfilter/ipset/ip_set_ahash.h>
 131
 132static inline void
 133hash_ipport4_data_next(struct ip_set_hash *h,
 134                       const struct hash_ipport4_elem *d)
 135{
 136        h->next.ip = d->ip;
 137        h->next.port = d->port;
 138}
 139
 140static int
 141hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
 142                  const struct xt_action_param *par,
 143                  enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 144{
 145        const struct ip_set_hash *h = set->data;
 146        ipset_adtfn adtfn = set->variant->adt[adt];
 147        struct hash_ipport4_elem data = { };
 148
 149        if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
 150                                 &data.port, &data.proto))
 151                return -EINVAL;
 152
 153        ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
 154
 155        return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 156}
 157
 158static int
 159hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
 160                  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 161{
 162        const struct ip_set_hash *h = set->data;
 163        ipset_adtfn adtfn = set->variant->adt[adt];
 164        struct hash_ipport4_elem data = { };
 165        u32 ip, ip_to, p = 0, port, port_to;
 166        u32 timeout = h->timeout;
 167        bool with_ports = false;
 168        int ret;
 169
 170        if (unlikely(!tb[IPSET_ATTR_IP] ||
 171                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
 172                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
 173                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
 174                return -IPSET_ERR_PROTOCOL;
 175
 176        if (tb[IPSET_ATTR_LINENO])
 177                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 178
 179        ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
 180        if (ret)
 181                return ret;
 182
 183        if (tb[IPSET_ATTR_PORT])
 184                data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
 185        else
 186                return -IPSET_ERR_PROTOCOL;
 187
 188        if (tb[IPSET_ATTR_PROTO]) {
 189                data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
 190                with_ports = ip_set_proto_with_ports(data.proto);
 191
 192                if (data.proto == 0)
 193                        return -IPSET_ERR_INVALID_PROTO;
 194        } else
 195                return -IPSET_ERR_MISSING_PROTO;
 196
 197        if (!(with_ports || data.proto == IPPROTO_ICMP))
 198                data.port = 0;
 199
 200        if (tb[IPSET_ATTR_TIMEOUT]) {
 201                if (!with_timeout(h->timeout))
 202                        return -IPSET_ERR_TIMEOUT;
 203                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 204        }
 205
 206        if (adt == IPSET_TEST ||
 207            !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
 208              tb[IPSET_ATTR_PORT_TO])) {
 209                ret = adtfn(set, &data, timeout, flags);
 210                return ip_set_eexist(ret, flags) ? 0 : ret;
 211        }
 212
 213        ip_to = ip = ntohl(data.ip);
 214        if (tb[IPSET_ATTR_IP_TO]) {
 215                ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
 216                if (ret)
 217                        return ret;
 218                if (ip > ip_to)
 219                        swap(ip, ip_to);
 220        } else if (tb[IPSET_ATTR_CIDR]) {
 221                u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 222
 223                if (!cidr || cidr > 32)
 224                        return -IPSET_ERR_INVALID_CIDR;
 225                ip_set_mask_from_to(ip, ip_to, cidr);
 226        }
 227
 228        port_to = port = ntohs(data.port);
 229        if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
 230                port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
 231                if (port > port_to)
 232                        swap(port, port_to);
 233        }
 234
 235        if (retried)
 236                ip = ntohl(h->next.ip);
 237        for (; !before(ip_to, ip); ip++) {
 238                p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
 239                                                       : port;
 240                for (; p <= port_to; p++) {
 241                        data.ip = htonl(ip);
 242                        data.port = htons(p);
 243                        ret = adtfn(set, &data, timeout, flags);
 244
 245                        if (ret && !ip_set_eexist(ret, flags))
 246                                return ret;
 247                        else
 248                                ret = 0;
 249                }
 250        }
 251        return ret;
 252}
 253
 254static bool
 255hash_ipport_same_set(const struct ip_set *a, const struct ip_set *b)
 256{
 257        const struct ip_set_hash *x = a->data;
 258        const struct ip_set_hash *y = b->data;
 259
 260        /* Resizing changes htable_bits, so we ignore it */
 261        return x->maxelem == y->maxelem &&
 262               x->timeout == y->timeout;
 263}
 264
 265/* The type variant functions: IPv6 */
 266
 267struct hash_ipport6_elem {
 268        union nf_inet_addr ip;
 269        __be16 port;
 270        u8 proto;
 271        u8 padding;
 272};
 273
 274struct hash_ipport6_telem {
 275        union nf_inet_addr ip;
 276        __be16 port;
 277        u8 proto;
 278        u8 padding;
 279        unsigned long timeout;
 280};
 281
 282static inline bool
 283hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1,
 284                        const struct hash_ipport6_elem *ip2,
 285                        u32 *multi)
 286{
 287        return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
 288               ip1->port == ip2->port &&
 289               ip1->proto == ip2->proto;
 290}
 291
 292static inline bool
 293hash_ipport6_data_isnull(const struct hash_ipport6_elem *elem)
 294{
 295        return elem->proto == 0;
 296}
 297
 298static inline void
 299hash_ipport6_data_copy(struct hash_ipport6_elem *dst,
 300                       const struct hash_ipport6_elem *src)
 301{
 302        memcpy(dst, src, sizeof(*dst));
 303}
 304
 305static inline void
 306hash_ipport6_data_zero_out(struct hash_ipport6_elem *elem)
 307{
 308        elem->proto = 0;
 309}
 310
 311static bool
 312hash_ipport6_data_list(struct sk_buff *skb,
 313                       const struct hash_ipport6_elem *data)
 314{
 315        if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
 316            nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
 317            nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto))
 318                goto nla_put_failure;
 319        return 0;
 320
 321nla_put_failure:
 322        return 1;
 323}
 324
 325static bool
 326hash_ipport6_data_tlist(struct sk_buff *skb,
 327                        const struct hash_ipport6_elem *data)
 328{
 329        const struct hash_ipport6_telem *e =
 330                (const struct hash_ipport6_telem *)data;
 331
 332        if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
 333            nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
 334            nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
 335            nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
 336                          htonl(ip_set_timeout_get(e->timeout))))
 337                goto nla_put_failure;
 338        return 0;
 339
 340nla_put_failure:
 341        return 1;
 342}
 343
 344#undef PF
 345#undef HOST_MASK
 346
 347#define PF              6
 348#define HOST_MASK       128
 349#include <linux/netfilter/ipset/ip_set_ahash.h>
 350
 351static inline void
 352hash_ipport6_data_next(struct ip_set_hash *h,
 353                       const struct hash_ipport6_elem *d)
 354{
 355        h->next.port = d->port;
 356}
 357
 358static int
 359hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
 360                  const struct xt_action_param *par,
 361                  enum ipset_adt adt, const struct ip_set_adt_opt *opt)
 362{
 363        const struct ip_set_hash *h = set->data;
 364        ipset_adtfn adtfn = set->variant->adt[adt];
 365        struct hash_ipport6_elem data = { };
 366
 367        if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
 368                                 &data.port, &data.proto))
 369                return -EINVAL;
 370
 371        ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
 372
 373        return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
 374}
 375
 376static int
 377hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
 378                  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 379{
 380        const struct ip_set_hash *h = set->data;
 381        ipset_adtfn adtfn = set->variant->adt[adt];
 382        struct hash_ipport6_elem data = { };
 383        u32 port, port_to;
 384        u32 timeout = h->timeout;
 385        bool with_ports = false;
 386        int ret;
 387
 388        if (unlikely(!tb[IPSET_ATTR_IP] ||
 389                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
 390                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
 391                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
 392                     tb[IPSET_ATTR_IP_TO] ||
 393                     tb[IPSET_ATTR_CIDR]))
 394                return -IPSET_ERR_PROTOCOL;
 395
 396        if (tb[IPSET_ATTR_LINENO])
 397                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 398
 399        ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
 400        if (ret)
 401                return ret;
 402
 403        if (tb[IPSET_ATTR_PORT])
 404                data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
 405        else
 406                return -IPSET_ERR_PROTOCOL;
 407
 408        if (tb[IPSET_ATTR_PROTO]) {
 409                data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
 410                with_ports = ip_set_proto_with_ports(data.proto);
 411
 412                if (data.proto == 0)
 413                        return -IPSET_ERR_INVALID_PROTO;
 414        } else
 415                return -IPSET_ERR_MISSING_PROTO;
 416
 417        if (!(with_ports || data.proto == IPPROTO_ICMPV6))
 418                data.port = 0;
 419
 420        if (tb[IPSET_ATTR_TIMEOUT]) {
 421                if (!with_timeout(h->timeout))
 422                        return -IPSET_ERR_TIMEOUT;
 423                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 424        }
 425
 426        if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
 427                ret = adtfn(set, &data, timeout, flags);
 428                return ip_set_eexist(ret, flags) ? 0 : ret;
 429        }
 430
 431        port = ntohs(data.port);
 432        port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
 433        if (port > port_to)
 434                swap(port, port_to);
 435
 436        if (retried)
 437                port = ntohs(h->next.port);
 438        for (; port <= port_to; port++) {
 439                data.port = htons(port);
 440                ret = adtfn(set, &data, timeout, flags);
 441
 442                if (ret && !ip_set_eexist(ret, flags))
 443                        return ret;
 444                else
 445                        ret = 0;
 446        }
 447        return ret;
 448}
 449
 450/* Create hash:ip type of sets */
 451
 452static int
 453hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 454{
 455        struct ip_set_hash *h;
 456        u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
 457        u8 hbits;
 458        size_t hsize;
 459
 460        if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
 461                return -IPSET_ERR_INVALID_FAMILY;
 462
 463        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
 464                     !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
 465                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
 466                return -IPSET_ERR_PROTOCOL;
 467
 468        if (tb[IPSET_ATTR_HASHSIZE]) {
 469                hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
 470                if (hashsize < IPSET_MIMINAL_HASHSIZE)
 471                        hashsize = IPSET_MIMINAL_HASHSIZE;
 472        }
 473
 474        if (tb[IPSET_ATTR_MAXELEM])
 475                maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
 476
 477        h = kzalloc(sizeof(*h), GFP_KERNEL);
 478        if (!h)
 479                return -ENOMEM;
 480
 481        h->maxelem = maxelem;
 482        get_random_bytes(&h->initval, sizeof(h->initval));
 483        h->timeout = IPSET_NO_TIMEOUT;
 484
 485        hbits = htable_bits(hashsize);
 486        hsize = htable_size(hbits);
 487        if (hsize == 0) {
 488                kfree(h);
 489                return -ENOMEM;
 490        }
 491        h->table = ip_set_alloc(hsize);
 492        if (!h->table) {
 493                kfree(h);
 494                return -ENOMEM;
 495        }
 496        h->table->htable_bits = hbits;
 497
 498        set->data = h;
 499
 500        if (tb[IPSET_ATTR_TIMEOUT]) {
 501                h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 502
 503                set->variant = set->family == NFPROTO_IPV4
 504                        ? &hash_ipport4_tvariant : &hash_ipport6_tvariant;
 505
 506                if (set->family == NFPROTO_IPV4)
 507                        hash_ipport4_gc_init(set);
 508                else
 509                        hash_ipport6_gc_init(set);
 510        } else {
 511                set->variant = set->family == NFPROTO_IPV4
 512                        ? &hash_ipport4_variant : &hash_ipport6_variant;
 513        }
 514
 515        pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
 516                 set->name, jhash_size(h->table->htable_bits),
 517                 h->table->htable_bits, h->maxelem, set->data, h->table);
 518
 519        return 0;
 520}
 521
 522static struct ip_set_type hash_ipport_type __read_mostly = {
 523        .name           = "hash:ip,port",
 524        .protocol       = IPSET_PROTOCOL,
 525        .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT,
 526        .dimension      = IPSET_DIM_TWO,
 527        .family         = NFPROTO_UNSPEC,
 528        .revision_min   = REVISION_MIN,
 529        .revision_max   = REVISION_MAX,
 530        .create         = hash_ipport_create,
 531        .create_policy  = {
 532                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
 533                [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
 534                [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
 535                [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
 536                [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
 537                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 538        },
 539        .adt_policy     = {
 540                [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
 541                [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
 542                [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
 543                [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
 544                [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
 545                [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
 546                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 547                [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
 548        },
 549        .me             = THIS_MODULE,
 550};
 551
 552static int __init
 553hash_ipport_init(void)
 554{
 555        return ip_set_type_register(&hash_ipport_type);
 556}
 557
 558static void __exit
 559hash_ipport_fini(void)
 560{
 561        ip_set_type_unregister(&hash_ipport_type);
 562}
 563
 564module_init(hash_ipport_init);
 565module_exit(hash_ipport_fini);
 566