当我们 netstat -lnt 查看本机侦听端口的时候,经常会看到类似下面的展示:

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地址:

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地址去连接:

telnet 192.168.56.101 1234

侦听端接受连接请求后会将来源地址解析成来源IPv4地址的IPv4-Mapped地址 "::ffff:192.168.56.102" 你用netstat去查看该连接,显示的依然是IPv4连接:

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/


浙江温州皮鞋湿,下雨进水不会胖。

IPv6 socket侦听in6addr_any的问题相关推荐

  1. ipv6学习之旅--组播侦听发现协议(MLD)

    组播侦听发现协议是ipv6才有的协议,他的原理是当源主机发送一份数据到一个组播地址,所有加入了这个组播地址的成员都可以收到一份数据的拷贝.并且只有组播成员才可以接收到数据.路由器通过MLD协议,可以了 ...

  2. 解决Python Socket UDP端口侦听线程内更新UI界面卡顿、奔溃的问题

    网络读卡器介绍:WIFI无线网络RFID云读卡器远程网络开关物流网NB-IoT4G刷卡阅读器-淘宝网 (taobao.com) Python使用PyQt5做UI界面,开启线程侦听UDP端口,端口接收到 ...

  3. IPV6 Socket编程

    IPV6 socket的练习程序,服务器打印客户端的地址,然后回送收到的消息. server_v6.c /*********************************************** ...

  4. ipv6 socket

    LINUX 下 ipv6 socket 编程 发布: 2009-7-11 10:57 | 作者: admin | 来源: IPv6之家 大家都知道,随着互联网上主机数量的增多,现有的32位IP地址已经 ...

  5. RDMA编程1 建立侦听

    #RDMA编程 建立连接 ##1. RDMA的学习环境搭建 RDMA需要专门的RDMA网卡或者InfiniBand卡才能使用,学习RDMA而又没有这些硬件设备,可以使用一个软件RDMA模拟环境,sof ...

  6. java 多线程监听同一个端口_使用多线程在Java服务器中同时侦听两个端口

    我正在构建一个简单的Java服务器,该服务器使用两个ServerSocket实例同时在两个端口上同时侦听客户端请求.这是服务器的代码: import java.io.PrintWriter; impo ...

  7. java 监听本地端口_Java-在本地端口上侦听RTP数据包

    因此,我目前正在开发一个客户端应用程序,该应用程序在端口5004上侦听RTP数据包.由于可能有多个服务器发送RTP数据包,因此我无法使用套接字连接到特定的远程主机.相反,我尝试了以下方法来侦听本地端口 ...

  8. php环境模拟stphp_用php模拟做服务端侦听端口

    参考:http://www.cnblogs.com/thinksasa/archive/2013/02/26/2934206.html http://blog.csdn.net/alongken200 ...

  9. Linux内核网络协议栈8—socket监听

    几个问题  了解以下几个问题的同学可以直接忽略下文: 1.listen 库函数主要做了什么?  2. 什么是最大并发连接请求数?  3.什么是等待连接队列? socket 监听相对还是比较简单的,先看 ...

最新文章

  1. OKR能带来哪些价值
  2. android textview 背景图片,Android—TextView 背景颜色与背景图片设置
  3. Struts2的struts.xml的配置细节
  4. .net core精彩实例分享 -- 基础篇
  5. android 透明度_Android智能视图翻转器
  6. Java多线程系列--“JUC线程池”01之 线程池架构
  7. Ableton Live 11 Suite for Mac(数字音乐音频制作软件)
  8. 需求分析岗的一点总结
  9. ASO如何做_ASO优化方案
  10. 学的java,想问问现在想做电商的项目怎末样?
  11. 解决Flex项目下bin-debug文件在其他电脑打开不显示的问题
  12. CRMchat 客服系统
  13. HTML对表格隔行变色
  14. 【转】欧几里德结构数据(Euclidean Structure Data) 以及非欧几里德结构数据(Non-Euclidean Structure Data)
  15. Mendix低代码平台,唯快不破
  16. 区块链技术系列(3)- Fabric基础架构原理
  17. 十进制与任意进制的转换
  18. 在网页中引用阿里iconfont字体图标的三种方式
  19. 《男女诗篇》 - 肖复兴
  20. 22年PMP考试内容大改,敏捷项目管理全套资料,不看过不了!

热门文章

  1. 如何实现触摸屏与多台PLC之间无线Profinet通信?
  2. 2019ACM南京网络赛 Holy Grail
  3. 中小企业办公自动化系统设计与实现(SSH)
  4. STM32 FMC篇-SDRAM(IS42S16400J)
  5. DAS、NAS和SAN
  6. 权重、关键词重要性降低,如何通过平台系统搭建解决
  7. 《算法零基础100讲》(第24讲) 字符串算法(四) - 字符计数法
  8. 论坛上的一段话,关于女人的!!
  9. 2022年,地产破局机会究竟在哪儿?
  10. MCE | mTOR 通路是如何调控自噬的