{{ v.name }}
{{ v.cls }}类
{{ v.price }} ¥{{ v.price }}
本文来自微信技术架构部的原创技术分享。
在上篇《ipv6技术详解:基本概念、应用现状、技术实践(上篇)》,我们讲解了ipv6的基本概念。本篇将继续从以下方面展开对ipv6的讲解:
如您对ipv6的基本概念尚未了解,请先阅读本文的上篇。
学习交流:
-即时通讯开发交流3群:185926912[推荐]
-移动端im开发入门文章:《新手入门一篇就够:从零开发移动端im》
(本文同步发布于:http://www.52im.net/thread-1607-1-1.html)
文章太长,分为两篇来讲,本文是2篇文章中的第2篇:
本文是系列文章中的下篇,主要讲解ipv6的应用现状和技术实践等。
本文后面主要的分析都是基于linux,会有涉及关于linux内核对ipv6的实现。主要是因为,现在ipv6的参考资料不多,除了与ipv6相关的rfc之外,还有少数可以参阅的ipv6国外文献,而linux内核一直都与跟随着ipv6的协议更新和变化,linux内核ipv6的实现是十分重要的参考材料之一。而且从事后台开发工作主要也是在linux平台下,熟悉linux下ipv6的实现也是为以后的工作做知识储备。ps:客户端开发的同学可以参考各自平台的文档......linux在很早之前就已经开始支持ipv6,目前我们接触最多的linux内核版本都很好地支持ipv6,同时也是支持ipv4/ipv6双栈体系。在linux操作系统中,ipv4是默认必须开启,ipv6是可选编译和配置开启。例如在编译内核的时候,需要选择ipv6编译选项才支持ipv6:
由于我们平时的开发工作在应用层,以上1-4是将会接触得最多。
本章我们通过实验,加深对ipv6的认识。这里的实验没有使用真实现网的ipv6接入点(目前国内绝大部分接入点都是教育网),而实验的目的主要是观察ipv6的数据包结构、ipv6的路由配置等,所以决定自己通过搭建中间路由器、应用服务器的方式做实验,便于抓包和代码分析。
客户端:windows7路由器:中间路由器使用自己编译和搭建的linux系统(内核2.6.32.27)应用服务器:ubuntu16.04lts版本。
为什么要使用自己编译的linux作为路由器?因为ipv6的实践类能参考的文献比较少,而linux内核的ipv6模块是最重要的参考资源之一,在实践中遇到问题可以使用打log和分析代码的方法解决。
ipv6地址的获取是最重要的环节之一。本实验使用开源的无状态自动配置服务radvd进行实验。
可以看到无状态自动配置过程十分简易(对比dhcpv4和dhcpv6来说),实际上,无状态自动配置可以单独组网使用,也可以配合有状态自动配置一般会配合使用,加强网络节点管理。涉及自动配置和地址检测等更多细节,可以查阅rfc1971、rfc4861。
本次实验主要是了解windows和linux的静态路由配置。
复用2的架构,在服务器端部署一个web服务,在客户端访问该web服务。web服务没有选择像apache或者nginx这样的庞然大物,而选择了很轻量的boa。原因是boa虽然原始支持ipv6,但是我想粗暴的把所有ipv4的socket套接字都替换成ipv6版本,尝试做一个自定义的升级。结果需要改动的代码非常少,不超过20行,boa就能完全支持ipv6。配合实验,写了一个简单的cgi,只是在版面echo字符串。如下图:
这部分将在过渡技术介绍中一起实验。
ipv6的提出,最重要的目的就是解决公网ipv4耗尽的问题,而且ipv6协议的设计就考虑到了更加好的效率、安全、扩展等方面,可以那么说,ipv6是未来网络发展的大趋势。但为什么ipv6已经发展了十几年了,目前在我们的工作和生活中还是比较少接触和使用。这里的原因是非常的复杂,有技术上障碍,因为ipv6和ipv4是两个完全不兼容的协议(在极少数的特定场景可以实现兼容),如果要从支持ipv4升级到ipv6,无论是应用程序用客户端、服务器程序端、路由器等等,都要同时支持ipv6才能解决问题,这个的升级改造需要花费的成本是巨大的。而且,正是由于技术上的升级花费大量的人力物力,无论是运营商还是互联网服务商,一方面要重视用户的体验问题,这个肯定不能强制客户更新换代硬件设备和软件,另一方面也要维护自身的投资和利益,更愿意去选择利用现有技术降低ipv4地址耗尽带来的压力,例如nat的广泛应用,就是ipv6推广使用的一个重要的“障碍”。由上所述,ipv4升级到ipv6肯定不会是一蹴而就的,是需要经历一个十分漫长的过渡阶段(用我厂通用的术语说,就是ipv4升级ipv6这个灰度的时间非常长),要数十年的时间都不为过。现阶段,就出现了ipv4慢慢过渡到ipv6的技术(或者叫过渡时期的技术)。过渡技术要解决最重要的问题就是,如何利用现在大规模的ipv4网络进行ipv6的通信。要解决上面的问题,这里主要介绍3种过渡技术:
本章节会对以上的过渡技术,选取几个典型的、我们未来最有机会接触到的具体的过渡技术结合实验观察过渡技术的具体实现和数据包的表现形式。
这种技术其实很好理解,就是通信节点同时支持ipv4和ipv6双栈。例如在同一个交换机下面有2个linux的节点,2个节点都是ipv4/ipv6双栈,节点间原来使用ipv4上的udp协议通信传输,现在需要升级为ipv6上的udp传输。由于2个节点都支持ipv6,那只要修改应用程序为ipv6的socket通信基本达到目的了。上面的例子在局域网通信的改造是很容易的。但是在广域网,问题就变得十分复杂了。因为主要问题是在广域网上的2个节点间往往经过多个路由器,按照双栈技术的部署要求,之间的所有节点都要支持ipv4/ipv6双栈,并且都要配置了ipv4的公网ip才能正常工作,这里就无法解决ipv4公网地址匮乏的问题。因此,双栈技术一般不会直接部署到网络中,而是配合其他过渡技术一起使用,例如在隧道技术中,在隧道的边界路由器就是双栈的,其他参与通信的节点不要求是双栈的。
当前的网络是以ipv4为主,因此尽可能地充分利用ipv4网络进行ipv6通信是十分好的手段之一。隧道技术就是这样子的一种过渡技术。隧道将ipv6的数据报文封装在ipv4的报文头部后面(ipv6的数据报文是ipv4的载荷部分),ipv6通信节点之间传输的ipv6数据包就可以穿越ipv4网络进行传输。隧道技术的一个很重要的优点是透明性,通过隧道进行通信的两个ipv6节点(或者节点上的应用程序)几乎感觉不到隧道的存在。
6to4是当前使用得比较广泛的一种自动配置隧道技术,这种技术采用特殊的ipv6地址,称为6to4地址,这种地址是以2002开头,接着后面的32位就是内嵌的隧道对端的ipv4地址。当边界路由器收到这类目的地址,取出ipv4地址建立隧道。6to4隧道一般用在路由器-路由器、主机-路由器、路由器-主机场景,典型的应用场景是两个ipv6的站点内主机通过6to4隧道进行相互访问。6to4隧道的一个限制是内嵌的ipv4地址必须是公网地址。6to4隧道实验过程如下。如下图,就是本次6to4实验中使用的隧道架构,该架构是典型的路由器-路由器隧道,隧道两侧的ipv6网络对隧道的存在无感知。
isatap全称是站点内自动隧道寻址协议(intra-siteautomatictunneladdressingprotocol),用来为ipv4网络中的ipv6双栈节点可以跨越ipv4网络访问外部的ipv6节点。isatap隧道一般用于主机-主机、主机-路由器的场景。isatap隧道实验过程如下所示。如下图就是本次实验使用的架构,是一种典型的主机-路由器场景。实验中需要在路由器2上部署radvd服务,用于客户端进行无状态自动配置地址。linux下的isatap隧道也是可以使用sit隧道实现。
前面的隧道技术,主要是在ipv4的数据报文承载着ipv6的数据报文,这是一种特殊的数据包格式(ipv6-in-ipv4),不同于我们熟悉的tcp、udp等传输层协议。而我们平常接触到的网络都存在于nat架构中(例如我们的办公网络和家庭网络),在这种网络架构中,路由器仅对于tcp、udp等传输层协议做nat处理,而无法正确处理ipv6-in-ipv4这种报文,例如使用isatap隧道,ipv6双栈节点与isatap路由器之前如果存在nat,isatap建立隧道失败;6to4隧道也会遇到同样的问题。teredo隧道是有微软公司主导的一项隧道技术,主要用于在nat网络架构下建立穿越nat的隧道。teredo隧道的核心思路,是将ipv6的数据封装成ipv4的udp数据包,利用nat对ipv4的udp支持进行穿越nat的传输,当udp包到达隧道的另外一端后,再把ipv4的包头、udp包头剥离,还原ipv6的数据包,再进行下一步的ipv6数据通信转发。teredo节点会分配一个以2001::/32的前缀,而且地址中还包含teredo的服务器、标志位和客户端外部映射模糊地址和端口号等信息。teredo的实现还会遇到nat的类型不同而被限制的问题。nat的类型有锥形nat、受限制的nat、对称nat几种,teredo只能在锥形nat和受限制的nat的环境下正常工作,而且在这两种nat需要处理的逻辑又是不一样的。因此teredo整体的实现会比较复杂。实验环境搭建:在linux平台下有开源的teredo实现版本:miredo。由于时间和文章篇幅的原因,而且部署miredo比较复杂,因此这里的实验等以后有机会再补充。
隧道技术是比较好地解决了在很长期一段时间内还是ipv4网络是主流的情况下ipv6节点(或者双栈节点)间的通信问题。但是由于ipv4到ipv6的过渡是十分漫长的,因此也需要解决ipv6节点与ipv4节点通信的问题。协议转换技术可以用来解决这个问题。协议转换技术根据协议在网络中位置的不同,分为网络层协议转换、传输层协议转换和应用层协议转换等。协议转换技术的核心思路就是在ipv4和ipv6通信节点之间部署中间层,将ipv4和ipv6相互映射转换。我们非常熟悉的nat也是一种典型的协议转换技术,是将私网ipv4地址映射转换为公网ipv4地址,这种转换技术又称为nat44。而我们接着要重点介绍的名为nat64/dns64的协议转换技术。
提到nat64/dns64,相信做ios客户端开发的同学一定非常熟悉。在2016年中开始,苹果要求app必须支持ipv6网络。而苹果官方提供的过渡解决方案正是nat64/dns64。以下是苹果提供的技术图:
在《ipv6socket编程》一文中,ray已经很详细介绍了ipv6下的socket编程细节和应该注意的问题。本章作为一个补充,介绍一下ipv6socket编程可能还会遇到的问题。
ipv4地址本质是一个32位整数,因此一般无论是存储层还是逻辑层,都经常将点分制的ipv4字符串地址转为32位整数使用。而在ipv6,情况就复杂多了(可能也有同学就想到,光是原子性就很难保证了)。举一个典型的例子,现在有个需求,分别统计每个ip的访问频次。在ipv4的情况下,最简单就是stl用std::map搞定(单线程),土豪一点的可以开个16g的数组用空间换时间。但是在ipv6的场景下,那就尴尬了,ipv6可是个128位整数,可以用map吗?可能会有人直接将原始的字符串类型的ipv6地址作为key来累计。一旦那么用,就要十分注意了。由于ipv6是支持前导0和连续0的压缩表示方式,而且支持英文字母大小写,例如:2001:db8:4::412001:db8:4:0:0:0:0:0:412001:0db8:4::412001
在ipv4和ipv6共存的一个很长的时间里,在socket编程上不得不面对的就是ipv6和ipv4一定程度的“兼容问题”。而在文章前面有提到,ipv6和ipv4和完全不兼容的两种协议,但是ipv6协议的地址空间更大,是可以使用ipv6的地址表示ipv4地址,例如ipv4映射地址,因此,在很特殊的情况下,ipv4和ipv6可以实现“兼容”,但是这种兼容是很有限的。在linux平台下,这种“兼容性”是如何表现的,我们这里来分析一下。在linux下面,以ipv6下的udpsocket举例,详细如下。有个udp协议的server改造ipv6,该server机器上有一个网卡并且同时配置ipv6和ipv4地址,支持双栈。server进程创建ipv6udpsocket套接字,绑定server本地任意地址(ipv4和ipv6都是以全0地址为绑定任意地址)。客户端是ipv4,向这个server发送udp请求数据包。
从前面的章节可以知道,ipv6具有自动配置地址的能力。链路本地地址是ipv6要求在每个接口默认自动配置生成的地址,用于链路上的通信,路由器不能转发链路本地地址。除了以上提到的特征外,链路本地地址就是一个普通的ipv6地址,我们可以使用这类地址做socket编程通信。但是我们在ipv6socket编程的时候使用链路本地地址,有一个细节需要注意。
本文主要科普介绍了ipv6的基本内容,配合各种实验分析比较清晰认识了ipv6的各种基本概念;也介绍一些“超纲”的内容(我们的工作中很可能不会接触到),但是我觉得这类内容在技术实现上十分有趣,可以在一些技术的方法和思路上面可能会给我们一些通用的启示,例如nat64/dns64就是使用中间层来处理ipv4和ipv6互通的问题,我们的工作中也确实经常遇到类似的技术问题。ipv6本身是一个很庞大的体系,还有很多高级内容没有介绍(ipv6-ipsec、移动ipv6等等)。而且查看和ipv6相关的rfc,不断在做修正,linux内核的ipv6模块代码也不断有配合新的rfc修改来做调整,引入新的逻辑,以适应各种场景的实际需求。有兴趣的同学可以一直留意rfc的变化和紧跟linux内核的版本发布。本文是我在结合各种文献和实验对ipv6理解的一个总结归纳,难免会有理解偏差和手抖的地方,希望各位同学熟悉的话能帮忙指出其中的错误,并且提供修改建议和意见,谢谢:)。(——接上篇《ipv6技术详解:基本概念、应用现状、技术实践(上篇)》,全文完——)
1、《深入解析ipv6(第3版)》2、《tcp/ip详解-卷1协议》3、《tcp/ip协议原理与应用(第4版)》4、《精通linux内核网络》5、rfc4380“teredo:tunnelingipv6overudpthroughnetworkaddresstranslations”6、rfc3596“dnsextensionstosupportipversion6”7、rfc4193“uniquelocalipv6unicastaddress”8、rfc3879“deprecatingsitelocaladdress”9、rfc2553“basicsocketinterfaceextensionsforipv6”10、rfc4214“intra-siteautomatictunneladdressprotocol(isatap)”11、rfc6147“dnsextensionsfornetworkaddresstranslationfromipv6clientstoipv4servers”12、rfc6052“ipv6addressingofipv4/ipv6translators”13、rfc6146“statefulnat64:networkaddressandprotocoltranslationfromipv6clientstoipv4servers”14、rfc3068“ananycastprefixfor6to4deployment”15、rfc2460“internetprotocol,version6specification”16、rfc4291“ipversion6addressingarchitecture”17、rfc1971“ipv6statelessaddressautoconfiguration”18、rfc4861“neighbordiscoveryforipversion6”19、https://developer.apple.com/libr...p40010220-ch213-sw1
1、linux-2.6.32.27源码(www.kernel.org)2、linux-3.10.108源码(www.kernel.org)3、linux-4.9.75源码(www.kernel.org)4、无状态自动配置服务radvd(http://www.litech.org/radvd/)5、nat64服务tayga(http://www.litech.org/tayga/)6、nat64/dns64服务ecdysis(http://ecdysis.viagenie.ca/)7、teredo服务mirodo(https://www.remlab.net/miredo/)8、轻量级web服务器boa(http://www.boa.org/)