| From stable-bounces@linux.kernel.org Wed Jul 18 02:51:26 2007 |
| From: Dmitry Butskoy <dmitry@butskoy.name> |
| Date: Wed, 18 Jul 2007 02:51:17 -0700 (PDT) |
| Subject: Fix error queue socket lookup in ipv6 |
| To: stable@kernel.org |
| Cc: bunk@stusta.de |
| Message-ID: <20070718.025117.94556618.davem@davemloft.net> |
| |
| From: Dmitry Butskoy <dmitry@butskoy.name> |
| |
| [IPV6]: MSG_ERRQUEUE messages do not pass to connected raw sockets |
| |
| From: Dmitry Butskoy <dmitry@butskoy.name> |
| |
| Taken from http://bugzilla.kernel.org/show_bug.cgi?id=8747 |
| |
| Problem Description: |
| |
| It is related to the possibility to obtain MSG_ERRQUEUE messages from the udp |
| and raw sockets, both connected and unconnected. |
| |
| There is a little typo in net/ipv6/icmp.c code, which prevents such messages |
| to be delivered to the errqueue of the correspond raw socket, when the socket |
| is CONNECTED. The typo is due to swap of local/remote addresses. |
| |
| Consider __raw_v6_lookup() function from net/ipv6/raw.c. When a raw socket is |
| looked up usual way, it is something like: |
| |
| sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); |
| |
| where "daddr" is a destination address of the incoming packet (IOW our local |
| address), "saddr" is a source address of the incoming packet (the remote end). |
| |
| But when the raw socket is looked up for some icmp error report, in |
| net/ipv6/icmp.c:icmpv6_notify() , daddr/saddr are obtained from the echoed |
| fragment of the "bad" packet, i.e. "daddr" is the original destination |
| address of that packet, "saddr" is our local address. Hence, for |
| icmpv6_notify() must use "saddr, daddr" in its arguments, not "daddr, saddr" |
| ... |
| |
| Steps to reproduce: |
| |
| Create some raw socket, connect it to an address, and cause some error |
| situation: f.e. set ttl=1 where the remote address is more than 1 hop to reach. |
| Set IPV6_RECVERR . |
| Then send something and wait for the error (f.e. poll() with POLLERR|POLLIN). |
| You should receive "time exceeded" icmp message (because of "ttl=1"), but the |
| socket do not receive it. |
| |
| If you do not connect your raw socket, you will receive MSG_ERRQUEUE |
| successfully. (The reason is that for unconnected socket there are no actual |
| checks for local/remote addresses). |
| |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| net/ipv6/icmp.c | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| --- a/net/ipv6/icmp.c |
| +++ b/net/ipv6/icmp.c |
| @@ -604,7 +604,7 @@ static void icmpv6_notify(struct sk_buff |
| |
| read_lock(&raw_v6_lock); |
| if ((sk = sk_head(&raw_v6_htable[hash])) != NULL) { |
| - while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, |
| + while ((sk = __raw_v6_lookup(sk, nexthdr, saddr, daddr, |
| IP6CB(skb)->iif))) { |
| rawv6_err(sk, skb, NULL, type, code, inner_offset, info); |
| sk = sk_next(sk); |