对于网络协议初学者来说要构造或解析一个网络协议数据包是比较困难的,我们可以借助一个功能强大的Python库Scapy来完成网络数据包的构造、解析和嗅探。Scapy使用类来表示协议栈,它能够对任何类型的数据包进行快速描述,例如构造一个ip层数据包只需要实例化一个IP类对象,并指定参数值即可:ip = IP(dst=”192.168.1.2”)。Scapy根据分层来构造数据包,每一层协议之间用”/”符号连接,例如要构造一个DNS协议的查询请求报文,可以通过代码dns = IP(dst=”192.168.1.2”)/UDP(dport=53)/DNS(qd=DNSQR(“www.gysecurity.cn”))来实现。
Scapy的常用函数
发送和接收数据包函数:
- send():用于发送数据包,但不等待响应。
- sendp():类似于send(),但可以包含Layer 2头部信息。
- sr()和sr1():发送数据包并等待响应,sr()返回所有响应,而sr1()只返回第一个响应。
- srloop():发送数据包并循环接收响应。
- srp():类似于sr(),但针对数据包进行二层处理,常用于以太网数据包的发送和接收。
- sendpfast():以更高的速度发送数据包,适用于性能要求较高的场景。
捕获数据包函数:
- sniff():用于捕获网络接口上的数据包,可以根据需要过滤特定的协议数据报文。
查看和分析数据包函数:
- ls():列出所有已知的协议和字段,展示协议和字段的层次结构及其关系。
- pkt.time:显示数据包的时间戳。
- pkt.len:显示数据包的长度。
- pkt.summary():显示数据包的摘要信息,包括源地址、目标地址等。
- pkt.show():显示详细的数据包信息,包括协议头、字段和载荷等。
下面以TCP三次握手和四次挥手为例子来演示如何使用Scapy来构造TCP报文,帮助大家理解TCP序列号和确认号的变化机制。
环境要求
处于同一个局域网内的两台pc机(可以是Windows或Linux系统)分别充当服务端以及客户端,两台机器都需要安装Python3,作为客户端的机器还需要安装Scapy和Wireshark。
实现过程
- 使用Python的socket模块编写一个TCP服务端。首先创建socket_server套接字,监听8888端口,然后接收客户端的连接请求,读取完客户端发送过来的数据后关闭连接,代码如下:
2. 启动Wireshark,选择局域网ip所使用的网卡,并设置过滤规则:tcp.port==8888
3. 客户端实现
3.1 建立连接
TCP协议通过3次握手实现建立连接,客户端需要进行第1次和第3次握手,第2次握手由服务端构建。第1次需要把标志位SYN设置为1,因此需要把flags设置为S,目标端口设置为服务端的端口8888,由于需要接收由服务端返回的第2次握手,所以需要使用sr()函数发送第1次握手报文,其代码如下:
第3次握手的dport,sport,seq,ack,flags需要根据第2次握手的数据报文内容构建,res为服务端返回的第2次握手,其中fields = res[0].res[0][1][1].fields为第2次握手数据内容,因此第3次握手的seq = fields[‘ack‘],ack = fields[‘seq‘] + 1,sport = fields[‘dport‘],第三次握手不需要服务端回复,所以只需要用send()函数发送。其代码如下:
运行客户端代码,切换到Wireshark,可以看到捕获到了TCP建立连接3次握手的数据报文,如下图:
3.2 发送数据
第3次握手并没有发送数据内容,服务端也没有返回响应,所以发送数据的时候ack和seq应该和第3次握手一样,未来将数据尽快推送到应用层需要将push标志位设置为1。客户清空Wireshark数据,运行客户端代码,可以看到捕获到了发送的数据报文,如下图:
3.3 释放连接
TCP释放连接需要进行4次挥手,其中第1次和第4次挥手由服务端发送,第2次和第3次挥手由客户端发送。服务端返回的第1次挥手为res_data,其中msg_fields = res_data[0].res[0][1][1].fields为第1次挥手数据内容,则第2次挥手需要设置ack = msg_fields[‘seq’] + 1,seq = msg_fields[‘ack’] ,flags = ‘A‘。由于第2次挥手并没有携带数据,因此第3次挥手的ack和seq和第2次挥手一样,flags设置为FA,因为第3次挥手后需要接收服务端返回的第4次挥手,所以用sr()函数发送。实现代码如下:
运行客户端代码后,发现Wireshark捕获到了4次挥手的数据包,如下图所示:
发表评论
您还未登录,请先登录。
登录