5
votes

I have a UDP Server which has to serve clients on both IPV4 and IPV6 address. I have created a single IPV6 socket to serve both the IPV4 and IPV6 clients.

The server stores IPAddress of the client on the very first communication. If it is a IPV4 client it stores as IPV4 Address and if it is a IPV6 client the server stores as IPV6 address. For all future communication it checks the storage whether this client is already known(stored) and then acts accordingly. For comparing the client address with the stored address I do a memcmp based on the family type (AF_INET and AF_INET6).

While communicating with IPV6 client the system is working normally but while communicating with IPV4 client the system behaves as if it never knew the client. While debugging I found that due to IPV6 the Socket Type the IPAddresss of the IPV4 client is received as IPV6 mapped IPV4 Address with family set to IPV6. To Solve this I need to compare between the IPV4 Stored address and the IPV6 mapped address. For this I am using sin_addr.s_addr of IPV4 structure and sin6_addr.in6_u.u6_addr32 of IPV6 structure. Please find the code snippet below.

ipv6_clientdata = (const struct sockaddr_in6 *)&sockStor;
ipv4_storeddata = (const struct sockaddr_in *)&(_stData[index].clientaddr);
if( (ipv6_clientdata->sin6_port == ipv4_storeddata->sin_port) && 
    (ipv6_clientdata->sin6_addr.in6_u.u6_addr32[3] == ipv4_storeddata->sin_addr.s_addr) 
  )
{
    addrfound = true;
}

I would like to know whether this method is the proper solution for comparing IPV6 Mapped IPV4 address with IPV4 address or is there any other better way.

1
I admit I don't have much experience with IPv6 yet, but won't e.g. recvfrom return the source address as AF_INET6 even when it's an IPv6-mapped IPv4 address?Some programmer dude
Sorry I skipped/forgot to mention the following feature. The Server gets the client address in two ways. 1) on First communication with client over UDP 2) The client might post its UDP Connection details over TCP as an XML data to the server. In this case the Client will provide only IPV4 address.Dinesh P.R.
You need also to check if the first 80 bits are zero and the next 16 bits are one before comparing the last 32 bits. Otherwise you don't know if you are dealing with a IPV4 mapped as IPV6.João Augusto

1 Answers

2
votes

As Joachim Pileborg reasoned, you don't need to care about this when the IPv4 address comes from an earlier packet received on the same socket because you will be comparing one mapped IPv4 address to another. It is only in the case that the IPv4 address was obtained from an external source that you have to care.

As João Augusto pointed out, you neglected to check that the IPv6 address indeed is an IPv4 mapped address before comparing the last 32 bits. There is a macro IN6_IS_ADDR_V4MAPPED that will help you do this:

if (
    IN6_IS_ADDR_V4MAPPED(&(ipv6_clientdata->sin6_addr)) &&
    (ipv6_clientdata->sin6_port == ipv4_storeddata->sin_port) &&
    (ipv6_clientdata->sin6_addr.in6_u.u6_addr32[3] == ipv4_storeddata->sin_addr.s_addr)
) {
    addrfound = true;
}