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 */ 2935b8dcf8SJozsef Kadlecsik #define IPSET_TYPE_REV_MAX 2 /* Counters support added */ 3010111a6eSJozsef Kadlecsik 315663bc30SJozsef Kadlecsik MODULE_LICENSE("GPL"); 325663bc30SJozsef Kadlecsik MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); 3335b8dcf8SJozsef Kadlecsik IP_SET_MODULE_DESC("hash:ip,port,ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); 345663bc30SJozsef Kadlecsik MODULE_ALIAS("ip_set_hash:ip,port,ip"); 355663bc30SJozsef Kadlecsik 365663bc30SJozsef Kadlecsik /* Type specific function prefix */ 375d50e1d8SJozsef Kadlecsik #define HTYPE hash_ipportip 385663bc30SJozsef Kadlecsik 395d50e1d8SJozsef Kadlecsik /* IPv4 variants */ 405663bc30SJozsef Kadlecsik 415d50e1d8SJozsef Kadlecsik /* Member elements */ 425663bc30SJozsef Kadlecsik struct hash_ipportip4_elem { 435663bc30SJozsef Kadlecsik __be32 ip; 445663bc30SJozsef Kadlecsik __be32 ip2; 455663bc30SJozsef Kadlecsik __be16 port; 465663bc30SJozsef Kadlecsik u8 proto; 475663bc30SJozsef Kadlecsik u8 padding; 485663bc30SJozsef Kadlecsik }; 495663bc30SJozsef Kadlecsik 505d50e1d8SJozsef Kadlecsik struct hash_ipportip4t_elem { 515663bc30SJozsef Kadlecsik __be32 ip; 525663bc30SJozsef Kadlecsik __be32 ip2; 535663bc30SJozsef Kadlecsik __be16 port; 545663bc30SJozsef Kadlecsik u8 proto; 555663bc30SJozsef Kadlecsik u8 padding; 565663bc30SJozsef Kadlecsik unsigned long timeout; 575663bc30SJozsef Kadlecsik }; 585663bc30SJozsef Kadlecsik 5900d71b27SJozsef Kadlecsik struct hash_ipportip4c_elem { 6000d71b27SJozsef Kadlecsik __be32 ip; 6100d71b27SJozsef Kadlecsik __be32 ip2; 6200d71b27SJozsef Kadlecsik __be16 port; 6300d71b27SJozsef Kadlecsik u8 proto; 6400d71b27SJozsef Kadlecsik u8 padding; 6500d71b27SJozsef Kadlecsik struct ip_set_counter counter; 6600d71b27SJozsef Kadlecsik }; 6700d71b27SJozsef Kadlecsik 6800d71b27SJozsef Kadlecsik struct hash_ipportip4ct_elem { 6900d71b27SJozsef Kadlecsik __be32 ip; 7000d71b27SJozsef Kadlecsik __be32 ip2; 7100d71b27SJozsef Kadlecsik __be16 port; 7200d71b27SJozsef Kadlecsik u8 proto; 7300d71b27SJozsef Kadlecsik u8 padding; 7400d71b27SJozsef Kadlecsik struct ip_set_counter counter; 7500d71b27SJozsef Kadlecsik unsigned long timeout; 7600d71b27SJozsef Kadlecsik }; 7700d71b27SJozsef Kadlecsik 785663bc30SJozsef Kadlecsik static inline bool 795663bc30SJozsef Kadlecsik hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1, 8089dc79b7SJozsef Kadlecsik const struct hash_ipportip4_elem *ip2, 8189dc79b7SJozsef Kadlecsik u32 *multi) 825663bc30SJozsef Kadlecsik { 835663bc30SJozsef Kadlecsik return ip1->ip == ip2->ip && 845663bc30SJozsef Kadlecsik ip1->ip2 == ip2->ip2 && 855663bc30SJozsef Kadlecsik ip1->port == ip2->port && 865663bc30SJozsef Kadlecsik ip1->proto == ip2->proto; 875663bc30SJozsef Kadlecsik } 885663bc30SJozsef Kadlecsik 895663bc30SJozsef Kadlecsik static bool 905663bc30SJozsef Kadlecsik hash_ipportip4_data_list(struct sk_buff *skb, 915663bc30SJozsef Kadlecsik const struct hash_ipportip4_elem *data) 925663bc30SJozsef Kadlecsik { 937cf7899dSDavid S. Miller if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) || 947cf7899dSDavid S. Miller nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip2) || 957cf7899dSDavid S. Miller nla_put_net16(skb, IPSET_ATTR_PORT, data->port) || 967cf7899dSDavid S. Miller nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto)) 977cf7899dSDavid S. Miller goto nla_put_failure; 985663bc30SJozsef Kadlecsik return 0; 995663bc30SJozsef Kadlecsik 1005663bc30SJozsef Kadlecsik nla_put_failure: 1015663bc30SJozsef Kadlecsik return 1; 1025663bc30SJozsef Kadlecsik } 1035663bc30SJozsef Kadlecsik 1043d14b171SJozsef Kadlecsik static inline void 1055d50e1d8SJozsef Kadlecsik hash_ipportip4_data_next(struct hash_ipportip4_elem *next, 1063d14b171SJozsef Kadlecsik const struct hash_ipportip4_elem *d) 1073d14b171SJozsef Kadlecsik { 1085d50e1d8SJozsef Kadlecsik next->ip = d->ip; 1095d50e1d8SJozsef Kadlecsik next->port = d->port; 1103d14b171SJozsef Kadlecsik } 1113d14b171SJozsef Kadlecsik 1125d50e1d8SJozsef Kadlecsik /* Common functions */ 1135d50e1d8SJozsef Kadlecsik #define MTYPE hash_ipportip4 1145d50e1d8SJozsef Kadlecsik #define PF 4 1155d50e1d8SJozsef Kadlecsik #define HOST_MASK 32 1165d50e1d8SJozsef Kadlecsik #include "ip_set_hash_gen.h" 1175d50e1d8SJozsef Kadlecsik 1185663bc30SJozsef Kadlecsik static int 1195663bc30SJozsef Kadlecsik hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb, 120b66554cfSJozsef Kadlecsik const struct xt_action_param *par, 1215d50e1d8SJozsef Kadlecsik enum ipset_adt adt, struct ip_set_adt_opt *opt) 1225663bc30SJozsef Kadlecsik { 1235d50e1d8SJozsef Kadlecsik const struct hash_ipportip *h = set->data; 1245663bc30SJozsef Kadlecsik ipset_adtfn adtfn = set->variant->adt[adt]; 1255d50e1d8SJozsef Kadlecsik struct hash_ipportip4_elem e = { }; 1265d50e1d8SJozsef Kadlecsik struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); 1275663bc30SJozsef Kadlecsik 128ac8cc925SJozsef Kadlecsik if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, 1295d50e1d8SJozsef Kadlecsik &e.port, &e.proto)) 1305663bc30SJozsef Kadlecsik return -EINVAL; 1315663bc30SJozsef Kadlecsik 1325d50e1d8SJozsef Kadlecsik ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip); 1335d50e1d8SJozsef Kadlecsik ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2); 1345d50e1d8SJozsef Kadlecsik return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); 1355663bc30SJozsef Kadlecsik } 1365663bc30SJozsef Kadlecsik 1375663bc30SJozsef Kadlecsik static int 1385663bc30SJozsef Kadlecsik hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], 1393d14b171SJozsef Kadlecsik enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) 1405663bc30SJozsef Kadlecsik { 1415d50e1d8SJozsef Kadlecsik const struct hash_ipportip *h = set->data; 1425663bc30SJozsef Kadlecsik ipset_adtfn adtfn = set->variant->adt[adt]; 1435d50e1d8SJozsef Kadlecsik struct hash_ipportip4_elem e = { }; 1445d50e1d8SJozsef Kadlecsik struct ip_set_ext ext = IP_SET_INIT_UEXT(h); 14520b2fab4SJozsef Kadlecsik u32 ip, ip_to = 0, p = 0, port, port_to; 1465e0c1eb7SJozsef Kadlecsik bool with_ports = false; 1475663bc30SJozsef Kadlecsik int ret; 1485663bc30SJozsef Kadlecsik 1495663bc30SJozsef Kadlecsik if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || 1505663bc30SJozsef Kadlecsik !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || 1515663bc30SJozsef Kadlecsik !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || 15200d71b27SJozsef Kadlecsik !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || 15300d71b27SJozsef Kadlecsik !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || 15400d71b27SJozsef Kadlecsik !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) 1555663bc30SJozsef Kadlecsik return -IPSET_ERR_PROTOCOL; 1565663bc30SJozsef Kadlecsik 1575663bc30SJozsef Kadlecsik if (tb[IPSET_ATTR_LINENO]) 1585663bc30SJozsef Kadlecsik *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); 1595663bc30SJozsef Kadlecsik 1605d50e1d8SJozsef Kadlecsik ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip) || 1615d50e1d8SJozsef Kadlecsik ip_set_get_extensions(set, tb, &ext); 1625663bc30SJozsef Kadlecsik if (ret) 1635663bc30SJozsef Kadlecsik return ret; 1645663bc30SJozsef Kadlecsik 1655d50e1d8SJozsef Kadlecsik ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &e.ip2); 1665663bc30SJozsef Kadlecsik if (ret) 1675663bc30SJozsef Kadlecsik return ret; 1685663bc30SJozsef Kadlecsik 1695663bc30SJozsef Kadlecsik if (tb[IPSET_ATTR_PORT]) 1705d50e1d8SJozsef Kadlecsik e.port = nla_get_be16(tb[IPSET_ATTR_PORT]); 1715663bc30SJozsef Kadlecsik else 1725663bc30SJozsef Kadlecsik return -IPSET_ERR_PROTOCOL; 1735663bc30SJozsef Kadlecsik 1745663bc30SJozsef Kadlecsik if (tb[IPSET_ATTR_PROTO]) { 1755d50e1d8SJozsef Kadlecsik e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); 1765d50e1d8SJozsef Kadlecsik with_ports = ip_set_proto_with_ports(e.proto); 1775663bc30SJozsef Kadlecsik 1785d50e1d8SJozsef Kadlecsik if (e.proto == 0) 1795663bc30SJozsef Kadlecsik return -IPSET_ERR_INVALID_PROTO; 1805663bc30SJozsef Kadlecsik } else 1815663bc30SJozsef Kadlecsik return -IPSET_ERR_MISSING_PROTO; 1825663bc30SJozsef Kadlecsik 1835d50e1d8SJozsef Kadlecsik if (!(with_ports || e.proto == IPPROTO_ICMP)) 1845d50e1d8SJozsef Kadlecsik e.port = 0; 1855663bc30SJozsef Kadlecsik 1865663bc30SJozsef Kadlecsik if (adt == IPSET_TEST || 1875663bc30SJozsef Kadlecsik !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] || 1885663bc30SJozsef Kadlecsik tb[IPSET_ATTR_PORT_TO])) { 1895d50e1d8SJozsef Kadlecsik ret = adtfn(set, &e, &ext, &ext, flags); 1905663bc30SJozsef Kadlecsik return ip_set_eexist(ret, flags) ? 0 : ret; 1915663bc30SJozsef Kadlecsik } 1925663bc30SJozsef Kadlecsik 1935d50e1d8SJozsef Kadlecsik ip_to = ip = ntohl(e.ip); 1945663bc30SJozsef Kadlecsik if (tb[IPSET_ATTR_IP_TO]) { 1955663bc30SJozsef Kadlecsik ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); 1965663bc30SJozsef Kadlecsik if (ret) 1975663bc30SJozsef Kadlecsik return ret; 1985663bc30SJozsef Kadlecsik if (ip > ip_to) 1995663bc30SJozsef Kadlecsik swap(ip, ip_to); 2005663bc30SJozsef Kadlecsik } else if (tb[IPSET_ATTR_CIDR]) { 2015663bc30SJozsef Kadlecsik u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); 2025663bc30SJozsef Kadlecsik 203b9fed748SJozsef Kadlecsik if (!cidr || cidr > 32) 2045663bc30SJozsef Kadlecsik return -IPSET_ERR_INVALID_CIDR; 205e6146e86SJozsef Kadlecsik ip_set_mask_from_to(ip, ip_to, cidr); 2064fe198e6SJozsef Kadlecsik } 2075663bc30SJozsef Kadlecsik 2085d50e1d8SJozsef Kadlecsik port_to = port = ntohs(e.port); 2095e0c1eb7SJozsef Kadlecsik if (with_ports && tb[IPSET_ATTR_PORT_TO]) { 2105663bc30SJozsef Kadlecsik port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); 2115663bc30SJozsef Kadlecsik if (port > port_to) 2125663bc30SJozsef Kadlecsik swap(port, port_to); 2135e0c1eb7SJozsef Kadlecsik } 2145663bc30SJozsef Kadlecsik 2153d14b171SJozsef Kadlecsik if (retried) 2166e27c9b4SJozsef Kadlecsik ip = ntohl(h->next.ip); 2173d14b171SJozsef Kadlecsik for (; !before(ip_to, ip); ip++) { 2186e27c9b4SJozsef Kadlecsik p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port) 2196e27c9b4SJozsef Kadlecsik : port; 2203d14b171SJozsef Kadlecsik for (; p <= port_to; p++) { 2215d50e1d8SJozsef Kadlecsik e.ip = htonl(ip); 2225d50e1d8SJozsef Kadlecsik e.port = htons(p); 2235d50e1d8SJozsef Kadlecsik ret = adtfn(set, &e, &ext, &ext, flags); 2245663bc30SJozsef Kadlecsik 2255663bc30SJozsef Kadlecsik if (ret && !ip_set_eexist(ret, flags)) 2265663bc30SJozsef Kadlecsik return ret; 2275663bc30SJozsef Kadlecsik else 2285663bc30SJozsef Kadlecsik ret = 0; 2295663bc30SJozsef Kadlecsik } 2303d14b171SJozsef Kadlecsik } 2315663bc30SJozsef Kadlecsik return ret; 2325663bc30SJozsef Kadlecsik } 2335663bc30SJozsef Kadlecsik 2345d50e1d8SJozsef Kadlecsik /* IPv6 variants */ 2355663bc30SJozsef Kadlecsik 2365663bc30SJozsef Kadlecsik struct hash_ipportip6_elem { 2375663bc30SJozsef Kadlecsik union nf_inet_addr ip; 2385663bc30SJozsef Kadlecsik union nf_inet_addr ip2; 2395663bc30SJozsef Kadlecsik __be16 port; 2405663bc30SJozsef Kadlecsik u8 proto; 2415663bc30SJozsef Kadlecsik u8 padding; 2425663bc30SJozsef Kadlecsik }; 2435663bc30SJozsef Kadlecsik 2445d50e1d8SJozsef Kadlecsik struct hash_ipportip6t_elem { 2455663bc30SJozsef Kadlecsik union nf_inet_addr ip; 2465663bc30SJozsef Kadlecsik union nf_inet_addr ip2; 2475663bc30SJozsef Kadlecsik __be16 port; 2485663bc30SJozsef Kadlecsik u8 proto; 2495663bc30SJozsef Kadlecsik u8 padding; 2505663bc30SJozsef Kadlecsik unsigned long timeout; 2515663bc30SJozsef Kadlecsik }; 2525663bc30SJozsef Kadlecsik 25300d71b27SJozsef Kadlecsik struct hash_ipportip6c_elem { 25400d71b27SJozsef Kadlecsik union nf_inet_addr ip; 25500d71b27SJozsef Kadlecsik union nf_inet_addr ip2; 25600d71b27SJozsef Kadlecsik __be16 port; 25700d71b27SJozsef Kadlecsik u8 proto; 25800d71b27SJozsef Kadlecsik u8 padding; 25900d71b27SJozsef Kadlecsik struct ip_set_counter counter; 26000d71b27SJozsef Kadlecsik }; 26100d71b27SJozsef Kadlecsik 26200d71b27SJozsef Kadlecsik struct hash_ipportip6ct_elem { 26300d71b27SJozsef Kadlecsik union nf_inet_addr ip; 26400d71b27SJozsef Kadlecsik union nf_inet_addr ip2; 26500d71b27SJozsef Kadlecsik __be16 port; 26600d71b27SJozsef Kadlecsik u8 proto; 26700d71b27SJozsef Kadlecsik u8 padding; 26800d71b27SJozsef Kadlecsik struct ip_set_counter counter; 26900d71b27SJozsef Kadlecsik unsigned long timeout; 27000d71b27SJozsef Kadlecsik }; 27100d71b27SJozsef Kadlecsik 2725d50e1d8SJozsef Kadlecsik /* Common functions */ 2735d50e1d8SJozsef Kadlecsik 2745663bc30SJozsef Kadlecsik static inline bool 2755663bc30SJozsef Kadlecsik hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1, 27689dc79b7SJozsef Kadlecsik const struct hash_ipportip6_elem *ip2, 27789dc79b7SJozsef Kadlecsik u32 *multi) 2785663bc30SJozsef Kadlecsik { 27929e3b160SYOSHIFUJI Hideaki / 吉藤英明 return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) && 28029e3b160SYOSHIFUJI Hideaki / 吉藤英明 ipv6_addr_equal(&ip1->ip2.in6, &ip2->ip2.in6) && 2815663bc30SJozsef Kadlecsik ip1->port == ip2->port && 2825663bc30SJozsef Kadlecsik ip1->proto == ip2->proto; 2835663bc30SJozsef Kadlecsik } 2845663bc30SJozsef Kadlecsik 2855663bc30SJozsef Kadlecsik static bool 2865663bc30SJozsef Kadlecsik hash_ipportip6_data_list(struct sk_buff *skb, 2875663bc30SJozsef Kadlecsik const struct hash_ipportip6_elem *data) 2885663bc30SJozsef Kadlecsik { 2897cf7899dSDavid S. Miller if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) || 2907cf7899dSDavid S. Miller nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip2.in6) || 2917cf7899dSDavid S. Miller nla_put_net16(skb, IPSET_ATTR_PORT, data->port) || 2927cf7899dSDavid S. Miller nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto)) 2937cf7899dSDavid S. Miller goto nla_put_failure; 2945663bc30SJozsef Kadlecsik return 0; 2955663bc30SJozsef Kadlecsik 2965663bc30SJozsef Kadlecsik nla_put_failure: 2975663bc30SJozsef Kadlecsik return 1; 2985663bc30SJozsef Kadlecsik } 2995663bc30SJozsef Kadlecsik 3005d50e1d8SJozsef Kadlecsik static inline void 3015d50e1d8SJozsef Kadlecsik hash_ipportip6_data_next(struct hash_ipportip4_elem *next, 3025d50e1d8SJozsef Kadlecsik const struct hash_ipportip6_elem *d) 3035663bc30SJozsef Kadlecsik { 3045d50e1d8SJozsef Kadlecsik next->port = d->port; 3055663bc30SJozsef Kadlecsik } 3065663bc30SJozsef Kadlecsik 3075d50e1d8SJozsef Kadlecsik #undef MTYPE 3085663bc30SJozsef Kadlecsik #undef PF 3095663bc30SJozsef Kadlecsik #undef HOST_MASK 3105663bc30SJozsef Kadlecsik 3115d50e1d8SJozsef Kadlecsik #define MTYPE hash_ipportip6 3125663bc30SJozsef Kadlecsik #define PF 6 3135663bc30SJozsef Kadlecsik #define HOST_MASK 128 3145d50e1d8SJozsef Kadlecsik #define IP_SET_EMIT_CREATE 3155d50e1d8SJozsef Kadlecsik #include "ip_set_hash_gen.h" 3163d14b171SJozsef Kadlecsik 3175663bc30SJozsef Kadlecsik static int 3185663bc30SJozsef Kadlecsik hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb, 319b66554cfSJozsef Kadlecsik const struct xt_action_param *par, 3205d50e1d8SJozsef Kadlecsik enum ipset_adt adt, struct ip_set_adt_opt *opt) 3215663bc30SJozsef Kadlecsik { 3225d50e1d8SJozsef Kadlecsik const struct hash_ipportip *h = set->data; 3235663bc30SJozsef Kadlecsik ipset_adtfn adtfn = set->variant->adt[adt]; 3245d50e1d8SJozsef Kadlecsik struct hash_ipportip6_elem e = { }; 3255d50e1d8SJozsef Kadlecsik struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); 3265663bc30SJozsef Kadlecsik 327ac8cc925SJozsef Kadlecsik if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, 3285d50e1d8SJozsef Kadlecsik &e.port, &e.proto)) 3295663bc30SJozsef Kadlecsik return -EINVAL; 3305663bc30SJozsef Kadlecsik 3315d50e1d8SJozsef Kadlecsik ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); 3325d50e1d8SJozsef Kadlecsik ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2.in6); 3335d50e1d8SJozsef Kadlecsik return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); 3345663bc30SJozsef Kadlecsik } 3355663bc30SJozsef Kadlecsik 3365663bc30SJozsef Kadlecsik static int 3375663bc30SJozsef Kadlecsik hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[], 3383d14b171SJozsef Kadlecsik enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) 3395663bc30SJozsef Kadlecsik { 3405d50e1d8SJozsef Kadlecsik const struct hash_ipportip *h = set->data; 3415663bc30SJozsef Kadlecsik ipset_adtfn adtfn = set->variant->adt[adt]; 3425d50e1d8SJozsef Kadlecsik struct hash_ipportip6_elem e = { }; 3435d50e1d8SJozsef Kadlecsik struct ip_set_ext ext = IP_SET_INIT_UEXT(h); 3445663bc30SJozsef Kadlecsik u32 port, port_to; 3455e0c1eb7SJozsef Kadlecsik bool with_ports = false; 3465663bc30SJozsef Kadlecsik int ret; 3475663bc30SJozsef Kadlecsik 3485663bc30SJozsef Kadlecsik if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || 3495663bc30SJozsef Kadlecsik !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || 3505663bc30SJozsef Kadlecsik !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || 3515663bc30SJozsef Kadlecsik !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || 35200d71b27SJozsef Kadlecsik !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || 35300d71b27SJozsef Kadlecsik !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || 3545663bc30SJozsef Kadlecsik tb[IPSET_ATTR_IP_TO] || 3555663bc30SJozsef Kadlecsik tb[IPSET_ATTR_CIDR])) 3565663bc30SJozsef Kadlecsik return -IPSET_ERR_PROTOCOL; 3575663bc30SJozsef Kadlecsik 3585663bc30SJozsef Kadlecsik if (tb[IPSET_ATTR_LINENO]) 3595663bc30SJozsef Kadlecsik *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); 3605663bc30SJozsef Kadlecsik 3615d50e1d8SJozsef Kadlecsik ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) || 3625d50e1d8SJozsef Kadlecsik ip_set_get_extensions(set, tb, &ext); 3635663bc30SJozsef Kadlecsik if (ret) 3645663bc30SJozsef Kadlecsik return ret; 3655663bc30SJozsef Kadlecsik 3665d50e1d8SJozsef Kadlecsik ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip2); 3675663bc30SJozsef Kadlecsik if (ret) 3685663bc30SJozsef Kadlecsik return ret; 3695663bc30SJozsef Kadlecsik 3705663bc30SJozsef Kadlecsik if (tb[IPSET_ATTR_PORT]) 3715d50e1d8SJozsef Kadlecsik e.port = nla_get_be16(tb[IPSET_ATTR_PORT]); 3725663bc30SJozsef Kadlecsik else 3735663bc30SJozsef Kadlecsik return -IPSET_ERR_PROTOCOL; 3745663bc30SJozsef Kadlecsik 3755663bc30SJozsef Kadlecsik if (tb[IPSET_ATTR_PROTO]) { 3765d50e1d8SJozsef Kadlecsik e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); 3775d50e1d8SJozsef Kadlecsik with_ports = ip_set_proto_with_ports(e.proto); 3785663bc30SJozsef Kadlecsik 3795d50e1d8SJozsef Kadlecsik if (e.proto == 0) 3805663bc30SJozsef Kadlecsik return -IPSET_ERR_INVALID_PROTO; 3815663bc30SJozsef Kadlecsik } else 3825663bc30SJozsef Kadlecsik return -IPSET_ERR_MISSING_PROTO; 3835663bc30SJozsef Kadlecsik 3845d50e1d8SJozsef Kadlecsik if (!(with_ports || e.proto == IPPROTO_ICMPV6)) 3855d50e1d8SJozsef Kadlecsik e.port = 0; 3865663bc30SJozsef Kadlecsik 3875e0c1eb7SJozsef Kadlecsik if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { 3885d50e1d8SJozsef Kadlecsik ret = adtfn(set, &e, &ext, &ext, flags); 3895663bc30SJozsef Kadlecsik return ip_set_eexist(ret, flags) ? 0 : ret; 3905663bc30SJozsef Kadlecsik } 3915663bc30SJozsef Kadlecsik 3925d50e1d8SJozsef Kadlecsik port = ntohs(e.port); 3935663bc30SJozsef Kadlecsik port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); 3945663bc30SJozsef Kadlecsik if (port > port_to) 3955663bc30SJozsef Kadlecsik swap(port, port_to); 3965663bc30SJozsef Kadlecsik 3973d14b171SJozsef Kadlecsik if (retried) 3986e27c9b4SJozsef Kadlecsik port = ntohs(h->next.port); 3995663bc30SJozsef Kadlecsik for (; port <= port_to; port++) { 4005d50e1d8SJozsef Kadlecsik e.port = htons(port); 4015d50e1d8SJozsef Kadlecsik ret = adtfn(set, &e, &ext, &ext, flags); 4025663bc30SJozsef Kadlecsik 4035663bc30SJozsef Kadlecsik if (ret && !ip_set_eexist(ret, flags)) 4045663bc30SJozsef Kadlecsik return ret; 4055663bc30SJozsef Kadlecsik else 4065663bc30SJozsef Kadlecsik ret = 0; 4075663bc30SJozsef Kadlecsik } 4085663bc30SJozsef Kadlecsik return ret; 4095663bc30SJozsef Kadlecsik } 4105663bc30SJozsef Kadlecsik 4115663bc30SJozsef Kadlecsik static struct ip_set_type hash_ipportip_type __read_mostly = { 4125663bc30SJozsef Kadlecsik .name = "hash:ip,port,ip", 4135663bc30SJozsef Kadlecsik .protocol = IPSET_PROTOCOL, 4145663bc30SJozsef Kadlecsik .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, 4155663bc30SJozsef Kadlecsik .dimension = IPSET_DIM_THREE, 416c15f1c83SJan Engelhardt .family = NFPROTO_UNSPEC, 41735b8dcf8SJozsef Kadlecsik .revision_min = IPSET_TYPE_REV_MIN, 41835b8dcf8SJozsef Kadlecsik .revision_max = IPSET_TYPE_REV_MAX, 4195663bc30SJozsef Kadlecsik .create = hash_ipportip_create, 4205663bc30SJozsef Kadlecsik .create_policy = { 4215663bc30SJozsef Kadlecsik [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, 4225663bc30SJozsef Kadlecsik [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, 4235663bc30SJozsef Kadlecsik [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, 4245663bc30SJozsef Kadlecsik [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, 4255663bc30SJozsef Kadlecsik [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, 42600d71b27SJozsef Kadlecsik [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, 4275663bc30SJozsef Kadlecsik }, 4285663bc30SJozsef Kadlecsik .adt_policy = { 4295663bc30SJozsef Kadlecsik [IPSET_ATTR_IP] = { .type = NLA_NESTED }, 4305663bc30SJozsef Kadlecsik [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, 4315663bc30SJozsef Kadlecsik [IPSET_ATTR_IP2] = { .type = NLA_NESTED }, 4325663bc30SJozsef Kadlecsik [IPSET_ATTR_PORT] = { .type = NLA_U16 }, 4335663bc30SJozsef Kadlecsik [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, 4345663bc30SJozsef Kadlecsik [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, 4355663bc30SJozsef Kadlecsik [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, 4365663bc30SJozsef Kadlecsik [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, 4375663bc30SJozsef Kadlecsik [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, 43800d71b27SJozsef Kadlecsik [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, 43900d71b27SJozsef Kadlecsik [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, 4405663bc30SJozsef Kadlecsik }, 4415663bc30SJozsef Kadlecsik .me = THIS_MODULE, 4425663bc30SJozsef Kadlecsik }; 4435663bc30SJozsef Kadlecsik 4445663bc30SJozsef Kadlecsik static int __init 4455663bc30SJozsef Kadlecsik hash_ipportip_init(void) 4465663bc30SJozsef Kadlecsik { 4475663bc30SJozsef Kadlecsik return ip_set_type_register(&hash_ipportip_type); 4485663bc30SJozsef Kadlecsik } 4495663bc30SJozsef Kadlecsik 4505663bc30SJozsef Kadlecsik static void __exit 4515663bc30SJozsef Kadlecsik hash_ipportip_fini(void) 4525663bc30SJozsef Kadlecsik { 4535663bc30SJozsef Kadlecsik ip_set_type_unregister(&hash_ipportip_type); 4545663bc30SJozsef Kadlecsik } 4555663bc30SJozsef Kadlecsik 4565663bc30SJozsef Kadlecsik module_init(hash_ipportip_init); 4575663bc30SJozsef Kadlecsik module_exit(hash_ipportip_fini); 458