Connecting an IPv4 Client to an IPv6 Server: Denial of Connection

I am experimenting with IPv6 sockets, especially the dual-stack features offered on Windows Vista and later, and apparently on Unix by default. I found that when I bind my server to a specific IP address or to the host name resolution on my local computer, I cannot accept the connection to the IPv4 client. However, when I get attached to INADDR_ANY, I can.

Please consider the following code for my server. You can see that I follow Microsoft's recommendations for creating an IPv6 socket, and then set the IPV6_V6ONLY flag to zero:

addrinfo* result, *pCurrent, hints; memset(&hints, 0, sizeof hints); // Must do this! hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; // We intend to use the addrinfo in a call to connect(). (I know it is ignored if we specify a server to connect to...) int nRet = getaddrinfo("powerhouse", "82", &hints, &result); SOCKET sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); int no = 0; if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&no, sizeof(no)) != 0) return -1; if (bind(sock, result->ai_addr, result->ai_addrlen) == SOCKET_ERROR) return -1; if (listen(sock, SOMAXCONN) == SOCKET_ERROR) return -1; SOCKET sockClient = accept(sock, NULL, NULL); 

Here is the code for my client. You can see that I am creating an IPv4 socket and trying to connect to my server:

 addrinfo* result, *pCurrent, hints; memset(&hints, 0, sizeof hints); // Must do this! hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo("powerhouse", "82", &hints, &result) != 0) return -1; SOCKET sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol); int nRet = connect(sock, result->ai_addr, result->ai_addrlen); 

The result of my connection is always 10061: connection failure.

If I changed my server code to bind to :: (or passed the getaddrinfo () NULL host (the same)) and changed the client code to specify the NULL host in the getaddrinfo () call, then the V4 client can connect normally.

Can someone explain why please? I have not read anything that we must specify a NULL host (hence using INADDR_ANY) if we want two-socket behavior. This may not be a requirement because I have a multihomed host and I want to accept IPv4 only on some available IP addresses?

EDIT 05/15/2013:

This is the relevant documentation that confused me why my code crashes:

From Double Stacks to IPv6 Winsock Applications

"Windows Vista and later offer the ability to create a single IPv6 that can handle both IPv6 and IPv4 traffic. For example, a TCP listening socket for IPv6 is placed in dual-stack mode and is connected to port 5001. This dual-core socket can accept TCP connections. IPv6 clients connecting to port 5001 and IPv4 TCP clients connecting to port 5001. "

"By default, the IPv6 socket created in Windows Vista and later works using IPv6 protocol. To make an IPv6 socket into a two-stack socket, the setsockopt function must be called using the IPv6_V6ONLY socket option to set this value to zero before the socket is bound to the IP address . If the socket option IPV6_V6ONLY is set to zero, you can use the socket created for the AF_INET6 address family. Send and receive packets to and from the IPv6 address or IPv4 displayed address. (Emphasis mine) "

+6
source share
2 answers

IPv4 and IPv6 are two separate protocols. Packets of one protocol cannot be processed using another protocol. That's why the concept of Dual Stack exists: your system runs both IPv4 and IPv6 protocol stacks, has both IPv4 and IPv6 addresses, etc.

Operating systems have a trick where you can have an IPv6 socket that listens on all IPv4 and IPv6 addresses. You still need to have both address families on the host, and it only works when binding to a wildcard address. Once you bind this socket to a fixed address that no longer works, and it will work only for the address to which you are bound.

So, if you want to listen to all available addresses, then set IPV6_V6ONLY to 0 and listen to the wildcard address. IPv4 clients will be displayed using IPv6 addresses starting with ::ffff: with the last 32 bits containing the IPv4 address.

If you want to bind to specific addresses, you will need sockets tied to each of the addresses that you want to listen to. Then you need to use ie select(...) to monitor these sockets and respond to those that become active because someone is connecting to them.

+7
source

This link http://www.masterraghu.com/subjects/np/introduction/unix_network_programming_v1.3/ch12lev1sec2.html gives more information on connecting IPv4 and IPv6,

Most dual-stack hosts should use the following rules when working with socket listening:

  • An IPv4 listening socket can only accept incoming connections from IPv4 clients.
  • If the server has an IPv6 listening socket that binds a wildcard address, and the IPV6_V6ONLY socket option (section 7.8) is not set, this socket can accept incoming connections from IPv4 or IPv6 clients. To connect to the IPv4 server client, the local IP address for the connection will be the corresponding IPv4-mapped IPv6.
  • If the server has an IPv6 listening socket that binds an IPv6 address other than the IPv4 mapped IPv6 address, or associates a wildcard but sets the IPv6_V6ONLY socket option (section 7.8), this socket can only accept incoming connections from IPv6 clients.
+2
source

Source: https://habr.com/ru/post/944704/


All Articles