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