简介
packetdrill
是 Google 开源的一个 测试脚本工具,可以用于测试TCP、UDP、IP网络协议栈,其是由基于时间序的脚本行组成,按时间顺序逐条执行。
它的语言设计十分接近于 tcpdump 和 strace ,包含四种类型的语句:
-
数据包。使用类似于 tcpdump 的语法,支持TCP、UDP、ICMP数据包,同时也提供了常见TCP选项的配置,包括 SACK、MSS、window scale等。
-
系统调用。使用类似于 strace 的语法。
-
Shell 命令。通过``进行调用,可以进行系统参数配置或断言验证网络协议栈状态。
-
Python 脚本。通过
%{ command }%
进行调用,可以输出或者断言验证 TCP 状态。
编译、安装
参考官方GitHub - packetdrill
基础使用
通过一个简单的例子,来看看 packetdrill 的使用。
下面一段脚本是用于测试 TCP 三次握手的过程。
1 |
|
脚本一共做了两件事情:
- 通过系统调用创建并配置 Socket ,绑定端口开始监听
1 |
|
我们创建了一个 Stream 类型的 Socket,并指定协议为 TCP。
0
表示绝对时间,即从第0秒开始。
…
是默认缺省,表示系统自动配置填充。
= 3
表示函数调用结果断言为 3 ,即创建的 Socket 对应的FD。
剩下的代码就是配置并监听。
这里可能会有一个疑问,为什么新建 Socket 对应的 FD 是 3 ?
对于一个进程而言,默认会打开 stdin(0) 、 stdout(1) 、stderr(2),那么正常情况下,第一个新打开的 FD 正好是 3。
- 三次握手
通过三行脚本来发起和校验三次握手的过程。
1 |
|
+0
相对时间,上一条命令执行结束的 0 秒后,开始执行当前命令。
<
往内核网络协议栈中,注入数据包。
>
从内核网络协议栈中,收到数据包,并断言收到的数据包与定义的包是否一致,例如 ack 是否为1。
S
SYN报文,对应 TCP 数据包中的 Flag。
0:0(0)
开始序号:结束序号(数据包长度)。首包 sequence 是0,SYN数据包没有数据payload,所以长度是0,结束序号 = 开始序号 + payload length = 0。
ack 1 win 1000
ACK序号为1,窗口大小为1000。
TCP 网络状态
TCP是可靠的,需要保持连接状态来维持连接,连接状态的变化往往是我们非常关注的部分。packetdrill 支持对连接状态的检查和查看,对应的 TCP 连接信息定义在了 tcp.h
文件中,内容如下:
1 |
|
当我们需要在连接的各个阶段查看状态变化时,可以通过 python 脚本进行打印:
1 |
|
脚本尝试在上一条命令执行结束后,立刻开始执行一段 python 脚本,打印 TCP 的超时重传时间。
Shell 命令
packetdrill 支持 Shell 命令调用,实现了在测试执行过程中,插入一些额外操作,例如系统配置获取和设置。
1 |
|
上面的命令尝试在前一条脚本执行结束后,立刻执行一段 Shell 命令,命令调用 sysctl 修改 TCP 配置,关闭了时间戳。
时间模式
由于大部分网络协议对时间都比较敏感,因此 packetdrill 的每一行脚本都需要严格定义时间。如果事件发生的时间与预期不符,会进行报错,并提示事件实际发生的时间。
在时间的定义上, packetdrill 也提供了多种模式的支持:
在使用中,可能会出现定义的时间与实际时间存在偏差的情况,不同测试模式以及环境,偏差的多少往往也会不同,有时会难以控制。这种情况下,可以调整时间偏差的容忍值:
1 |
|
本地/远程测试
packetdrill 支持两种测试模式:本地模式与远程模式。
- 本地模式
本地模式可在单机环境下进行,packetdrill 使用本地单机和一个 TUN 虚拟网络设备进行数据包传输和测试,可用于测试系统调用、Sockets、TCP/IP协议层。
本地模式是 packetdrill的默认模式,调用起来也十分简单:
1 |
|
- 远程模式
在远程模式下,我们运行两个独立的 packetdrill 进程,它们在两个不同的机器上,通过 LAN 进行数据传输,可用于测试整个网络系统,包括系统调用、Sockets、TCP、IP、NIC硬件和驱动、无线网络等。
在使用远程模式时,需要定义好两端所扮演的角色,分为客户端和服务端。
首先需要开启服务端,接收客户端连接请求:
1 |
|
而在创建客户端进程时,需要指定角色及服务端参数:
1 |
|
两者通过 TCP 进行连接,并由客户端将脚本内容发送到服务端,两者共同协同完成整个脚本,整个过程主要用于测试客户端网络协议栈。
总结
packetdrill 语法并不复杂,能帮助我们学习和测试内核网络协议栈,模拟一些极端场景下的网络数据包。在 Google 发布的论文中,他们投入了超过18个月的时间,使用 packetdrill 来测试 Linux 内核网络模块,并且发现一些 bug,包括 DSACK undo、TCP Fast Open server等。