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