0%

由ICMP引出对TCPIP网络模型思考

名词解释:ICMP( Internet Control Message Protocol 网络控制消息协议 )

关键问题:为什么ICMP属于网络层

前情提要

学习计算机网络知识的时候,最开始都要死记硬背一下OSI七层或者TCP/IP五层模型的划分。

在学习网络数据封装的时候,我们也知道数据是一层包裹着一层的
数据封装格式

但是从Linux TCP/IP协议栈实现的角度来看,我会觉得实际的设计与这个模型有一点偏差。

Linux的struct iphdr结构体是网络层的数据包头格式,结构如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__be16 tot_len;
__be16 id;
__be16 frag_off;
__u8 ttl;
__u8 protocol;
__sum16 check;
__struct_group(/* no tag */, addrs, /* no attrs */,
__be32 saddr;
__be32 daddr;
);
/*The options start here. */
};

我们可以看到IP版本、源地址目的地址等我们常见元素的定义。

其中的protocol 字段对应的是IP协议上层使用的协议,对应in.h中的枚举定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#if __UAPI_DEF_IN_IPPROTO
/* Standard well-defined IP protocols. */
enum {
IPPROTO_IP = 0, /* Dummy protocol for TCP */
#define IPPROTO_IP IPPROTO_IP
IPPROTO_ICMP = 1, /* Internet Control Message Protocol */
#define IPPROTO_ICMP IPPROTO_ICMP
IPPROTO_IGMP = 2, /* Internet Group Management Protocol */
#define IPPROTO_IGMP IPPROTO_IGMP
IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */
#define IPPROTO_IPIP IPPROTO_IPIP
IPPROTO_TCP = 6, /* Transmission Control Protocol */
#define IPPROTO_TCP IPPROTO_TCP
IPPROTO_EGP = 8, /* Exterior Gateway Protocol */
#define IPPROTO_EGP IPPROTO_EGP
IPPROTO_PUP = 12, /* PUP protocol */
#define IPPROTO_PUP IPPROTO_PUP
IPPROTO_UDP = 17, /* User Datagram Protocol */
...省略
};
#endif

iphdr结构体头文件(ip.h) protocol定义(in.h)可以点击访问

在之前介绍ICMP数据拦截器的文章中,我们通过判断判断IP头的protocol 字段是否等于IPPROTO_ICMP 来判断数据包是否属于ICMP数据包。

换句话来说,ICMP协议是由IP协议所承载,运行在IP协议之上,而TCP和UDP协议也是运行在IP协议之上。

但是,在五层模型中,ICMP协议属于网络层的协议,而TCP/UDP属于传输层。

如果对于TCP类型的数据来说,数据封装会类似这样

【以太网帧头【IP报文【TCP头【data 】 】 】 】

也就是 物理/数据链路层帧头 + 网络层报文 + 传输层报文 + 上层应用数据组成

对于ICMP类型的数据来说,封装是这样的

【以太网帧头【IP报文【ICMP头【data 】 】 】 】
所以就是 物理/数据链路层帧头 + 网络层报文 + 网络层报文 + data


为什么ICMP属于网络层

在网上搜索了一下,我觉得在知乎上看到作者车小胖的解释比较能帮助我的理解 ,点击访问知乎原文

简单来说,应用层的HTTP协议、网络层的TCP协议,都有自己的纠错机制,当数据不可达时,可以有抛出错误的办法。

但是IP协议包头部分并没有相关的错误通知机制,假设只有IP协议的情况,如果客户端发送了一个请求到服务器,但是服务器内核协议栈解析发现服务器上并没有对应的端口在监听,那么客户端可能就只能知道发出的数据没有响应,但并不清楚是由于网络传输过程中的原因导致,还是服务器的原因导致。

而在有ICMP协议的情况下,如果服务端没有监听对应的端口,客户端发送数据过来时,内核协议栈会返回一个ICMP报文,由ICMP表明当前目的不可达(ICMP_DEST_UNREACH),不可达的具体的原因是端口不可达(ICMP_PORT_UNREACH)。

因此,ICMP可以被认为是IP协议的附属协议,ICMP协议基于IP协议,为网络的连通性提供指示。

如何理解网络层与传输层的划分

经过了第二部分的解释,我们应该可以理解为什么ICMP与TCP都基于IP协议,但ICMP属于网络层的原因。

我们来列举一下场景的网络层协议和传输层协议(TCP/IP五层模型)

网络层:

  • IP
  • ICMP
  • IGMP
  • ARP(OSI七层模型中属于数据链路层)
  • VRRP

传输层:

  • TCP
  • UDP

融会贯通一下,我这样来理解网络层和传输层

  • 网络层:组建网络或者指示网络运行情况,提供路由选择等功能
  • 传输层:基于网络层,负责为应用层提供传输数据的能力,并屏蔽IP类型/物理网络接口类型等信息

你们觉得这样理解对吗? 这样是否能更容易理解TCP/IP五层模型了呢?