[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <49BF0F4D.7000409@cosmosbay.com>
Date: Tue, 17 Mar 2009 03:47:41 +0100
From: Eric Dumazet <dada1@...mosbay.com>
To: Brian Haley <brian.haley@...com>
CC: Felix von Leitner <felix-kernel@...e.de>, netdev@...r.kernel.org
Subject: Re: socket api problem: can't bind an ipv6 socket to ::ffff:0.0.0.0
Brian Haley a écrit :
> Felix von Leitner wrote:
>> Here's an strace:
>>
>> socket(PF_INET6, SOCK_STREAM, IPPROTO_IP) = 3
>> fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
>> fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
>> setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
>> bind(3, {sa_family=AF_INET6, sin6_port=htons(6969), inet_pton(AF_INET6, "::ffff:0.0.0.0", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = -1 EADDRNOTAVAIL (Cannot assign requested address)
>>
>> This is supposed to work, and it works on other operating systems, even
>> on Mac OS X.
>>
>> I think it used to work on Linux, too.
>>
>> I'm using 2.6.29-rc7 right now, but others have reported this not
>> working on distro kernels, too.
>
> I don't think this ever worked on Linux, from the very beginning of inet6_bind():
>
> /* Check if the address belongs to the host. */
> if (addr_type == IPV6_ADDR_MAPPED) {
> v4addr = addr->sin6_addr.s6_addr32[3];
> if (inet_addr_type(net, v4addr) != RTN_LOCAL) {
> err = -EADDRNOTAVAIL;
> goto out;
> }
> } else {
>
> So if it's a mapped address, the lower 32-bits must contain a local address.
> RFC 3493 doesn't specifically mention what to do with ::ffff:0.0.0.0, so this
> looks like a gray area to me.
>
> So are you trying to get IPv4-only behavior out of this socket? Seems like the
> wrong way to go about it.
To me, section 3.7 of RFC 3493 is not gray. It is only refering to interoperate
with IPV4 applications.
Ie *sending* UDP messages to IPV4 nodes, or *connect* to TCP IPV4 nodes.
So "::ffff:0.0.0.0" has no meaning to contact an IPV4 node, since 0.0.0.0 is not
a valid IPV4 address.
RFC 2373 is also clear
Part of RFC 3493 :
Applications may use AF_INET6 sockets to open TCP connections to IPv4
nodes, or send UDP packets to IPv4 nodes, by simply encoding the
destination's IPv4 address as an IPv4-mapped IPv6 address, and
passing that address, within a sockaddr_in6 structure, in the
connect() or sendto() call. When applications use AF_INET6 sockets
to accept TCP connections from IPv4 nodes, or receive UDP packets
from IPv4 nodes, the system returns the peer's address to the
application in the accept(), recvfrom(), or getpeername() call using
a sockaddr_in6 structure encoded this way.
RFC 2373 states :
The IPv6 transition mechanisms [TRAN] include a technique for hosts
and routers to dynamically tunnel IPv6 packets over IPv4 routing
infrastructure. IPv6 nodes that utilize this technique are assigned
special IPv6 unicast addresses that carry an IPv4 address in the low-
order 32-bits. This type of address is termed an "IPv4-compatible
IPv6 address" and has the format:
| 80 bits | 16 | 32 bits |
+--------------------------------------+--------------------------+
|0000..............................0000|0000| IPv4 address |
+--------------------------------------+----+---------------------+
A second type of IPv6 address which holds an embedded IPv4 address is
also defined. This address is used to represent the addresses of
IPv4-only nodes (those that *do not* support IPv6) as IPv6 addresses.
This type of address is termed an "IPv4-mapped IPv6 address" and has
the format:
| 80 bits | 16 | 32 bits |
+--------------------------------------+--------------------------+
|0000..............................0000|FFFF| IPv4 address |
+--------------------------------------+----+---------------------+
So using the "::ffff:0.0.0.0" as a local address for an
IPv6 socket is a paradox, since "IPv4-mapped IPV6 address"
are for IPV4-only nodes.
If you want to accept only IPV4 connections, why use AF_INET6 in the first
place ?
Check how is implemented sctp_v6_cmp_addr() to see how expensive it
is to handle extensive ipv6 address comparisons...
/* Compare addresses exactly.
* v4-mapped-v6 is also in consideration.
*/
static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
const union sctp_addr *addr2)
{
if (addr1->sa.sa_family != addr2->sa.sa_family) {
if (addr1->sa.sa_family == AF_INET &&
addr2->sa.sa_family == AF_INET6 &&
ipv6_addr_v4mapped(&addr2->v6.sin6_addr)) {
if (addr2->v6.sin6_port == addr1->v4.sin_port &&
addr2->v6.sin6_addr.s6_addr32[3] ==
addr1->v4.sin_addr.s_addr)
return 1;
}
if (addr2->sa.sa_family == AF_INET &&
addr1->sa.sa_family == AF_INET6 &&
ipv6_addr_v4mapped(&addr1->v6.sin6_addr)) {
if (addr1->v6.sin6_port == addr2->v4.sin_port &&
addr1->v6.sin6_addr.s6_addr32[3] ==
addr2->v4.sin_addr.s_addr)
return 1;
}
return 0;
}
if (!ipv6_addr_equal(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr))
return 0;
/* If this is a linklocal address, compare the scope_id. */
if (ipv6_addr_type(&addr1->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) {
if (addr1->v6.sin6_scope_id && addr2->v6.sin6_scope_id &&
(addr1->v6.sin6_scope_id != addr2->v6.sin6_scope_id)) {
return 0;
}
}
return 1;
}
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists