linux/net/netfilter/ipset/ip_set_hash_netnet.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org>
   3 * Copyright (C) 2013 Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>
   4 */
   5
   6/* Kernel module implementing an IP set type: the hash:net type */
   7
   8#include <linux/jhash.h>
   9#include <linux/module.h>
  10#include <linux/ip.h>
  11#include <linux/skbuff.h>
  12#include <linux/errno.h>
  13#include <linux/random.h>
  14#include <net/ip.h>
  15#include <net/ipv6.h>
  16#include <net/netlink.h>
  17
  18#include <linux/netfilter.h>
  19#include <linux/netfilter/ipset/pfxlen.h>
  20#include <linux/netfilter/ipset/ip_set.h>
  21#include <linux/netfilter/ipset/ip_set_hash.h>
  22
  23#define IPSET_TYPE_REV_MIN      0
  24/*                              1          Forceadd support added */
  25/*                              2          skbinfo support added */
  26#define IPSET_TYPE_REV_MAX      3       /* bucketsize, initval support added */
  27
  28MODULE_LICENSE("GPL");
  29MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>");
  30IP_SET_MODULE_DESC("hash:net,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
  31MODULE_ALIAS("ip_set_hash:net,net");
  32
  33/* Type specific function prefix */
  34#define HTYPE           hash_netnet
  35#define IP_SET_HASH_WITH_NETS
  36#define IPSET_NET_COUNT 2
  37
  38/* IPv4 variants */
  39
  40/* Member elements  */
  41struct hash_netnet4_elem {
  42        union {
  43                __be32 ip[2];
  44                __be64 ipcmp;
  45        };
  46        u8 nomatch;
  47        u8 padding;
  48        union {
  49                u8 cidr[2];
  50                u16 ccmp;
  51        };
  52};
  53
  54/* Common functions */
  55
  56static bool
  57hash_netnet4_data_equal(const struct hash_netnet4_elem *ip1,
  58                        const struct hash_netnet4_elem *ip2,
  59                        u32 *multi)
  60{
  61        return ip1->ipcmp == ip2->ipcmp &&
  62               ip1->ccmp == ip2->ccmp;
  63}
  64
  65static int
  66hash_netnet4_do_data_match(const struct hash_netnet4_elem *elem)
  67{
  68        return elem->nomatch ? -ENOTEMPTY : 1;
  69}
  70
  71static void
  72hash_netnet4_data_set_flags(struct hash_netnet4_elem *elem, u32 flags)
  73{
  74        elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
  75}
  76
  77static void
  78hash_netnet4_data_reset_flags(struct hash_netnet4_elem *elem, u8 *flags)
  79{
  80        swap(*flags, elem->nomatch);
  81}
  82
  83static void
  84hash_netnet4_data_reset_elem(struct hash_netnet4_elem *elem,
  85                             struct hash_netnet4_elem *orig)
  86{
  87        elem->ip[1] = orig->ip[1];
  88}
  89
  90static void
  91hash_netnet4_data_netmask(struct hash_netnet4_elem *elem, u8 cidr, bool inner)
  92{
  93        if (inner) {
  94                elem->ip[1] &= ip_set_netmask(cidr);
  95                elem->cidr[1] = cidr;
  96        } else {
  97                elem->ip[0] &= ip_set_netmask(cidr);
  98                elem->cidr[0] = cidr;
  99        }
 100}
 101
 102static bool
 103hash_netnet4_data_list(struct sk_buff *skb,
 104                       const struct hash_netnet4_elem *data)
 105{
 106        u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 107
 108        if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) ||
 109            nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip[1]) ||
 110            nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
 111            nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) ||
 112            (flags &&
 113             nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
 114                goto nla_put_failure;
 115        return false;
 116
 117nla_put_failure:
 118        return true;
 119}
 120
 121static void
 122hash_netnet4_data_next(struct hash_netnet4_elem *next,
 123                       const struct hash_netnet4_elem *d)
 124{
 125        next->ipcmp = d->ipcmp;
 126}
 127
 128#define MTYPE           hash_netnet4
 129#define HOST_MASK       32
 130#include "ip_set_hash_gen.h"
 131
 132static void
 133hash_netnet4_init(struct hash_netnet4_elem *e)
 134{
 135        e->cidr[0] = HOST_MASK;
 136        e->cidr[1] = HOST_MASK;
 137}
 138
 139static int
 140hash_netnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
 141                  const struct xt_action_param *par,
 142                  enum ipset_adt adt, struct ip_set_adt_opt *opt)
 143{
 144        const struct hash_netnet4 *h = set->data;
 145        ipset_adtfn adtfn = set->variant->adt[adt];
 146        struct hash_netnet4_elem e = { };
 147        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
 148
 149        e.cidr[0] = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK);
 150        e.cidr[1] = INIT_CIDR(h->nets[0].cidr[1], HOST_MASK);
 151        if (adt == IPSET_TEST)
 152                e.ccmp = (HOST_MASK << (sizeof(e.cidr[0]) * 8)) | HOST_MASK;
 153
 154        ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]);
 155        ip4addrptr(skb, opt->flags & IPSET_DIM_TWO_SRC, &e.ip[1]);
 156        e.ip[0] &= ip_set_netmask(e.cidr[0]);
 157        e.ip[1] &= ip_set_netmask(e.cidr[1]);
 158
 159        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 160}
 161
 162static int
 163hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
 164                  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 165{
 166        const struct hash_netnet4 *h = set->data;
 167        ipset_adtfn adtfn = set->variant->adt[adt];
 168        struct hash_netnet4_elem e = { };
 169        struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
 170        u32 ip = 0, ip_to = 0;
 171        u32 ip2 = 0, ip2_from = 0, ip2_to = 0, ipn;
 172        u64 n = 0, m = 0;
 173        int ret;
 174
 175        if (tb[IPSET_ATTR_LINENO])
 176                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 177
 178        hash_netnet4_init(&e);
 179        if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
 180                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
 181                return -IPSET_ERR_PROTOCOL;
 182
 183        ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
 184        if (ret)
 185                return ret;
 186
 187        ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from);
 188        if (ret)
 189                return ret;
 190
 191        ret = ip_set_get_extensions(set, tb, &ext);
 192        if (ret)
 193                return ret;
 194
 195        if (tb[IPSET_ATTR_CIDR]) {
 196                e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 197                if (!e.cidr[0] || e.cidr[0] > HOST_MASK)
 198                        return -IPSET_ERR_INVALID_CIDR;
 199        }
 200
 201        if (tb[IPSET_ATTR_CIDR2]) {
 202                e.cidr[1] = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
 203                if (!e.cidr[1] || e.cidr[1] > HOST_MASK)
 204                        return -IPSET_ERR_INVALID_CIDR;
 205        }
 206
 207        if (tb[IPSET_ATTR_CADT_FLAGS]) {
 208                u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
 209
 210                if (cadt_flags & IPSET_FLAG_NOMATCH)
 211                        flags |= (IPSET_FLAG_NOMATCH << 16);
 212        }
 213
 214        if (adt == IPSET_TEST || !(tb[IPSET_ATTR_IP_TO] ||
 215                                   tb[IPSET_ATTR_IP2_TO])) {
 216                e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0]));
 217                e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[1]));
 218                ret = adtfn(set, &e, &ext, &ext, flags);
 219                return ip_set_enomatch(ret, flags, adt, set) ? -ret :
 220                       ip_set_eexist(ret, flags) ? 0 : ret;
 221        }
 222
 223        ip_to = ip;
 224        if (tb[IPSET_ATTR_IP_TO]) {
 225                ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
 226                if (ret)
 227                        return ret;
 228                if (ip_to < ip)
 229                        swap(ip, ip_to);
 230                if (unlikely(ip + UINT_MAX == ip_to))
 231                        return -IPSET_ERR_HASH_RANGE;
 232        } else {
 233                ip_set_mask_from_to(ip, ip_to, e.cidr[0]);
 234        }
 235
 236        ip2_to = ip2_from;
 237        if (tb[IPSET_ATTR_IP2_TO]) {
 238                ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);
 239                if (ret)
 240                        return ret;
 241                if (ip2_to < ip2_from)
 242                        swap(ip2_from, ip2_to);
 243                if (unlikely(ip2_from + UINT_MAX == ip2_to))
 244                        return -IPSET_ERR_HASH_RANGE;
 245        } else {
 246                ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]);
 247        }
 248        ipn = ip;
 249        do {
 250                ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr[0]);
 251                n++;
 252        } while (ipn++ < ip_to);
 253        ipn = ip2_from;
 254        do {
 255                ipn = ip_set_range_to_cidr(ipn, ip2_to, &e.cidr[1]);
 256                m++;
 257        } while (ipn++ < ip2_to);
 258
 259        if (n*m > IPSET_MAX_RANGE)
 260                return -ERANGE;
 261
 262        if (retried) {
 263                ip = ntohl(h->next.ip[0]);
 264                ip2 = ntohl(h->next.ip[1]);
 265        } else {
 266                ip2 = ip2_from;
 267        }
 268
 269        do {
 270                e.ip[0] = htonl(ip);
 271                ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr[0]);
 272                do {
 273                        e.ip[1] = htonl(ip2);
 274                        ip2 = ip_set_range_to_cidr(ip2, ip2_to, &e.cidr[1]);
 275                        ret = adtfn(set, &e, &ext, &ext, flags);
 276                        if (ret && !ip_set_eexist(ret, flags))
 277                                return ret;
 278
 279                        ret = 0;
 280                } while (ip2++ < ip2_to);
 281                ip2 = ip2_from;
 282        } while (ip++ < ip_to);
 283        return ret;
 284}
 285
 286/* IPv6 variants */
 287
 288struct hash_netnet6_elem {
 289        union nf_inet_addr ip[2];
 290        u8 nomatch;
 291        u8 padding;
 292        union {
 293                u8 cidr[2];
 294                u16 ccmp;
 295        };
 296};
 297
 298/* Common functions */
 299
 300static bool
 301hash_netnet6_data_equal(const struct hash_netnet6_elem *ip1,
 302                        const struct hash_netnet6_elem *ip2,
 303                        u32 *multi)
 304{
 305        return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) &&
 306               ipv6_addr_equal(&ip1->ip[1].in6, &ip2->ip[1].in6) &&
 307               ip1->ccmp == ip2->ccmp;
 308}
 309
 310static int
 311hash_netnet6_do_data_match(const struct hash_netnet6_elem *elem)
 312{
 313        return elem->nomatch ? -ENOTEMPTY : 1;
 314}
 315
 316static void
 317hash_netnet6_data_set_flags(struct hash_netnet6_elem *elem, u32 flags)
 318{
 319        elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
 320}
 321
 322static void
 323hash_netnet6_data_reset_flags(struct hash_netnet6_elem *elem, u8 *flags)
 324{
 325        swap(*flags, elem->nomatch);
 326}
 327
 328static void
 329hash_netnet6_data_reset_elem(struct hash_netnet6_elem *elem,
 330                             struct hash_netnet6_elem *orig)
 331{
 332        elem->ip[1] = orig->ip[1];
 333}
 334
 335static void
 336hash_netnet6_data_netmask(struct hash_netnet6_elem *elem, u8 cidr, bool inner)
 337{
 338        if (inner) {
 339                ip6_netmask(&elem->ip[1], cidr);
 340                elem->cidr[1] = cidr;
 341        } else {
 342                ip6_netmask(&elem->ip[0], cidr);
 343                elem->cidr[0] = cidr;
 344        }
 345}
 346
 347static bool
 348hash_netnet6_data_list(struct sk_buff *skb,
 349                       const struct hash_netnet6_elem *data)
 350{
 351        u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 352
 353        if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) ||
 354            nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip[1].in6) ||
 355            nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
 356            nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) ||
 357            (flags &&
 358             nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
 359                goto nla_put_failure;
 360        return false;
 361
 362nla_put_failure:
 363        return true;
 364}
 365
 366static void
 367hash_netnet6_data_next(struct hash_netnet6_elem *next,
 368                       const struct hash_netnet6_elem *d)
 369{
 370}
 371
 372#undef MTYPE
 373#undef HOST_MASK
 374
 375#define MTYPE           hash_netnet6
 376#define HOST_MASK       128
 377#define IP_SET_EMIT_CREATE
 378#include "ip_set_hash_gen.h"
 379
 380static void
 381hash_netnet6_init(struct hash_netnet6_elem *e)
 382{
 383        e->cidr[0] = HOST_MASK;
 384        e->cidr[1] = HOST_MASK;
 385}
 386
 387static int
 388hash_netnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
 389                  const struct xt_action_param *par,
 390                  enum ipset_adt adt, struct ip_set_adt_opt *opt)
 391{
 392        const struct hash_netnet6 *h = set->data;
 393        ipset_adtfn adtfn = set->variant->adt[adt];
 394        struct hash_netnet6_elem e = { };
 395        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
 396
 397        e.cidr[0] = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK);
 398        e.cidr[1] = INIT_CIDR(h->nets[0].cidr[1], HOST_MASK);
 399        if (adt == IPSET_TEST)
 400                e.ccmp = (HOST_MASK << (sizeof(u8) * 8)) | HOST_MASK;
 401
 402        ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6);
 403        ip6addrptr(skb, opt->flags & IPSET_DIM_TWO_SRC, &e.ip[1].in6);
 404        ip6_netmask(&e.ip[0], e.cidr[0]);
 405        ip6_netmask(&e.ip[1], e.cidr[1]);
 406
 407        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 408}
 409
 410static int
 411hash_netnet6_uadt(struct ip_set *set, struct nlattr *tb[],
 412                  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 413{
 414        ipset_adtfn adtfn = set->variant->adt[adt];
 415        struct hash_netnet6_elem e = { };
 416        struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
 417        int ret;
 418
 419        if (tb[IPSET_ATTR_LINENO])
 420                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 421
 422        hash_netnet6_init(&e);
 423        if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
 424                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
 425                return -IPSET_ERR_PROTOCOL;
 426        if (unlikely(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_IP2_TO]))
 427                return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
 428
 429        ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]);
 430        if (ret)
 431                return ret;
 432
 433        ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip[1]);
 434        if (ret)
 435                return ret;
 436
 437        ret = ip_set_get_extensions(set, tb, &ext);
 438        if (ret)
 439                return ret;
 440
 441        if (tb[IPSET_ATTR_CIDR]) {
 442                e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 443                if (!e.cidr[0] || e.cidr[0] > HOST_MASK)
 444                        return -IPSET_ERR_INVALID_CIDR;
 445        }
 446
 447        if (tb[IPSET_ATTR_CIDR2]) {
 448                e.cidr[1] = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
 449                if (!e.cidr[1] || e.cidr[1] > HOST_MASK)
 450                        return -IPSET_ERR_INVALID_CIDR;
 451        }
 452
 453        ip6_netmask(&e.ip[0], e.cidr[0]);
 454        ip6_netmask(&e.ip[1], e.cidr[1]);
 455
 456        if (tb[IPSET_ATTR_CADT_FLAGS]) {
 457                u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
 458
 459                if (cadt_flags & IPSET_FLAG_NOMATCH)
 460                        flags |= (IPSET_FLAG_NOMATCH << 16);
 461        }
 462
 463        ret = adtfn(set, &e, &ext, &ext, flags);
 464
 465        return ip_set_enomatch(ret, flags, adt, set) ? -ret :
 466               ip_set_eexist(ret, flags) ? 0 : ret;
 467}
 468
 469static struct ip_set_type hash_netnet_type __read_mostly = {
 470        .name           = "hash:net,net",
 471        .protocol       = IPSET_PROTOCOL,
 472        .features       = IPSET_TYPE_IP | IPSET_TYPE_IP2 | IPSET_TYPE_NOMATCH,
 473        .dimension      = IPSET_DIM_TWO,
 474        .family         = NFPROTO_UNSPEC,
 475        .revision_min   = IPSET_TYPE_REV_MIN,
 476        .revision_max   = IPSET_TYPE_REV_MAX,
 477        .create_flags[IPSET_TYPE_REV_MAX] = IPSET_CREATE_FLAG_BUCKETSIZE,
 478        .create         = hash_netnet_create,
 479        .create_policy  = {
 480                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
 481                [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
 482                [IPSET_ATTR_INITVAL]    = { .type = NLA_U32 },
 483                [IPSET_ATTR_BUCKETSIZE] = { .type = NLA_U8 },
 484                [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
 485                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 486                [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 487        },
 488        .adt_policy     = {
 489                [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
 490                [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
 491                [IPSET_ATTR_IP2]        = { .type = NLA_NESTED },
 492                [IPSET_ATTR_IP2_TO]     = { .type = NLA_NESTED },
 493                [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
 494                [IPSET_ATTR_CIDR2]      = { .type = NLA_U8 },
 495                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 496                [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
 497                [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 498                [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
 499                [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
 500                [IPSET_ATTR_COMMENT]    = { .type = NLA_NUL_STRING,
 501                                            .len  = IPSET_MAX_COMMENT_SIZE },
 502                [IPSET_ATTR_SKBMARK]    = { .type = NLA_U64 },
 503                [IPSET_ATTR_SKBPRIO]    = { .type = NLA_U32 },
 504                [IPSET_ATTR_SKBQUEUE]   = { .type = NLA_U16 },
 505        },
 506        .me             = THIS_MODULE,
 507};
 508
 509static int __init
 510hash_netnet_init(void)
 511{
 512        return ip_set_type_register(&hash_netnet_type);
 513}
 514
 515static void __exit
 516hash_netnet_fini(void)
 517{
 518        rcu_barrier();
 519        ip_set_type_unregister(&hash_netnet_type);
 520}
 521
 522module_init(hash_netnet_init);
 523module_exit(hash_netnet_fini);
 524