15d50e1d8SJozsef Kadlecsik /* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> 25663bc30SJozsef Kadlecsik * 35663bc30SJozsef Kadlecsik * This program is free software; you can redistribute it and/or modify 45663bc30SJozsef Kadlecsik * it under the terms of the GNU General Public License version 2 as 55663bc30SJozsef Kadlecsik * published by the Free Software Foundation. 65663bc30SJozsef Kadlecsik */ 75663bc30SJozsef Kadlecsik 85663bc30SJozsef Kadlecsik /* Kernel module implementing an IP set type: the hash:ip,port,ip type */ 95663bc30SJozsef Kadlecsik 105663bc30SJozsef Kadlecsik #include <linux/jhash.h> 115663bc30SJozsef Kadlecsik #include <linux/module.h> 125663bc30SJozsef Kadlecsik #include <linux/ip.h> 135663bc30SJozsef Kadlecsik #include <linux/skbuff.h> 145663bc30SJozsef Kadlecsik #include <linux/errno.h> 155663bc30SJozsef Kadlecsik #include <linux/random.h> 165663bc30SJozsef Kadlecsik #include <net/ip.h> 175663bc30SJozsef Kadlecsik #include <net/ipv6.h> 185663bc30SJozsef Kadlecsik #include <net/netlink.h> 195663bc30SJozsef Kadlecsik #include <net/tcp.h> 205663bc30SJozsef Kadlecsik 215663bc30SJozsef Kadlecsik #include <linux/netfilter.h> 225663bc30SJozsef Kadlecsik #include <linux/netfilter/ipset/pfxlen.h> 235663bc30SJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set.h> 245663bc30SJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set_getport.h> 255663bc30SJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set_hash.h> 265663bc30SJozsef Kadlecsik 2735b8dcf8SJozsef Kadlecsik #define IPSET_TYPE_REV_MIN 0 2800d71b27SJozsef Kadlecsik /* 1 SCTP and UDPLITE support added */ 29fda75c6dSOliver Smith /* 2 Counters support added */ 3007cf8f5aSJosh Hunt /* 3 Comments support added */ 31af331419SAnton Danilov /* 4 Forceadd support added */ 32af331419SAnton Danilov #define IPSET_TYPE_REV_MAX 5 /* skbinfo support added */ 3310111a6eSJozsef Kadlecsik 345663bc30SJozsef Kadlecsik MODULE_LICENSE("GPL"); 355663bc30SJozsef Kadlecsik MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); 3635b8dcf8SJozsef Kadlecsik IP_SET_MODULE_DESC("hash:ip,port,ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); 375663bc30SJozsef Kadlecsik MODULE_ALIAS("ip_set_hash:ip,port,ip"); 385663bc30SJozsef Kadlecsik 395663bc30SJozsef Kadlecsik /* Type specific function prefix */ 405d50e1d8SJozsef Kadlecsik #define HTYPE hash_ipportip 415663bc30SJozsef Kadlecsik 4203c8b234SJozsef Kadlecsik /* IPv4 variant */ 435663bc30SJozsef Kadlecsik 445d50e1d8SJozsef Kadlecsik /* Member elements */ 455663bc30SJozsef Kadlecsik struct hash_ipportip4_elem { 465663bc30SJozsef Kadlecsik __be32 ip; 475663bc30SJozsef Kadlecsik __be32 ip2; 485663bc30SJozsef Kadlecsik __be16 port; 495663bc30SJozsef Kadlecsik u8 proto; 505663bc30SJozsef Kadlecsik u8 padding; 515663bc30SJozsef Kadlecsik }; 525663bc30SJozsef Kadlecsik 535663bc30SJozsef Kadlecsik static inline bool 545663bc30SJozsef Kadlecsik hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1, 5589dc79b7SJozsef Kadlecsik const struct hash_ipportip4_elem *ip2, 5689dc79b7SJozsef Kadlecsik u32 *multi) 575663bc30SJozsef Kadlecsik { 585663bc30SJozsef Kadlecsik return ip1->ip == ip2->ip && 595663bc30SJozsef Kadlecsik ip1->ip2 == ip2->ip2 && 605663bc30SJozsef Kadlecsik ip1->port == ip2->port && 615663bc30SJozsef Kadlecsik ip1->proto == ip2->proto; 625663bc30SJozsef Kadlecsik } 635663bc30SJozsef Kadlecsik 645663bc30SJozsef Kadlecsik static bool 655663bc30SJozsef Kadlecsik hash_ipportip4_data_list(struct sk_buff *skb, 665663bc30SJozsef Kadlecsik const struct hash_ipportip4_elem *data) 675663bc30SJozsef Kadlecsik { 687cf7899dSDavid S. Miller if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) || 697cf7899dSDavid S. Miller nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip2) || 707cf7899dSDavid S. Miller nla_put_net16(skb, IPSET_ATTR_PORT, data->port) || 717cf7899dSDavid S. Miller nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto)) 727cf7899dSDavid S. Miller goto nla_put_failure; 735663bc30SJozsef Kadlecsik return 0; 745663bc30SJozsef Kadlecsik 755663bc30SJozsef Kadlecsik nla_put_failure: 765663bc30SJozsef Kadlecsik return 1; 775663bc30SJozsef Kadlecsik } 785663bc30SJozsef Kadlecsik 793d14b171SJozsef Kadlecsik static inline void 805d50e1d8SJozsef Kadlecsik hash_ipportip4_data_next(struct hash_ipportip4_elem *next, 813d14b171SJozsef Kadlecsik const struct hash_ipportip4_elem *d) 823d14b171SJozsef Kadlecsik { 835d50e1d8SJozsef Kadlecsik next->ip = d->ip; 845d50e1d8SJozsef Kadlecsik next->port = d->port; 853d14b171SJozsef Kadlecsik } 863d14b171SJozsef Kadlecsik 875d50e1d8SJozsef Kadlecsik /* Common functions */ 885d50e1d8SJozsef Kadlecsik #define MTYPE hash_ipportip4 895d50e1d8SJozsef Kadlecsik #define PF 4 905d50e1d8SJozsef Kadlecsik #define HOST_MASK 32 915d50e1d8SJozsef Kadlecsik #include "ip_set_hash_gen.h" 925d50e1d8SJozsef Kadlecsik 935663bc30SJozsef Kadlecsik static int 945663bc30SJozsef Kadlecsik hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb, 95b66554cfSJozsef Kadlecsik const struct xt_action_param *par, 965d50e1d8SJozsef Kadlecsik enum ipset_adt adt, struct ip_set_adt_opt *opt) 975663bc30SJozsef Kadlecsik { 985663bc30SJozsef Kadlecsik ipset_adtfn adtfn = set->variant->adt[adt]; 9994729f8aSMark Rustad struct hash_ipportip4_elem e = { .ip = 0 }; 100ca134ce8SJozsef Kadlecsik struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 1015663bc30SJozsef Kadlecsik 102ac8cc925SJozsef Kadlecsik if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, 1035d50e1d8SJozsef Kadlecsik &e.port, &e.proto)) 1045663bc30SJozsef Kadlecsik return -EINVAL; 1055663bc30SJozsef Kadlecsik 1065d50e1d8SJozsef Kadlecsik ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip); 1075d50e1d8SJozsef Kadlecsik ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2); 1085d50e1d8SJozsef Kadlecsik return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); 1095663bc30SJozsef Kadlecsik } 1105663bc30SJozsef Kadlecsik 1115663bc30SJozsef Kadlecsik static int 1125663bc30SJozsef Kadlecsik hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], 1133d14b171SJozsef Kadlecsik enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) 1145663bc30SJozsef Kadlecsik { 1155d50e1d8SJozsef Kadlecsik const struct hash_ipportip *h = set->data; 1165663bc30SJozsef Kadlecsik ipset_adtfn adtfn = set->variant->adt[adt]; 11794729f8aSMark Rustad struct hash_ipportip4_elem e = { .ip = 0 }; 118ca134ce8SJozsef Kadlecsik struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 11920b2fab4SJozsef Kadlecsik u32 ip, ip_to = 0, p = 0, port, port_to; 1205e0c1eb7SJozsef Kadlecsik bool with_ports = false; 1215663bc30SJozsef Kadlecsik int ret; 1225663bc30SJozsef Kadlecsik 1235663bc30SJozsef Kadlecsik if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || 1245663bc30SJozsef Kadlecsik !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || 1255663bc30SJozsef Kadlecsik !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || 12600d71b27SJozsef Kadlecsik !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || 12700d71b27SJozsef Kadlecsik !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || 128af331419SAnton Danilov !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || 129af331419SAnton Danilov !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || 130af331419SAnton Danilov !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || 131af331419SAnton Danilov !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) 1325663bc30SJozsef Kadlecsik return -IPSET_ERR_PROTOCOL; 1335663bc30SJozsef Kadlecsik 1345663bc30SJozsef Kadlecsik if (tb[IPSET_ATTR_LINENO]) 1355663bc30SJozsef Kadlecsik *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); 1365663bc30SJozsef Kadlecsik 1375d50e1d8SJozsef Kadlecsik ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip) || 1385d50e1d8SJozsef Kadlecsik ip_set_get_extensions(set, tb, &ext); 1395663bc30SJozsef Kadlecsik if (ret) 1405663bc30SJozsef Kadlecsik return ret; 1415663bc30SJozsef Kadlecsik 1425d50e1d8SJozsef Kadlecsik ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &e.ip2); 1435663bc30SJozsef Kadlecsik if (ret) 1445663bc30SJozsef Kadlecsik return ret; 1455663bc30SJozsef Kadlecsik 1465663bc30SJozsef Kadlecsik if (tb[IPSET_ATTR_PORT]) 1475d50e1d8SJozsef Kadlecsik e.port = nla_get_be16(tb[IPSET_ATTR_PORT]); 1485663bc30SJozsef Kadlecsik else 1495663bc30SJozsef Kadlecsik return -IPSET_ERR_PROTOCOL; 1505663bc30SJozsef Kadlecsik 1515663bc30SJozsef Kadlecsik if (tb[IPSET_ATTR_PROTO]) { 1525d50e1d8SJozsef Kadlecsik e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); 1535d50e1d8SJozsef Kadlecsik with_ports = ip_set_proto_with_ports(e.proto); 1545663bc30SJozsef Kadlecsik 1555d50e1d8SJozsef Kadlecsik if (e.proto == 0) 1565663bc30SJozsef Kadlecsik return -IPSET_ERR_INVALID_PROTO; 1575663bc30SJozsef Kadlecsik } else 1585663bc30SJozsef Kadlecsik return -IPSET_ERR_MISSING_PROTO; 1595663bc30SJozsef Kadlecsik 1605d50e1d8SJozsef Kadlecsik if (!(with_ports || e.proto == IPPROTO_ICMP)) 1615d50e1d8SJozsef Kadlecsik e.port = 0; 1625663bc30SJozsef Kadlecsik 1635663bc30SJozsef Kadlecsik if (adt == IPSET_TEST || 1645663bc30SJozsef Kadlecsik !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] || 1655663bc30SJozsef Kadlecsik tb[IPSET_ATTR_PORT_TO])) { 1665d50e1d8SJozsef Kadlecsik ret = adtfn(set, &e, &ext, &ext, flags); 1675663bc30SJozsef Kadlecsik return ip_set_eexist(ret, flags) ? 0 : ret; 1685663bc30SJozsef Kadlecsik } 1695663bc30SJozsef Kadlecsik 1705d50e1d8SJozsef Kadlecsik ip_to = ip = ntohl(e.ip); 1715663bc30SJozsef Kadlecsik if (tb[IPSET_ATTR_IP_TO]) { 1725663bc30SJozsef Kadlecsik ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); 1735663bc30SJozsef Kadlecsik if (ret) 1745663bc30SJozsef Kadlecsik return ret; 1755663bc30SJozsef Kadlecsik if (ip > ip_to) 1765663bc30SJozsef Kadlecsik swap(ip, ip_to); 1775663bc30SJozsef Kadlecsik } else if (tb[IPSET_ATTR_CIDR]) { 1785663bc30SJozsef Kadlecsik u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); 1795663bc30SJozsef Kadlecsik 180b9fed748SJozsef Kadlecsik if (!cidr || cidr > 32) 1815663bc30SJozsef Kadlecsik return -IPSET_ERR_INVALID_CIDR; 182e6146e86SJozsef Kadlecsik ip_set_mask_from_to(ip, ip_to, cidr); 1834fe198e6SJozsef Kadlecsik } 1845663bc30SJozsef Kadlecsik 1855d50e1d8SJozsef Kadlecsik port_to = port = ntohs(e.port); 1865e0c1eb7SJozsef Kadlecsik if (with_ports && tb[IPSET_ATTR_PORT_TO]) { 1875663bc30SJozsef Kadlecsik port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); 1885663bc30SJozsef Kadlecsik if (port > port_to) 1895663bc30SJozsef Kadlecsik swap(port, port_to); 1905e0c1eb7SJozsef Kadlecsik } 1915663bc30SJozsef Kadlecsik 1923d14b171SJozsef Kadlecsik if (retried) 1936e27c9b4SJozsef Kadlecsik ip = ntohl(h->next.ip); 1943d14b171SJozsef Kadlecsik for (; !before(ip_to, ip); ip++) { 1956e27c9b4SJozsef Kadlecsik p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port) 1966e27c9b4SJozsef Kadlecsik : port; 1973d14b171SJozsef Kadlecsik for (; p <= port_to; p++) { 1985d50e1d8SJozsef Kadlecsik e.ip = htonl(ip); 1995d50e1d8SJozsef Kadlecsik e.port = htons(p); 2005d50e1d8SJozsef Kadlecsik ret = adtfn(set, &e, &ext, &ext, flags); 2015663bc30SJozsef Kadlecsik 2025663bc30SJozsef Kadlecsik if (ret && !ip_set_eexist(ret, flags)) 2035663bc30SJozsef Kadlecsik return ret; 2045663bc30SJozsef Kadlecsik else 2055663bc30SJozsef Kadlecsik ret = 0; 2065663bc30SJozsef Kadlecsik } 2073d14b171SJozsef Kadlecsik } 2085663bc30SJozsef Kadlecsik return ret; 2095663bc30SJozsef Kadlecsik } 2105663bc30SJozsef Kadlecsik 21103c8b234SJozsef Kadlecsik /* IPv6 variant */ 2125663bc30SJozsef Kadlecsik 2135663bc30SJozsef Kadlecsik struct hash_ipportip6_elem { 2145663bc30SJozsef Kadlecsik union nf_inet_addr ip; 2155663bc30SJozsef Kadlecsik union nf_inet_addr ip2; 2165663bc30SJozsef Kadlecsik __be16 port; 2175663bc30SJozsef Kadlecsik u8 proto; 2185663bc30SJozsef Kadlecsik u8 padding; 2195663bc30SJozsef Kadlecsik }; 2205663bc30SJozsef Kadlecsik 2215d50e1d8SJozsef Kadlecsik /* Common functions */ 2225d50e1d8SJozsef Kadlecsik 2235663bc30SJozsef Kadlecsik static inline bool 2245663bc30SJozsef Kadlecsik hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1, 22589dc79b7SJozsef Kadlecsik const struct hash_ipportip6_elem *ip2, 22689dc79b7SJozsef Kadlecsik u32 *multi) 2275663bc30SJozsef Kadlecsik { 22829e3b160SYOSHIFUJI Hideaki / 吉藤英明 return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) && 22929e3b160SYOSHIFUJI Hideaki / 吉藤英明 ipv6_addr_equal(&ip1->ip2.in6, &ip2->ip2.in6) && 2305663bc30SJozsef Kadlecsik ip1->port == ip2->port && 2315663bc30SJozsef Kadlecsik ip1->proto == ip2->proto; 2325663bc30SJozsef Kadlecsik } 2335663bc30SJozsef Kadlecsik 2345663bc30SJozsef Kadlecsik static bool 2355663bc30SJozsef Kadlecsik hash_ipportip6_data_list(struct sk_buff *skb, 2365663bc30SJozsef Kadlecsik const struct hash_ipportip6_elem *data) 2375663bc30SJozsef Kadlecsik { 2387cf7899dSDavid S. Miller if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) || 2397cf7899dSDavid S. Miller nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip2.in6) || 2407cf7899dSDavid S. Miller nla_put_net16(skb, IPSET_ATTR_PORT, data->port) || 2417cf7899dSDavid S. Miller nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto)) 2427cf7899dSDavid S. Miller goto nla_put_failure; 2435663bc30SJozsef Kadlecsik return 0; 2445663bc30SJozsef Kadlecsik 2455663bc30SJozsef Kadlecsik nla_put_failure: 2465663bc30SJozsef Kadlecsik return 1; 2475663bc30SJozsef Kadlecsik } 2485663bc30SJozsef Kadlecsik 2495d50e1d8SJozsef Kadlecsik static inline void 2505d50e1d8SJozsef Kadlecsik hash_ipportip6_data_next(struct hash_ipportip4_elem *next, 2515d50e1d8SJozsef Kadlecsik const struct hash_ipportip6_elem *d) 2525663bc30SJozsef Kadlecsik { 2535d50e1d8SJozsef Kadlecsik next->port = d->port; 2545663bc30SJozsef Kadlecsik } 2555663bc30SJozsef Kadlecsik 2565d50e1d8SJozsef Kadlecsik #undef MTYPE 2575663bc30SJozsef Kadlecsik #undef PF 2585663bc30SJozsef Kadlecsik #undef HOST_MASK 2595663bc30SJozsef Kadlecsik 2605d50e1d8SJozsef Kadlecsik #define MTYPE hash_ipportip6 2615663bc30SJozsef Kadlecsik #define PF 6 2625663bc30SJozsef Kadlecsik #define HOST_MASK 128 2635d50e1d8SJozsef Kadlecsik #define IP_SET_EMIT_CREATE 2645d50e1d8SJozsef Kadlecsik #include "ip_set_hash_gen.h" 2653d14b171SJozsef Kadlecsik 2665663bc30SJozsef Kadlecsik static int 2675663bc30SJozsef Kadlecsik hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb, 268b66554cfSJozsef Kadlecsik const struct xt_action_param *par, 2695d50e1d8SJozsef Kadlecsik enum ipset_adt adt, struct ip_set_adt_opt *opt) 2705663bc30SJozsef Kadlecsik { 2715663bc30SJozsef Kadlecsik ipset_adtfn adtfn = set->variant->adt[adt]; 27294729f8aSMark Rustad struct hash_ipportip6_elem e = { .ip = { .all = { 0 } } }; 273ca134ce8SJozsef Kadlecsik struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 2745663bc30SJozsef Kadlecsik 275ac8cc925SJozsef Kadlecsik if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, 2765d50e1d8SJozsef Kadlecsik &e.port, &e.proto)) 2775663bc30SJozsef Kadlecsik return -EINVAL; 2785663bc30SJozsef Kadlecsik 2795d50e1d8SJozsef Kadlecsik ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); 2805d50e1d8SJozsef Kadlecsik ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2.in6); 2815d50e1d8SJozsef Kadlecsik return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); 2825663bc30SJozsef Kadlecsik } 2835663bc30SJozsef Kadlecsik 2845663bc30SJozsef Kadlecsik static int 2855663bc30SJozsef Kadlecsik hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[], 2863d14b171SJozsef Kadlecsik enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) 2875663bc30SJozsef Kadlecsik { 2885d50e1d8SJozsef Kadlecsik const struct hash_ipportip *h = set->data; 2895663bc30SJozsef Kadlecsik ipset_adtfn adtfn = set->variant->adt[adt]; 29094729f8aSMark Rustad struct hash_ipportip6_elem e = { .ip = { .all = { 0 } } }; 291ca134ce8SJozsef Kadlecsik struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 2925663bc30SJozsef Kadlecsik u32 port, port_to; 2935e0c1eb7SJozsef Kadlecsik bool with_ports = false; 2945663bc30SJozsef Kadlecsik int ret; 2955663bc30SJozsef Kadlecsik 2965663bc30SJozsef Kadlecsik if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || 2975663bc30SJozsef Kadlecsik !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || 2985663bc30SJozsef Kadlecsik !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || 2995663bc30SJozsef Kadlecsik !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || 30000d71b27SJozsef Kadlecsik !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || 30100d71b27SJozsef Kadlecsik !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || 302af331419SAnton Danilov !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || 303af331419SAnton Danilov !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || 304af331419SAnton Danilov !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE) || 3055663bc30SJozsef Kadlecsik tb[IPSET_ATTR_IP_TO] || 3065663bc30SJozsef Kadlecsik tb[IPSET_ATTR_CIDR])) 3075663bc30SJozsef Kadlecsik return -IPSET_ERR_PROTOCOL; 3085663bc30SJozsef Kadlecsik 3095663bc30SJozsef Kadlecsik if (tb[IPSET_ATTR_LINENO]) 3105663bc30SJozsef Kadlecsik *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); 3115663bc30SJozsef Kadlecsik 3125d50e1d8SJozsef Kadlecsik ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) || 3135d50e1d8SJozsef Kadlecsik ip_set_get_extensions(set, tb, &ext); 3145663bc30SJozsef Kadlecsik if (ret) 3155663bc30SJozsef Kadlecsik return ret; 3165663bc30SJozsef Kadlecsik 3175d50e1d8SJozsef Kadlecsik ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip2); 3185663bc30SJozsef Kadlecsik if (ret) 3195663bc30SJozsef Kadlecsik return ret; 3205663bc30SJozsef Kadlecsik 3215663bc30SJozsef Kadlecsik if (tb[IPSET_ATTR_PORT]) 3225d50e1d8SJozsef Kadlecsik e.port = nla_get_be16(tb[IPSET_ATTR_PORT]); 3235663bc30SJozsef Kadlecsik else 3245663bc30SJozsef Kadlecsik return -IPSET_ERR_PROTOCOL; 3255663bc30SJozsef Kadlecsik 3265663bc30SJozsef Kadlecsik if (tb[IPSET_ATTR_PROTO]) { 3275d50e1d8SJozsef Kadlecsik e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); 3285d50e1d8SJozsef Kadlecsik with_ports = ip_set_proto_with_ports(e.proto); 3295663bc30SJozsef Kadlecsik 3305d50e1d8SJozsef Kadlecsik if (e.proto == 0) 3315663bc30SJozsef Kadlecsik return -IPSET_ERR_INVALID_PROTO; 3325663bc30SJozsef Kadlecsik } else 3335663bc30SJozsef Kadlecsik return -IPSET_ERR_MISSING_PROTO; 3345663bc30SJozsef Kadlecsik 3355d50e1d8SJozsef Kadlecsik if (!(with_ports || e.proto == IPPROTO_ICMPV6)) 3365d50e1d8SJozsef Kadlecsik e.port = 0; 3375663bc30SJozsef Kadlecsik 3385e0c1eb7SJozsef Kadlecsik if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { 3395d50e1d8SJozsef Kadlecsik ret = adtfn(set, &e, &ext, &ext, flags); 3405663bc30SJozsef Kadlecsik return ip_set_eexist(ret, flags) ? 0 : ret; 3415663bc30SJozsef Kadlecsik } 3425663bc30SJozsef Kadlecsik 3435d50e1d8SJozsef Kadlecsik port = ntohs(e.port); 3445663bc30SJozsef Kadlecsik port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); 3455663bc30SJozsef Kadlecsik if (port > port_to) 3465663bc30SJozsef Kadlecsik swap(port, port_to); 3475663bc30SJozsef Kadlecsik 3483d14b171SJozsef Kadlecsik if (retried) 3496e27c9b4SJozsef Kadlecsik port = ntohs(h->next.port); 3505663bc30SJozsef Kadlecsik for (; port <= port_to; port++) { 3515d50e1d8SJozsef Kadlecsik e.port = htons(port); 3525d50e1d8SJozsef Kadlecsik ret = adtfn(set, &e, &ext, &ext, flags); 3535663bc30SJozsef Kadlecsik 3545663bc30SJozsef Kadlecsik if (ret && !ip_set_eexist(ret, flags)) 3555663bc30SJozsef Kadlecsik return ret; 3565663bc30SJozsef Kadlecsik else 3575663bc30SJozsef Kadlecsik ret = 0; 3585663bc30SJozsef Kadlecsik } 3595663bc30SJozsef Kadlecsik return ret; 3605663bc30SJozsef Kadlecsik } 3615663bc30SJozsef Kadlecsik 3625663bc30SJozsef Kadlecsik static struct ip_set_type hash_ipportip_type __read_mostly = { 3635663bc30SJozsef Kadlecsik .name = "hash:ip,port,ip", 3645663bc30SJozsef Kadlecsik .protocol = IPSET_PROTOCOL, 3655663bc30SJozsef Kadlecsik .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, 3665663bc30SJozsef Kadlecsik .dimension = IPSET_DIM_THREE, 367c15f1c83SJan Engelhardt .family = NFPROTO_UNSPEC, 36835b8dcf8SJozsef Kadlecsik .revision_min = IPSET_TYPE_REV_MIN, 36935b8dcf8SJozsef Kadlecsik .revision_max = IPSET_TYPE_REV_MAX, 3705663bc30SJozsef Kadlecsik .create = hash_ipportip_create, 3715663bc30SJozsef Kadlecsik .create_policy = { 3725663bc30SJozsef Kadlecsik [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, 3735663bc30SJozsef Kadlecsik [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, 3745663bc30SJozsef Kadlecsik [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, 3755663bc30SJozsef Kadlecsik [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, 3765663bc30SJozsef Kadlecsik [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, 37700d71b27SJozsef Kadlecsik [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, 3785663bc30SJozsef Kadlecsik }, 3795663bc30SJozsef Kadlecsik .adt_policy = { 3805663bc30SJozsef Kadlecsik [IPSET_ATTR_IP] = { .type = NLA_NESTED }, 3815663bc30SJozsef Kadlecsik [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, 3825663bc30SJozsef Kadlecsik [IPSET_ATTR_IP2] = { .type = NLA_NESTED }, 3835663bc30SJozsef Kadlecsik [IPSET_ATTR_PORT] = { .type = NLA_U16 }, 3845663bc30SJozsef Kadlecsik [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, 3855663bc30SJozsef Kadlecsik [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, 3865663bc30SJozsef Kadlecsik [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, 3875663bc30SJozsef Kadlecsik [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, 3885663bc30SJozsef Kadlecsik [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, 38900d71b27SJozsef Kadlecsik [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, 39000d71b27SJozsef Kadlecsik [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, 391fda75c6dSOliver Smith [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, 392af331419SAnton Danilov [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, 393af331419SAnton Danilov [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, 394af331419SAnton Danilov [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, 3955663bc30SJozsef Kadlecsik }, 3965663bc30SJozsef Kadlecsik .me = THIS_MODULE, 3975663bc30SJozsef Kadlecsik }; 3985663bc30SJozsef Kadlecsik 3995663bc30SJozsef Kadlecsik static int __init 4005663bc30SJozsef Kadlecsik hash_ipportip_init(void) 4015663bc30SJozsef Kadlecsik { 4025663bc30SJozsef Kadlecsik return ip_set_type_register(&hash_ipportip_type); 4035663bc30SJozsef Kadlecsik } 4045663bc30SJozsef Kadlecsik 4055663bc30SJozsef Kadlecsik static void __exit 4065663bc30SJozsef Kadlecsik hash_ipportip_fini(void) 4075663bc30SJozsef Kadlecsik { 4085663bc30SJozsef Kadlecsik ip_set_type_unregister(&hash_ipportip_type); 4095663bc30SJozsef Kadlecsik } 4105663bc30SJozsef Kadlecsik 4115663bc30SJozsef Kadlecsik module_init(hash_ipportip_init); 4125663bc30SJozsef Kadlecsik module_exit(hash_ipportip_fini); 413