如何理解tcpdump的抓包日志

tcpdump 是一个强大的抓包工具,它可以用于抓取指定网络端口上的数据,这在某些场景下会非常有用。tcpdump 的命令参数相当复杂,打开它的 man page,你会发现有好多页内容,真让人头大。此外它的日志输出格式也比较独特,如果不了解规则的话将很难读懂。

通常情况下,一个命令的常用参数不会太多,man page 大而全的做法反而使得上手困难(太长,难以阅读)。因此,我建议你尝试一下 tldr,它与 man page 相反(TL;DR——Too Long, Didn’t Read),只提供命令最常见的用法,以简洁友好的方式展现出来,非常适合快速了解一个命令。

常用的命令参数

如下是 tcpdump 命令在 tldr 中的展示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Dump traffic on a network.
More information: <https://www.tcpdump.org>.

- List available network interfaces:
tcpdump -D

- Capture the traffic of a specific interface:
tcpdump -i eth0

- Capture all TCP traffic showing contents (ASCII) in console:
tcpdump -A tcp

- Capture the traffic from or to a host:
tcpdump host www.example.com

- Capture the traffic from a specific interface, source, destination and destination port:
tcpdump -i eth0 src 192.168.1.1 and dst 192.168.1.2 and dst port 80

- Capture the traffic of a network:
tcpdump net 192.168.1.0/24

- Capture all traffic except traffic over port 22 and save to a dump file:
tcpdump -w dumpfile.pcap port not 22

- Read from a given dump file:
tcpdump -r dumpfile.pcap

搞懂上面这些命令,基本就能满足大多数场景,如果有更复杂的需求,还是要结合 man page 探索下更高级的用法。

man page中提供的一个示例

为了讲解日志格式,man page 里提供了一个抓包日志示例:这是使用 rlogin 从主机 rtsg 登录到主机 csam 的部分日志。

1
2
3
4
5
6
7
8
9
IP rtsg.1023 > csam.login: Flags [S], seq 768512:768512, win 4096, opts [mss 1024]
IP csam.login > rtsg.1023: Flags [S.], seq, 947648:947648, ack 768513, win 4096, opts [mss 1024]
IP rtsg.1023 > csam.login: Flags [.], ack 1, win 4096
IP rtsg.1023 > csam.login: Flags [P.], seq 1:2, ack 1, win 4096, length 1
IP csam.login > rtsg.1023: Flags [.], ack 2, win 4096
IP rtsg.1023 > csam.login: Flags [P.], seq 2:21, ack 1, win 4096, length 19
IP csam.login > rtsg.1023: Flags [P.], seq 1:2, ack 21, win 4077, length 1
IP csam.login > rtsg.1023: Flags [P.], seq 2:3, ack 21, win 4077, urg 1, length 1
IP csam.login > rtsg.1023: Flags [P.], seq 3:4, ack 21, win 4077, urg 1, length 1
  1. 第一行。主机 rtsg 通过 1023 端口向主机 csam 的 login 端口发送了一个数据包,Flag 中的 S 表示设置了 SYN 标志,说明这是一个 SYN 包。这个包的 seq 是 768512,序号的格式是 first:last,其中已发送的数据中不包含 last 所指向的字节,对于本例来说,发送的数据为空。
  2. 第二行。主机 csam 向主机 rtsg 回复了一个 ACK,对应于 Flag 中的 .,同时还设置了 SYN 标识,可以看出这是 3 次握手中的第二个数据包。同样,它也不包含任何数据,因此 seq 值为 947648:947648。ACK 的值为 768513 = 768512 + 1,表示期望的数据包序号。win 4096 表示窗口大小,也就是本地可以缓存的数据大小。
  3. 第六行。rtsg 向 csam 发送了长度为 19 的数据包,序号为 2 - 20,并且设置了 PUSH 标志。
  4. 第七行。csam 回复 rtsg 收到了数据,ack 21 表示已经收到了序号为 20 的数据,期望序号为 21。win 4077 表示此时它的窗口大小为 4077,可以看出已收到的 19 个字节的数据就在缓冲区中。
  5. 第八行和第九行。csam 分别向 rtsg 发送了一个字节的紧急数据(均设置了 urg 标志)

tcp数据格式

如果不带任选字段(Options),tcp header 的长度为 20 个字节,它的格式如下图所示:

1
2
3
4
5
6
7
8
9
10
11
12
0                            15                              31
-----------------------------------------------------------------
| source port | destination port |
-----------------------------------------------------------------
| sequence number |
-----------------------------------------------------------------
| acknowledgment number |
-----------------------------------------------------------------
| HL | rsvd |C|E|U|A|P|R|S|F| window size |
-----------------------------------------------------------------
| TCP checksum | urgent pointer |
-----------------------------------------------------------------

0-1 字节:16位的源端口号

2-3字节:16位的目的端口号

4-7字节:32位序号

8-11字节:32位确认序号

12-13字节:4位首部长度、保留位、标志位 CWR | ECE | URG | ACK | PSH | RST | SYN | FIN

14-15字节:16位窗口大小

16-17字节:16位校验和

18-19字节:16位紧急指针

根据标志位过滤

只保留设置了 syn 标志或 fin 标志的数据包

1
tcpdump 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0'

更多请参考 man page

man page提供的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
To print all packets arriving at or departing from sundown:
tcpdump host sundown

To print traffic between helios and either hot or ace:
tcpdump host helios and \( hot or ace \)

To print all IP packets between ace and any host except helios:
tcpdump ip host ace and not helios

To print all traffic between local hosts and hosts at Berkeley:
tcpdump net ucb-ether

To print all ftp traffic through internet gateway snup: (note that the expression is quoted to prevent
the shell from (mis-)interpreting the parentheses):
tcpdump 'gateway snup and (port ftp or ftp-data)'

To print traffic neither sourced from nor destined for local hosts (if you gateway to one other net,
this stuff should never make it onto your local net).
tcpdump ip and not net localnet

To print the start and end packets (the SYN and FIN packets) of each TCP conversation that involves a
non-local host.
tcpdump 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net localnet'

To print all IPv4 HTTP packets to and from port 80, i.e. print only packets that contain data, not, for
example, SYN and FIN packets and ACK-only packets. (IPv6 is left as an exercise for the reader.)
tcpdump 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'

To print IP packets longer than 576 bytes sent through gateway snup:
tcpdump 'gateway snup and ip[2:2] > 576'

To print IP broadcast or multicast packets that were not sent via Ethernet broadcast or multicast:
tcpdump 'ether[0] & 1 = 0 and ip[16] >= 224'

To print all ICMP packets that are not echo requests/replies (i.e., not ping packets):
tcpdump 'icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply'