tcpdump

tcpdump man

tcpdump 须在管理员权限下运行。

1
2
#tcpdump
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
  • 输出结果表明 tcpdump 的监听网卡为 ens33
  • 默认截断大小为 262144 字节(随版本而改变),超过该数字报文会被截断。

使用 ifconfig 查看其他网卡:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifconfig
ens33 Link encap:Ethernet HWaddr 00:0c:29:48:09:a9
inet addr:192.168.248.128 Bcast:192.168.248.255 Mask:255.255.255.0
inet6 addr: fe80::555a:9e00:3f14:e7f/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:12058 errors:0 dropped:0 overruns:0 frame:0
TX packets:4911 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:9115911 (9.1 MB) TX bytes:577567 (577.5 KB)

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:1110 errors:0 dropped:0 overruns:0 frame:0
TX packets:1110 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1022006 (1.0 MB) TX bytes:1022006 (1.0 MB)

-i 指定网卡

上面默认监听网卡是 ens33 ,我们也可以指定为 lo

1
2
 tcpdump -i lo
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes

-i any 可以监听所有网卡。


-nn 直接显示IP和端口号

1
2
3
4
5
#tcpdump -i lo
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
01:12:54.640796 IP localhost.44438 > localhost.12345: Flags [S], seq 1028792545, win 65495, options [mss 65495,sackOK,TS val 1381449987 ecr 0,nop,wscale 7], length 0
01:12:54.640834 IP localhost.12345 > localhost.44438: Flags [S.], seq 3925511357, ack 1028792546, win 65483, options [mss 65495,sackOK,TS val 1381449987 ecr 1381449987,nop,wscale 7], length 0
01:12:54.640870 IP localhost.44438 > localhost.12345: Flags [.], ack 1, win 512, options [nop,nop,TS val 1381449987 ecr 1381449987], length 0

监听环回网卡时,我们运行自己编写的简易 TCP 服务器端和客户端的回射程序,结果输出以上三次握手内容。其中主机地址为 localhost ,由于 server 和 client 都在一台主机,所以都为 localhost 。如果服务器的端口为著名端口(如 ssh 为 22 号端口),那么 22 也会显示为 ssh。若想直接显示 IP 和端口号,则使用 -nn 命令:

1
2
#tcpdump -i lo -nn
01:14:54.615811 IP 127.0.0.1.44438 > 127.0.0.1.12345: Flags [P.], seq 1028792546:1028792548, ack 3925511358, win 512, options [nop,nop,TS val 1381569983 ecr 1381449987], length 2

-n 不将IP转换为域名

不讲 IP 转为域名,则可以省去 DNS 查询,输出速度会快很多。


过滤主机

  • 抓取所有经过 eth1,目的或源地址是 192.168.1.1 的网络数据
1
#tcpdump -i eth1 host 192.168.1.1
  • 指定源地址
1
#tcpdump -i eth1 src host 192.168.1.1
  • 指定目的地址
1
#tcpdump -i eth1 dst host 192.168.1.1
  • 也可直接指定域名:
1
#tcpdump -i eth1 dest host "baidu.com"

过滤端口

  • 抓取所有经过 eth1,目的或源端口是 25 的网络数据
1
#tcpdump -i eth1 port 25
  • 指定源端口
1
#tcpdump -i eth1 src port 25
  • 指定目的端口
1
#tcpdump -i eth1 dst port 25
  • 指定端口范围:portrange

    1
    # tcpdump -i lo portrange 10000-20000
  • 对于著名端口,可直接用应用层协议替代,相当于宏:

    1
    # tcpdump port http 

网段过滤

1
2
3
#tcpdump -i eth1 net 192.168
#tcpdump -i eth1 src net 192.168
#tcpdump -i eth1 dst net 192.168.0.0/16

协议过滤

1
2
3
#tcpdump arp  
#tcpdump ip
#tcpdump tcp

不能直接过滤协议,如下

1
#tcpdump http  

而应该

1
#tcpdump port http

常用表达式

1
2
3
非 : ! 或 not 
且 : && 或 and
或 : || 或 or
1
2
#tcpdump -i lo -nn tcp && dst port 12345 && src host 127.0.0.1
#tcpdump -i lo -nn tcp and dst port 12345 and src host 127.0.0.1

有时条件比较复杂的需要用括号:

1
2
#tcpdump -i eth1 '((tcp) and (! port 80) and ((dst host 192.168.1.254) or (dst host 192.168.1.200)))'
抓取所有经过eth1,目的地址是192.168.1.254或192.168.1.200,并且端口不是80的TCP数据

如果使用括号,则整个表达式需要用 ''"" 包住。


包头过滤

1
2
3
proto[x:y]          : 过滤从x字节开始的y字节数。比如ip[2:2]过滤出3、4字节(从第0字节开始)
proto[x:y] & z = 0 : proto[x:y]和z的与操作为0
proto[x:y] & z !=0 : proto[x:y]和z的与操作不为0

IP报头格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 \bit
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0 |Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4 | Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12 | Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16 | Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20 | Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24 | Options | Padding | <-- optional
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28 | DATA ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\byte

TCP报头格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   0                   1                   2                   3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 \bit
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0 | Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4 | Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8 | Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |C|E|U|A|P|R|S|F| |
12 | Offset| Res. |W|C|R|C|S|S|Y|I| Window |
| | |R|E|G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16 | Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20 | Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24 | data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
\byte
1
2
# tcpdump -i lo "tcp[2:2]=12345"
只显示目的端口号为12345的报文

TCP标记定义在TCP头的第 13 个字节:

1
2
# tcpdump -i lo "src port 12345 && tcp[13]&1 = 1"
只显示目的端口号为12345的FIN报文

TCP标记宏可以替代数值:

tcpflags , tcp-fin , tcp-syn , tcp-rst , tcp-push , tcp-push , tcp-ack , tcp-urg

1
# tcpdump -i lo "dst port 12345 && tcp[tcpflags]&tcp-fin=tcp-fin"

-w 输出到文件、-r 读取文件

1
# tcpdump tcp -w test.cap

把信息输出到 test.cap 文件。将文件保存为 cappcap 类型就能方便地使用 wireshark 打开并分析:

1
# tcpdump tcp -r test.cap

读取 test.cap 文件并打印在终端,同时也可以使用过滤规则:

1
# tcpdump tcp -r test.cap port 12345

输出时间

  • -t:在每行的输出中不输出时间
  • -tt:在每行的输出中会输出时间戳
  • -ttt:输出每两行打印的时间间隔(以毫秒为单位)
  • -tttt:在每行打印的时间戳之前添加日期的打印
1
2
3
4
5
6
7
8
9
10
11
12
# tcpdump -t dst  "baidu.com"
IP 192.168.248.128 > 39.156.66.10: ICMP echo request, id 11930, seq 1650, length 64

# tcpdump -tt dst "baidu.com"
1680352032.093467 IP 192.168.248.128 > 39.156.66.10: ICMP echo request, id 11930, seq 1662, length 64

# tcpdump -ttt dst "baidu.com"
00:00:00.000000 IP 192.168.248.128 > 39.156.66.10: ICMP echo request, id 11930, seq 1672, length 64
00:00:01.002438 IP 192.168.248.128 > 39.156.66.10: ICMP echo request, id 11930, seq 1673, length 64

# tcpdump -tttt dst "baidu.com"
2023-04-01 05:27:30.131073 IP 192.168.248.128 > 39.156.66.10: ICMP echo request, id 11930, seq 1680, length 64

-v 展示详细信息

-v:产生详细的输出。比如包的TTL,id标识,数据包长度,以及IP包的一些选项:

1
2
3
4
root@ubuntu:/home/butcher/Documents# tcpdump -v dst  "baidu.com"
tcpdump: listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
05:36:46.543701 IP (tos 0x0, ttl 64, id 44013, offset 0, flags [DF], proto ICMP (1), length 84)
192.168.248.128 > 39.156.66.10: ICMP echo request, id 12115, seq 7, length 64

-c 指定接收报文个数

1
2
3
4
5
6
7
# tcpdump -v -c 3 
05:46:32.275269 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 192.168.248.2 tell 192.168.248.1, length 46
05:46:32.276545 IP (tos 0x0, ttl 64, id 50690, offset 0, flags [DF], proto UDP (17), length 72)
192.168.248.128.34566 > 192.168.248.2.domain: 39118+ PTR? 2.248.168.192.in-addr.arpa. (44)
05:46:32.280758 IP (tos 0x0, ttl 128, id 35219, offset 0, flags [none], proto UDP (17), length 127)
192.168.248.2.domain > 192.168.248.128.34566: 39118 NXDomain 0/1/0 (99)
3 packets captured

抓满指定数量的报文后自动停止。

-C -W 分文件写入

1
#tcpdump -C 1 -W 4 -w test

-C 和 -w 配套使用,后者将抓包情况写入文件,前者指定每个文件的最大大小,单位为 1MB(小文件利于分析)。

  • -C 1 :指定单个文件最大为 1MB
  • -W :指定最多写 4 个文件
  • -w :写入文件

每个文件会依次添加后缀:test1、test2、test3、test4 。注意,如果写满这 4 个文件后,数据还在持续,那么会重新覆盖这 4 个文件并继续写入,而不会新建文件。


-Q 指定方向

  • -Q in :只显示收到的数据
  • -Q out :只显示发出的数据
1
2
3
4
# tcpdump -Q in
06:04:34.157713 IP 192.168.248.1.50277 > 239.255.255.250.1900: UDP, length 175
06:04:34.163603 IP 192.168.248.2.domain > 192.168.248.128.34566: 27092 NXDomain 0/1/0 (103)
06:04:35.003369 IP 180.101.49.186.https > 192.168.248.128.33644: Flags [.], ack 769671203, win 64240, length 0

-s 指定截取大小

-s 指定每个包捕获的长度、单位是 byte,而不是默认的 262144 字节;如果超过了设定的大小限制,包就会被截断,并在打印行出现[|proto]这种标识,这个proto就是被截断的报文的协议名字。但是抓取越长,包的处理时间越长,并且会减少 tcpdump 可缓存的数据包的数量,从而会导致数据包的丢失,所以在能抓取我们想要的包的前提下,抓取长度越小越好,一般只抓报头 ,抓 80 个字节一般就能包含 TCP 层、IP 层、链路层。

-s 0 使用默认长度 262144。

-e 显示链路层信息

1
2
3
# tcpdump  -e 
06:49:36.315000 00:0c:29:48:09:a9 (oui Unknown) > 00:50:56:fb:6d:e0 (oui Unknown), ethertype IPv4 (0x0800), length 54: 192.168.248.128.33644 > 180.101.49.186.https: Flags [.], ack 565954419, win 65535, length 0

-F 指定过滤过滤表达式文件

有些过滤表达式经常用,但又很冗长,每次输入都很麻烦。所以可以保存为文件,每次 tcpdump 时指定该文件为过滤规则:

1
#tcpdump -F filter_file

该命令行中的其他命令会被忽略。


less,greater 指定大小

1
#tcpdump less 100

-X 打印数据内容
-X 除了打印每个数据包的头之外,还可以用十六进制和ASCII打印每个数据包的数据(不包括链路级头,-XX 可包含):