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