linux/net/netfilter/ipset/ip_set_hash_ipportip.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,port,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_getport.h>
  25#include <linux/netfilter/ipset/ip_set_hash.h>
  26
  27#define IPSET_TYPE_REV_MIN      0
  28/*                              1    SCTP and UDPLITE support added */
  29/*                              2    Counters support added */
  30/*                              3    Comments support added */
  31/*                              4    Forceadd support added */
  32#define IPSET_TYPE_REV_MAX      5 /* skbinfo support added */
  33
  34MODULE_LICENSE("GPL");
  35MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
  36IP_SET_MODULE_DESC("hash:ip,port,ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
  37MODULE_ALIAS("ip_set_hash:ip,port,ip");
  38
  39/* Type specific function prefix */
  40#define HTYPE           hash_ipportip
  41
  42/* IPv4 variant */
  43
  44/* Member elements  */
  45struct hash_ipportip4_elem {
  46        __be32 ip;
  47        __be32 ip2;
  48        __be16 port;
  49        u8 proto;
  50        u8 padding;
  51};
  52
  53static inline bool
  54hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,
  55                          const struct hash_ipportip4_elem *ip2,
  56                          u32 *multi)
  57{
  58        return ip1->ip == ip2->ip &&
  59               ip1->ip2 == ip2->ip2 &&
  60               ip1->port == ip2->port &&
  61               ip1->proto == ip2->proto;
  62}
  63
  64static bool
  65hash_ipportip4_data_list(struct sk_buff *skb,
  66                         const struct hash_ipportip4_elem *data)
  67{
  68        if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
  69            nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip2) ||
  70            nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
  71            nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto))
  72                goto nla_put_failure;
  73        return false;
  74
  75nla_put_failure:
  76        return true;
  77}
  78
  79static inline void
  80hash_ipportip4_data_next(struct hash_ipportip4_elem *next,
  81                         const struct hash_ipportip4_elem *d)
  82{
  83        next->ip = d->ip;
  84        next->port = d->port;
  85}
  86
  87/* Common functions */
  88#define MTYPE           hash_ipportip4
  89#define HOST_MASK       32
  90#include "ip_set_hash_gen.h"
  91
  92static int
  93hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
  94                    const struct xt_action_param *par,
  95                    enum ipset_adt adt, struct ip_set_adt_opt *opt)
  96{
  97        ipset_adtfn adtfn = set->variant->adt[adt];
  98        struct hash_ipportip4_elem e = { .ip = 0 };
  99        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
 100
 101        if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
 102                                 &e.port, &e.proto))
 103                return -EINVAL;
 104
 105        ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
 106        ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2);
 107        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 108}
 109
 110static int
 111hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
 112                    enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 113{
 114        const struct hash_ipportip4 *h = set->data;
 115        ipset_adtfn adtfn = set->variant->adt[adt];
 116        struct hash_ipportip4_elem e = { .ip = 0 };
 117        struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
 118        u32 ip, ip_to = 0, p = 0, port, port_to;
 119        bool with_ports = false;
 120        int ret;
 121
 122        if (tb[IPSET_ATTR_LINENO])
 123                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 124
 125        if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
 126                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
 127                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO)))
 128                return -IPSET_ERR_PROTOCOL;
 129
 130        ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip);
 131        if (ret)
 132                return ret;
 133
 134        ret = ip_set_get_extensions(set, tb, &ext);
 135        if (ret)
 136                return ret;
 137
 138        ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &e.ip2);
 139        if (ret)
 140                return ret;
 141
 142        e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
 143
 144        if (tb[IPSET_ATTR_PROTO]) {
 145                e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
 146                with_ports = ip_set_proto_with_ports(e.proto);
 147
 148                if (e.proto == 0)
 149                        return -IPSET_ERR_INVALID_PROTO;
 150        } else {
 151                return -IPSET_ERR_MISSING_PROTO;
 152        }
 153
 154        if (!(with_ports || e.proto == IPPROTO_ICMP))
 155                e.port = 0;
 156
 157        if (adt == IPSET_TEST ||
 158            !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
 159              tb[IPSET_ATTR_PORT_TO])) {
 160                ret = adtfn(set, &e, &ext, &ext, flags);
 161                return ip_set_eexist(ret, flags) ? 0 : ret;
 162        }
 163
 164        ip_to = ip = ntohl(e.ip);
 165        if (tb[IPSET_ATTR_IP_TO]) {
 166                ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
 167                if (ret)
 168                        return ret;
 169                if (ip > ip_to)
 170                        swap(ip, ip_to);
 171        } else if (tb[IPSET_ATTR_CIDR]) {
 172                u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 173
 174                if (!cidr || cidr > HOST_MASK)
 175                        return -IPSET_ERR_INVALID_CIDR;
 176                ip_set_mask_from_to(ip, ip_to, cidr);
 177        }
 178
 179        port_to = port = ntohs(e.port);
 180        if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
 181                port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
 182                if (port > port_to)
 183                        swap(port, port_to);
 184        }
 185
 186        if (retried)
 187                ip = ntohl(h->next.ip);
 188        for (; !before(ip_to, ip); ip++) {
 189                p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
 190                                                       : port;
 191                for (; p <= port_to; p++) {
 192                        e.ip = htonl(ip);
 193                        e.port = htons(p);
 194                        ret = adtfn(set, &e, &ext, &ext, flags);
 195
 196                        if (ret && !ip_set_eexist(ret, flags))
 197                                return ret;
 198
 199                        ret = 0;
 200                }
 201        }
 202        return ret;
 203}
 204
 205/* IPv6 variant */
 206
 207struct hash_ipportip6_elem {
 208        union nf_inet_addr ip;
 209        union nf_inet_addr ip2;
 210        __be16 port;
 211        u8 proto;
 212        u8 padding;
 213};
 214
 215/* Common functions */
 216
 217static inline bool
 218hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1,
 219                          const struct hash_ipportip6_elem *ip2,
 220                          u32 *multi)
 221{
 222        return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
 223               ipv6_addr_equal(&ip1->ip2.in6, &ip2->ip2.in6) &&
 224               ip1->port == ip2->port &&
 225               ip1->proto == ip2->proto;
 226}
 227
 228static bool
 229hash_ipportip6_data_list(struct sk_buff *skb,
 230                         const struct hash_ipportip6_elem *data)
 231{
 232        if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
 233            nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip2.in6) ||
 234            nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
 235            nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto))
 236                goto nla_put_failure;
 237        return false;
 238
 239nla_put_failure:
 240        return true;
 241}
 242
 243static inline void
 244hash_ipportip6_data_next(struct hash_ipportip6_elem *next,
 245                         const struct hash_ipportip6_elem *d)
 246{
 247        next->port = d->port;
 248}
 249
 250#undef MTYPE
 251#undef HOST_MASK
 252
 253#define MTYPE           hash_ipportip6
 254#define HOST_MASK       128
 255#define IP_SET_EMIT_CREATE
 256#include "ip_set_hash_gen.h"
 257
 258static int
 259hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
 260                    const struct xt_action_param *par,
 261                    enum ipset_adt adt, struct ip_set_adt_opt *opt)
 262{
 263        ipset_adtfn adtfn = set->variant->adt[adt];
 264        struct hash_ipportip6_elem e = { .ip = { .all = { 0 } } };
 265        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
 266
 267        if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
 268                                 &e.port, &e.proto))
 269                return -EINVAL;
 270
 271        ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
 272        ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2.in6);
 273        return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 274}
 275
 276static int
 277hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
 278                    enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 279{
 280        const struct hash_ipportip6 *h = set->data;
 281        ipset_adtfn adtfn = set->variant->adt[adt];
 282        struct hash_ipportip6_elem e = {  .ip = { .all = { 0 } } };
 283        struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
 284        u32 port, port_to;
 285        bool with_ports = false;
 286        int ret;
 287
 288        if (tb[IPSET_ATTR_LINENO])
 289                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 290
 291        if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
 292                     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
 293                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO)))
 294                return -IPSET_ERR_PROTOCOL;
 295        if (unlikely(tb[IPSET_ATTR_IP_TO]))
 296                return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
 297        if (unlikely(tb[IPSET_ATTR_CIDR])) {
 298                u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
 299
 300                if (cidr != HOST_MASK)
 301                        return -IPSET_ERR_INVALID_CIDR;
 302        }
 303
 304        ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip);
 305        if (ret)
 306                return ret;
 307
 308        ret = ip_set_get_extensions(set, tb, &ext);
 309        if (ret)
 310                return ret;
 311
 312        ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip2);
 313        if (ret)
 314                return ret;
 315
 316        e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
 317
 318        if (tb[IPSET_ATTR_PROTO]) {
 319                e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
 320                with_ports = ip_set_proto_with_ports(e.proto);
 321
 322                if (e.proto == 0)
 323                        return -IPSET_ERR_INVALID_PROTO;
 324        } else {
 325                return -IPSET_ERR_MISSING_PROTO;
 326        }
 327
 328        if (!(with_ports || e.proto == IPPROTO_ICMPV6))
 329                e.port = 0;
 330
 331        if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
 332                ret = adtfn(set, &e, &ext, &ext, flags);
 333                return ip_set_eexist(ret, flags) ? 0 : ret;
 334        }
 335
 336        port = ntohs(e.port);
 337        port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
 338        if (port > port_to)
 339                swap(port, port_to);
 340
 341        if (retried)
 342                port = ntohs(h->next.port);
 343        for (; port <= port_to; port++) {
 344                e.port = htons(port);
 345                ret = adtfn(set, &e, &ext, &ext, flags);
 346
 347                if (ret && !ip_set_eexist(ret, flags))
 348                        return ret;
 349
 350                ret = 0;
 351        }
 352        return ret;
 353}
 354
 355static struct ip_set_type hash_ipportip_type __read_mostly = {
 356        .name           = "hash:ip,port,ip",
 357        .protocol       = IPSET_PROTOCOL,
 358        .features       = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
 359        .dimension      = IPSET_DIM_THREE,
 360        .family         = NFPROTO_UNSPEC,
 361        .revision_min   = IPSET_TYPE_REV_MIN,
 362        .revision_max   = IPSET_TYPE_REV_MAX,
 363        .create         = hash_ipportip_create,
 364        .create_policy  = {
 365                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
 366                [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
 367                [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
 368                [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
 369                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 370                [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 371        },
 372        .adt_policy     = {
 373                [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
 374                [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
 375                [IPSET_ATTR_IP2]        = { .type = NLA_NESTED },
 376                [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
 377                [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
 378                [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
 379                [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
 380                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 381                [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
 382                [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
 383                [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
 384                [IPSET_ATTR_COMMENT]    = { .type = NLA_NUL_STRING,
 385                                            .len  = IPSET_MAX_COMMENT_SIZE },
 386                [IPSET_ATTR_SKBMARK]    = { .type = NLA_U64 },
 387                [IPSET_ATTR_SKBPRIO]    = { .type = NLA_U32 },
 388                [IPSET_ATTR_SKBQUEUE]   = { .type = NLA_U16 },
 389        },
 390        .me             = THIS_MODULE,
 391};
 392
 393static int __init
 394hash_ipportip_init(void)
 395{
 396        return ip_set_type_register(&hash_ipportip_type);
 397}
 398
 399static void __exit
 400hash_ipportip_fini(void)
 401{
 402        rcu_barrier();
 403        ip_set_type_unregister(&hash_ipportip_type);
 404}
 405
 406module_init(hash_ipportip_init);
 407module_exit(hash_ipportip_fini);
 408