$ sudo docker pull alpine:3.8
$ sudo docker run -d --name ctn-1 alpine:3.8 sleep 3600d$ sudo docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES233bc36bde4b alpine:3.8 "sleep 3600d" 1 minutes ago Up 14 minutes ctn-1
$ sudo docker exec -it ctn-1 sh
/ # ifconfigeth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:09 inet addr:172.17.0.9 Bcast:0.0.0.0 Mask:255.255.0.0
/ # apk update
/ # apk add tcpdump
/ # wget http://example.comConnecting to example.com (93.184.216.34:80)index.html 100% |*****************************| 1270 0:00:00 ETA
wget http://example.com
,能看到如下类 似的输出。为了方便后面的讨论,这里将一些字段去掉了,并做了适当的对齐:/ # tcpdump -n -S -i eth0 host example.com1 02:52:44.513700 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [S] , seq 3310420140, length 02 02:52:44.692890 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [S.], seq 1353235534, ack 3310420141, length 03 02:52:44.692953 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353235535, length 04 02:52:44.693009 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [P.], seq 3310420141:3310420215, ack 1353235535, length 74: HTTP: GET / HTTP/1.15 02:52:44.872266 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [.] , ack 3310420215, length 06 02:52:44.873342 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [.] , seq 1353235535:1353236983, ack 3310420215, length 1448: HTTP: HTTP/1.1 200 OK7 02:52:44.873405 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353236983, length 08 02:52:44.874533 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [P.], seq 1353236983:1353237162, ack 3310420215, length 179: HTTP9 02:52:44.874560 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353237162, length 010 02:52:44.874705 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [F.], seq 3310420215, ack 1353237162, length 011 02:52:45.053732 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [.] , ack 3310420216, length 012 02:52:45.607825 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [F.], seq 1353237162, ack 3310420216, length 013 02:52:45.607869 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353237163, length 0
-n
:打印 IP 而不是 hostname,打印端口号而不是协议(例如打印 80 而不是 http)-S
:打印绝对时间戳-i eth0
:指定从 eth0 网卡抓包host example.com
:抓和 example.com 通信的包(双向)-w
命令可以将抓到的包写到文件,注意这和用重定向方式将输出写到文件是不同的。后者写的只是标准输出打印的 LOG,而 -w
写的是原始包。/ # tcpdump -i eth0 host example.com -w example.pcap
^C
13 packets captured
13 packets received by filter
0 packets dropped by kernel
tcpdump
或者 wireshark
之类的网络流量分析工具打开。02:52:44.513700
表示抓到这个包的时间是** 02 时 52 分 44 秒 513 毫秒**IP
包S
表示 syn
包.
表示 ack
包F
表示 fin
包P
表示 push
包(发送正常数据)1 02:52:44.513700 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [S] , seq 3310420140, length 0
2 02:52:44.692890 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [S.], seq 1353235534, ack 3310420141, length 0
3 02:52:44.692953 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353235535, length 0
#1
包含以下信息:#1
序列号是 3310420140,这是客户端的初始序列号(客户端和服务端分别维护自己的序列号,两者没有关系;另外,初始序列号是系统选择的,一般不是 0)#1
length 为 0,因为 SYN 包不带 TCP payload,所有信息都在 TCP header#2
的 ack 是 3310420140
,等于 #1
的 seq 加 1,这就说明,#2
是 #1
的应答包。S.
,即 SYN+ACK1353235534
,这是服务端的初始序列号02:52:44.692890
,说明时间过了 18ms
#3
的 ack 等于 #2
的 seq 加 1,说明 #3
是 #2
的应答包。.
,即 ACK4 02:52:44.693009 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [P.], seq 3310420141:3310420215, ack 1353235535, length 74: HTTP: GET / HTTP/1.15 02:52:44.872266 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [.] , ack 3310420215, length 06 02:52:44.873342 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [.] , seq 1353235535:1353236983, ack 3310420215, length 1448: HTTP: HTTP/1.1 200 OK7 02:52:44.873405 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353236983, length 08 02:52:44.874533 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [P.], seq 1353236983:1353237162, ack 3310420215, length 179: HTTP9 02:52:44.874560 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353237162, length 0
#4
: client 向 server 发起 HTTP GET 请求,请求路径为根路径(/),这个 packet 长度为 74 字节#5
: 发送了 ACK 包,对 #4
进行确认#6
: 发送了 1448 字节的数据给 client#7
: client 对 server 的 #6
进行应答#8
: server 向 client 端继续发送 179 字节数据#9
: client 对 server 的 #8
进行应答10 02:52:44.874705 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [F.], seq 3310420215, ack 1353237162, length 011 02:52:45.053732 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [.] , ack 3310420216, length 012 02:52:45.607825 IP 93.184.216.34.80 > 172.17.0.9.41038: Flags [F.], seq 1353237162, ack 3310420216, length 013 02:52:45.607869 IP 172.17.0.9.41038 > 93.184.216.34.80: Flags [.] , ack 1353237163, length 0
-r
读取 pcap 文件,并以指定的格式输出包的信息,最后输出的内容 和上面看到的类似。我们上面的流量非常简单,所以看 tcpdump 的输出就够了。#1
在 08:00:05.125
发送出去,请求建立连接1s
后,客户端仍然没有收到服务端的 ACK 包,触发客户端 TCP 超时重传2s
,仍然没有收到 ACK 包,再次触发超时重传tcp.stream eq 1
,这其实就是其强大的过滤表达式。ip.addr == 192.168.1.1
过滤 SRC IP 或 DST IP 是 192.168.1.1
的包ip.src_host == 192.168.1.1 and ip.dst_host == 192.168.1.2
过滤 SRC IP 是 192.168.1.1
,并且 DST IP 是 192.168.1.2
的包tcp.port == 80
源端口或目的端口是 80 的包tcp.flags.reset == 1
过滤 TCP RST 包。先找到 RST 包,然后右键 Follow -> TCP Stream 是常用的排障方式tcp.analysis.retransmission
过滤所有的重传包热文推荐