patch-pre2.0.7 linux/net/ipv4/tcp_input.c

Next file: linux/net/ipv4/udp.c
Previous file: linux/net/ipv4/tcp.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file pre2.0.6/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
@@ -146,14 +146,14 @@
  *	right...
  */
 
-static inline struct sock * get_tcp_sock(u32 saddr, u16 sport, u32 daddr, u16 dport)
+static inline struct sock * get_tcp_sock(u32 saddr, u16 sport, u32 daddr, u16 dport, u32 paddr, u16 pport)
 {
 	struct sock * sk;
 
 	sk = (struct sock *) th_cache_sk;
 	if (!sk || saddr != th_cache_saddr || daddr != th_cache_daddr ||
 	    sport != th_cache_sport || dport != th_cache_dport) {
-		sk = get_sock(&tcp_prot, dport, saddr, sport, daddr);
+		sk = get_sock(&tcp_prot, dport, saddr, sport, daddr, paddr, pport);
 		if (sk) {
 			th_cache_saddr=saddr;
 			th_cache_daddr=daddr;
@@ -461,6 +461,14 @@
 	newsk->dummy_th.source = skb->h.th->dest;
 	newsk->dummy_th.dest = skb->h.th->source;
 	
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+	/* 
+	 *	Deal with possibly redirected traffic by setting num to
+	 *	the intended destination port of the received packet.
+	 */
+	newsk->num = ntohs(skb->h.th->dest);
+
+#endif
 	/*
 	 *	Swap these two, they are from our point of view. 
 	 */
@@ -1628,6 +1636,27 @@
 	}
 }
 
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+/*
+ *	Check whether a received TCP packet might be for one of our
+ *	connections.
+ */
+
+int tcp_chkaddr(struct sk_buff *skb)
+{
+	struct iphdr *iph = skb->h.iph;
+	struct tcphdr *th = (struct tcphdr *)(skb->h.raw + iph->ihl*4);
+	struct sock *sk;
+
+	sk = get_sock(&tcp_prot, th->dest, iph->saddr, th->source, iph->daddr, 0, 0);
+
+	if (!sk) return 0;
+	/* 0 means accept all LOCAL addresses here, not all the world... */
+	if (sk->rcv_saddr == 0) return 0;
+	return 1;
+}
+#endif
+
 /*
  *	A TCP packet has arrived.
  *		skb->h.raw is the TCP header.
@@ -1640,6 +1669,9 @@
 	struct tcphdr *th;
 	struct sock *sk;
 	int syn_ok=0;
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+	int r;
+#endif
 
 	/*
 	 * "redo" is 1 if we have already seen this skb but couldn't
@@ -1673,7 +1705,7 @@
 			default:
 				/* CHECKSUM_UNNECESSARY */
 		}
-		sk = get_tcp_sock(saddr, th->source, daddr, th->dest);
+		sk = get_tcp_sock(saddr, th->source, daddr, th->dest, dev->pa_addr, skb->redirport);
 		if (!sk)
 			goto no_tcp_socket;
 		skb->sk = sk;
@@ -1753,7 +1785,16 @@
 			 *	this problem so I'm ignoring it 
 			 */
 			   
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+			/*
+			 * We may get non-local addresses and still want to
+			 * handle them locally, due to transparent proxying.
+			 * Thus, narrow down the test to what is really meant.
+			 */
+			if(th->rst || !th->syn || th->ack || (r = ip_chk_addr(daddr) == IS_BROADCAST || r == IS_MULTICAST))
+#else
 			if(th->rst || !th->syn || th->ack || ip_chk_addr(daddr)!=IS_MYADDR)
+#endif
 			{
 				kfree_skb(skb, FREE_READ);
 				return 0;
@@ -1904,7 +1945,7 @@
 			sk->err=ECONNRESET;
 			tcp_set_state(sk, TCP_CLOSE);
 			sk->shutdown = SHUTDOWN_MASK;
-			sk=get_sock(&tcp_prot, th->dest, saddr, th->source, daddr);
+			sk=get_sock(&tcp_prot, th->dest, saddr, th->source, daddr, dev->pa_addr, skb->redirport);
 			/* this is not really correct: we should check sk->users */
 			if (sk && sk->state==TCP_LISTEN)
 			{

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this