【问题标题】:Comparing IPV4 socket(sockaddr_in) with IPV6 Socket(sockaddr_in6)比较 IPV4 套接字(sockaddr_in)与 IPV6 套接字(sockaddr_in6)
【发布时间】:2012-07-27 22:11:45
【问题描述】:

我有一个 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。请在下面找到代码 sn-p。

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 地址的正确解决方案,还是有其他更好的方法。

【问题讨论】:

  • 我承认我对 IPv6 还没有太多经验,但不会,例如recvfrom 将源地址返回为 AF_INET6,即使它是 IPv6 映射的 IPv4 地址?
  • 对不起,我跳过/忘了提及以下功能。服务器通过两种方式获取客户端地址。 1) 首次通过 UDP 与客户端通信 2) 客户端可能通过 TCP 将其 UDP 连接详细信息作为 XML 数据发布到服务器。在这种情况下,客户端将只提供 IPV4 地址。
  • 在比较最后 32 位之前,您还需要检查前 80 位是否为零,接下来的 16 位是否为 1。否则你不知道你是否正在处理映射为 IPV6 的 IPV4。

标签: c++ sockets udp


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-05
    • 2014-01-06
    • 1970-01-01
    • 2015-12-25
    • 1970-01-01
    • 2011-12-26
    • 1970-01-01
    • 2012-11-05
    相关资源
    最近更新 更多