IPv6的全称是Internet Protocol Version 6(互联网协议第6版)的缩写,是互联网工程任务组(IETF)设计的用于替代IPv4的下一代IP协议,其地址数量号称可以为全世界的每一粒沙子编上一个地址 。
由于IPv4最大的问题在于网络地址(公网IP)资源不足,无论是PC电脑,还是移动端的手机和PAD都需要占用IP地址,IPv4面临着即将被用尽的窘境,严重制约了互联网的应用和发展。IPv6的使用,不仅能解决网络地址资源数量的问题,而且也解决了多种接入设备连入互联网的障碍 。
IPv6地址和规范将会逐渐普及。2020年3月23日,工业和信息化部发布《关于开展2020年IPv6端到端贯通能力提升专项行动的通知》,要求到2020年末,IPv6活跃连接数达到11.5 亿,较2019年8亿连接数的目标提高了43%。随着IPv6的发展与逐步普及,我们的软件也要添加对IPv6地址的支持,不再是仅仅支持IPv4了。
本文简单的梳理一下IPv6的IP地址结构和分配方式,同时也介绍一下基本使用方法,在此分享给大家。
一、IPv6的地址结构定义
节点、链路、站点、接口在IPv6里面的概念如下:
- 节点:具有IPv6地址且接口配置为支持IPV6的任何系统,可以理解为主机和路由器。每个节点上至少要有一个链路本地单播地址,另外还可分配任何类型(单播、泛播和多播)或范围的IPv6地址。
- 链路:单一且连续的网络介质,其两端均连接有路由器。节点所在的网络就是链路本地的范围,通常是不能跨越路由器的,也就是在一条链路上。以太网就是一个交换机下的所有设备都在一个链路上。
- 站点:就是一个企业内部的网络,可以有多个网段,类似IPv4的私网范围。但目前已经被RFC废除了,IPv6一般也不需要私网的存在意义。
- 接口:比如一个网卡的网口、上网的电话线口,一个节点可以被分配多个接口,而每个接口可以有多个ipv6地址。所有类型的IPv6地址都是属于接口(Interface)而不是节点(node),在单播地址中,IPv6 地址的最后 64 位是对于 IPv6 地址的 64 位前缀而言唯一的接口标识(由MAC地址自动生成,或者根据EUI-64规范手动生成)。一个接口在一个子网前缀中唯一。
1、IPv6地址表示
1)冒分十六进制表示法:IPv6地址包括128比特,以16位为一分组,每个16位分组写成4个十六进制数,中间用冒号分隔。如
- 21DA:00D3:0000:0000:02AA:00FF:FE28:9C5A
2)表示方法对大小写不敏感:16比特的十六进制数对大小写不敏感,如:
- 21DA:00D3:0000:0000:02aa:00ff:fe28:9C5A 。
3)每组的前导0可简化表示:IPv6地址中每个16位分组中的前导零位可以去除做简化表示,如:
- 21DA:D3:0:0:2AA:FF:FE28:9C5A
4)中间比特连续为0的情况:可以把连续出现的0省略掉,用::代替(注意::只能出现一次,否则不能确定到底有多少省略的0),该符号也能用来压缩地址中前部和尾部的相邻的连续零位,如下所示:
- 21DA:D3:0:0:2AA:FF:FE28:9C5A 等价于 21DA:D3::2AA:FF:FE28:9C5A
- FF01:0:0:0:0:0:0:101 等价于 FF01::101
- 0:0:0:0:0:0:0:1 等价于 ::1
- 0:0:0:0:0:0:0:0 等价于 ::
5)在IPv4和IPv6混合环境:x:x:x:x:x:x:d.d.d.d,其中x是地址中6个高阶16位分组的十六进制值,d是地址中4个低阶8位分组的十进制值(标准IPv4表示)。例如地址0:0:0:0:0:0:13.1.68.3,
- 0:0:0:0:0:FFFF:129.144.52.38 写成压缩形式为::13.1.68.3,::FFFF.129.144.52.38。
6)URL中使用文本IPv6地址:文本地址应该用符号‘[’和‘]’来封闭。例如文本IPv6地址
- FEDC:BA98:7654:3210:FEDC:BA98:7654:3210写作URL示例为http://[
- FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html。
7)前缀表示方法:
- ipv6-address/prefix-length 其中,ipv6-address为16进制表示的128比特地址;prefix-length为10进制表示的地址前缀长度。和IPv4类似,IPv6的子网前缀和链路关联,多个子网前缀可分配给同一链路。
例如,2001:0DB8:0:CD30::/60
当书写节点地址和该节点地址的前缀(例如,节点的子网前缀)时,二者合并写法如下:
节点地址
- 2001:0DB8:0:CD30:123:4567:89AB:CDEF
- 和它的子网号 2001:0DB8:0:CD30::/60
二者能够缩写为
- 2001:0DB8:0:CD30:123:4567:89AB:CDEF/60
2、EUI-64格式
EUI-64格式:扩展惟一标识符
在IPV6中,无状态自动配置机制使用EUI-64格式来自动配置IPV6地址。所谓无状态自动配置是指在网络中没有DHCP服务器的情况下,允许节点自行配置IPV6地址的机制。
EUI-64的构造规则:根据接口的MAC地址再加上固定的前缀来生成一个IPV6的地址。
工作原理:自动将48bit的以太网MAC地址扩展成64bit,再挂在一个64bit的前缀后面,组成一个IPV6地址
步骤一、将48位的MAC地址从中间分开,插入一个固定数值FFFE
0050:3EE4:4C00-->0050:3EFF:FEE4:4C00
步骤二、将第7个比特位反转,如果原来是0,就变为1,如果原来是1,就变为0
0050:3EFF:FEE4:4C00-->0250:3EFF:FEE4:4C00
步骤三、加上前缀:比如加上链路本地地址前缀FE80,FE80::0250:3EFF:FEE4:4C00 这就是一个完整的IPV6地址。
反转的原因:在MAC地址中,第7比特为1表示本地管理,为0表示全球管理;在EUI-64格式中,第7位为1表示全球惟一,为0表示本地惟一
3、 IPv6地址分类
- IPv6地址分为单播地址、任播地址、多播地址。和IPv4相比,取消了广播地址类型,以更丰富的多播地址代替,同时增加了任播地址类型。任播地址取自(具有任何范围的)单播地址空间,在句法上任播地址与单播地址难以区分。
- “未指定的地址”(全0)、环回地址(::1)和嵌入IPv4地址的IPv6地址从0000 0000格式前缀中分配。
- 除多播地址(格式前缀1111 1111)外,格式前缀从001到111的地址都必须有64比特的EUI-64格式的接口标识符。
- 所有格式前缀不是多播格式前缀(1111 1111)的IPv6地址都是IPv6单播格式(任播和IPv6单播格式相同)。IPv6单播地址和IPv4单播地址一样可聚合。
4、IPv6单播地址
单一接口的标识符,用于一对一的连接。
IPv6单播地址由子网前缀和接口ID两部分组成。子网前缀由IANA、ISP和各组织分配。接口标识符目前定义为64比特,可以由本地链路标识MAC生成或采用EUI-64格式随机算法生成以保证唯一性。
有以下六种类型:
1)可聚合全球单播地址
目前已分配的地址前缀:
- 2001::/3, 2000::
- ~3fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
目前实际用于IPV6 因特网运作的前缀:
- 2001::/16;
- 2002::/16为使用6to4过渡机制节点保留;
- 3ffe::/16由于6bone测试目的前缀。
2)本地链路地址
节点启用ipv6,每个接口自动会生成一个本地链路地址。其前缀64bit是固定的,其后64bit的接口ID根据EUI-64格式来构造。
链路本地地址只能在本地链路通信,不能过路由。
3)站点本地地址
IPV6私网地址,就像IPV4的私网地址一样。只能在站点内使用,不能用于公网。
最初设计站点本地地址是用于不需要全球前缀的站点内部寻址。现在,站点本地地址已经过时了,在新的实现中,必须不再支持由[RFC3513]定义的这个前缀的特殊性质(即,新的实现必须将此前缀看作是全球单播)。
已有的实现和部署可以继续使用这个前缀。
4)不确定地址
单播地址0:0:0:0:0:0:0:0称为不确定地址。它不能分配给任何节点。它的一个应用示例是初始化主机时,在主机未取得自己的地址以前,可在它发送的任何IPv6包的源地址字段放上不确定地址。不确定地址不能在IPv6包中用作目的地址,也不能用在IPv6路由头中;
5)回环地址
单播地址0:0:0:0:0:0:0:1称为回环地址。节点用它来向自身发送IPv6包。它不能分配给任何物理接口。
6)带有嵌入ipv4地址的ipv6地址
分两类:Ipv4兼容的ipv6地址 和 Ipv4映射的ipv6地址。
Ipv4兼容的ipv6地址:ipv4地址必须全球唯一。像::13.1.68.3这种前96比特全0的地址,主要用在一种自动隧道技术,目的地址为这种地址的报文会被自动IPv4隧道封装,由于这种技术不能解决地址耗尽问题,已经逐渐被废弃。
Ipv4映射的ipv6地址:像::FFFF.129.144.52.38这种最前80比特为全0,中间16比特为全1,最后32比特为IPv4地址,这种地址用来把只支持IPv4的节点用IPv6地址表示。在支持双栈的IPv6节点上,IPv6应用发送目的报文是这种地址时,实际上发出的报文为IPv4报文(目的地址是“IPv4映射的IPv6地址”中的IPv4地址)。
5、IPv6任播地址
一到近模式,多个设备共享一个地址。
IPv6任播地址是分配给一套属于不同节点的接口的全球地址,地址格式和IPv6单播地址相同,用来标识一组接口的地址,一般这些接口属于不同的节点。
分配相同的ipv6地址给拥有相同功能的设备,发送方发送一个以任播地址为目标的包,路由器接收到这个包后,就转发给具有这个地址的离它最近的设备。当一个单播地址被分配给多个接口时,单播地址自动变成任播地址。
如下边两个图所示,第一个配置没有冲突的地址,第二个配置了另外一台主机一样的地址。同一链路的两个主机配置了相同的ipv6地址后,后边的地址标注就是“复制”。
用途:
IPv6任播地址的用途之一是用来标识属于同一提供因特网服务的组织的一组路由器。这些地址可在IPv6路由头中作为中间转发路由器,以使报文能够通过特定一组路由器进行转发。
另一个用途就是标识特定子网的一组路由器,报文只要被其中一个路由器接收即可。
其中有些任播地址是已经定义好的,如子网路由器任播地址,格式如下。
任播地址中“子网前缀”用来标识一个特定链路。此任播地址在句法上,与该链路上接口标识符设置为0的接口的单播地址相同。发送到子网路由器任播地址的报文会被送到子网中的一个路由器。所有路由器都必须支持子网任播地址。
子网路由器任播地址用于节点需要和远端子网上所有路由器中的一个(不关心具体是哪一个)通信时使用。例如,一个移动节点需要和它的“家乡”子网上的所有移动代理中的一个进行通信。
任播地址具有以下限制:
- 任播地址不得用作IPv6 数据包的源地址;
- 任播地址不得分配给IPv6 主机,但是可以分配给IPv6 路由器。
6、IPv6多播地址
一对多模式。
IPv6多播地址用来标识一组接口,一般这些接口属于不同的节点。一个节点可能属于0到多个多播组。发往多播地址的报文被多播地址标识的所有接口接收。
1)IPv6多播地址格式定义:
FF00::/8
其中:
① 11111111:8比特。标识此地址为多播地址
② Flags:4比特。flag域中定义如下:
最高的3比特标记为保留域,必须为0
- T = 0表示为永久分配(“公认”)多播地址(由IANA分配);
- T = 1表示为多播,表示用户可使用的临时多播地址
③ Scope:4比特。用来标记此多播组的应用范围。
④ group ID
标识多播组(可能是永久的,也可能是临时的,范围由scope定义)
2) IPv6永久分配的多播地址
目前的永久分配(“周知”)多播组如下:
保留的多播地址:
- FF00::---FF0F::(共16个地址)
所有节点的地址:
- FF01:0:0:0:0:0:0:1 (节点本地)
- FF02:0:0:0:0:0:0:1 (链路本地,在本地链路范围内的所有节点)
所有路由器地址:
- FF01:0:0:0:0:0:0:2 (节点本地)
- FF02:0:0:0:0:0:0:2 (链路本地,在本地链路范围内的所有路由器)
- FF05:0:0:0:0:0:0:2 (站点本地)
被请求节点的地址:
- FF02:0:0:0:0:1:FFXX:XXXX/104
上述地址由被请求节点的单播或任播地址形成:取被请求节点单播或泛播地址的低24比特,在前面增加前缀FF02:0:0:0:0:1:FF00::/104构成。
对于节点或路由器的接口上配置的每个单播地址或者任播地址,都会自动生成一个对应的被请求节点的组播地址。只在本地链路范围有效。
特点:
- 在本地链路上,被请求的节点的组播地址通常只包含一个用户
- 只要知道一个节点的IPV6地址,就能计算出它的被请求节点的组播地址,例如,和IPv6地址4037::01:800:200E:8C6C对应的被请求节点多播地址是FF02::1:FF0E:8C6C。
作用:
- 在IPV6中没有ARP,ICMP替代了ARP的功能,被请求节点的组播地址用IPv6邻居发现协议中,用在邻居请求报文中,由于只有后24比特单播地址相同的节点才会接收目的地址为此地址的报文,因此减少了通信流量(和IPv4 ARP相比)。
- 用于重复地址检测(DAD:Duplicate address Detection),无状态配置时,节点利用DAD验证在其本地链路此地址是否被使用。
7、必须支持的Ipv6地址
1) 节点必须支持的IPv6地址
- 每个主机必须把下列地址作为自身的地址
- 自身接口的链路本地地址
- 分配的单播地址
- 环回地址
- 所有节点多播地址
- 每个分配的单播或多播地址对应的被请求节点多播地址
- 此主机所属的其它多播组地址
2) 路由器必须支持的IPv6地址
- 接口配置为路由器接口的子网路由器泛播地址
- 任何其它路由器配置的泛播地址
- 所有路由器多播地址
- 此路由器所属的其它多播组地址
二、IPv6地址分配
1、地址配置
IPv6支持无状态地址自动配置和状态地址自动配置两种地址自动配置方式。
无状态地址自动配置:
- 无状态自动配置不需要手动配置主机,只需对路由器进行很少的配置(如果需要的话),而且不需要其他服务器。无状态机制允许主机生成其本身的地址。无状态机制使用本地信息以及由路由器通告的非本地信息来生成地址。
- 需要配置地址的网络接口先使用邻居发现机制获得一个链路本地地址。网络接口得到这个链路本地地址之后,再接收路由器宣告的地址前缀,结合接口标识得到一个全球地址。IPv6节点通过地址自动配置得到IPv6地址和网关地址。
在自动配置过程中,主机将执行以下操作:
- 为每个接口创建链路本地地址,该操作不要求链路上有路由器。
- 检验地址在链路上是否唯一,该操作不要求链路上有路由器。
- 确定全局地址是应通过无状态机制、有状态机制还是这两种机制来获取。(要求链路上有路由器。)
状态地址自动配置:如动态主机配置协议(DHCP),需要一个DHCP服务器,通过客户机/服务器模式从DHCP服务器处得到地址配置的信息。
2、地址分配
① 全球单播地址空间分配
因特网分配地址权威机构(IANA)负责IPv6地址空间的分配。目前IANA从整个可聚合全球单播地址空间(格式前缀为001)中取2001::/16进行分配。
② IPv6实验网络地址分配(6BONE)
6BONE网络是全球范围的IPv6实验网络,使用网络前缀3ffe:0000::/16。每个伪顶级聚合分配3ffe:0800::/28范围内的/28前缀,最多支持2048个伪顶级聚合。处于末端的站点从上游提供者得到/48前缀,每个站点内还可细分为多个/64前缀。
6BONE网络按层次化结构分配地址,地址空间由IANA定义配,分配策略在RFC2921(6BONE伪顶级聚合和网络层聚合格式)中定义。
三、IPv6的使用
1) 首先启用ipv6,方法如下:
本地测试使用windows环境。
或者命令行形式:ipv6 install
XP系统下可以使用netsh-->interface-->ipv6-->install来安装ipv6协议。
也可以如下图所示,协议部分添加,后边会有ipv6的安装。
启用ipv6后,主机就会自动生成一个ipv6链路本地地址。
2) 也可以手动配置ipv6地址
可以使用界面配置:
也可以命令行配置:
- cmd
- netsh
- i ipv6
- show i 记住 本地连接 中的索引值
- add address int=索引值 ipv6地址
- show address int=索引值
3) ipv6地址查看
ipconfig
查看时会发现有隧道地址如下:
Ipv6和ipv4通过隧道通讯,是要有特别的协议和设备来支持,比如上图的teredo,这个有机会下一篇案例再介绍。
启用teredo就会有teredo的隧道地址,一般用来和外部主机对通。本地测试使用本地链路地址或者手动配置的地址就可以了。
注:一般链路本地自动生成是根据MAC地址使用EUI-64格式作为接口ID,但是我电脑上的却不是,查看其他几个电脑的就是根据MAC生成的,像是使用随机码生成方式,只要地址在链路内唯一就可以。
4) 关于ipv6的几个点简介
① PfcNtop 和 PfcPton
PFC模块提供的PfcNtop、 PfcPton封装了inet_ntop和 inet_pton的功能,主要用来做ip地址和其字符串表示形式的转换。
② 结构体PFC_IPADDR
- typedef struct PROTO_API tagPFC_IPADDR
- {
- PFC_TRANSPORT_TYPE m_emType; ///< transport type
- PFC_IPADDR_UNION m_tAddr; ///< IP address
- u16 m_wPort; ///< port number, host format
- PFC_DISTRIBUTION_TYPE m_emDistribution;
- }
协议组件提供的用来表示ipv4 or ipv6的结构体。
- m_emType指示是ipv4还是ipv6,默认值是无效值none。
- m_tAddr是union类型,表示ipv4 oripv6的具体ip地址。其中ipv6的具体表示如下:
- /// PFC IPv6 address
- typedef struct
- {
- u8 m_abyIP[PFC_IPV6_ADDR_SIZE]; ///< 16 byte IP address
- u16 m_wScopeId; ///< scope
- } PFC_IPADDRv6;
PFC_IPV6_ADDR_SIZE 为16个字节的宏。所以ipv6地址使用16个字节的u8数组表示。m_wScopeId主要是给链路本地地址使用,因为链路本地地址在一个链路上唯一,而一个主机可以使用相同的链路本地地址接入两个不同的链路,那么就要用scopeid来区分。此字段对应sockaddr_in6结构体里的uint32_t sin6_scope_id。经测试,如果系统只有一个链路本地地址,win7、win10不用填此字段对通链路上的机器也没有问题,但是和xp系统的对通就有问题。
③ getaddrinfo函数
获取ip地址,gethostbyname和gethostbyaddr这两个函数仅仅支持IPv4,getaddrinfo可以支持ipv4和ipv6,返回的是一个sockaddr结构的链表而不是一个地址清单。这个方法,协议组件暂未提供封装,有需求自己欢快使用吧。
最后
IPv6涉及的东西特别多,有些概念上的东西有时很不容易理解,必须查资料啊查资料然后理解它们。本篇只根据rfc4291 介绍了IPv6的部分内容,以后还需要查阅更多的资料IPv6的其他方面的内容。