众所周知, 32 位的 IPv4 地址已经基本耗尽 (这里的耗尽只是说的分配完了, 实际上有相当一部分并没有投入到使用中), 新一代的网络协议 --IPv6 采用 128 位的地址长度拥有更大的地址空间, 如此大的地址空间, 可以给地球上的每粒沙子分配一个 IPv6 地址. IPv6 网络普及的声音喊了很多年, 在国内由于受限于各种因素却一直没有推广开. 2017 年 11 月开始中共中央办公厅和国务院办公厅印发了《推荐互联网协议第六版(IPv6) 规模部署行动计划》http://www.xinhuanet.com/politics/2017-11/26/c_1122012631.htm, 并发出通知, 要求各地区各部门结合实际认真贯彻落实. 这条新闻传达了一个很重要的信息: 这个是推进中国 IPv6 发展的战略总动员令. 2018 年 6 月份, 网信办对三大运营商和国内头部的 50 家互联网公司发出红头文件, 要求各大运营商和头部互联网公司给出各自的实施方案和排期, 并定下目标: 在 2018 年年底国内 IPv6 活跃用户数上升一个阶段. 所以从 2018 年 6 月份开始, 各大公司的 IPv6 改造才紧锣密鼓改造起来, 并且在 2018 年底取得了相当的成果.
由于 IPv6 网络协议相对来说还是一个比较新的协议, 在推广过程中, 很多人对这个网络协议缺乏必备的知识, 所以在这里写一篇简单的文章对该协议进行简单介绍和应用.
基础概念
软件支持
当前大部分操作系统和硬件都比较好地支持 IPv6 了, 简单列举如下:
Windows:Windows 7,Windows 8.x,Windows 10, 默认开启 IPv6;
Linux: 内核 2.6.x, 内核 3.x, 内核 4.x 已经支持 IPv6(需要手动开启);
iOS:IOS9 开始已经支持 IPv6 Only,2016 年苹果已经强制要求 App 必须支持 IPv6;
Android 也已经支持 IPv6(但是不支持 DHCPv6).
如何查看手机或者电脑的网络是否支持 IPv6 呢, 在手机或者电脑上的浏览器中打开: Ipv6-test.com, 显示如下说明你的手机网络已经支持 IPv6, 并已经分配了 IPv6 地址.
图一: 查看当前网络是否支持 IPv6
从上述截图中我们可以看到, 当前大部分支持 IPv6 的网络环境中都是双栈环境, 即同时支持 IPv4 和 IPv6, 也就是当我们连接运营商 LTE 网络的时候, 它一般会分配一个 IPv4 地址(一般是 10. 开头的内网地址), 和一个 IPv6 地址(全球单播地址, 相当于 ipv4 里面的公网地址). 双栈环境下, 用户自动选择使用什么 IPv6 或者 IPv4 协议去连接远端服务, 如果服务端域名支持 IPv6(域名解析中存在 AAAA 记录), 客户端则会优先使用 IPv6 协议去连接服务端(特殊情况下除外); 当服务端域名只支持 IPv4(DNS 解析中只有 A 记录), 客户端则会使用 IPv4 协议去连接服务端, 完成请求.
IPv6 协议简介
先看一个简单的 IPv6 报文抓包图:
图二: ipv6 数据报文
从 WireShark 的报文信息来看, IPv6 报文的报文类型字段, 头部字段和 IPv4 报文存在较大的差异. RFC2460 定义了 IPv6 数据报格式. 总体结构上, IPv6 数据报格式与 IPv4 数据报格式是一样的, 也是由 IP 报头和数据 (在 IPv6 中称为有效载荷) 这两个部分组成的, 但在 IPv6 数据报数据部分还可以包括 0 个或者多个 IPv6 扩展报头(Extension header), 如下图所示. IP 报头部分固定为 40 字节长度, 而有效载荷部分最长不得超过 65535 字节.
图三: IPv6 头部字段
简单介绍下 IPv6 报文中的各个头部字段:
Version(版本): 该字段表示 IP 版本, 值为 6.
Traffic class(流量类别): 该字段及其功能类似于 IPv4 的业务类型字段. 该字段以区分业务编码点 (DSCP) 标记一个 IPv6 数据包, 以此指明数据包应当如何处理.
Flow label(流标签): 该字段用来标记 IP 数据包的一个流, 当前的标准中没有定义如何管理和处理流标签的细节.
Payload length(有效载荷长度): 该字段表示有效载荷的长度, 有效载荷是指紧跟 IPv6 基本报头的数据包, 包含 IPv6 扩展报头.
Next header(下一报头): 该字段指明了跟随在 IPv6 基本报头后的扩展报头的信息类型.
更多详细比较可以参考这篇文章:
IPV6 报文头部格式:
IPv6 地址表示方法
IPv6 地址由八组, 每组四位 16 进制数字组成, 每组之间由 ":" 来分隔, 看个简单的例子:
2001:cdba:0000:0000:0000:0000:3257:9652, 每个: 前后都是 4 位 16 进制的数字, 共分隔成 8 组)
根据简写规则, 上述地址可以简写成如下表示:
1. 省略前导零, 上述 ip 地址可以表示为:
2001:cdba:0:0:0:0:3257:9652(4 个 0 简写成 1 个 0)
2. 通过使用双冒号 (::) 代替一系列零来指定 Ipv6 地址, 上述地址可以表示为:
2001:cdba::3257:9652(:0:0:0:0: 简写成::, 即省略所有的 0, 需要注意(一个 IP 地址中只可使用一次双冒号)
IPv6 地址分类
IPv6 地址是单个或一组接口的 128 位标识符. 在 IPv4 中, ip 地址分为 A,B,C,D,E 五类, 而 IPv6 突破了 IPv4 类别划分, 主要划分为三种地址类型: 单播地址, 组播地址和任意播地址, 各类地址的介绍如下:
单播 (Unicast) 地址: 单播地址作为一个单一的接口标识符. IPv6 数据包发送到一个单播地址被传递到由该地址标识的接口. 对应于 IPv4 的普通公网和私网地址;
多播 (MultiCast) 地址: 多播地址作为一组标识符, 多播地址的行为 / 接口可能属于不同的节点集合. IPv6 数据包发送到多播地址被传递到多个接口;
任播 (AnyCast) 地址: 一组接口 (一般属于不同节点) 的标识符. 发往任播地址的包被送给该地址标识的接口之一(路由协议度量距离最近的).
单播地址是使用最为广泛的一类地址, 单播地址中包含了多种地址类型, 包括:
1-1. 单播地址
1-1-1 全球单播地址
前缀 2000::/3, 指的是在 IPv6 的前 3bit, 必须为二进制的 001. 而二进制换化为十六进制, 需要 4bit 的二进制数, 所以 IPv6 全球单播地址的从左到右的第一字段的变化范围为 "0010" 到 "0011", 换化为十六进制变化范围就为 2 到 3. 那么如下图 4 所示, 表示 IPv6 全球单播地址的范围. 相当于 IPv4 的公网地址(IPv6 的诞生根本上就是为了解决 IPv4 公网地址耗尽的问题). 这种地址在全球的路由器间可以路由.
图四. IPv6 全球单播地址的范围
1-1-2 链路本地地址
前缀 FE80::/10, 顾名思义, 此类地址用于同一链路上的节点间的通信, 主要用于自动配置地址和邻居节点发现过程. Windows 和 Linux 开启 IPv6 后, 默认会给网卡接口自动配置一个链路本地地址. 也就是说, 一个接口一定有一个链路本地地址. 如下图:
图五. IPv6 链路本地地址
每个接口必须至少有一个链路本地地址; 每个接口可以配置 1 个以上的单播地址, 例如一个接口可以配置一个链路本地地址, 同时也可以配置一个全球单播地址.
注意: 很容易会把链路本地地址和 IPv4 的私网 / 内网地址对应起来, 其实链路本地地址对应于 IPv4 的 APIPA 地址, 也就是 169.254 开头的地址(典型场景就是 Windows 开启自动获取地址而获取失败后自动分配一个 169.254 的地址). 而 IPv4 私网对应于 IPv6 的唯一本地地址.
1-1-3 唯一本地地址
前缀 FC00::/7, 相当于 IPv4 的私网地址(10.0.0.0,172.16.0.0,192.168.0.0), 在 RFC4193 中新定义的一种解决私网需求的单播地址类型.
在 IPv4 中, 利用 NAT 技术私网内的网络节点可以使用统一的公网出口访问互联网资源, 大大节省了 IPv4 公网地址的消耗(IPv6 推进缓慢的原因之一). 另一方面, 由于默认情况下私网内节点与外界通信的发起是单向的, 网络访问仅仅能从私网内发起, 外部发起的请求会被统一网关或者防火墙阻隔掉, 这样的网络架构很好的保护了私网内的节点安全性和私密性. 因此, 在安全性和私密性要求下, IPv6 中同样需要支持私网, 并且也需要支持 NAT. 在 Linux 内核 3.7 版本开始加入对 IPv6 NAT 的支持, 实现的方式和 IPv4 下的差别不大(Linux 内核代码中变量和函数的命名几乎就是 ctrl+c 和 ctrl+v 过来的).IPv6 唯一本地地址配置如下图:
图六. IPv6 唯一本地地址
1-1-4 特殊地址
除了上述那些常见的单播地址, IPv6 中还有一些特殊地址, 简单列举如下:
全 0 的地址::/128 为未定义地址, 大家不要去使用
除了最后一位是 1, 其它都是 0 的地址::1/128 为本地环回地址, 同 IPv4 里面的 127.0.0.1
FF00::/8 这个网段的地址都是多播地址
IPv6 相关网络工具
dig
dns 解析, 查看一个域名是否具有 AAAA 记录
图七. dig 获取域名的 AAAA 记录
curl
通过 IPv6 网络协议进行请求响应, 获取服务端数据
图八. curl 通过 IPv6 获取接口数据
ping6
查看 IPv6 网络的连通性和域名解析的正确性
图九. ping6 测试 IPv6 网络连通性
telnet
查看对应 IPv6 地址端口是否开放
图十. telnet 查看端口可用性
mtr
IPv6 网络连通性判断工具
图十一. mtr 查看 IPv6 网络连通性
traceroute6
IPv6 网络测试, 评估和管理工具
图十二. traceroute6 查看 IPv6 路由节点情况
ip&route
查看本机 IPv6 路由表
图十三. 查看本机 IPv6 路由表
关于移动应用在 IPv6 和 IPv4 网络环境中自动降级机制的研究
由于最近在帮助业务上线 IPv6, 所以简单使用安卓手机 (小米 5S+MIUI10 + 浏览器) 验证了下手机在双栈环境中如何自动选择合适的协议向服务端请求数据. 具体过程如下:
第一步需要对服务端的域名进行 DNS 解析. 客户端获取域名的 DNS 解析时, 会先请求域名的 AAAA 记录, 等 DNS 服务器返回域名的 AAAA 记录解析后, 然后再请求域名的 A 记录. 具体过程如下抓包截图:
图十四. DNS 解析抓包
第二步根据获取到的域名的 AAAA 记录和 A 记录情况, 执行不同的操作:
1. 如果 AAAA 记录中存在有效的 IPv6 地址, 且本地网络支持 IPv6, 则会优先使用 AAAA 记录里面对应 IPv6 地址通过 IPv6 网络协议去连接服务端, 当通过域名的 AAAA 记录无法连接上服务端, 客户端一般会重试 4 次(重试过程大概总计会耗费 300ms 左右, 视具体网络环境而定), 如果四次都无法通过 IPV6 地址连接上服务端, 客户端会自动降级使用 IPV4 协议连接服务端, 具体过程如下图.
图十五. IPv6 和 IPv4 自动降级机制
2. 如果域名的 AAAA 记录中存在有效的 IPv6 地址, 但是本地网络不支持 IPv6, 则会直接使用 A 记录中的 IPv4 地址通过 IPv4 网络协议去连接服务端;
3. 如果 DNS 服务器返回的 AAAA 记录解析中没有包含有效的 IPv6 地址, 只有有效的 A 记录, 则会直接使用 A 记录中的 IPv4 地址通过 IPV4 网络协议去连接服务端.
总结
本篇文章仅仅只是对 IPv6 协议做了简单介绍, 涉及的知识方面较少. 更多写的是在业务上线 IPv6 过程中学习到的或者使用过的一些知识, 工具. 很多 IPv6 的基本概念并没有介绍到, 比如说邻居发现协议, DHCPv6,ICMPv6,PMTU,EUI-64 计算链路本地地址等, 这些协议在网络上已经有很多比较好的文章或者权威协议对这些知识点进行了介绍, 大家不妨多动手谷歌下.
来源: https://juejin.im/post/5c7e2d55e51d45604e59f76a