在遇到我们连接网络连不上去的时候,我们回想着ping一下,那么ping是如何工作的
ping是基于了ICMP协议工作的,ICMP全称是Internet Control Message Protocol,就是互联网控制报文协议,关键词就是控制
如何去控制呢?
网络包在复杂的环境中通信的时候,可以能遇到各种各样的问题,在遇到问题的时候,需要标明遇到了什么问题,导致的发送失败,总不能死的不明不白的,对应的失败情况和成功情况,就有了标识序号
ICMP是封装在IP包里面的,所以就需要源地址和目标地址,其本身并不是具有太大的格式的
ICMP的报文有很多的类型,不同类型有不同的代码,常见的类型是主动请求是8,主动请求的应答是0
那么我们就仔细说下查询报文的类型,
一般来说,为了细分所有的类型,我们分别使用两位去标识,一位是TYPE,一位是CODE,比如说,我ping,ping就是一种查询报文,是一种主动请求,并且获得了主动应答的ICMP协议,所以ping发的包是符合ICMP协议的,增加了自己的格式
对于ping的主动请求,就是ICMP ECHO REQUEST ,同理主动请求的回复,称为ICMP ECHO REPLY,比起原生的ICMP,这里多了两个字段,一个是标识符,说明是去干什么的,一个是序号,如果发了10个,只回来两个,说明情况不妙,同样ping中还会存放请求的时间值,来计算往返时间
对应着ICMP如果发送出去的包因为某些原因失败了,就会返回差错报文,常见的错误报文有,终点不可达为3,源抑制为4,超时为11,重定向为5,这对应的,这些是体现在标识符上的
对应的解释为:
1,终点不可达,就是可以说是本想把粮草送过去,但是没有送达
只需为什么没送达,会在code中说明更为详细的原因,序号对应的0为网络不可达,1为主机不可达,2为协议不可达,3为端口不可达,需要进行分片分包但是设置了不可分片的为4
对应的解释为
网络不可达 地方不对啊
主机不可达 到了地方没找到对应主机啊
协议不可达,到了主机人家不认这个协议啊
端口不可达,找对了机器,但是没有对应的端口
需要分片但是设置了不分片,人家设置的mtu不是那么大啊
2.源抑制:就是让发送端放慢发送的速度,处理端处理不完
3.时间超时,就是超过了网络包的生存时间还是没有送到
4.路由重定向,就是下次发送的路由器换一下,因为之前的路线可能绕路了,所以下次别再绕了
差错报文的格式就是在原有的IP的后面跟上出错的那个IP头和IP正文的前八个字节
ping的整体流程
整体流程就假设我们是192.168.1.1,去ping192.168.1.2,都在一个子网网段里面,在主机A里面运行ping 192.168.1.2时候,会出现什么事情?
ping命令执行的时候,源主机会构建一个ICMP的数据包,ICMP中包含多个字段,主要就是类型字段和序号字段,类型字段是8,表明是个ping的发送请求包,然后还有就是序号,每次多发送一个请求包,就会序号+1,而且也会在报文中加入发送时间
然后封装完成了,连带着目标地址192.168.1.2交给了IP层,这样IP层就能拿到了目的地址192.168.1.2,连带着自己的IP地址,进行构建了IP层,然后交给了MAC层,如果有了ARP映射表里的对应的Mac,直接使用,没有就去广播一下,然后Mac层构建一个数据帧,加上一些控制信息,依据一些控制信息,来将其传送出去
主机B在收到这个数据帧的话,会检查他们的目的MAC地址是否符合,符合就接受,不然就丢弃,然后接受后检查数据帧,符合就交给主机的IP层,IP层检查后,提取有用的信息给ICMP协议
主机B会建立一个ICMP应答包,对应的数据类型字段为0,顺序号为接受到的顺序号,在发送出去
如果在规定的时间内,源主机没有接到返回的应答包,就认为主机不可达,如果收到了,就根据现在时间减去发送的时间,得到时间的延迟
如果跨网段的话,还会涉及到网关的转发和路由器的转发
如果在自己的可控范围内得话,遇到了网络不通的情况,直接ping目的的IP,最好能够清晰的知道自己的网络拓扑,理论上需要知道自己的主机到目的主机之间需要经过哪些的设备,逐个的去ping中间的设备和机器,这样的话,通过tcpdump -i eth0 icmp,查看这些包有没有到达某个点,来推断错的位置
ping这样就说完了
但是对于有些程序,可以利用ICMP的特殊规则,来进行检测网络
比如Traceroute
1.设置了特殊的TTL,来追踪经过的路由器,比如参数设置指向某个ip,他会发送一个UDP的数据包,然后将TTL设置为1,这个TTL是指的,没经过了一个关卡,就会减一,减到0了,就是超时返回了,这样中间路由器不止一个,第一个就会超时,然后直接返回一个超时的网络差错包,
接下来,将TTL设置为2,这样过了第一关,第二关就牺牲了,依次反复,知道到达了目的主机,这样Traceroute,就能拿到到达目的ip的所有路由器IP,
至于如何去看UDP怎么到达了目的主机呢?Traceroute程序会发送一份UDP数据包给目的主机,但是,他会选择一个不可能的只作为UDP的端口号,大于了30000,这样如果数据到达了,也会产生一份端口不可达的错误ICMP报文返回,如果一直没有消息,才是超时
2.查询路径的MTU,就是设置不分片的编制,然后发送的第一个分组的长度正好和出口MTU相等,如果遇到了窄的关口会被卡住,发送ICMP网络差错包,类型为需要分片但设置了不分片,这样就能获取到路径的MTU
小结:
ICMP就相当于网络世界的侦察兵,我们说了一种是主动探查的查询报文,一种异常报告的差错报文
ping使用查询报文,Traceroute使用差错报文来做一些事情
课后思考
1.发送的报文有问题的时候,会发送一个ICMP的差错报文返回,如果差错报文出现了问题呢?
2.如果跨路由器,跨网关去ping,怎么办呢?
TTL是网络包的一个,告诉路由器包在网络上呆的时间太长需要被丢弃,TTL原本设想为,超过了超时时间,超过此范围就需要被丢弃,每个路由器在收到的时候对TTL减一,减为0就变为了弃包
1.对于ICMP的差错报文出错的可能为,目的地址为广播地址,或者源地址不唯一的时候不发差错报文
ICMP和IP层一层,属于网络层的,udp会返回ICMP报文
Ping使用了什么的网络编程接口
对于Ping,使用的还是Socket编程接口,具体的为ICMP,创建了Scket
具体命令如下
socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)
建立Socket
对应的创建UDP和创建TCP的格式如下
socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)
socket(AF_INFT,SOCK_DGRAM,IPPROTO_UDP)
ICMP差错报文是如何发送的
是交给内核返回的,在内核之中,有一个函数专门用于发送ICMP的包
void icmp_send(struct sk_buff *skb_in,int type,int code,__be32 info)
目标不可达,调用如下的函数
icmp_send(skb,ICMP_DEST_UNREACH,ICMP_PORT_UNREAH,0)
当IP大小超过MTU的时候,发送需要分片的ICMP
if(ip_exceeds_mtu(skb,mtu)){
icmp_send(skb,ICMP_DEST,UNREACH,ICMP_FRAG_NEEDED,htonl(mtu));
goto drop;
}