30 January 2020
Network(4) -- The Internet Protocol (IP): IPv4, Addressing, IPv6, and More
by Jerry Zhang
IPv4的数据包格式
network layer的数据包叫做datagram.
- 版本号:4 bits,路由器通过版本号,决定怎么读取该数据包后面的内容。
- 头部长度:4 bits,因为IPv4的数据包可以包含未知数量的options内容,所以需要这个长度来决定这个数据包的有效负载(真正的内容,也就是从transport layer传来的segment)从哪里开始。大多数IP数据包都不含可选内容,因此一般来说,头部的长度是20 byte(上图里每一行是4个bytes, 也就是说前5行是header,第6行开始后面的全是data)
- 服务类型Type of service(TOS):比如real-time的数据包。TOS中的两个bits还可以用来标注网络拥堵。
- 数据包长度Datagram length: 16 bits, 数据包的总长度,头部加数据,单位是byte。最大值为65535。但是一般来说很少超过1500bytes,因为Ethernet frame的payload最大就是1500。
- Identifier, flags, fragmentation offset(这三个词不知道怎么翻译):用来做IP分片的。
- 存活时间time-to-live(TTL):用来保证这个数据包不会在网络中永远循环下去。每经过一个路由器,它就会减1。如果为0了,路由器必须扔掉它。
- 协议:用来说明这个数据包要传给transport-layer的哪个协议,比如6代表TCP,17代表UDP。它的功能跟传输层中的端口号类似。这个协议号是网络层和传输层之间的纽带,而端口号是传输层和应用层之间的纽带。
- Header checksum: 用来帮助路由器检查bit error。把每两个bytes看作一个数,然后用1s complement求和。如果最高位有进位,要加回到最末位。最后把1变成0,把0变成1。这样最后把所有的数包括checksum都加到一起,理论上应该是1111111111111111。路由器一般会丢掉那些检测到错误的包。每次路由器都要重新计算checksum,因为TTL存活时间和options这两个字段的值是变化的。为什么在传输层和网络层都需要检查错误呢?首先,在IP层,只检查IP的header,而TCP/UDP检查整个数据包(segment)。其次,TCP不一定非要使用IP协议,也可以使用其他协议比如ATM。而IP也可以包含一些不通过TCP/UDP传输的数据。
- 源地址和目标地址:当发送者创建datagram数据包时,会把它自己的IP地址放到source IP address这个字段,并把最终的目标地址放到destination IP address字段。
- 可选内容:很少使用,因此为了减少开销,把它定义为可选项。但也带来一些麻烦,比如数据不知道从哪里开始了。而且,一些包需要处理可选项而另一些包不需要,所以路由器处理包的时间可能差别很大。
- 数据:大多数情况下,数据字段包含的是TCP or UDP的传输层数据包。
一个IP数据包包含20个字节的头部信息(假设没有可选项)。如果携带的是TCP segment,那么这个数据包就有40个字节的头部信息(IP头20个字节,TCP头20个字节)
IPv4数据包分段
Ethernet frames可以携带最多1500字节的数据。链路层可以携带数据的最大值叫做maximum transmission unit(MTU)。因为IP包需要封装在链路层的包里面,所以IP包的长度受到MTU严格的限制。限制大小不是问题,问题是可能用到不同的链路层协议,每个协议可能会有不同的MTU。
假设现在路由器收到一个IP datagram数据包,正想转发出去,结果发现输出链接的MTU小于当前这个数据包。怎么办?只能把它拆分成多少链路层的数据包,link-layer frame,然后分别发出去。这些小包叫做fragment碎片。
这些碎片到达之后需要重新组装。IPv4的设计者感觉重新组装会使这个协议非常复杂并使路由器性能下降。因些只在最终端才去重新组装。
当终端主机接收到一连串的数据包后,它需要确定哪些是碎片,哪些是原来的完整的。如果一些包是碎片,它还要继续确定什么时候收到的上一个碎片,怎么把这些碎片重新组装好。因此IPv4的设计者设计了identification, flag, and fragmentation offset这三个字段。当datagram数据包被创建时,发送的主机就盖个戳,指定id和发送接收地址。一般来说,主机每发送一个datagram数据包,它就增加一个id号。当一个路由器需要分成碎片时,就用原来的起始地址,目标地址,以及ID来区分。当最终的接收者从一个发送者收到一系列包的时候,它就会检查id来确定哪些是属于同一个原始数据包的。因为IP是不可靠的服务,为了确保收到了最后一个碎片,最后一个碎片的flag会被设置为0,所有其他碎片都设置为1。同时,为了确定是否有碎片丢失,offset这个字段用来指定这个碎片在原始的datagram里的什么位置。
IPv4寻址
首先说说主机和路由器是怎么连接到网络中的。一台主机一般只有一个单一的连接连到网络。主机和物理连接线的交界叫做interface(接口)。路由器就会有多个链接,之间的交界也叫做接口。因为每个主机和路由器都能发送和接收数据包,因此每个接口都需要有它自己的IP地址。因此,技术上说,一个IP地址是与一个接口相关联的,而不是与一台主机或是一个路由器相关联的。
每个IP地址32位,大约40亿个可用的IP地址,用dotted-decimal notation来表示。在每一台主机和路由器上的每一个接口,都必须有一个全球唯一的IP地址(除了NAT后面的那些接口)。这些地址不能随意选择。IP地址的一部分由它所在的子网决定。多台主机和一个路由接口可以构成一个子网。我们可以指定一个地址给这个子网,比如223.1.1.0/24。/24的意思是前24位定义了这个子网。书中Figure 4.18这个子网是由三个主机的接口和一个路由接口组成的。
网络地址的分配策略叫Classless Interdomain Routing(CIDR),它定义了子网寻址的表示方法。32位的IP地址被分成两部分,a.b.c.d/x,x表示第一部分有多少位。最左边的x位构成了这个IP地址的网络部分,也叫prefix或者network prefix。一个组织一般会被分配一块连续的地址。这样,这个组织内的所有设置就可以有相同的前缀。当我们学BGP路由协议时就会知道,组织外的路由器只考虑前缀。这就极大地减少了转发表的大小。剩下的32-x位就用来在这个组织内部转发。这些剩下的bits可能还有下面的子网结构。比如a.b.c.d/21可能代表一个组织,a.b.c.d/24可能表示该组织内部的某一个子网。
在使用CIDR以前,网络的某一部分只能用8,16,24个bits进行分割,也叫classful addressing, 分别叫做A,B,C网。C类网只有254个地址,对大多数组织来说太少了。而B类网可以有65534(书里这个数字写错了)个主机。利用效率非常低下。
比如一个ISP对外广播说发送给我所有匹配200.23.16.0/20的数据包,那么外界并不知道它内部其实还有8个子网。这种用单一的一个前缀来广播多个子网的方法也叫地址聚合address aggregation或者路由聚合route aggregation。
但是思考这样一个问题,如果一家公司收购了另一家公司,然后母公司的一个组织单位想通过这个子公司连接到网络,这时怎么办?比如母公司IP地址是200.23.16.0/20,子公司IP地址是199.31.0.0/16,那个组织单位的IP地址是200.23.18.0/23,并不在这个地址范围内。一般的解决办法是,这个组织保持它的IP地址不变,但是被收购的子公司就需要对外宣称,发给我所有匹配199.31.0.0/16或者200.23.18.0/23的包。那么以后外界就会通过longest prefix matching最长匹配法则,来路由到正确的地址。
IP broadcast address 255.255.255.255。当一个主机用这个目标地址发送数据包时,消息就会被发送到同一个子网中的所有主机。路由器也可以转发这个消息给它邻居子网。(尽管一般它们不转)
获得一块地址
网络管理员首先联系ISP。比如,某个ISP拥有地址块200.23.16.0/20。他们就可以把这些地址分成8等份连续的地址块。那ISP这些地址是从哪里来的呢?IP地址是由the Internet Corporation for Assigned Names and Numbers(ICANN)统一分配的。他们也负责管理DNS根服务器,还负责分配和解析域名。
获得一个主机地址:Dynamic Host Configuration Protocol动态主机配置协议
一个组织获得一块地址后,就能分配单个IP地址给主机或者路由接口了。系统管理员一般会手动给路由器配置IP地址。主机的地址一般使用Dynamic Host Configuration Protocol(DHCP)。通过这个协议,主机可以自动获得IP地址。可以配置为某台主机每次连接到网络时都会被分配同一个IP,也可以配置为分配一个临时IP。DHCP可以自动把主机连接到网络中,因此也被称作plug-and-play or zeroconf协议。这个协议非常适合用于频繁更换网络的场景,比如一个学生经常从图书馆走到教室又走到卧室。
DHCP是一个客户端服务端的协议,客户端新进入一个网络希望获得网络配置信息,包括它自己的IP地址。在最简单的情况下,每个子网都会有一个DHCP server。如果没有的话,就需要一个知道这个网络DHCP服务器地址的DHCP relay agent(中继代理,一般就是一个路由器)。
对于一台新进入网络的主机,DHCP分4步:
- DHCP server discovery: 新到的主机第一件事就是要找到DHCP服务器。这一步是通过DHCP discover message实现的。客户端通过一个UDP的包把该消息发送到port 67。但是这个包发送给谁呢?主机不知道要跟谁联系,因此创建一个IP datagram,用255.255.255.255作为目标IP,广播出去,把自己的IP设置为0.0.0.0。
- DHCP server offer(s): 一个DHCP服务器接收到一个DHCP discover message之后,就会用一个DHCP offer message响应客户端,也通过255.255.255.255(因为此时客户端还没有IP地址呢)。因为一个子网中可能不止有一个DHCP服务器,所以客户端可能会接收到多个offer。每个offer都包含一个交易ID,