《Unix 网络编程》12:IPv4 和 IPv6 的互操作性
IPv4 和 IPv6 的互操作性
系列文章导航:《Unix 网络编程》笔记
IPv4客户端与IPv6服务器
IPv4 Mapped IPv6 address
双栈主机的一个基本特性是其上的 IPv6 服务器既能处理 IPv4 客户,又能处理 IPv6客户,这是通过使用 IPv4 映射的 IPv6 地址实现的:
例如:
graph LR;
A("206.52.225.32") --映射为IPv6--> B("::FFFF:206.52.225.32")
通信的流程
(以TCP为例)关键步骤是:
- 接收端的数据链路通过查看以太网类型字段把每个帧传递给相应的 IP 模块。IPv4 模块结合其上的 TCP 模块检测到 IPv4 数据报的目的端口对应的是一个 IPv6 套接字,就把该数据报 IPv4 首部中的源 IPv4 地址转换成一个等价的 IPv4 映射的 IPv6 地址
- 当服务器发送 TCP 分节时,目的地址为所映射 IPv4 地址的 IPv4 载送数据报
总结
- 因此等于是这些底层模块向上提供了一种抽象,使得 IPv6 服务器无需关心向自己发起请求的是 IPv4 还是 IPv6,具体的转换工作是由下层来做的
- 除非服务器显式检查这个 IPv6 地址是不是一个 IPv4 映射的 IPv6 地址(使用后文介绍的 IN6_IS_ADDR_V4MAPPED),否则它永远不知道其是 IPv4 还是 IPv6
- UDP 也有类似的机制
- 反过来则不行,不能将 IPv6 地址映射为 IPv4 地址
IPv6客户端与IPv4服务器
这里的假设前提是:
- 客户端是一个运行双栈的 IPv6 客户
- IPv6 客户启动后调用 getaddrinfo 单纯查找 IPv6 地址,并在 hints 中设置了
AI_V4MAPPED
标志(见11章)
总结
- 与上文相似,这里是由底层模块向上提供了一种抽象,使得 IPv6 客户无需关心自己发起请求的目标是 IPv4 还是 IPv6,具体的转换工作是由下层来做的
- 同样,反过来不行,IPv4 客户不能向 IPv6 服务器发起请求
对互操作性的总结
如图所示:
- 加星号的表示如果客户端选用 IPv4 地址就可以工作
- 在可见的未来,双栈会很普及,所以如果我们把图中的红色部分去除,会发现几乎都可以通信
地址是否是映射的 IPv6
一小类的 IPv6 应用必须清楚与其通信的是不是 IPv4 对端,是不是经过映射的 IPv6 地址,可以用如下的宏解决:
#include <netinet/in.h>
前七个宏用来测试 IPv6 地址的基本类型
后五个宏测试 IPv6 多播地址的范围
一个例子:
FTP 客户端通过控制连接向服务器发送 PORT 指令,以让服务器建立一个数据连接
PORT 指令需要根据服务器的 IP 版本决定发送的指令的具体格式