ping 使用 ICMP 协议, ICMP 工作在 IP层所以无端口号,当多个进程使用 ICMP 的时候, 怎么判断该 ICMP Message 属于哪个进程?
不像其他应用层的协议如http, 直接监控80端口, ping 若直接使用ICMP, 那它怎么知道来的数据包就是属于它的呢?
虽然ICMP协议没有端口号(Port Number),但是ICMP协议有IDENTIFIER(ID)。
-
TCP、UDP的Port Number占据2个byte,16 个bit位。
-
ICMP的ID也占据2个byte,16个bit位。
不同用户Ping进程(不同的进程号Process ID),填入ID字段。当Ping包(Echo Reply)返回时,ID字段原封未动,操作系统内核根据ID字段,其实就是进程ID号,通知对应的Ping进程从接收队列(Incoming Queue)取走,做进一步的处理。
TCP/UDP的Port Number,有Source、Destination,一共2个,对吗?
是的。
可是为何ICMP的ID,只有1个,为什么?
Ping包的接收端,是一个操作内核进程,代码执行位于ip_icmp.o。
它的工作很简单,就是将收到的Ping包反弹(Reflect),但反弹之前需要:
-
源IP、目的IP位置对调
-
更新IP TTL
-
修改ICMP Type=8(Echo)到0(Reply)
-
重新计算ICMP Checksum
然后调用ip_output.o的ip_output(),更新IP头Checksum,查询路由表,找到出接口,调用interface_output()将Reply报文发出。
整个过程都懒得瞅ID一眼!
Who Cares?
当然是用户侧了,因为可能有多个用户Ping进程(不同的进程号Process ID),同时Ping相同的目的IP = 8.8.8.8,这个返回的Reply报文究竟是哪个进程的?
假设,一个用户唯一的物理接口IP = 1.1.1.1,
一个Ping进程ID = 33333,Ping 8.8.8.8
一个Ping进程ID = 35555,Ping 8.8.8.8
答案很简单,
-
如果Reply 报文的ID = 33333,那么就是进程ID = 33333的。
-
如果Reply 报文的ID = 35555,那么就是进程ID = 35555的。
-
如果Reply 报文的ID = other,丢弃。
以上解决了Ping包的Reply报文找用户进程的难题。但是,还遗留一个小问题,即进程ID(33333)一共Ping了10个包,Ping进程又是如何将Echo包与Echo Reply包一一对应起来?
依赖于图片中的Sequence Number字段,每个Ping包都有唯一的Sequence Number。
这个Sequence Number在去程(Echo)、返程(Reply)也是原封未动的。
用户进程依赖于Sequence Number将Echo与Reply关联起来。
比如Sequence Number =0 的Echo,只对Reply的Sequence Number =0感兴趣。
-
如果定时器超时(通常2秒)之前到达,Ping打印输出Success!
-
如果定时器超时之前没有到达,Ping打印输出Timeout!
-
如果定时器超时之前没有到达Reply,但是收到ICMP Error报文(Type 3 Code 4),Ping打印输出“Fragment Needed,DF Set”。
这就说明Ping包太大,超出某个路由器的出接口的MTU(最大传输单元),但是由于Ping包的DF(Don’t Fragment)=1。
可以将Ping包调小,直到成功为止。通过这样的方法,可以大概率探测出用户到服务器方向所有路由器出接口MTU的最小值。
原文始发于微信公众号(车小胖谈网络):Ping 没有端口号, 如何保证数据的正确接收?
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论