网络层的七七八八

网络层主要实现点对点通信,路由器通过路由表和IP地址进行路由控制,再委托数据链路层将数据包发送到最终目标地址,在连接到网络的不同数据链路中进行通信,是实现全球网络互联的关键部分。

IP

相关概念

IP地址的格式我们都知道,通过CIDR将32位的IP地址分为网络号和主机号。网络寻址所需要的网络号可以通过IP地址和子网掩码做与运算求出。

广播

广播地址分为本地广播和直接广播,直接广播出于安全考虑大多数情况会在路由器上设置不转发。
本地广播像之前文章中DHCP用到的,主机没有IP地址,也不知道网段的地址,目的IP设为255.255.255.255会被广播到相同数据链路上的所有主机(以太网通过将MAC地址设置为ff:ff:ff:ff:ff:ff在同数据链路上广播出去),但是不会被路由器转发到其他的网段去。
直接广播:直接广播地址是主机位全1,例如192.168.1.255/24,将一个数据报发送到该地址,那么192.168.1.1~192.168.1.254的主机都会接收到。

多播

多播主要用于给其他网段指定的多台主机,通常通过路由器复制数据包实现,多播使用D类地址,即首四位固定为1110的地址,地址段244.0.0.0 ~ 239.255.255.255。有一些地址被明确规定了作用,例如:224.0.0.1组会将包发送到路由器之外的所有主机,224.0.0.2的组将包发送到所有路由器。
IPV4的多播依赖于IGMP,IGMP有两大作用:

  1. 通知路由器想要接受多播消息,路由器收到通知后会将该消息转发到其他路由器。
  2. 通知交换机想要接收的多播地址,支持IGMP的交换机就会过滤多播地址,因为多播是基于IP的,而我们知道普通的二层交换机只能处理数据链路层的包,所以支持IGMP的交换机需要同时支持解析IP的包。

localhost

环回地址(loopback)就是让主机自己给自己发数据包,包不会流向网络,127.0.0.1 ~ 127.255.255.255段的地址都是环回地址,IP协议栈解析到该类地址时不会丢到数据链路层去封装,而是直接通过IP栈处理。cat /etc/hosts查看域名配置:

通过netstat查看localhost的使用情况:

Tips:通过ping 127.0.0.1判断IP协议栈本身是否正常

IP首部

IP报文格式如下图:

各字段含义

  • Version:IP首部版本号,常用IPv4的值为4,IPv6的值为6
  • IHL(Internet Header Length):IP首部的大小,单位为4bytes,没有可选项(黄色部分Options)的IP包长度为5,5 * 4 bytes = 20 bytes
  • TOS(Type Of Service):由应用来设置吞吐、延迟、优先级等特性。现在拆分出了DSCP(Differential Services Codepoin)和ECN(Explicit Congestion Notification)。
    • DSCP:主要提供包的优先级控制,通过配置DiffServ域,在域中的路由器会根据DSCP值进行优先级处理,网络拥塞时甚至可以丢弃低优先级的包
    • ECN:报告网络拥堵情况,如果路由器检测到网络拥堵,会设置ECN为11,即ECT值为1,CE值为1,从而通知发送端TCP网络拥堵,发送端会调节拥塞窗口减慢发送速率
      • ECT(ECN-Capable Transport):告诉上层TCP是否处理ECN,1为处理
      • CE(Congenstion Experienced):出现网络拥堵情况,1为拥堵
  • Total Length:IP首部和Data总长度,最大为65535 Bytes(16位,2的16次方),受数据链路层MTU长度限制,实际传输中无法一次传输这么长的数据,需要通过IP分片来处理,发送端IP层分片接收端IP层重组,因此对于上层协议栈来说,包的最大长度是可以达到65535的。
  • ID(Identification):用于分片和重组,IP包的身份标识,IP包分片后该标识会被放置到每个分片上。接收端会根据ID和片偏移(FO)对包进行重组
  • Flags:表示包分片的相关信息,第一位的值是0无意义,第二位(0:可以分片,1:不可分片),第三位表示是否是最后一个分片(0:是最后一个分片,1:是中间的分片)
  • FO(Fragment Offset):第一个分片的偏移量为0,13bit总共可以表示8192(2的13次方)个偏移量,偏移的单位为8字节,可以表示的数据量为8 * 8192 = 65536
  • TTL(Time To Live):Ping命令中常见的字段,表示包可以经过多少个路由器,每经过一个就减少1,TTL为0时包被丢弃
  • Protocol:是IP层上层协议类型的编号,比如ICMP:1、IPv4:4、IPv6:41、UDP:178
  • Header Checksum:校验IP数据包首部是否被破坏,不校验数据部分。
  • src.addr(Source Address):发送端IP地址
  • dst.addr(Destination Address):接收端IP地址
  • Options:进行网络诊断时使用,长度可变,包含安全级别、源路径、路径记录、时间戳
  • Padding:Options可能会导致首部长度不是32 bit的整数倍(根据IHL字段IP首部大小的单位为4Bytes,32 bits),Padding会填0将IP首部长度调整为32 bit的整数倍。
  • Data:包含上层协议的首部与数据

路由控制

路由的含义是通过路由器的不断转发,让数据包最终达到目的地址的。路由器根据路由控制表与目的IP地址进行转发,确保数据包达到目标主机。大概流程是这样的:
包从主机网卡发出到第一个路由器 ->
第一个路由器拿到目的地址后查路由表,确定下一跳要走的路由器 ->
确定好下一个路由器的IP后,需要委托数据链路层将包发出去,通过ARP拿到下一个路由器的MAC地址后,生成新的MAC首部,通过数据链路层发送(具体操作看这里)->
包被不断地转发由最终目的主机接收。

下面看如何控制路由策略和路由表,路由策略的配置方式分为静态路由和动态路由:

静态路由

路由表控制

通过ip route命令可以进行路由表的管理

# 发送到10.10.10.11的包需要经过10.211.55.3这一跳,从enp0s5这个网卡出去
ip route add 10.10.10.11 via 10.211.55.3 dev enp0s5
# 通过ip route查看
root@yielde:~# ip route
10.10.10.11 via 10.211.55.3 dev enp0s5

另外ip route还可以看到几条缺省路由,例如

10.211.55.0/24 dev enp0s5 proto kernel scope link src 10.211.55.3 metric 100

# proto kernel: 该路由由内核添加
# scope link:表明可以通过enp0s5与网段10.211.55.0/24的任何地址通信
# dev enp0s5:使用网卡enp0s5
# src 10.211.55.3:使用该网卡路由时使用的源地址是 10.211.55.3
# metric 100:路由的优先级,静态路由的metric为100,值越小优先级越高

路由规则

可以配置多个路由表,根据IP地址、设备、和IP首部中的TOC来控制不同类型的包通过不同的路由表走

# 通过10.211.51.0/24网段来的包走路由表20,10.211.52.0/24来的走30
ip rule add from 10.211.51.0/24 table 20
ip rule add from 10.211.52.0/24 table 30

综合使用ip route和ip rule让特定的主机走特定的路由表,比如我们让192.168.1.101主机的包通过自定义的路由表走IP为60.190.27.189网口出去,可以添加这样的规则:

# 添加路由表
echo 200 t1 >> /etc/iproute2/rt_tables

# 添加路由表规则,包通过网口eth3网关为60.190.27.189出去
ip route add default via 60.190.27.189 dev eth3 table t1

# 添加规则,让该主机的包走路由表t1
ip rule add from 192.168.1.101 table t1

ip route flush cache

iptables

ip routeip rule都是决定包该怎么走,iptables则可以对过来的包做控制,比如丢掉某个网段过来的包,或者拒绝ICMP协议包等操作,这篇博文有大量示例:
https://www.cnblogs.com/ggjucheng/archive/2012/08/19/2646476.html

动态路由

在实际的网络使用中静态路由和动态路由时一起使用的。静态路由只适合对少量节点进行特定的通信配置,如果涉及大量的数据链路和路由节点,节点故障会对网络通信造成严重的影响,而且需要大量的人工干预,这个时候就需要路由器自己来做些事情,保证网络的正常通信,例如自动维护路由表、路由规则,绕过故障节点等。
这里面有两个问题第一个是如何又快又准确的将包送到?第二个是全世界有那么多网络节点,如何管理?先看看我们是怎样接入互联网的。

互联网的连接

忽略数据链路层或应用层的设备,简单想想以下各点就是路由器

  1. 运营商下设多个接入点供用户接入(POP),这些POP会接入到运营商的NOC(Network Operation Center),NOC其实可以看成是性能更强的POP,NOC和POP,POP和POP之间互联,实现运营商直接或运营商内各接入点的通信。把运营商提供的这种区域称为AS(Autonomous System)
  2. 因为运营商的种类和数量过于庞大,将他们都一一互连是不现实的,于是又往上加了一层IX(Internet eXchange),不同的运营商接入IX,通过IX进行通信。
  3. 运营商内部使用IGP进行通信,世界各网络运营商使用EGP进行通信。

IGP(Interior Gateway Protocol)

内部网关协议主要用于数据中心内部的路由决策。一种是OSPF协议,基于链路状态路由协议实现,链路状态路由协议是说每一台路由器本地都保存着一样的网络拓扑结构,如果邻居下线或者出现新的邻居导致拓扑结构发生变化,则会将变化的部分广播给其他的路由器,其他路由器更新本地拓扑结构。当发生通信时,根据该拓扑图使用Dijkstra算法找到最短路径将包转发送达,因为它只广播拓扑变化的部分,并且各节点之间可以及时同步,所以是更适用于ISP内部的路由方式。

EGP(Exterior Gateway Protocol)

外部网关协议主要用于AS之间的通信。一种是边界网关协议(BGP),BGP通过TCP实现,现在AS之间通信使用eBGP,保证可靠性的同时可以对包的传输和控制做更多的操作。
BGP会生成一个AS Path List,会记录到达目标地址的多条路径、不同路径的距离、以及经过的AS的编号,通常会选择途径AS最少的路径进行传输。

分片与重组

我们知道数据链路层有MTU的限制,例如以太网默认MTU为1500 Bytes,IP层受Total Length的长度限制,最大为65535,但是IP包传输是需要委托数据链路层来发送的,超过了数据链路层MTU就需要对IP包进行分片,除最后一个分片,其余分片单位为8Bytes的倍数。分片可以由路由器来完成,而重组只能由最终的主机来做(因为每个分片的传输路径可能不同,而且网络层的传输是不可靠的,中间的分片可能会丢失)。

分片

首部中记录的ID、Flags、Fo字段就是作用于分片重组的,ID唯一标识了每个包,Flags可以拿到是否是最后一个分片,Fo是每个分片相对于第一个分片的偏移量,目的主机可以通过这三个字段来进行重组。分片步骤:

  1. 检查Flags的第二位,0为可分片,1为不可分片,如果设置了1并且包的长度超过了链路层的MTU,则路由器会丢弃该包,并且发送ICMP目标不可达差错报文(Type:3,错误代码为4,下文ICMP有介绍)
  2. 除了最后一个分片,其余分片长度为8Bytes的整数倍(Fo字段的单位为8Bytes),基于MTU计算分片长度
  3. 设置Flags的第三位,最后一片值为0,其余为1
  4. 设置Fo,相对于包开头的偏移量
  5. 生成ID并将ID复制到每个分片(通过首部Options设置,也可以只设置ID到第一个分片)
  6. 重新计算并设置IP首部的Total Length和Header Checksum

委托数据链路层进行发送,发送途中如果分片的长度大于某一设备的MTU,则会再进行分片。

重组

目的主机需要准备一个缓冲区用于存放分片,需要准备一个计时器,找到ID相同的分片,通过Fo和Flags将分片组装起来,如果重组过程中发生超时,会发送一个传输超时的ICMP差错报文(Type:11,错误码为1)并清空缓冲区。

路径MTU发现

路由器分片会增加路由器的负载,另外分片处理中,如果一个分片丢失,则IP包作废,之前的分片和传输操作都是无用功。路径MTU让发送端主机来做分片工作,路由器只负责沟通和传输分片。具体做法:

  1. 在发送端主机将Flags第二位设置为1禁止分片,如果路由器发现该包需要分片才能传输,会丢弃并通过ICMP差错报文告诉主机MTU
  2. 主机根据拿到的MTU对包进行分片处理,主机会缓存该MTU最少10分钟的时间,后续包发送会根据该MTU进行分片,如果超过缓存时间,后续发送会再次进行路径MTU发现操作

UDP的包会在下一次发送时交给IP协议栈来处理分片,而TCP有重发机制,所以会直接在TCP协议栈进行分片,然后交给IP协议栈进行打包和发送(不需要IP层来分片)。

网络层相关技术

ICMP(Internet Control Message Protocol)

ICMP是封装在IP包里面的,ICMP最多的应用场景就是用来确认网络是否正常和进行诊断的,它可以返回包没有被送达的原因。ICMP有很多类型,常用的如下:
0:主动应答
3:目标不可达
5:路由重定向
8:主动请求
11:传输超时

查询报文

ping

查询报文用于诊断网络,我们用的ping就是基于ICMP工作的,只不过多出了Identifier和Sequence Number用于标识ping不同的地址和ping包的发送顺序,ping命令抓包如下:

我们看到有BE和LE的分类,是因为ping报文在windows系统和linux系统存储方式不同,windows是小端序LE(little-endian),Linux是大端序(big-endian),wireshark显示了两种序列。

通过Type:8可以看到这是一个主动请求的包,Timestamp保存发送时间戳用来计算往返时间。
抓包一个应答包:

差错报文

差错报文是当网络发生故障时通知错误原因,
目标不可达(Type:3),当IP数据包无法到达目的地址时,会给发送端返回一个目标不可达的消息,这个消息中会包含错误码,例如:
0:网络不可达
1:主机不可达
2:协议不可达
3:端口不可达
4:需要分片但是设置了不可分片标志位
7:未知的目标主机
路由重定向(Type:5),路由器发现发送包使用的路径不是最优路径时,会发送该消息告知发送端有一条更快的路径,发送端将该路径追加到路由表中,下次发送走这条路径。
传输超时(Type:11),上面IP首部的TTL字段,如果包传输的TTL被减为0而丢弃,路由器会发送一个传输超时的消息给发送端,错误码为0(错误码为1表示包在重组时超时),告知发送端该包已经被丢弃。

traceroute

除了遇到真正的错误,traceroute会使用icmp的规则设置不合理的值来达到不同的目的。比如跟踪一个包,拿到它的中间路由。

  1. 设置TTL为1,向指定地址发UDP数据包,我们知道每经过一跳路由,TTL减1,减到0这个包就被丢掉了。
  2. 路由器给主机发送时间超时的ICMP差错报文
  3. 继续发送设置TTL为2,去拿第二跳的地址
  4. traceroute设置的UDP端口号大于30000,如果主机收到了会返回一个端口不可达的报文,这时traceroute就知道包已经送到主机了

traceroute公网地址的时候有时候看不到中间路由,因为路由器做了设置不会发回ICMP差错报文

DNS(Domain Name System)

给IP地址取个名字,比如我们在配置分布式系统时,没有DNS服务器通常会在hosts文件中写一条主机名和IP地址的映射。DNS系统就是维护这种映射的一个系统,从根域名服务器开始分层大致分为:
根DNS:返回顶级域DNS的IP地址
顶级域DNS:返回权威DNS的IP地址
权威DNS:返回主机的IP地址
主机上会配置本地DNS服务器(一般就是配置的DHCP),主机通过DNS解析器向域名服务器发起查询。

DNS解析

  1. 客户端先查看hosts文件,如果有直接向该IP发送消息,如果没有需要通过DNS解析器(Resolver)去请求本地DNS服务器,以请求www.baidu.com为例
  2. 本地DNS收到请求后,如果缓存中有该映射返回给客户端,如果没有就向根DNS服务器请求
  3. 根DNS会返回管理该域名的下一层DNS的IP地址给本地DNS,就是顶级DNS的IP地址(管理.com)
  4. 本地DNS继续请求顶级DNS(.com、.net、.org等域名),它们保存着baidu.com等权威DNS的地址,将权威DNS的IP地址返回给本地DNS(管理baidu.com)
  5. 本地DNS请求权威DNS(baidu.com),权威DNS将客户端要的www.baidu.com的IP地址返回到本地DNS
  6. 本地DNS将最终的IP地址返回给客户端

NAT(Network Address Translator)

IPv4的地址越来越稀少,我们知道同一数据链路的IP地址如果相同的话会引起冲突。进入互联网通信需要全局IP地址,全球有那么多用户,IPv4根本不够给每个用户分配一个全局IPv4地址,就像我们想在外面访问家里的电脑一样,以前可以给运营商打电话申请一个全局IP地址将电脑暴露在公网上直接访问,现在给运营商打电话只能花钱买,所以需要一些内网穿透的技术来做。
NAT就是在访问互联网时将本地的私有地址转换为全局IP地址的的技术,也是生成一个私有IP与全局IP的映射表,如果私网中有多个主机要访问互联网,单单IP映射没法区分到底要路由到哪台主机,于是又加入了端口号,通过端口号和IP来做映射,这种技术叫NAPT(Network Address Port Translation)。

比方我们的内网有两台主机11.11.11.1111.11.11.22,通过相同的TCP端口888来访问目标服务器200.200.200.200:80,包到达路由器后需要将这两个地址转换为路由器的全局IP地址33.33.33.33,如果没有端口映射,那么收包的时候路由器就无法确认该把这个包交给哪台主机,通过NAPT技术,路由器将11.11.11.11:888映射为33.33.33.33:222,将11.11.11.22:888映射为33.33.33.33.:111,通过这两个地址与服务器通信,收包后直接根据映射表发给对应主机即可。

在TCP中,首次握手的SYN包发出就会在表中添加一条映射记录,关闭连接时收到FIN包的确认应答后从表中删除这条映射

DHCP(Dynamic Host Configuration Protocol)

自动分配IP地址,在我DHCP和PXE是怎么工作的文章中有记录。

ARP(Address Resolution Protocol)

通过IP地址找MAC地址,上一篇文章的数据链路层的七七八八中有记录,但是ARP只能用于IPv4,IPv6需要使用ICMPv6来完成。

学习自:
《趣谈网络协议》刘超
《图解TCP/IP》
《图解HTTP》
《网络是怎样连接的》

posted @ 2023-10-26 13:26  佟晖  阅读(515)  评论(0编辑  收藏  举报