如何使用C sockets API监听所有IPV6地址

12
我维护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轻松验证。
现在看看“case AF_INET6:”后面的398行左右。当 -G 设置为false时,listen_global选项也将被设置;这段代码是有效的。目前有一个来自未知贡献者的以下评论:
/* 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;”是否基本上正确?如果还有其他问题,请指出。

你尝试过对守护进程进行strace吗? - jpalecek
2个回答

22

因为在许多IPv6网络堆栈上,默认情况下,IPv6套接字将同时侦听IPv4和IPv6。 IPv4连接将被透明处理并映射到IPv6空间的子集。但是,这意味着您无法在与IPv4套接字相同的端口上绑定IPv6套接字,除非更改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 默认情况下将其打开...


2
Linux的默认值实际上来自sysctl。因此,您不能完全依赖默认值。但是,如果系统管理员没有更改它,则默认为关闭(在我看来关闭是最合理的默认值)。 - Per Johansson

1

从随机 Linux 系统的 include 文件中查看,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也无法监听。也许这就是问题所在。


你的诊断的第二部分是正确的(请参见Dietrich Epp的回复),我怀疑你对第一部分也是正确的。 - ESR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接