5

我有一个 UDP 服务器,它必须为 IPV4 和 IPV6 地址上的客户端提供服务。我创建了一个 IPV6 套接字来同时为 IPV4 和 IPV6 客户端提供服务。

服务器在第一次通信时存储客户端的 IPAddress。如果是 IPV4 客户端,则存储为 IPV4 地址,如果是 IPV6 客户端,则服务器存储为 IPV6 地址。对于所有未来的通信,它会检查存储是否该客户端是已知的(存储的),然后采取相应的行动。为了将客户端地址与存储的地址进行比较,我根据族类型(AF_INET 和 AF_INET6)执行 memcmp。

在与 IPV6 客户端通信时,系统正常工作,但在与 IPV4 客户端通信时,系统的行为就好像它从来不知道客户端一样。在调试时,我发现由于 IPV6 的套接字类型,IPV4 客户端的 IPAddresss 被接收为 IPV6 映射的 IPV4 地址,其系列设置为 IPV6。为了解决这个问题,我需要比较 IPV4 存储地址和 IPV6 映射地址。为此,我使用 IPV4 结构的 sin_addr.s_addr 和 IPV6 结构的 sin6_addr.in6_u.u6_addr32。请在下面找到代码片段。

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;
}

我想知道这种方法是否是将 IPV6 映射的 IPV4 地址与 IPV4 地址进行比较的正确解决方案,还是有其他更好的方法。

4

1 回答 1

2

正如Joachim Pileborg 所推理的,当 IPv4 地址来自同一套接字上接收的较早数据包时,您无需关心这一点,因为您将一个映射的 IPv4 地址与另一个进行比较。只有在 IPv4 地址是从外部来源获得的情况下,您才需要注意。

正如João Augusto指出的那样,在比较最后 32 位之前,您忽略了检查 IPv6 地址是否确实是 IPv4 映射地址。有一个宏IN6_IS_ADDR_V4MAPPED可以帮助你做到这一点:

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;
}
于 2012-07-31T00:21:57.313 回答