1 #include <net/netfilter/nf_tproxy.h> 2 #include <linux/module.h> 3 #include <net/inet6_hashtables.h> 4 #include <net/addrconf.h> 5 #include <net/udp.h> 6 #include <net/tcp.h> 7 8 const struct in6_addr * 9 nf_tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr, 10 const struct in6_addr *daddr) 11 { 12 struct inet6_dev *indev; 13 struct inet6_ifaddr *ifa; 14 struct in6_addr *laddr; 15 16 if (!ipv6_addr_any(user_laddr)) 17 return user_laddr; 18 laddr = NULL; 19 20 indev = __in6_dev_get(skb->dev); 21 if (indev) { 22 read_lock_bh(&indev->lock); 23 list_for_each_entry(ifa, &indev->addr_list, if_list) { 24 if (ifa->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED)) 25 continue; 26 27 laddr = &ifa->addr; 28 break; 29 } 30 read_unlock_bh(&indev->lock); 31 } 32 33 return laddr ? laddr : daddr; 34 } 35 EXPORT_SYMBOL_GPL(nf_tproxy_laddr6); 36 37 struct sock * 38 nf_tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff, 39 struct net *net, 40 const struct in6_addr *laddr, 41 const __be16 lport, 42 struct sock *sk) 43 { 44 const struct ipv6hdr *iph = ipv6_hdr(skb); 45 struct tcphdr _hdr, *hp; 46 47 hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr); 48 if (hp == NULL) { 49 inet_twsk_put(inet_twsk(sk)); 50 return NULL; 51 } 52 53 if (hp->syn && !hp->rst && !hp->ack && !hp->fin) { 54 /* SYN to a TIME_WAIT socket, we'd rather redirect it 55 * to a listener socket if there's one */ 56 struct sock *sk2; 57 58 sk2 = nf_tproxy_get_sock_v6(net, skb, thoff, hp, tproto, 59 &iph->saddr, 60 nf_tproxy_laddr6(skb, laddr, &iph->daddr), 61 hp->source, 62 lport ? lport : hp->dest, 63 skb->dev, NF_TPROXY_LOOKUP_LISTENER); 64 if (sk2) { 65 inet_twsk_deschedule_put(inet_twsk(sk)); 66 sk = sk2; 67 } 68 } 69 70 return sk; 71 } 72 EXPORT_SYMBOL_GPL(nf_tproxy_handle_time_wait6); 73 74 struct sock * 75 nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp, 76 const u8 protocol, 77 const struct in6_addr *saddr, const struct in6_addr *daddr, 78 const __be16 sport, const __be16 dport, 79 const struct net_device *in, 80 const enum nf_tproxy_lookup_t lookup_type) 81 { 82 struct sock *sk; 83 struct tcphdr *tcph; 84 85 switch (protocol) { 86 case IPPROTO_TCP: 87 switch (lookup_type) { 88 case NF_TPROXY_LOOKUP_LISTENER: 89 tcph = hp; 90 sk = inet6_lookup_listener(net, &tcp_hashinfo, skb, 91 thoff + __tcp_hdrlen(tcph), 92 saddr, sport, 93 daddr, ntohs(dport), 94 in->ifindex, 0); 95 96 if (sk && !refcount_inc_not_zero(&sk->sk_refcnt)) 97 sk = NULL; 98 /* NOTE: we return listeners even if bound to 99 * 0.0.0.0, those are filtered out in 100 * xt_socket, since xt_TPROXY needs 0 bound 101 * listeners too 102 */ 103 break; 104 case NF_TPROXY_LOOKUP_ESTABLISHED: 105 sk = __inet6_lookup_established(net, &tcp_hashinfo, 106 saddr, sport, daddr, ntohs(dport), 107 in->ifindex, 0); 108 break; 109 default: 110 BUG(); 111 } 112 break; 113 case IPPROTO_UDP: 114 sk = udp6_lib_lookup(net, saddr, sport, daddr, dport, 115 in->ifindex); 116 if (sk) { 117 int connected = (sk->sk_state == TCP_ESTABLISHED); 118 int wildcard = ipv6_addr_any(&sk->sk_v6_rcv_saddr); 119 120 /* NOTE: we return listeners even if bound to 121 * 0.0.0.0, those are filtered out in 122 * xt_socket, since xt_TPROXY needs 0 bound 123 * listeners too 124 */ 125 if ((lookup_type == NF_TPROXY_LOOKUP_ESTABLISHED && (!connected || wildcard)) || 126 (lookup_type == NF_TPROXY_LOOKUP_LISTENER && connected)) { 127 sock_put(sk); 128 sk = NULL; 129 } 130 } 131 break; 132 default: 133 WARN_ON(1); 134 sk = NULL; 135 } 136 137 pr_debug("tproxy socket lookup: proto %u %pI6:%u -> %pI6:%u, lookup type: %d, sock %p\n", 138 protocol, saddr, ntohs(sport), daddr, ntohs(dport), lookup_type, sk); 139 140 return sk; 141 } 142 EXPORT_SYMBOL_GPL(nf_tproxy_get_sock_v6); 143 144 MODULE_LICENSE("GPL"); 145 MODULE_AUTHOR("Balazs Scheidler, Krisztian Kovacs"); 146 MODULE_DESCRIPTION("Netfilter IPv4 transparent proxy support"); 147