1
votes

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 ) );
}
2
I found these slides, which seemed appropriate for your question.jxh

2 Answers

2
votes

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

2
votes

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.