Reputation: 55
I am trying to create a socket to allow for IPv4-to-IPv4, IPv4-to-IPv6, IPv6-to-IPv4, and IPv6-to-IPv6 address connections.
1.) Are the protocol combinations (e.g. IPv4-to-IPv6, IPv6-to-IPv4) permissible?
2.) If so, do I use the family of the source address or destination address for creating the socket?
Currently I am using the source address and am getting socket error 10014 WSAEFAULT when using IPv6 source address and IPv4 destination address.
Relevant parts of code:
if ( !strchr( srcAddr, '[' ) )
sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
else
sock = socket( AF_INET6, SOCK_STREAM, IPPROTO_TCP );
if ( !strchr( srcAddr, '[' ) )
{
rc = bind( sock, ( struct sockaddr * ) &sAddrSrc,
sizeof( sAddrSrc ) );
}
else
{
rc = bind( sock, ( struct sockaddr * ) &sAddrSrc6,
sizeof( sAddrSrc6 ) );
}
if ( !strchr( destAddr, '[' ) )
{
rc = connect( sock, (struct sockaddr *) &sAddrDest,
sizeof(sAddrDest) );
}
else
{
rc = connect( sock, ( struct sockaddr * ) &sAddrDest6,
sizeof( sAddrDest6 ) );
}
Upvotes: 1
Views: 1056
Reputation: 6877
You can use an IPv6 socket to connect to either IPv4 addresses or IPv6 ones. IPv4 sockets can only connect to IPv4 destinations. On the server side, an IPv6 socket can accept connections from IPv6 or IPv4, and an IPv4 socket can only accept IPv4 connections.
You really should avoid parsing the address yourself, use getaddrinfo
. It won't parse the []
however, so you have to extract the part within first. getaddrinfo
will tell you if you should use an IPv4 socket or an IPv6 one, however if you always want to use IPv6 you can set ai_family
to AF_INET6
and then add AI_V4MAPPED
to ai_flags
. In that case the returned address will be ::ffff:IPv4
if needed which is what an IPv6 socket needs to connect to an IPv4 destination.
On the server side, use an IPv6 socket, and then make sure to call setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof(int))
to let it accept both IPv6 and IPv4 connections. (Note that MSVC might not accept this C99 syntax.)
All that being said, you can't connect to an IPv6 destination if you've already called bind with an IPv4 source, nor vice versa, but the answer applies if you don't call bind on the connection side, or wait to choose what address to bind until after you call getaddrinfo.
Upvotes: 2
Reputation: 1389
No you cannot connect to a different address family than the one your socket is configured with. IPv6 and IPv4 use different network stacks so if you are trying to connect to an IPv6 endpoint, then you must use IPv6 as a source address too.
In your case, you would need 2 sockets if you want to connect to one IPv4 address and another one for the IPv6 address.
On the server side, 2 sockets are also necessary to listen to IPv4 and IPv6. Both sockets can bind to the same port number (since both are different network stacks) but they will listen on different IP addresses.
This EBook is a really good reference for both IPv4 and IPv6 routing: Tcp/IP fundamentals for Microsoft Windows
Upvotes: 2