2012-07-30 68 views
5

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

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

与IPV6客户端通信时,系统正常工作,但在与IPV4客户端通信时,系统表现得好像从来不知道客户端一样。在调试过程中,我发现由于IPV6是Socket Type,因此IPV4客户端的IP地址被作为IPV6映射的IPV4地址接收,而IPV4地址族被设置为IPV6。为了解决这个问题,我需要比较IPV4存储地址和IPV6映射地址。为此,我使用IPV4结构的sin_addr.s_addr和IPV6结构的sin6_addr.in6_u.u6_addr32。请找到下面的代码片段。比较IPV4套接字(sockaddr_in)与IPV6套接字(sockaddr_in6)

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

我想知道这种方法是否是与IPV4地址比较IPV6映射IPv4地址的妥善解决或有任何其他更好的办法。

+0

我承认我没有太多的IPv6经验,但不会例如即使它是IPv6映射的IPv4地址,recvfrom也返回源地址作为AF_INET6? – 2012-07-30 09:11:36

+0

对不起,我跳过/忘记提及以下功能。服务器通过两种方式获取客户端地址。 1)第一次与客户端通过UDP进行通信2)客户端可能通过TCP将其UDP连接细节作为XML数据发布到服务器。在这种情况下,客户将只提供IPV4地址。 – 2012-07-30 09:13:42

+3

在比较最后的32位之前,还需要检查前80位是否为零,接下来的16位是否为1。否则,您不知道您是否正在处理映射为IPV6的IPV4。 – 2012-07-30 10:08:17

回答

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