请选择 进入手机版 | 继续访问电脑版

IPv6 socket侦听in6addr_any的问题

[复制链接]
期待幸福 发表于 2021-1-2 19:43:26 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
当我们 netstat -lnt 查察本机侦听端口的时候,经常会看到雷同下面的展示:
  1. tcp6       0      0 :::22                   :::*                    LISTEN      658/sshd: /usr/sbin
复制代码
显然,sshd创建了一个IPv6 socket,在in6addr_any所在上侦听22号端口。
此时,我用一个该呆板的IPv4所在去毗连22号端口,通照旧不通呢?为了避开无关的讨论,我假设net.ipv6.bindv6only的值为0。
固然是通的,不信你试试。想知道细节上Why的去看源码好了,这块代码很简朴。我这里想引出一个和reuseport有关的问题。
按照TCP的语义,侦听一个端口这件事和IP所在无关,仅仅和端口有关,按照socket的语义,bind一个所在需要同时提供IP所在和端口。
因此,在实现上,我们要区分开哪些是TCP规定的,哪些是socket规定的:


  • socket必须按照所在族举行分类,比方说IPv4 socket,IPv6 socket。
  • 侦听某个端口的TCP不能区分毗连来自IPv4所在照旧IPv6所在。
  IPv4 socket是AF_INET族,IPv6 socket是AF_INET6族,我讨厌术语,就不说这些了。
在实现上,Linux显然用同一张hash表生存包罗IPv4,IPv6在内的所有侦听socket,无论是IPv4照旧IPv6的侦听socket,在bind的最终,均会以其bind的端口为键值插入到同一张hash表中,注意,这张hash表和IP所在完全无关。
当TCP毗连到来的时候,协议栈会提取数据包的目标端口,以此为键值来查询唯一的这张生存侦听socket的hash表,我们假设找到了一个匹配的IPv6 socket,而且该socket bind的是in6addr_any所在,那么问题来了:


  • 如果泉源毗连是一个IPv6报文,显然是可以乐成创建毗连的。
  • 如果泉源毗连是一个IPv4报文,能不能让它创建毗连呢?
这就要看如何明白 in6addr_any所在 了,即 "0:0:0:0:0:0:0:0" 这个IPv6所在包罗不包罗IPv4的 "0.0.0.0" ,对于Linux系统,在 bindv6only 关闭的情况下,答案显然是肯定的。所以,当一个IPv6 socket在bind in6addr_any之后侦听的话,无论是使用IPv4照旧使用IPv6,均可以乐成创建毗连。
好比我用以下的代码bind了一个IPv6所在:
  1. inet_pton(AF_INET6, "0:0:0:0:0:0:0:0", (struct sockaddr_in6 *)&srvaddr.sin6_addr);srvaddr.sin6_port = htons(1234);bind(lsd, (struct sockaddr*)&srvaddr, sizeof(srvaddr));listen(lsd, 10);
复制代码
然后我用一个IPv4所在去毗连:
  1. telnet 192.168.56.101 1234
复制代码
侦听端继承毗连请求后会未泉源所在分析成泉源IPv4所在的IPv4-Mapped所在 "::ffff:192.168.56.102" 你用netstat去查察该毗连,显示的依然是IPv4毗连:
  1. tcp6       0      0 192.168.56.101:1234     192.168.56.102:52802    ESTABLISHED 29047/./a.out
复制代码
现在细节已经很清楚了,问题是,在保存bindv6only为0的前提下,如何让IPv6 socket不再继承IPv4的毗连呢?
倒也不难,方法是:


  • IPv6 socket启用reuseport,再创建一个IPv4 socket,bind到0.0.0.0的同一个端口即可。
如此一来,纵然是IPv6 socket在in6addr_any上侦听,它也不会继承IPv4的毗连了,IPv4的毗连完全由IPv4 socket来处理处罚。
这个在Linux的实现中非常有意思,因为它太简朴了。简朴说就是,对于侦听同一个端口的情况:


  • IPv6 socket插入到hash链表的末端。
  • IPv4 socket插入到hash链表的头部。
  • 侦听socket的查找从hash链表头部开始遍历。
显然,侦听同一个端口的IPv4 socket和IPv6 socket不大概在同一个reuseport组,它们只能按照自己在链表中的位置被遍历。因此,如果来了IPv4的毗连请求,在遍历到IPv6 socket之前,首先会掷中IPv4 socket。
简朴的逻辑不必说太多。
OpenBSD与Linux差别,它不允许IPv4报文被IPv6 socket处理处罚,即便该IPv6 socket已经bind了in6addr_any所在,也要各管各的。OpenBSD的这种实现方式与Linux相比,到底是更简朴了照旧更复杂了呢?
不得而知。
原来是还想再聊聊IPv4-Mapped所在的,特别是和安全相关的issue,但是时间不允许了,详情看这里:https://lwn.net/Articles/8646/
  浙江温州皮鞋湿,下雨进水不会胖。

来源:https://blog.csdn.net/dog250/article/details/112058148
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


专注素材教程免费分享
全国免费热线电话

18768367769

周一至周日9:00-23:00

反馈建议

27428564@qq.com 在线QQ咨询

扫描二维码关注我们

Powered by Discuz! X3.4© 2001-2013 Comsenz Inc.( 蜀ICP备2021001884号-1 )