linux/net/netfilter/ipset/ip_set_hash_ip.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:ip 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#include <net/tcp.h>
  20
  21#include <linux/netfilter.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 REVISION_MIN    0
  27#define REVISION_MAX    1       /* Counters support */
  28
  29MODULE_LICENSE("GPL");
  30MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
  31IP_SET_MODULE_DESC("hash:ip", REVISION_MIN, REVISION_MAX);
  32MODULE_ALIAS("ip_set_hash:ip");
  33
  34/* Type specific function prefix */
  35#define HTYPE           hash_ip
  36#define IP_SET_HASH_WITH_NETMASK
  37
  38/* IPv4 variants */
  39
  40/* Member elements */
  41struct hash_ip4_elem {
  42        /* Zero valued IP addresses cannot be stored */
  43        __be32 ip;
  44};
  45
  46struct hash_ip4t_elem {
  47        __be32 ip;
  48        unsigned long timeout;
  49};
  50
  51struct hash_ip4c_elem {
  52        __be32 ip;
  53        struct ip_set_counter counter;
  54};
  55
  56struct hash_ip4ct_elem {
  57        __be32 ip;
  58        struct ip_set_counter counter;
  59        unsigned long timeout;
  60};
  61
  62/* Common functions */
  63
  64static inline bool
  65hash_ip4_data_equal(const struct hash_ip4_elem *e1,
  66                    const struct hash_ip4_elem *e2,
  67                    u32 *multi)
  68{
  69        return e1->ip == e2->ip;
  70}
  71
  72static inline bool
  73hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *e)
  74{
  75        if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, e->ip))
  76                goto nla_put_failure;
  77        return 0;
  78
  79nla_put_failure:
  80        return 1;
  81}
  82
  83static inline void
  84hash_ip4_data_next(struct hash_ip4_elem *next, const struct hash_ip4_elem *e)
  85{
  86        next->ip = e->ip;
  87}
  88
  89#define MTYPE           hash_ip4
  90#define PF              4
  91#define HOST_MASK       32
  92#include "ip_set_hash_gen.h"
  93
  94static int
  95hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
  96              const struct xt_action_param *par,
  97              enum ipset_adt adt, struct ip_set_adt_opt *opt)
  98{
  99        const struct hash_ip *h = set->data;
 100        ipset_adtfn adtfn = set->variant->adt[adt];
 101        struct hash_ip4_elem e = {};
 102        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 103        __be32 ip;
 104
 105        ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
 106        ip &= ip_set_netmask(h->netmask);
 107        if (ip == 0)
 108                return -EINVAL;
 109
 110        e.ip = ip;
 111        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 112}
 113
 114static int
 115hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
 116              enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 117{
 118        const struct hash_ip *h = set->data;
 119        ipset_adtfn adtfn = set->variant->adt[adt];
 120        struct hash_ip4_elem e = {};
 121        struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
 122        u32 ip, ip_to, hosts;
 123        int ret = 0;
 124
 125        if (unlikely(!tb[IPSET_ATTR_IP] ||
 126                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
 127                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
 128                     !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
 129                return -IPSET_ERR_PROTOCOL;
 130
 131        if (tb[IPSET_ATTR_LINENO])
 132                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 133
 134        ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
 135              ip_set_get_extensions(set, tb, &ext);
 136        if (ret)
 137                return ret;
 138
 139        ip &= ip_set_hostmask(h->netmask);
 140
 141        if (adt == IPSET_TEST) {
 142                e.ip = htonl(ip);
 143                if (e.ip == 0)
 144                        return -IPSET_ERR_HASH_ELEM;
 145                return adtfn(set, &e, &ext, &ext, flags);
 146        }
 147
 148        ip_to = ip;
 149        if (tb[IPSET_ATTR_IP_TO]) {
 150                ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
 151                if (ret)
 152                        return ret;
 153                if (ip > ip_to)
 154                        swap(ip, ip_to);
 155        } else if (tb[IPSET_ATTR_CIDR]) {
 156                u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 157
 158                if (!cidr || cidr > 32)
 159                        return -IPSET_ERR_INVALID_CIDR;
 160                ip_set_mask_from_to(ip, ip_to, cidr);
 161        }
 162
 163        hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
 164
 165        if (retried)
 166                ip = ntohl(h->next.ip);
 167        for (; !before(ip_to, ip); ip += hosts) {
 168                e.ip = htonl(ip);
 169                if (e.ip == 0)
 170                        return -IPSET_ERR_HASH_ELEM;
 171                ret = adtfn(set, &e, &ext, &ext, flags);
 172
 173                if (ret && !ip_set_eexist(ret, flags))
 174                        return ret;
 175                else
 176                        ret = 0;
 177        }
 178        return ret;
 179}
 180
 181/* IPv6 variants */
 182
 183/* Member elements */
 184struct hash_ip6_elem {
 185        union nf_inet_addr ip;
 186};
 187
 188struct hash_ip6t_elem {
 189        union nf_inet_addr ip;
 190        unsigned long timeout;
 191};
 192
 193struct hash_ip6c_elem {
 194        union nf_inet_addr ip;
 195        struct ip_set_counter counter;
 196};
 197
 198struct hash_ip6ct_elem {
 199        union nf_inet_addr ip;
 200        struct ip_set_counter counter;
 201        unsigned long timeout;
 202};
 203
 204/* Common functions */
 205
 206static inline bool
 207hash_ip6_data_equal(const struct hash_ip6_elem *ip1,
 208                    const struct hash_ip6_elem *ip2,
 209                    u32 *multi)
 210{
 211        return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6);
 212}
 213
 214static inline void
 215hash_ip6_netmask(union nf_inet_addr *ip, u8 prefix)
 216{
 217        ip6_netmask(ip, prefix);
 218}
 219
 220static bool
 221hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *e)
 222{
 223        if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6))
 224                goto nla_put_failure;
 225        return 0;
 226
 227nla_put_failure:
 228        return 1;
 229}
 230
 231static inline void
 232hash_ip6_data_next(struct hash_ip4_elem *next, const struct hash_ip6_elem *e)
 233{
 234}
 235
 236#undef MTYPE
 237#undef PF
 238#undef HOST_MASK
 239#undef HKEY_DATALEN
 240
 241#define MTYPE           hash_ip6
 242#define PF              6
 243#define HOST_MASK       128
 244
 245#define IP_SET_EMIT_CREATE
 246#include "ip_set_hash_gen.h"
 247
 248static int
 249hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
 250              const struct xt_action_param *par,
 251              enum ipset_adt adt, struct ip_set_adt_opt *opt)
 252{
 253        const struct hash_ip *h = set->data;
 254        ipset_adtfn adtfn = set->variant->adt[adt];
 255        struct hash_ip6_elem e = {};
 256        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
 257
 258        ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
 259        hash_ip6_netmask(&e.ip, h->netmask);
 260        if (ipv6_addr_any(&e.ip.in6))
 261                return -EINVAL;
 262
 263        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 264}
 265
 266static int
 267hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
 268              enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 269{
 270        const struct hash_ip *h = set->data;
 271        ipset_adtfn adtfn = set->variant->adt[adt];
 272        struct hash_ip6_elem e = {};
 273        struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
 274        int ret;
 275
 276        if (unlikely(!tb[IPSET_ATTR_IP] ||
 277                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
 278                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
 279                     !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
 280                     tb[IPSET_ATTR_IP_TO] ||
 281                     tb[IPSET_ATTR_CIDR]))
 282                return -IPSET_ERR_PROTOCOL;
 283
 284        if (tb[IPSET_ATTR_LINENO])
 285                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 286
 287        ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
 288              ip_set_get_extensions(set, tb, &ext);
 289        if (ret)
 290                return ret;
 291
 292        hash_ip6_netmask(&e.ip, h->netmask);
 293        if (ipv6_addr_any(&e.ip.in6))
 294                return -IPSET_ERR_HASH_ELEM;
 295
 296        ret = adtfn(set, &e, &ext, &ext, flags);
 297
 298        return ip_set_eexist(ret, flags) ? 0 : ret;
 299}
 300
 301static struct ip_set_type hash_ip_type __read_mostly = {
 302        .name           = "hash:ip",
 303        .protocol       = IPSET_PROTOCOL,
 304        .features       = IPSET_TYPE_IP,
 305        .dimension      = IPSET_DIM_ONE,
 306        .family         = NFPROTO_UNSPEC,
 307        .revision_min   = REVISION_MIN,
 308        .revision_max   = REVISION_MAX,
 309        .create         = hash_ip_create,
 310        .create_policy  = {
 311                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
 312                [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
 313                [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
 314                [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
 315                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 316                [IPSET_ATTR_NETMASK]    = { .type = NLA_U8  },
 317                [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 318        },
 319        .adt_policy     = {
 320                [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
 321                [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
 322                [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
 323                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 324                [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
 325                [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
 326                [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
 327        },
 328        .me             = THIS_MODULE,
 329};
 330
 331static int __init
 332hash_ip_init(void)
 333{
 334        return ip_set_type_register(&hash_ip_type);
 335}
 336
 337static void __exit
 338hash_ip_fini(void)
 339{
 340        ip_set_type_unregister(&hash_ip_type);
 341}
 342
 343module_init(hash_ip_init);
 344module_exit(hash_ip_fini);
 345