OSI & TCP/IP 参考模型

理解协议之前先说说两个计算机系统之间通讯的常用概念模型:

OSI
开放系统互联参考模型(Open System Interconnect Reference Model),是用于特征化标准化电信通讯/计算机间通讯(而不需要关心其底层实现和技术细节)而被国际标准化组织定制的,其一共有 7 个抽象层。
TCP/IP 参考模型
同样是一个概念模型,其实它正式的名称应该是 互联网协议套件(Internet protocol suite),因为其原始协议为 TCP 和 IP 协议而被一般称为 TCP/IP 参考模型。它有时也因为其开发受到美国国防部下属机构资助而以 DoD 模型(Department of Defense Model) 被人知晓。
这个套件包含了一系列常用的网络通讯协议,定义了端对端通讯如何打包、确定地址、发送、路由寻址、接收数据。它一共有 4 个抽象层。

注意的是,这边并不讨论过于抽象化的概念,仅仅是描述以便于理解各协议作用和相互的联系。

两个概念模型的抽象层对比:

OSI Model Protocol Examples TCP/IP Model
Application Layer DNS,FTP,HTTP,Telnet,SMTP Application Layer
Presentation Layer TLS,MIME,XDR
Session Layer PPTP,SOCKS
Transport Layer TCP,UDP Transport Layer
Network Layer IP,ICMP,IPsec Internet Layer
Data Link Layer ARP,NDP,MAC,PPP Link Layer
Physical Layer DSL,IEEE802.11,USB,Bluetooth

数据包在发送时会先一层层地添加各种协议头,而在接收时则一层层剥去各种协议头,以接收一个 http 协议数据为例:

http 封包过程

这是一个简单且常见的例子,如果被通过 TLS 加密了的话,那么在添加了 HTTP Header 后会给整个 HTTP Data 做加密后再次添加 TCP Header 。

针对 TCP/IP 模型来看,虽然普遍认为是 4 层模型,但是如果把 Link Layer 再划分两层来看对于设备/数据方面的描述往往会更加方便,这也就是一些 5 层 TCP/IP 模型的说法了。依旧看图:

TCP/IP 模型图解

Packet, Frame, Bit 不再叙述,理解为对应层的简单表述单位即可,至于哪些具体设备用在哪一层,这个看设备功能对应的协议即可。

IP

IP(Internet Protocol) 位于 OSI 模型的第三层,用于封装上层数据包给其添加 IP 头传给下层。这是一个无状态的协议。

IPv4

RFC 791 中定义

IP 头格式及字段说明

头格式如下:

bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
0 Version IHL DSCP ECN Total Length
32 Identification Flags Fragment Offset
64 Time to Live Protocol Header Checksum
96 Source IP Address
128 Destination IP Address
160 Options (if IHL > 5) Padding

字段说明:

Version
0100, 即十进制的 4 ,单纯的版本号
IHL
因特网报头长度(Internet Header Length) 顾名思义,定义了 IP 头的长度,其中一个 bit 代表 32bits 的长度。因为 Options 是可变的,所以最小为 0101(160bits),而最大为 1111(480bits)。
DSCP
差分服务代码点(Differentiated Services Code Point)RFC 2474 中定义,这个 6bits 的字段服务于 差分服务(DiffServ) 的,差分服务是一个计算机网络架构,其定义了一个简单、可扩展的粗粒度的网络流量分类和管理机制,并为现代网络提供了 服务质量(Quality of Service)
ECN
显式拥塞通知(Explicit Congestion Notification)RFC 3168 中定义,它提供了端端间在不丢失数据包的情况下的网络拥塞通知(需要网络基础设备支持并且通信两端启用的情况下)。
DSCP 字段和 ECN 字段替换了过时的 服务类型(Type of Service) 字段。
Total Length
以字节为单位定义了整个 IP 包的大小。最少为 20 字节(只有包头没有负载的情况下),最大为 65535(0xffff) 字节。规定所有主机必须支持最小 576 字节的 IP 数据报(datagram) [1],不过有时候链路本身可能会限制的更加厉害,那么超出大小的数据报就会 被分片(be fragmented) , 这将由主机或者路由器所处理。
Identification
用于识别属于单独一个数据报的一组碎片,不过有一些试验性的工作也建议把这个用在其他的方面,比如添加包追踪信息以帮助追踪用有欺骗性源地址的数据报,但是 RFC 6864 已经禁止这样子的使用了。
Flags

3 个用于控制/识别碎片的 bit 字段:

  • bit0: 保留字段,必须置 1
  • bit1: (DF) 0 = 可以分片(May Fragment) , 1 = 禁止分片(Don't Fragment) ,在 DF 被置 1 的情况下,如果路由必须分片数据报后才发送,则该数据报会被丢弃,一般用在当需要发送给没有足够资源处理碎片的主机的情况下。这个位也可以用来做 路径最大传输单元发现(PMTUD)(Path Maximum Transmission Unit Discovery)
  • bit2: (MF) 0 = 最后的碎片(Last Fragment) , 1 = 更多碎片(More Fragments) ,对于被分片的数据报来说, 除了最后一个的其它碎片 MF 都被置 1,最后一个置 0,如何将最后一个碎片与其它未被分片的数据报区分,则依赖下一个描述字段。
Fragment Offset
碎片偏移量以 8 字节块为一个单位,第一个碎片偏移量为 0,最大的偏移量为 (213 − 1) × 8 = 65528  bytes ,加上 IP 头的最小长度,可以达到 IP 数据报的最大长度了。而区分一个碎片组的最后一个碎片和未被分片的数据报,也是由这个字段来判断的。
Time To Live
8 位的 TTL 字段限制了数据报的生命周期,避免了其被永远得留在网络上。这个字段在理论上是以秒为单位的,不过每一个 跃点(hop) 最少也需要给 TTL 减一,所以实际上使用是按照跃点限制数来使用的, IPv6 中也已经做了字段的重命名。当 TTL 字段变成 0 时,当前跃点会丢弃这个数据报,并发送一个 ICMP 超时报文(Type=11)给该数据报发送者。
Protocol
定义了 IP 数据报的数据部分所使用的协议类型,详细的协议序号可以看 List of IP Protocol Number
Header Checksum

IP 头校验和是用来被路由检查当前 IP 包的头是否正确完整的。它是一个 16 位的把 IP 头以 16 位反码格式相加的和的 反码(one's complement) [2] ,计算校验和时需要把本字段全置 0。每当数据报到达一个路由后,会先计算头的校验和和头本身提供的进行比较以验证,如果校验和不匹配则丢弃该数据报,匹配的情况下则减小 TTL 值,并重新计算校验和。至于如何计算校验和和验证的,举例如下:

以下数全以 16 进制表示
假设有一个 IP 头 4500 0034 eb35 4000 4006 d1fc 0a00 0713 2f5a 3d25 ,其中 d1fc 就是其携带的 IP Header Checksum
计算校验和
替换校验和字段为全 0 后相加 4500 + 0034 + eb35 + 4000 + 4006 + 0000 + 0a00 + 0713 + 2f5a + 3d25 = 22e01
因为机制是需要以 16 位反码格式相加,可以注意到这边出现了循环进位的情况,那么再次相加 0002 + 2e01 = 2e03
再取其反码 ~2e03 = d1fc
验证校验和
只需要在计算时不替换校验和字段内容,以计算校验和相同方式进行计算,判断最后结果是否为 0000 即可。
Source Address
定义了数据包发送者所对应的地址,可以被 网络地址转换(network address translation) 设备所修改。
Destination address
定义了数据包接收者所对应的地址,同样可以被网络地址转换设备所修改。
Options
这个字段是可选的,当 IHL 大于 5 时意味着这个字段存在有内容。当本字段的结束位置和 IP 头结束位置不一致时,需要在本字段结束位置加上 EOL(0x00)(End of Option List) 选项。
本字段一共有两种格式:
  • 一个单一的 8 位的 选项类型(option-type)
  • 8 位选项类型 + 8 位的 选项长度(option-length) + 当前的多个 8 位的 选项数据(option-data) 。选项长度是以 8 位为基本单位来计算的包括选项类型字段、选项长度字段和选项数据字段的总长度。

选项类型字段又分为三个字段:

  • 1 位长度的 复制标记(copied flag) ,当置 1 时意味着数据报分片后,当前表示的选项将会复制到所有碎片中。
  • 2 位长度的 选项类别(option class) ,单纯的指示选项类型,0 代表控制类,1 和 3 是保留的,2 代表调试和测量类。
  • 5 位长度的 选项序号(option number) ,这个就基本用来定义那种选项了,具体的可以看 IP Option Numbers
Padding
顾名思义,这个字段是用来补全的。IP 头的总长度需要满足 32 bits 的倍数,当 options 字段满足不了 32 bits 的倍数时,则在其后添加 0 以补全到 32 bits 倍数长度。

分片和重组(Fragmentation and Reassembly)

IP 数据报的传输是独立于底层传输技术的,而底层传输会因为硬件的不同而导致拥有不同的传输速度,以及不同的 最大传输单元(MTU)(Maximum Transmission Unit) 。当传输的数据报大小超过了当前的 MTU,那么数据报就可能被分片。不过 IPv6 的实现不一样,下文会有说明。

分片如图:

IPv4 分片过程

图示已经较为清晰地展示了一个数据报被分片的过程,简单总结下就是: 当一个路由器接收到一个数据包,它会检测目标地址并确定发送该数据包的网卡接口以及该接口对应的 MTU,如果数据包长度大于该 MTU 并且 IP 头的 Flags.DF 字段为 0,那么该数据报就可以被分片。分片的最大数据长度为 MTU - Header Length 。分片后所有碎片的 Identification 字段是一样的,Total Length 字段自然会改变,除了最后一个碎片外,其他碎片的 Flags.MF 字段会置 1,即使后续再次被分片,MF 已经置 1 的碎片被分片后依旧置 1,碎片偏移量计算是前一个碎片的数据长度(不包含 IP 头)除以 8,最后重新计算每个碎片的 IP 头校验和。

至于重组,当数据包满足以下两个条件之一即可判断为碎片:

  • Flags.MF 位被置 1
  • Fragment Offset 非零

当接收者收到碎片后,会根据碎片 IP 头信息内的源/目标地址、协议 ID 和 Identification 字段来判断属于一个数据报的碎片,当接收者接收到本数据报的 Flags.MF 为 0,Fragment Offset 非零的碎片时,会根据这个碎片的偏移量计算出本数据报的数据长度(不包含 IP 头),计算方法是 offset of last fragment × 8 +  data length of last fragment = total data length (bytes) 。当判断得出获取的数据报碎片的数据总长度与计算长度相等,则开始按照碎片偏移量对碎片进行重组。

IPv6

RFC 2460 中定义

合理的 IPv6 地址总数大约有 3.4 × 1038 个,约是 IPv4 地址总数的 7.9 × 1028 倍,可以有效解决目前 IPv4 地址资源匮乏的问题。除了地址更多外,IPv6 还新加了一些 IPv4 下没有的功能,比如更简单的地址分配方式( 无状态地址自动配置(stateless address autoconfiguration) )。IPv6 的标准化了子网的主机标识符部分为 64 bits 以方便自动从数据链路层获取地址信息( 媒体访问控制(MAC)(media access control) 地址)来格式化它。因为 IPv6 子网的标准大小是 264 ,所以实际可用的 IPv6 地址空间会小很多,但也正因为如此,改善了网络管理。

IPv6 头和 IPv4 头是不同的,所以也无法互操作,两个协议版本间的数据交换需要依赖过渡机制,比如 6to4、6in4、Teredo 等,这些就不解释了。

地址表示

详细的可以看 RFC 4291

地址长度一共是 128 个字,总共分为 8 组每组 16 个字,通常以 16 进制来表示,比如 2001:470:00f1:0000:54a8:22a0:e7b0:4f572607:f8b0:4005:080a:0000:0000:0000:2004 。地址本身可以按照两条规则来进行简化:

  • 每一个组的从高位开始的连续零可以省略,比如上述的 00f1 即可写成 f1,那么就变成了 2001:470:f1:0000:54a8:22a0:e7b0:4f57
  • 连续的全为零的组可以用双引号 :: 进行替代,带有多个连续全零组的地址只能替代一次,不然会在解析地址是造成混淆,同时如果全零组是单独一个则不应该用 :: 来代替。那么上述两个地址最后的简化形式就是 2001:470:f1:0:54a8:22a0:e7b0:4f572607:f8b0:4005:80a::2004

当一个地址有两个位置可以简化为 :: 时,优先简化最左边的,比如 2001:db8:0:0:1:0:0:1 应该简化为 2001:db8::1:0:0:1

本地回环地址是 ::1/128

单播/任意播(Unicast/Anycast) 地址一般由一个 64 位的用于路由的网络前缀和一个 64 位的用于确定主机网卡的接口标识符位组成,格式如下:

IPv6 单播/任意播地址组成

网络前缀又由路由前缀和子网 ID 构成,它们的大小是不定的,接口标识符位的值可以根据接口 MAC 地址以修改过的 EUI-64 [3] 格式生成,也可以由 DHCPv6 服务器生成,也可以自动随机生成或者手动指定。

本地链接(Link-Local) 地址是用于单链接上通信以实现地址自动配置、邻居发现等功能的,路由器不应该转发任何源/目的地址为 Link-Local 地址的数据包,其格式是:

IPv6 Link-Local 地址组成

IPv6 的 多播(multicast) 地址是一组接口(通常属于不同的节点)的标识符,一个接口也可以属于任意个多播组。多播地址格式如下:

IPv6 多播地址组成

flgs 字段是 4 个标签的组合,从高到低依次为:

0 R P T
  • 最高位目前为保留字,初始化为零。
  • R 位的定义和使用在 RFC 3956
  • P 位的定义和使用在 RFC 3306
  • T 位为 1 意味着这是一个被 IANA ( 互联网号码分配机构(Internet Assigned Numbers Authority) )永久分配的多播地址,为 0 意味着是一个非永久分配的多播地址。

scop 字段用于限制多播地址的适用范围,不看了,需要的时候直接再看 RFC 吧,以及相关的常用 Multicast addresses

一类比较特殊的单播地址是 ULA ( 唯一本地地址(Unique Local Address) ),类似于 IPv4 的私有地址,可用于私有网络,地址字段是 fc00::/7 ,无法在全球网络上被寻址到,定义在 RFC 4193 。注意的是虽然说其可以被分为两个 /8 的地址组,但目前仅 fd00::/8 可以被本地分配, fc00::/8 则可能会在将来被另外定义。

而有关任意播地址的保留地址,有如下几种(相关的 RFC 有 RFC 2373RFC 2526 ):

  • 子网路由的任意播地址,在语法上就类似把普通单播地址的接口标识段全置 1,当数据包发送到子网路由的任意播地址时,数据包会发送到该子网的一个路由器上,比如当移动主机需要与其子网的一个移动代理通信的时候,其格式为:
子网路由任意播地址组成
  • 其它保留的子网任播地址格式分为两种

    • 一种是当当前子网接口标志段是 64 位的修改版 EUI-64 [3] 格式时,接口标识段从高位数第 7 位的 universal/local 位必须置 0,表示地址不是全局唯一的,对应字段的其它位全置 1。详细的格式为:
    保留子网任意播地址组成0
    • 另一种是子网接口标识段非修改版 EUI-64 [3] 格式并且连长度也可以不等于 64 位,相比而言,接口标识段除了最低位数的 7 位其他全置 1,其格式为:
    保留子网任意播地址组成1
    • 就这两种格式的相同字段做说明,子网前缀就是和普通单播地址的子网前缀一样处理对待。最低位的 7 位的任播 ID 则确定了当前子网下一个特定的任播地址,目前仅 0x7e 是一个已经被定义的任播 ID,代表 移动 IPv6 家代理任播(Mobile IPv6 Home-Agents anycast) ,其他 0x00-0x7d & 0x7f 都是保留中。

其他保留地址可以看 Reserved IPv6 addresses

为了更高效的 路由聚合(route aggregation) ,目前分配在互联网上可用的 IPv6 地址只有全部的八分之一,为 2000::/3 ,剩下的地址则有用于其他目的或者留给了今后使用。

IP 头及字段说明

相对于 IPv4 的一些主要改变:

  • 长度是 IPv4 头的至少两倍,但是因为一些简化处理机制,路由在处理 IPv6 头的时候反而更加高效。
  • 不再实现路由上的 IP 分片,主机本身可以做 PMTUD 来确保发送数据包足够小以使得可以到达目标端,或者直接发送小于默认 MTU(1280 bytes) 的包。
  • 没有了头校验和,校验由链路层和更高一层协议合作完成,注意的是在 IPv4 中 UDP 校验和为 0,也就是没有校验的,但是在 IPv6 中必须要实现校验。
  • TTL 字段更名为 Hop Limit 以符合其实际的身份。
固定头格式
bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
0 Version Traffic Class Flow Label
32 Payload Length Next Header Hop Limit
64 Source Address
96
128
160
192 Destination Address
224
256
288

字段说明:

Version
4 位的固定 IP 版本 0110(6)。
Traffic Class
8 位的这个通信类型段被分成 6 位的 DSCP 字段和 2 位的 ECN 字段,功能参见 IPv4 对应字段说明。
Flow Label
20 位的流标签字段被发信端用来标记数据包的序列以暗示路由/交换机在存在多个出口通路的情况下走固定的通路以避免包被重新排序,一般用于实时应用。
Payload Length
16 位的负载长度字段是用于表示包括扩展头在内的所有 IPv6 负载的长度的。当本数据包有携带 特大包(Jumbogram) 负载选项的 逐跳(Hop-by-Hop) 选项扩展头时,本字段长度需置 0。
Next Header
顾名思义,表示紧接着的下一个 header 的类型,可以是高一层(传输层)对应负载的头类型,也可以是本层的相关头类型(比如 ICMPv6),也可以是扩展头类型。类型序号是和 IPv4 Protocol 字段所对应的共享的,同样可以看 List of IP Protocol Number
Hop Limit
替代了 IPv4 的 TTL 字段,当数据包每经过一个中间节点便把值减一,当为 0 时,丢弃该数据包。
Source Address
发送端的 IPv6 地址
Destination Address
接收端的 IPv6 地址
扩展头

与 IPv4 不同,IPv6 的可选网络层信息是存放在一个单独的介于 IPv6 头和对应负载头(比如 TCP、IMCPv6 等)之间的扩展头里面的。一个 IPv6 数据包可以包含零、一或者多个扩展头,包含多个扩展头时的数据包可以如图表示:

IPv6 扩展头

值的注意的是,扩展头不会在数据包传输过程中被处理,并且在目的地接收到本次数据包后,会依次处理扩展头而不能跳过某一个直接处理下一个。但有一个例外必须在传输过程中被所有节点处理的,那便是 Hop-by-Hop Options 头,当存在这个头时,该头必须紧跟在 IPv6 固定头后面。

为了使后续的头可以继续保证按照 8 字节边界对齐,每一个扩展头的长度必须为 8 字节的倍数。

当一个节点无法识别 Next Header 字段的值或者在非固定头的 Next Header 字段识别到 0 时,需要向数据包的发送源发送代码值为 1 ( 1 代表「遇到无法识别的 Next Header 类型」)的 ICMP 参数问题(Parameter Problem) 信息,并将该 ICMP 信息的指针字段值设置为无法识别的字段相对于原始 IPv6 包的偏移量。

建议的数据包内扩展头连接顺序如下(强烈建议):

  • (IPv6 header)
  • Hop-by-Hop Options header (0)
  • Destination Options header (60)
  • Routing header (43)
  • Fragment header (44)
  • Authentication header (51)
  • Encapsulating Security Payload header (50)
  • Destination Options header (60)
  • (负载协议头)

除了 Destination Options header 最多可以出现两次之外,其他的扩展头最多只能出现一次。上述说明的顺序以及出现次数是一个建议的并非强制的(除了 Hop-by-Hop Options 必须紧跟 IPv6 头之后出现且仅能出现一次之外),节点也应该要有处理非建议顺序/次数扩展头的能力。

当 Next Header 字段的值为十进制的 59 时,代表没有其他的头/负载跟在这个后面了,IPv6 包在这个头结束。如果说 IPv6 头的负载长度大于所有扩展头的长度的话,那么意味着还是有负载在这个 IPv6 的数据包下的,这种情况下,本数据包经过的路由器并不会来处理这些负载,但主机则会忽略掉这些负载。

大多数扩展头的通用格式可以看 RFC 6564 ,已经定义的是不被这个 RFC 所描述的,又其是 Fragment Header,相去甚远。下面来描述常用的扩展头:

IPv6 扩展头的 选项类型(Option Type) 八位的前三位有单独的定义及说明,详细的看 RFC 2460 4.2 节。

Hop-by-Hop Options header 和 Destination Options header 都是用来携带可选信息的,只不过前者携带的信息会被经过的每一个节点所处理,而后者携带的信息仅会被目的节点所处理,它们的扩展头结构相同,如下:

bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
0 Next Header Hdr Ext Len Options and Padding
32 Options and Padding
64
Optional Options and Padding
...
...

依次来说明字段:

Next Header
和 IPv6 头的同名字段一致,表示下一个头的类型
Hdr Ext Len
表示当前这个扩展头的长度,注意计算时不包括最开始的 8 个字节,也就是 Actual Lenght (bytes) = (Hdr Ext Len + 1) × 8 。同时也意味着最小的长度为 8 个字节。
Options
包含了一个或者多个的 类型-长度-值(Type-Length-Value) (TLV)编码的选项。同时在当选项长度不足以满足 8 个字节的倍数时填充 padding。
Padding

分两种格式:

  • Pad1 格式,长度为一个字节,值为零,可以理解为就是填充了一个字节的零。
  • PanN 格式,区分于上述格式,当需要的 padding 大于一个字节的时候,不应该填充多个 Pad1 而是应该使用 PadN,详细字段格式如下:
bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ...
0 1 Opt Data Len ZERO ...

第一个字节为类型, Opt Data Len 代表本 PadN 字段从第 16 位开始需要填充多少字节的零,这样子就可以实现 2 字节到 N(N>2) 字节的填充了。

当发送端需要发送的数据包大于链路上的 MTU 时,发送端会把数据分片,然后将碎片作为单独的数据包发送,并将相关信息存放在 Fragment 扩展头中(而发送路径中间节点不会对数据包做任何分片操作,上述已有相关说明)。本扩展头格式如下:

bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
0 Next Header Reserved Fragment Offset Res M
32 Identification

字段说明:

Next Header
和之前一样,表示下一个头的类型
Reserved
保留字段,初始化为零,接收时会忽略
Fragment Offset
这个 13 位的字段存储的值是以 8 字节为一个单位来表示的,代表了本扩展头后跟的数据相对于原始数据包的偏移量。
Res
保留字段,初始化为零,接收时会忽略
M
这是一个标记, 1 代表还有更多的碎片, 0 代表这是最后一个碎片。
Identification
这个 32 位的字段是用于区分不同原始包的碎片的。每当发送端判断一个数据包需要被分片的时候变生成一个(一般是较上一个相同源/目的地址的碎片的 ID 加一,并循环计数)。接收端则根据此 ID 以及源/目的地址判断相同的原始数据包。

其他的扩展头可以看对应的 RFC。

无状态地址自动配置(SLAAC)

当节点的系统启动时,该节点会自动为每一个启用 IPv6 的接口创建一个前缀为 fe80::/64 的 Link-Local 地址,这个过程利用了邻居发现协议 [4] 的一个组件,是独立的和 SLAAC 无关的。主机会发送一个 路由请求信息(Router Solicitation message) 到路由器,然后路由器会返回一条 路由公告信息(Router Advertisement message) 给主机,一般携带一个 64 位地址前缀,而低 64 位的接口标识段则根据修改过的 EUI-64 [3] 格式生成。

当地址生成好了之后,生成的地址被称为尝试性地址,为了确保地址的唯一性,本节点会加入到当前尝试性地址的 被请求节点多播地址组(Solicited-node multicast address) 以及面向所有主机的多播地址 ff02::1/128 组中,并以当前尝试性地址为目标地址,未指定地址 ::/128 为源地址发送 邻居请求信息(Neighbor Solicitation message) 。只有当本节点既没有收到以当前尝试性地址为目标地址的邻居请求信息,也没有收到以当前尝试性地址为源地址的 邻居公告信息(Neighbor Advertisement message) 时,才算确定了地址的唯一性。

每一个 IPv6 地址都会有生命周期,在没有被配置的情况下是无限长的。如果要配置的话,可以被路由器返回的路由公告(RAs)所配置,也可以手动修改,地址的生命周期可以被 RAs 所更新。如果地址没有被更新或者就是达到了生命周期限制了,那么该地址就会被弃用,不会再有连接使用这个地址直到再次被分配。

当使用 SLAAC 时,默认的接口标识字段由对应的接口 MAC 地址所调整而来,这样子就可以根据当前 IPv6 地址长期追踪到单独的一台机器,甚至一个用户。为了避免用户身份和一个 IPv6 地址长期绑定在一起,节点也可以以基于时间的随机数为基础来生成接口标识段并赋予该地址一个较短的生命周期。

TODO: 详解邻居发现协议以及 ICMPv6

TODO: 整理同一网卡多个 IPv6 地址时,默认地址选择问题 ,参考 RFC 6724

TCP

传输控制协议(Transmission Control Protocol) 是 TCP/IP 模型的一个主要协议,它为 IP 网络下的程序通讯提供了可靠、有序、带错误检查的字节流传输。TCP 优化了传输的准确性(确保所有收到的字节与发送时候的字节一致且顺序一样)而并非及时性,可能会因为等待乱序的消息或者需要重传的消息而耗费好多秒,所以不适用于诸如语音之类的要求实时性高的场景。

直接看 wikipedia 吧,有时间再整理了。 下同

UDP

未完

未完

注解

[1]OSI 参考模型中定义了在网络层的数据单元是 数据包(packet) ,但是 IP 定义其传输的数据名为 数据报(datagram) ,所以两者在本文会存在互用的情况。个人认为,数据包不一定是数据报,但 IP 数据报一定是数据包。
[2]反码也被成为一补数/一补码,在做相加/减运算时,即使没有计算溢出,也会因为出现 循环进位(end-around carry) 或者 循环借位(end-around borrow) 而导致运算错误,所以当出现这两种情况时,需要把超出部分的 bit 加/减到中间结果的最右,以得到最后结果。而大部分计算机整数运算时所采用的 补码(two's complement) (也被称为二补数)则没有这个问题。
[3](1, 2, 3, 4) EUI( 扩展唯一标识符(Extended Unique Identifier) )-64 是 IEEE 所声明的商标,是形成 MAC 地址的规则之一。其一般派生自对应的 48 位的标识符,在 48 位标识符中间插入 FF:FE 即可,比一个 48 位的标识符 50:6a:03:cb:1b:0b 所对应的 64 位标识符为 50:6a:03:ff:fe:cb:1b:0b 。而当需要用于表示 IPv6 的接口标识段的值时还需要进一步修改,修改方法是把 EUI-64 地址的从高位数第 7 位( Universal/Local 位)取反,那么就变成了 52:6a:03:ff:fe:cb:1b:0b ,针对一个网络前缀为 2001:470:f1:0: 的 IPv6 地址,此时完整的表示就是 2001:470:f1:0:526a:03ff:fecb:1b0b
[4]邻居发现协议(Neighbor Discovery Protocol) (NDP,ND) 工作在 TCP/IP 参考模型的链路层,结合 IPv6 一起使用,其任务是有,自动配置节点地址、发现链路上的其它节点、确定其它节点的地址、重复地址检测、发现可用路由器及 DNS 服务器、发现地址前缀(子网前缀?)、维护其它已经激活的邻居节点的可达性信息。
显示 Disqus 评论(需自备梯子)