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