11602Srgrimes// SPDX-License-Identifier: GPL-2.0-only 21602Srgrimes#include <net/netfilter/nf_tproxy.h> 31602Srgrimes#include <linux/module.h> 41602Srgrimes#include <net/inet6_hashtables.h> 51602Srgrimes#include <net/addrconf.h> 61602Srgrimes#include <net/udp.h> 71602Srgrimes#include <net/tcp.h> 81602Srgrimes 91602Srgrimesconst struct in6_addr * 101602Srgrimesnf_tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr, 111602Srgrimes const struct in6_addr *daddr) 121602Srgrimes{ 131602Srgrimes struct inet6_dev *indev; 141602Srgrimes struct inet6_ifaddr *ifa; 151602Srgrimes struct in6_addr *laddr; 161602Srgrimes 171602Srgrimes if (!ipv6_addr_any(user_laddr)) 181602Srgrimes return user_laddr; 191602Srgrimes laddr = NULL; 201602Srgrimes 211602Srgrimes indev = __in6_dev_get(skb->dev); 221602Srgrimes if (indev) { 231602Srgrimes read_lock_bh(&indev->lock); 241602Srgrimes list_for_each_entry(ifa, &indev->addr_list, if_list) { 251602Srgrimes if (ifa->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED)) 261602Srgrimes continue; 271602Srgrimes 281602Srgrimes laddr = &ifa->addr; 291602Srgrimes break; 301602Srgrimes } 311602Srgrimes read_unlock_bh(&indev->lock); 321602Srgrimes } 331602Srgrimes 341602Srgrimes return laddr ? laddr : daddr; 351602Srgrimes} 361602SrgrimesEXPORT_SYMBOL_GPL(nf_tproxy_laddr6); 371602Srgrimes 3883551Sdillonstruct sock * 3983551Sdillonnf_tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff, 4083551Sdillon struct net *net, 411602Srgrimes const struct in6_addr *laddr, 4255127Speter const __be16 lport, 431602Srgrimes struct sock *sk) 4455127Speter{ 451602Srgrimes const struct ipv6hdr *iph = ipv6_hdr(skb); 461602Srgrimes struct tcphdr _hdr, *hp; 471602Srgrimes 488870Srgrimes hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr); 491602Srgrimes if (hp == NULL) { 501602Srgrimes inet_twsk_put(inet_twsk(sk)); 511602Srgrimes return NULL; 521602Srgrimes } 5376176Smarkm 5476176Smarkm if (hp->syn && !hp->rst && !hp->ack && !hp->fin) { 551602Srgrimes /* SYN to a TIME_WAIT socket, we'd rather redirect it 561602Srgrimes * to a listener socket if there's one */ 571602Srgrimes struct sock *sk2; 5817141Sjkh 591602Srgrimes sk2 = nf_tproxy_get_sock_v6(net, skb, thoff, tproto, 601602Srgrimes &iph->saddr, 611602Srgrimes nf_tproxy_laddr6(skb, laddr, &iph->daddr), 621602Srgrimes hp->source, 631602Srgrimes lport ? lport : hp->dest, 641602Srgrimes skb->dev, NF_TPROXY_LOOKUP_LISTENER); 651602Srgrimes if (sk2) { 661602Srgrimes nf_tproxy_twsk_deschedule_put(inet_twsk(sk)); 671602Srgrimes sk = sk2; 681602Srgrimes } 691602Srgrimes } 701602Srgrimes 711603Srgrimes return sk; 721603Srgrimes} 731602SrgrimesEXPORT_SYMBOL_GPL(nf_tproxy_handle_time_wait6); 741602Srgrimes 751602Srgrimesstruct sock * 7618798Speternf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, 771602Srgrimes const u8 protocol, 781602Srgrimes const struct in6_addr *saddr, const struct in6_addr *daddr, 791602Srgrimes const __be16 sport, const __be16 dport, 8018798Speter const struct net_device *in, 8118798Speter const enum nf_tproxy_lookup_t lookup_type) 821603Srgrimes{ 8318798Speter struct inet_hashinfo *hinfo = net->ipv4.tcp_death_row.hashinfo; 8418798Speter struct sock *sk; 8518798Speter 861602Srgrimes switch (protocol) { 871603Srgrimes case IPPROTO_TCP: { 881602Srgrimes struct tcphdr _hdr, *hp; 891602Srgrimes 901602Srgrimes hp = skb_header_pointer(skb, thoff, 9118798Speter sizeof(struct tcphdr), &_hdr); 9218798Speter if (hp == NULL) 931602Srgrimes return NULL; 941603Srgrimes 9518798Speter switch (lookup_type) { 9682263Speter case NF_TPROXY_LOOKUP_LISTENER: 9718798Speter sk = inet6_lookup_listener(net, hinfo, skb, 981602Srgrimes thoff + __tcp_hdrlen(hp), 991602Srgrimes saddr, sport, 1001603Srgrimes daddr, ntohs(dport), 1011603Srgrimes in->ifindex, 0); 1021602Srgrimes 1031603Srgrimes if (sk && !refcount_inc_not_zero(&sk->sk_refcnt)) 1041602Srgrimes sk = NULL; 10518798Speter /* NOTE: we return listeners even if bound to 1061602Srgrimes * 0.0.0.0, those are filtered out in 10782263Speter * xt_socket, since xt_TPROXY needs 0 bound 1081603Srgrimes * listeners too 1091602Srgrimes */ 11082263Speter break; 11182263Speter case NF_TPROXY_LOOKUP_ESTABLISHED: 11282263Speter sk = __inet6_lookup_established(net, hinfo, saddr, sport, daddr, 11382263Speter ntohs(dport), in->ifindex, 0); 11482263Speter break; 11582263Speter default: 11682263Speter BUG(); 11782263Speter } 1181602Srgrimes break; 1191602Srgrimes } 1201602Srgrimes case IPPROTO_UDP: 1211602Srgrimes sk = udp6_lib_lookup(net, saddr, sport, daddr, dport, 12282263Speter in->ifindex); 12382263Speter if (sk) { 1241603Srgrimes int connected = (sk->sk_state == TCP_ESTABLISHED); 1251602Srgrimes int wildcard = ipv6_addr_any(&sk->sk_v6_rcv_saddr); 1261602Srgrimes 12718798Speter /* NOTE: we return listeners even if bound to 12818798Speter * 0.0.0.0, those are filtered out in 1291603Srgrimes * xt_socket, since xt_TPROXY needs 0 bound 1301602Srgrimes * listeners too 1311602Srgrimes */ 13218798Speter if ((lookup_type == NF_TPROXY_LOOKUP_ESTABLISHED && (!connected || wildcard)) || 1331602Srgrimes (lookup_type == NF_TPROXY_LOOKUP_LISTENER && connected)) { 1341602Srgrimes sock_put(sk); 1351602Srgrimes sk = NULL; 1361602Srgrimes } 13718798Speter } 13818798Speter break; 13918798Speter default: 14018798Speter WARN_ON(1); 14118798Speter sk = NULL; 14218798Speter } 14318798Speter 14418798Speter pr_debug("tproxy socket lookup: proto %u %pI6:%u -> %pI6:%u, lookup type: %d, sock %p\n", 14518798Speter protocol, saddr, ntohs(sport), daddr, ntohs(dport), lookup_type, sk); 14618798Speter 1471602Srgrimes return sk; 1481602Srgrimes} 1491602SrgrimesEXPORT_SYMBOL_GPL(nf_tproxy_get_sock_v6); 1501602Srgrimes 1511602SrgrimesMODULE_LICENSE("GPL"); 15218798SpeterMODULE_AUTHOR("Balazs Scheidler, Krisztian Kovacs"); 15318798SpeterMODULE_DESCRIPTION("Netfilter IPv6 transparent proxy support"); 15418798Speter