linux/net/netfilter/ipset/ip_set_hash_net.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */
   3
   4/* Kernel module implementing an IP set type: the hash:net 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/ipset/pfxlen.h>
  18#include <linux/netfilter/ipset/ip_set.h>
  19#include <linux/netfilter/ipset/ip_set_hash.h>
  20
  21#define IPSET_TYPE_REV_MIN      0
  22/*                              1    Range as input support for IPv4 added */
  23/*                              2    nomatch flag support added */
  24/*                              3    Counters support added */
  25/*                              4    Comments support added */
  26/*                              5    Forceadd support added */
  27#define IPSET_TYPE_REV_MAX      6 /* skbinfo mapping support added */
  28
  29MODULE_LICENSE("GPL");
  30MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
  31IP_SET_MODULE_DESC("hash:net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
  32MODULE_ALIAS("ip_set_hash:net");
  33
  34/* Type specific function prefix */
  35#define HTYPE           hash_net
  36#define IP_SET_HASH_WITH_NETS
  37
  38/* IPv4 variant */
  39
  40/* Member elements  */
  41struct hash_net4_elem {
  42        __be32 ip;
  43        u16 padding0;
  44        u8 nomatch;
  45        u8 cidr;
  46};
  47
  48/* Common functions */
  49
  50static inline bool
  51hash_net4_data_equal(const struct hash_net4_elem *ip1,
  52                     const struct hash_net4_elem *ip2,
  53                     u32 *multi)
  54{
  55        return ip1->ip == ip2->ip &&
  56               ip1->cidr == ip2->cidr;
  57}
  58
  59static inline int
  60hash_net4_do_data_match(const struct hash_net4_elem *elem)
  61{
  62        return elem->nomatch ? -ENOTEMPTY : 1;
  63}
  64
  65static inline void
  66hash_net4_data_set_flags(struct hash_net4_elem *elem, u32 flags)
  67{
  68        elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
  69}
  70
  71static inline void
  72hash_net4_data_reset_flags(struct hash_net4_elem *elem, u8 *flags)
  73{
  74        swap(*flags, elem->nomatch);
  75}
  76
  77static inline void
  78hash_net4_data_netmask(struct hash_net4_elem *elem, u8 cidr)
  79{
  80        elem->ip &= ip_set_netmask(cidr);
  81        elem->cidr = cidr;
  82}
  83
  84static bool
  85hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
  86{
  87        u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
  88
  89        if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
  90            nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
  91            (flags &&
  92             nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
  93                goto nla_put_failure;
  94        return false;
  95
  96nla_put_failure:
  97        return true;
  98}
  99
 100static inline void
 101hash_net4_data_next(struct hash_net4_elem *next,
 102                    const struct hash_net4_elem *d)
 103{
 104        next->ip = d->ip;
 105}
 106
 107#define MTYPE           hash_net4
 108#define HOST_MASK       32
 109#include "ip_set_hash_gen.h"
 110
 111static int
 112hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
 113               const struct xt_action_param *par,
 114               enum ipset_adt adt, struct ip_set_adt_opt *opt)
 115{
 116        const struct hash_net4 *h = set->data;
 117        ipset_adtfn adtfn = set->variant->adt[adt];
 118        struct hash_net4_elem e = {
 119                .cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
 120        };
 121        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
 122
 123        if (e.cidr == 0)
 124                return -EINVAL;
 125        if (adt == IPSET_TEST)
 126                e.cidr = HOST_MASK;
 127
 128        ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
 129        e.ip &= ip_set_netmask(e.cidr);
 130
 131        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 132}
 133
 134static int
 135hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
 136               enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 137{
 138        const struct hash_net4 *h = set->data;
 139        ipset_adtfn adtfn = set->variant->adt[adt];
 140        struct hash_net4_elem e = { .cidr = HOST_MASK };
 141        struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
 142        u32 ip = 0, ip_to = 0;
 143        int ret;
 144
 145        if (tb[IPSET_ATTR_LINENO])
 146                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 147
 148        if (unlikely(!tb[IPSET_ATTR_IP] ||
 149                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
 150                return -IPSET_ERR_PROTOCOL;
 151
 152        ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
 153        if (ret)
 154                return ret;
 155
 156        ret = ip_set_get_extensions(set, tb, &ext);
 157        if (ret)
 158                return ret;
 159
 160        if (tb[IPSET_ATTR_CIDR]) {
 161                e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 162                if (!e.cidr || e.cidr > HOST_MASK)
 163                        return -IPSET_ERR_INVALID_CIDR;
 164        }
 165
 166        if (tb[IPSET_ATTR_CADT_FLAGS]) {
 167                u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
 168
 169                if (cadt_flags & IPSET_FLAG_NOMATCH)
 170                        flags |= (IPSET_FLAG_NOMATCH << 16);
 171        }
 172
 173        if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
 174                e.ip = htonl(ip & ip_set_hostmask(e.cidr));
 175                ret = adtfn(set, &e, &ext, &ext, flags);
 176                return ip_set_enomatch(ret, flags, adt, set) ? -ret :
 177                       ip_set_eexist(ret, flags) ? 0 : ret;
 178        }
 179
 180        ip_to = ip;
 181        if (tb[IPSET_ATTR_IP_TO]) {
 182                ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
 183                if (ret)
 184                        return ret;
 185                if (ip_to < ip)
 186                        swap(ip, ip_to);
 187                if (ip + UINT_MAX == ip_to)
 188                        return -IPSET_ERR_HASH_RANGE;
 189        }
 190        if (retried)
 191                ip = ntohl(h->next.ip);
 192        do {
 193                e.ip = htonl(ip);
 194                ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
 195                ret = adtfn(set, &e, &ext, &ext, flags);
 196                if (ret && !ip_set_eexist(ret, flags))
 197                        return ret;
 198
 199                ret = 0;
 200        } while (ip++ < ip_to);
 201        return ret;
 202}
 203
 204/* IPv6 variant */
 205
 206struct hash_net6_elem {
 207        union nf_inet_addr ip;
 208        u16 padding0;
 209        u8 nomatch;
 210        u8 cidr;
 211};
 212
 213/* Common functions */
 214
 215static inline bool
 216hash_net6_data_equal(const struct hash_net6_elem *ip1,
 217                     const struct hash_net6_elem *ip2,
 218                     u32 *multi)
 219{
 220        return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
 221               ip1->cidr == ip2->cidr;
 222}
 223
 224static inline int
 225hash_net6_do_data_match(const struct hash_net6_elem *elem)
 226{
 227        return elem->nomatch ? -ENOTEMPTY : 1;
 228}
 229
 230static inline void
 231hash_net6_data_set_flags(struct hash_net6_elem *elem, u32 flags)
 232{
 233        elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
 234}
 235
 236static inline void
 237hash_net6_data_reset_flags(struct hash_net6_elem *elem, u8 *flags)
 238{
 239        swap(*flags, elem->nomatch);
 240}
 241
 242static inline void
 243hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr)
 244{
 245        ip6_netmask(&elem->ip, cidr);
 246        elem->cidr = cidr;
 247}
 248
 249static bool
 250hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
 251{
 252        u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 253
 254        if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
 255            nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
 256            (flags &&
 257             nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
 258                goto nla_put_failure;
 259        return false;
 260
 261nla_put_failure:
 262        return true;
 263}
 264
 265static inline void
 266hash_net6_data_next(struct hash_net6_elem *next,
 267                    const struct hash_net6_elem *d)
 268{
 269}
 270
 271#undef MTYPE
 272#undef HOST_MASK
 273
 274#define MTYPE           hash_net6
 275#define HOST_MASK       128
 276#define IP_SET_EMIT_CREATE
 277#include "ip_set_hash_gen.h"
 278
 279static int
 280hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
 281               const struct xt_action_param *par,
 282               enum ipset_adt adt, struct ip_set_adt_opt *opt)
 283{
 284        const struct hash_net6 *h = set->data;
 285        ipset_adtfn adtfn = set->variant->adt[adt];
 286        struct hash_net6_elem e = {
 287                .cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
 288        };
 289        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
 290
 291        if (e.cidr == 0)
 292                return -EINVAL;
 293        if (adt == IPSET_TEST)
 294                e.cidr = HOST_MASK;
 295
 296        ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
 297        ip6_netmask(&e.ip, e.cidr);
 298
 299        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 300}
 301
 302static int
 303hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
 304               enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 305{
 306        ipset_adtfn adtfn = set->variant->adt[adt];
 307        struct hash_net6_elem e = { .cidr = HOST_MASK };
 308        struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
 309        int ret;
 310
 311        if (tb[IPSET_ATTR_LINENO])
 312                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 313
 314        if (unlikely(!tb[IPSET_ATTR_IP] ||
 315                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
 316                return -IPSET_ERR_PROTOCOL;
 317        if (unlikely(tb[IPSET_ATTR_IP_TO]))
 318                return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
 319
 320        ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip);
 321        if (ret)
 322                return ret;
 323
 324        ret = ip_set_get_extensions(set, tb, &ext);
 325        if (ret)
 326                return ret;
 327
 328        if (tb[IPSET_ATTR_CIDR]) {
 329                e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 330                if (!e.cidr || e.cidr > HOST_MASK)
 331                        return -IPSET_ERR_INVALID_CIDR;
 332        }
 333
 334        ip6_netmask(&e.ip, e.cidr);
 335
 336        if (tb[IPSET_ATTR_CADT_FLAGS]) {
 337                u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
 338
 339                if (cadt_flags & IPSET_FLAG_NOMATCH)
 340                        flags |= (IPSET_FLAG_NOMATCH << 16);
 341        }
 342
 343        ret = adtfn(set, &e, &ext, &ext, flags);
 344
 345        return ip_set_enomatch(ret, flags, adt, set) ? -ret :
 346               ip_set_eexist(ret, flags) ? 0 : ret;
 347}
 348
 349static struct ip_set_type hash_net_type __read_mostly = {
 350        .name           = "hash:net",
 351        .protocol       = IPSET_PROTOCOL,
 352        .features       = IPSET_TYPE_IP | IPSET_TYPE_NOMATCH,
 353        .dimension      = IPSET_DIM_ONE,
 354        .family         = NFPROTO_UNSPEC,
 355        .revision_min   = IPSET_TYPE_REV_MIN,
 356        .revision_max   = IPSET_TYPE_REV_MAX,
 357        .create         = hash_net_create,
 358        .create_policy  = {
 359                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
 360                [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
 361                [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
 362                [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
 363                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 364                [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 365        },
 366        .adt_policy     = {
 367                [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
 368                [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
 369                [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
 370                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 371                [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 372                [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
 373                [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
 374                [IPSET_ATTR_COMMENT]    = { .type = NLA_NUL_STRING,
 375                                            .len  = IPSET_MAX_COMMENT_SIZE },
 376                [IPSET_ATTR_SKBMARK]    = { .type = NLA_U64 },
 377                [IPSET_ATTR_SKBPRIO]    = { .type = NLA_U32 },
 378                [IPSET_ATTR_SKBQUEUE]   = { .type = NLA_U16 },
 379        },
 380        .me             = THIS_MODULE,
 381};
 382
 383static int __init
 384hash_net_init(void)
 385{
 386        return ip_set_type_register(&hash_net_type);
 387}
 388
 389static void __exit
 390hash_net_fini(void)
 391{
 392        rcu_barrier();
 393        ip_set_type_unregister(&hash_net_type);
 394}
 395
 396module_init(hash_net_init);
 397module_exit(hash_net_fini);
 398