【问题标题】:How to listen on all IPV6 addresses using C sockets API如何使用 C 套接字 API 监听所有 IPV6 地址
【发布时间】:2011-09-19 15:38:11
【问题描述】:

我维护 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 行。 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;”名义上正确吗?我还缺少什么(如果有的话)?

【问题讨论】:

  • 你试过跟踪守护进程吗?

标签: c ipv6


【解决方案1】:

地址已被使用的原因是因为在许多 IPv6 网络堆栈上,默认情况下 IPv6 套接字将同时侦听 IPv4 和 IPv6。 IPv4 连接将被透明处理并映射到subset of the IPv6 space。但是,这意味着您无法在与 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 默认开启...

【讨论】:

  • Linux 默认其实是来自 sysctl。所以你不能依赖那里的默认值。但是,如果系统管理员没有更改它,它会默认为关闭。 (关闭是最合理的默认 IMO)。
【解决方案2】:

查看随机 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 也不能。或许这就是困扰你的原因。

【讨论】:

  • 您的诊断的第二部分是正确的(参见 Dietrich Epp 的回复),我怀疑您对第一部分也是正确的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-03
  • 2016-05-30
  • 1970-01-01
相关资源
最近更新 更多