知之者不如好之者,好之者不如乐之者
实验目的
通过实验简单了解 packetdrill 时间模型中的其他时间。
时间模型
由于许多协议对时间非常敏感,所以在「packetdrill」 脚本中增加了对时间灵活性的支持。每个语句都有一个时间戳,由 「packetdrill」 强制执行:如果事件没有在指定的时间发生,则 「packetdrill」 会标记一个错误并报告实际时间。
「packetdrill」时间模型
Model |
Syntax |
Description |
Absolute |
0.750 |
Specifies the specific time at which an event should occur. |
Relative |
+0.2 |
Specifies the interval after the last event at which an event should occur. |
Wildcard |
* |
Allows an event to occur at any time. |
Range |
0.750~0.9 |
Requires the given event to occur with in the timer ange. |
Loose |
--tolerance_usecs=800 |
Allows all events to happen with in a range(from the command line). |
Blocking |
0.750...0.9 |
Specifies a blocking system call that starts/returns at the given times. |
避免伪造失败
使用 --tolerance_usecs 参数值 4ms,使得事件只要在期望时间的 4ms 范围内发生,即认为测试是成功的。
基础脚本
# cat tcp_3hs_000.pkt
// TCP 基础之三次握手
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 bind(3, ..., ...) = 0
+0 listen(3, 1) = 0
+0 < S 0:0(0) win 10000 <mss 1460>
+0 > S. 0:0(0) ack 1 <...>
+0.01 < . 1:1(0) ack 1 win 10000
+0 accept(3, ..., ...) = 4
其他时间
以 TCP 三次握手为基础,测试时间模型中的其他时间,包括 Wildcard、Range、Loose 和 Blocking。
实验测试 Wildcard
初步修改的脚本,TCP 三次握手阶段时间模型全部改为 * 模式。
# cat tcp_3hs_time_008.pkt
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 bind(3, ..., ...) = 0
+0 listen(3, 1) = 0
* < S 0:0(0) win 10000 <mss 1460>
* > S. 0:0(0) ack 1 <...>
* < . 1:1(0) ack 1 win 10000
* accept(3, ..., ...) = 4
测试结果,实际测试执行失败,提示了相关错误,意思是只能用于出站方向的数据包,也就是 > 。
# packetdrill tcp_3hs_time_008.pkt
tcp_3hs_time_008.pkt:6: semantic error: event time <star> can only be used with outbound packets
#
继续修改脚本,执行成功。
# cat tcp_3hs_time_008.pkt
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 bind(3, ..., ...) = 0
+0 listen(3, 1) = 0
+0 < S 0:0(0) win 10000 <mss 1460>
* > S. 0:0(0) ack 1 <...>
+0.01 < . 1:1(0) ack 1 win 10000
+ accept(3, ..., ...) = 4
#
# packetdrill tcp_3hs_time_008.pkt
#
抓包结果,一切正常。
# tcpdump -i any -nn port 8080
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
21:00:46.828389 ? In IP 192.0.2.1.37099 > 192.168.40.249.8080: Flags [S], seq 0, win 10000, options [mss 1460], length 0
21:00:46.828402 ? Out IP 192.168.40.249.8080 > 192.0.2.1.37099: Flags [S.], seq 1935225306, ack 1, win 65535, options [mss 1460], length 0
21:00:46.838495 ? In IP 192.0.2.1.37099 > 192.168.40.249.8080: Flags [.], ack 1, win 10000, length 0
21:00:46.838545 ? Out IP 192.168.40.249.8080 > 192.0.2.1.37099: Flags [F.], seq 1, ack 1, win 65535, length 0
21:00:46.838553 ? In IP 192.0.2.1.37099 > 192.168.40.249.8080: Flags [R.], seq 1, ack 1, win 10000, length 0
实验测试 Range
初步修改脚本,同样只能用于出站方向的数据包,也就是 > ,时间范围为 0.044~0.054 。
# cat tcp_3hs_time_009.pkt
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 bind(3, ..., ...) = 0
+0 listen(3, 1) = 0
+0 < S 0:0(0) win 10000 <mss 1460>
0.044~0.054 > S. 0:0(0) ack 1 <...>
+0.01 < . 1:1(0) ack 1 win 10000
+0 accept(3, ..., ...) = 4
测试结果,实际测试执行失败,提示了相关错误,事件发生的时间 0.000059 sec 不在时间范围 0.044000~0.054000 内。
# packetdrill tcp_3hs_time_009.pkt
tcp_3hs_time_009.pkt:7: error handling packet: timing error: expected outbound packet in time range 0.044000~0.054000 sec but happened at 0.000059 sec
script packet: 0.044000 S. 0:0(0) ack 1
actual packet: 0.000059 S. 0:0(0) ack 1 win 65535 <mss 1460>
#
继续修改脚本,执行成功。
# cat tcp_3hs_time_009.pkt
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 bind(3, ..., ...) = 0
+0 listen(3, 1) = 0
+0 < S 0:0(0) win 10000 <mss 1460>
0.004~0.005 > S. 0:0(0) ack 1 <...>
+0.01 < . 1:1(0) ack 1 win 10000
+0 accept(3, ..., ...) = 4
#
# packetdrill tcp_3hs_time_009.pkt
#
抓包结果,一切正常。
# tcpdump -i any -nn port 8080
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
22:14:42.288390 ? In IP 192.0.2.1.43605 > 192.168.66.212.8080: Flags [S], seq 0, win 10000, options [mss 1460], length 0
22:14:42.288406 ? Out IP 192.168.66.212.8080 > 192.0.2.1.43605: Flags [S.], seq 386595060, ack 1, win 65535, options [mss 1460], length 0
22:14:42.298508 ? In IP 192.0.2.1.43605 > 192.168.66.212.8080: Flags [.], ack 1, win 10000, length 0
22:14:42.298567 ? Out IP 192.168.66.212.8080 > 192.0.2.1.43605: Flags [F.], seq 1, ack 1, win 65535, length 0
22:14:42.298576 ? In IP 192.0.2.1.43605 > 192.168.66.212.8080: Flags [R.], seq 1, ack 1, win 10000, length 0
当然也可以以绝对时间来编写测试,执行同样成功。
# cat tcp_3hs_time_010.pkt
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
0.01 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
0.02 bind(3, ..., ...) = 0
0.03 listen(3, 1) = 0
0.04 < S 0:0(0) win 10000 <mss 1460>
0.044~0.054 > S. 0:0(0) ack 1 <...>
0.05 < . 1:1(0) ack 1 win 10000
0.06 accept(3, ..., ...) = 4
#
# packetdrill tcp_3hs_time_010.pkt
#
实验测试 Loose
Loose 模式实际是调整的 --tolerance_usecs 参数值,默认值是 4ms。
在《理解时间模型之相对时间》文章中,曾有一个测试脚本测试未成功,是由于 script packet: 0.004059 秒,还有一个自身执行的时间偏离,如果是 0.004059 秒,加上偏移就是在[0.000059,0.008059]内,真实数据包的 0.000054 秒不在其中,因此测试失败 。之后通过修改 0.004 为 0.003 后测试成功,因为这样 script packet 的执行时间加上偏移,肯定是在 [0.000000,0.007000]内,脚本会执行成功。
# cat tcp_3hs_time_006.pkt
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 bind(3, ..., ...) = 0
+0 listen(3, 1) = 0
+0 < S 0:0(0) win 10000 <mss 1460>
+0.004 > S. 0:0(0) ack 1 <...>
+0.01 < . 1:1(0) ack 1 win 10000
+0 accept(3, ..., ...) = 4
#
# packetdrill tcp_3hs_time_006.pkt
tcp_3hs_time_006.pkt:7: error handling packet: timing error: expected outbound packet at 0.004059 sec but happened at 0.000054 sec; tolerance 0.004000 sec
script packet: 0.004059 S. 0:0(0) ack 1
actual packet: 0.000054 S. 0:0(0) ack 1 win 65535 <mss 1460>
#
那么通过修改 --tolerance_usecs 参数值为 5ms,也可以成功 ,因为这样 script packet 的执行时间加上偏移,肯定是在[0.000000,0.009000]内,脚本会执行成功。
# cat tcp_3hs_time_011.pkt
--tolerance_usecs = 5000
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
+0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 bind(3, ..., ...) = 0
+0 listen(3, 1) = 0
+0 < S 0:0(0) win 10000 <mss 1460>
+0.004 > S. 0:0(0) ack 1 <...>
+0.01 < . 1:1(0) ack 1 win 10000
+0 accept(3, ..., ...) = 4
#
# packetdrill tcp_3hs_time_011.pkt
#
抓包结果,一切正常。
# tcpdump -i any -nn port 8080
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
22:35:22.220397 ? In IP 192.0.2.1.40423 > 192.168.75.11.8080: Flags [S], seq 0, win 10000, options [mss 1460], length 0
22:35:22.220418 ? Out IP 192.168.75.11.8080 > 192.0.2.1.40423: Flags [S.], seq 3758488528, ack 1, win 65535, options [mss 1460], length 0
22:35:22.230509 ? In IP 192.0.2.1.40423 > 192.168.75.11.8080: Flags [.], ack 1, win 10000, length 0
22:35:22.230562 ? Out IP 192.168.75.11.8080 > 192.0.2.1.40423: Flags [F.], seq 1, ack 1, win 65535, length 0
22:35:22.230570 ? In IP 192.0.2.1.40423 > 192.168.75.11.8080: Flags [R.], seq 1, ack 1, win 10000, length 0
实验测试 Blocking
Blocking 模式也比较特殊,定义的是指定阻塞系统调用在给定的时间开始/返回。
基础脚本,通过strace输出系统调用时间,各系统调用时间间隔基本都在几十到百微秒之内。
# strace -Ttt -e trace=network packetdrill tcp_3hs_000.pkt
...
11:37:03.808371 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 8 <0.000011>
11:37:03.808504 setsockopt(8, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 <0.000004>
11:37:03.808584 bind(8, {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.168.103.108")}, 16) = 0 <0.000006>
11:37:03.808656 listen(8, 1) = 0 <0.000006>
...
修改脚本,预期0.10...0.105,测试执行失败,提示系统调用返回实际发生在 0.100521 sec,而期望的是在 0.105000 sec,也就是[0.101000,0.109000]内,因此失败。
# cat tcp_3hs_time_012.pkt
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
0.10...0.105 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 bind(3, ..., ...) = 0
+0 listen(3, 1) = 0
+0 < S 0:0(0) win 10000 <mss 1460>
+0 > S. 0:0(0) ack 1 <...>
+0.01 < . 1:1(0) ack 1 win 10000
+0 accept(3, ..., ...) = 4
#
# packetdrill tcp_3hs_time_012.pkt
tcp_3hs_time_012.pkt:2: timing error: expected system call return at 0.105000 sec but happened at 0.100521 sec; tolerance 0.004000 sec
#
继续修改脚本,0.10...0.1043,也就是[0.100300,0.108300]内,执行成功。
# cat tcp_3hs_time_013.pkt
0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
0.10...0.1043 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
+0 bind(3, ..., ...) = 0
+0 listen(3, 1) = 0
+0 < S 0:0(0) win 10000 <mss 1460>
+0 > S. 0:0(0) ack 1 <...>
+0.01 < . 1:1(0) ack 1 win 10000
+0 accept(3, ..., ...) = 4
#
# packetdrill tcp_3hs_time_013.pkt
#
可以通过 -f 参数得到输出,可见 setsockopt()相较于 socket() 开始时间确实间隔了约 10ms,符合 0.10 的设定。
...
strace: Process 75716 attached
[11:46:37.300375 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 8 <0.000015> ]
[11:46:37.400964 setsockopt(8, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 <0.000008> ]
[11:46:37.401169 bind(8, {sa_family=AF_INET, sin_port=htons(8080), sin_addr=inet_addr("192.168.77.51")}, 16) = 0 <0.000008> ]
[11:46:37.401250 listen(8, 1) = 0 <0.000005> ]
...
抓包结果,因为并没有修改三次握手的数据包,所以没有什么变化。
# tcpdump -i any -nn port 8080
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
22:28:30.210863 ? In IP 192.0.2.1.59281 > 192.168.8.128.8080: Flags [S], seq 0, win 10000, options [mss 1460], length 0
22:28:30.210891 ? Out IP 192.168.8.128.8080 > 192.0.2.1.59281: Flags [S.], seq 1173665299, ack 1, win 65535, options [mss 1460], length 0
22:28:30.222750 ? In IP 192.0.2.1.59281 > 192.168.8.128.8080: Flags [.], ack 1, win 10000, length 0
22:28:30.223030 ? Out IP 192.168.8.128.8080 > 192.0.2.1.59281: Flags [F.], seq 1, ack 1, win 65535, length 0
22:28:30.223045 ? In IP 192.0.2.1.59281 > 192.168.8.128.8080: Flags [R.], seq 1, ack 1, win 10000, length 0
往期推荐
原文始发于微信公众号(Echo Reply):Wireshark & Packetdrill | 理解时间模型之其他时间
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论