--- ./net/ipv4/tcp_ipv4.c 2008-01-14 15:44:07 +0100 +++ ./net/ipv4/tcp_ipv4.c 2008-01-19 12:24:23 +0100 @@ -1853,8 +1853,7 @@ } #ifdef CONFIG_IP_FOREIGN_BIND -/* Could be done with netfilter hook. Not clear how to hook this in right place. */ - +/* Checks if the SKB may be delivered to a local socket */ struct sk_buff *tcp_v4_nonlocal_deliver(struct sk_buff *skb) { struct sock *sk; @@ -1874,15 +1873,36 @@ th = (struct tcphdr*)(skb->nh.raw + ihl); - sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source, - skb->nh.iph->daddr, ntohs(th->dest), - 0); - if (sk) { + sk = __tcp_v4_lookup_established(skb->nh.iph->saddr, th->source, + skb->nh.iph->daddr, ntohs(th->dest), + skb->dev); + if (sk) + goto deliver; + + /* We deliver to listening sockets only when they have been enabled for + * transparent binding. This is important to consider because we don't + * want to deliver to local sockets during an IP takeover for instance, + * causing previous local addresses to be considered foreign. Note: + * ideally we should check for the transparent flag during the lookup, + * otherwise we prevent matching on INADDR_ANY when a non-transparent + * socket is already bound to an explicit address. -WT. + */ + + sk = tcp_v4_lookup_listener(skb->nh.iph->daddr, ntohs(th->dest), + skb->dev); + if (!sk) + goto out; + + if (!(sk->reuse & 4)) { sock_put(sk); - ip_local_deliver(skb); - return NULL; + goto out; } +deliver: + sock_put(sk); + ip_local_deliver(skb); + return NULL; + out: return skb; } --- ./net/ipv4/af_inet.c 2008-01-14 15:44:05 +0100 +++ ./net/ipv4/af_inet.c 2008-01-19 13:27:10 +0100 @@ -507,7 +507,8 @@ #ifdef CONFIG_IP_FOREIGN_BIND if (sk->reuse & 4) { - if (chk_addr_ret != RTN_UNICAST) { + if (chk_addr_ret != RTN_UNICAST && + addr->sin_addr.s_addr != INADDR_ANY) { /* Not a foreign address really, hence port is ours. */ sk->reuse &= ~4; } else {