如何使用C套接字API侦听所有IPV6地址

时间:2011-09-19 15:38:12

标签: c ipv6

我维护GPSD,这是一个广泛部署的开源服务守护程序,可监控GPS和其他大地测量传感器。它在IPv4和IPv6上侦听端口2947上的客户端应用程序连接。为了安全和隐私,它通常只监听环回地址,但守护进程有一个-G选项,用于使其监听任何地址。

问题:-G选项在IPv4中有效,但我无法弄清楚如何使其与IPv6一起使用。应该基于各种教程示例工作的方法不会产生错误,表明该地址已在使用中。我正在寻求帮助来解决IPv6网络编程经验丰富的人。

相关代码位于http://git.berlios.de/cgi-bin/gitweb.cgi?p=gpsd;a=blob;f=gpsd.c;h=ee2156caf03ca23405f57f3e04e9ef306a75686f;hb=HEAD

此代码在IPv4下的-G和非G情况下都能正常运行,因为可以使用netstat -l轻松验证。

现在在“案例AF_INET6:”之后查看第398行。 listen_global选项由-G设置;如果为false,则代码成功。目前有一个以下评论,继承自一个未知的贡献者,如下所示:

/* else */
        /* BAD:  sat.sa_in6.sin6_addr = in6addr_any;
     * the simple assignment will not work (except as an initializer)
     * because sin6_addr is an array not a simple type
     * we could do something like this:
     * memcpy(sat.sa_in6.sin6_addr, in6addr_any, sizeof(sin6_addr));
     * BUT, all zeros is IPv6 wildcard, and we just zeroed the array
     * so really nothing to do here
     */

根据我查找的各种教程示例,分配“sat.sa_in6.sin6_addr = in6addr_any;” (尽管评论)是正确的,它确实编译。但是,使用-G启动时无法声明监听地址已被使用。

作业是“sat.sa_in6.sin6_addr = in6addr_any;”名义上正确吗?还有什么,如果有的话,我错过了吗?

2 个答案:

答案 0 :(得分:20)

地址已被使用的原因是因为在许多IPv6网络堆栈中,默认情况下,IPv6套接字将同时侦听IPv4和IPv6。 IPv4连接将以透明方式处理并映射到subset of the IPv6 space。但是,这意味着您无法在不更改IPv6套接字上的设置的情况下绑定到与IPv4套接字相同的端口上的IPv6套接字。有意义吗?

在致电bind之前这样做(这是从我的一个项目中获取):

int on = 1;
if (addr->sa_family == AF_INET6) {
    r = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
    if (r)
        /* error */
}

不幸的是,IPV6_V6ONLY平台之间没有默认值 - 这基本上意味着如果你愿意,你总是需要明确打开或关闭它,除非你不关心其他平台。 Linux默认情况下将其关闭,Windows默认启用它...

答案 1 :(得分:1)

从随机Linux系统的包含文件中看,in6addr_any的声明如下:

extern const struct in6_addr in6addr_any;        /* :: */
extern const struct in6_addr in6addr_loopback;   /* ::1 */
#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }

所以,也许INIT数组的接近程度混淆了谁在GPSD的来源中留下了这个评论。实际类型显然是struct in6_addr,可以分配。

我确实环顾四周,并发现了一些暗示,如果IPv4已经在侦听“任何”地址,那么IPv6也不能。也许这就是咬你的东西。