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