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;
 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
 260        if (retried)
 261                ip = ntohl(h->next.ip);
 262        do {
 263                e.ip = htonl(ip);
 264                ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
 265                ret = adtfn(set, &e, &ext, &ext, flags);
 266
 267                if (ret && !ip_set_eexist(ret, flags))
 268                        return ret;
 269
 270                ret = 0;
 271        } while (ip++ < ip_to);
 272        return ret;
 273}
 274
 275/* IPv6 variant */
 276
 277struct hash_netiface6_elem_hashed {
 278        union nf_inet_addr ip;
 279        u8 physdev;
 280        u8 cidr;
 281        u8 nomatch;
 282        u8 elem;
 283};
 284
 285struct hash_netiface6_elem {
 286        union nf_inet_addr ip;
 287        u8 physdev;
 288        u8 cidr;
 289        u8 nomatch;
 290        u8 elem;
 291        u8 wildcard;
 292        char iface[IFNAMSIZ];
 293};
 294
 295/* Common functions */
 296
 297static bool
 298hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1,
 299                          const struct hash_netiface6_elem *ip2,
 300                          u32 *multi)
 301{
 302        return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
 303               ip1->cidr == ip2->cidr &&
 304               (++*multi) &&
 305               ip1->physdev == ip2->physdev &&
 306               (ip1->wildcard ?
 307                strncmp(ip1->iface, ip2->iface, strlen(ip1->iface)) == 0 :
 308                strcmp(ip1->iface, ip2->iface) == 0);
 309}
 310
 311static int
 312hash_netiface6_do_data_match(const struct hash_netiface6_elem *elem)
 313{
 314        return elem->nomatch ? -ENOTEMPTY : 1;
 315}
 316
 317static void
 318hash_netiface6_data_set_flags(struct hash_netiface6_elem *elem, u32 flags)
 319{
 320        elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
 321}
 322
 323static void
 324hash_netiface6_data_reset_flags(struct hash_netiface6_elem *elem, u8 *flags)
 325{
 326        swap(*flags, elem->nomatch);
 327}
 328
 329static void
 330hash_netiface6_data_netmask(struct hash_netiface6_elem *elem, u8 cidr)
 331{
 332        ip6_netmask(&elem->ip, cidr);
 333        elem->cidr = cidr;
 334}
 335
 336static bool
 337hash_netiface6_data_list(struct sk_buff *skb,
 338                         const struct hash_netiface6_elem *data)
 339{
 340        u32 flags = (data->physdev ? IPSET_FLAG_PHYSDEV : 0) |
 341                    (data->wildcard ? IPSET_FLAG_IFACE_WILDCARD : 0);
 342
 343        if (data->nomatch)
 344                flags |= IPSET_FLAG_NOMATCH;
 345        if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
 346            nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
 347            nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
 348            (flags &&
 349             nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
 350                goto nla_put_failure;
 351        return false;
 352
 353nla_put_failure:
 354        return true;
 355}
 356
 357static void
 358hash_netiface6_data_next(struct hash_netiface6_elem *next,
 359                         const struct hash_netiface6_elem *d)
 360{
 361}
 362
 363#undef MTYPE
 364#undef HOST_MASK
 365
 366#define MTYPE           hash_netiface6
 367#define HOST_MASK       128
 368#define HKEY_DATALEN    sizeof(struct hash_netiface6_elem_hashed)
 369#define IP_SET_EMIT_CREATE
 370#include "ip_set_hash_gen.h"
 371
 372static int
 373hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
 374                    const struct xt_action_param *par,
 375                    enum ipset_adt adt, struct ip_set_adt_opt *opt)
 376{
 377        struct hash_netiface6 *h = set->data;
 378        ipset_adtfn adtfn = set->variant->adt[adt];
 379        struct hash_netiface6_elem e = {
 380                .cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
 381                .elem = 1,
 382        };
 383        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
 384
 385        if (adt == IPSET_TEST)
 386                e.cidr = HOST_MASK;
 387
 388        ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
 389        ip6_netmask(&e.ip, e.cidr);
 390
 391        if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
 392#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
 393                const char *eiface = SRCDIR ? get_physindev_name(skb) :
 394                                              get_physoutdev_name(skb);
 395
 396                if (!eiface)
 397                        return -EINVAL;
 398                STRLCPY(e.iface, eiface);
 399                e.physdev = 1;
 400#endif
 401        } else {
 402                STRLCPY(e.iface, SRCDIR ? IFACE(in) : IFACE(out));
 403        }
 404
 405        if (strlen(e.iface) == 0)
 406                return -EINVAL;
 407
 408        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 409}
 410
 411static int
 412hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
 413                    enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 414{
 415        ipset_adtfn adtfn = set->variant->adt[adt];
 416        struct hash_netiface6_elem e = { .cidr = HOST_MASK, .elem = 1 };
 417        struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
 418        int ret;
 419
 420        if (tb[IPSET_ATTR_LINENO])
 421                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 422
 423        if (unlikely(!tb[IPSET_ATTR_IP] ||
 424                     !tb[IPSET_ATTR_IFACE] ||
 425                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
 426                return -IPSET_ERR_PROTOCOL;
 427        if (unlikely(tb[IPSET_ATTR_IP_TO]))
 428                return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
 429
 430        ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip);
 431        if (ret)
 432                return ret;
 433
 434        ret = ip_set_get_extensions(set, tb, &ext);
 435        if (ret)
 436                return ret;
 437
 438        if (tb[IPSET_ATTR_CIDR]) {
 439                e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 440                if (e.cidr > HOST_MASK)
 441                        return -IPSET_ERR_INVALID_CIDR;
 442        }
 443
 444        ip6_netmask(&e.ip, e.cidr);
 445
 446        nla_strscpy(e.iface, tb[IPSET_ATTR_IFACE], IFNAMSIZ);
 447
 448        if (tb[IPSET_ATTR_CADT_FLAGS]) {
 449                u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
 450
 451                if (cadt_flags & IPSET_FLAG_PHYSDEV)
 452                        e.physdev = 1;
 453                if (cadt_flags & IPSET_FLAG_NOMATCH)
 454                        flags |= (IPSET_FLAG_NOMATCH << 16);
 455                if (cadt_flags & IPSET_FLAG_IFACE_WILDCARD)
 456                        e.wildcard = 1;
 457        }
 458
 459        ret = adtfn(set, &e, &ext, &ext, flags);
 460
 461        return ip_set_enomatch(ret, flags, adt, set) ? -ret :
 462               ip_set_eexist(ret, flags) ? 0 : ret;
 463}
 464
 465static struct ip_set_type hash_netiface_type __read_mostly = {
 466        .name           = "hash:net,iface",
 467        .protocol       = IPSET_PROTOCOL,
 468        .features       = IPSET_TYPE_IP | IPSET_TYPE_IFACE |
 469                          IPSET_TYPE_NOMATCH,
 470        .dimension      = IPSET_DIM_TWO,
 471        .family         = NFPROTO_UNSPEC,
 472        .revision_min   = IPSET_TYPE_REV_MIN,
 473        .revision_max   = IPSET_TYPE_REV_MAX,
 474        .create_flags[IPSET_TYPE_REV_MAX] = IPSET_CREATE_FLAG_BUCKETSIZE,
 475        .create         = hash_netiface_create,
 476        .create_policy  = {
 477                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
 478                [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
 479                [IPSET_ATTR_INITVAL]    = { .type = NLA_U32 },
 480                [IPSET_ATTR_BUCKETSIZE] = { .type = NLA_U8 },
 481                [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
 482                [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
 483                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 484                [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 485        },
 486        .adt_policy     = {
 487                [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
 488                [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
 489                [IPSET_ATTR_IFACE]      = { .type = NLA_NUL_STRING,
 490                                            .len  = IFNAMSIZ - 1 },
 491                [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 492                [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
 493                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 494                [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
 495                [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
 496                [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
 497                [IPSET_ATTR_COMMENT]    = { .type = NLA_NUL_STRING,
 498                                            .len  = IPSET_MAX_COMMENT_SIZE },
 499                [IPSET_ATTR_SKBMARK]    = { .type = NLA_U64 },
 500                [IPSET_ATTR_SKBPRIO]    = { .type = NLA_U32 },
 501                [IPSET_ATTR_SKBQUEUE]   = { .type = NLA_U16 },
 502        },
 503        .me             = THIS_MODULE,
 504};
 505
 506static int __init
 507hash_netiface_init(void)
 508{
 509        return ip_set_type_register(&hash_netiface_type);
 510}
 511
 512static void __exit
 513hash_netiface_fini(void)
 514{
 515        rcu_barrier();
 516        ip_set_type_unregister(&hash_netiface_type);
 517}
 518
 519module_init(hash_netiface_init);
 520module_exit(hash_netiface_fini);
 521