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编程中的相关函数的应用方法;通过对相关命令的底层协议进行分析,也加深了我对网络管理和监控命令的工作原理的理解;总的来说,此次实验收获很多。