Windows提供了一系列用于检测网络状态,监控计算机与其他主机之间会话的命令用户可以通过这些命令发现、诊断网络连接问题,发现和处理外部终端为非法访问计算机资源而创建的会话。
本次实验采用Python实现基本网络命令Ping。
1、ping的底层协议ICMP
ICMP 数据包的格式如下:
Type: 该字段有 1 个字节,表示特定类型的 ICMP 报文。
一台主机向一个节点发送一个类型字段值为8的ICMP报文,如果途中没有异常(如果没有被路由丢弃,目标不回应ICMP或者传输失败),则目标返回类型字段值为0的ICMP报文,说明这台主机存在。
Code: 该字段有 1 个字节,进一步细分 ICMP 的类型。如上图所示,Type 的值为 8,Code 的值为 0,表示回显请求。
Checksum: 该字段有 2 个字节,表示校验和。
Identifier:该字段有 2 个字节,用于匹配 Request/Reply 的标识符。
Seq Num:该字段有 2 个字节,用于匹配 Request/Reply 的序列号。
Data: 该字段有4个字节,数据载荷。
2、相关函数
2.1 校验和函数
在发送数据时,为了计算数据包的检验和。应该按如下步骤:
1、把校验和字段设置为0;
2、把需要校验的数据看成以16位为单位的数子组成,依次进行二进制反码求和;
3、把得到的结果存入校验和字段中
2.2 请求request 函数
主要功能:将初步构建好的icmp数据包进行二进制转换,计算校验和,在用此校验和替代原先的校验和字段,而后进行二次打包;
2.3 实例化socket函数
主要功能:实例化一个套接口,并将request中打包好的数据通过此套接字发送到网络。(在发送数据到网络前,需记录当前请求时间,用于计算往返行程的时间)
通过socket.socket(family,type,protocol)实现套接字的创建。
1、family:协议簇/地址簇,socket.AF_INET 服务器之间网络通信;
2、Type: socket的类型,socket.SOCK_RAW 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;
3、protocol:协议类型,IPPROTO_ICMP为1;(socket.getprotobyname(protocolname)的作用是将Internet协议名称转换为协议编号)
通过rawsocket.sendto(string,address)发送数据。
1、将string中的数据发送到连接的套接字中(即rawsocket);
2、address是形式为(ipaddr,port)的元组,指定远程地址;
2.4 接收reply函数
主要功能:实例化select对象,对已创建好的套接字进行监听,若套接字满足可读条件,则开始接收数据包。接收后,从接收的数据包中获取ICMP报文头部字段并对其进行反转编码。通过观察反转编码后ICMP报文头部的Type字段是否等于0来判断请求、应答的途中是否发生异常,通过观察Seq Num是否与请求时相同来匹配对应报文。(在接收前需记录当前接收时间,用于计算往返行程的时间)
通过select.select(rawsocket,[],[],timeout)实现对套接口进行监听。
1、select的参数中第1个是监控和接收对应套接口所有的输入的data,就是指外部发过来的数据,第2个是监控和接收所有要发出去的data,第3个监控错误信息,第4个是时间限制。
2、select函数阻塞进程,直到rawsocket中的套接字被触发(在此例中,套接字接收到客户端发来的握手信号,从而变得可读,满足select函数的“可读”条件)
3、“可读”:当套接字缓冲区大于1byte时,就被标记为可读。也就是说,当套接字收到客户端发来的数据,就变成可读,然后select就会把这个套接字取出来,进入下一步程序。
通过rawsocket.recvfrom(bufsize)设置接收的数据包。bufsize指定了要接收的最大数据量。
2.5 ping函数
主要功能:实现4次请求、应答过程,并计算相关时间。
3、实验结果
程序运行结果:
对应的抓包结果:
总结与体会
通过此次实验,加深了我对ping命令的理解。通过python代码实现ping命令的过程,让我更加熟练的掌握了socket编程中的相关函数的应用方法;通过对相关命令的底层协议进行分析,也加深了我对网络管理和监控命令的工作原理的理解;总的来说,此次实验收获很多。