我维护GPSD,这是一个广泛部署的开源服务守护进程,可以监控GPS和其他大地测量传感器.它在IPv4和IPv6上侦听端口2947上的客户端应用程序连接.为了安全和隐私,它通常只监听环回地址,但守护进程有一个-G选项,用于使其监听任何地址.
问题:-G选项在IPv4中有效,但我无法弄清楚如何使其与IPv6一起使用.应该基于各种教程示例工作的方法不会产生错误,表明该地址已在使用中.我正在寻求帮助来解决IPv6网络编程经验丰富的人.
此代码在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
*/
Run Code Online (Sandbox Code Playgroud)
根据我查找的各种教程示例,分配"sat.sa_in6.sin6_addr = in6addr_any;" (尽管评论)是正确的,它确实编译.但是,使用-G启动时无法声明监听地址已被使用.
作业是"sat.sa_in6.sin6_addr = in6addr_any;" 名义上正确吗?还有什么,如果有的话,我错过了什么?
Die*_*Epp 21
地址已被使用的原因是因为在许多IPv6网络堆栈上,默认情况下IPv6套接字将同时监听IPv4和IPv6.IPv4连接将以透明方式处理并映射到IPv6空间的子集.但是,这意味着您无法在不更改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 */
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,跨平台没有默认值IPV6_V6ONLY
- 这基本上意味着如果你愿意,你总是需要明确打开或关闭它,除非你不关心其他平台.Linux默认情况下将其关闭,Windows默认启用它...