Linux中使用TCPDUMP嗅探数据包
1. 概述
在本文中,我们将研究Linux 中的工具tcpdump。特别是,我们将学习如何在 Linux 环境中使用tcpdump捕获网络数据包。
2. tcpdump
2.1. tcpdump简介
tcpdump 是 Linux 中的网络数据包嗅探器工具。本质上,它在接口上侦听并转储通过该接口的任何数据包。通过转储,我们将能够更深入地了解通过节点的数据包。
2.2. 安装
要在基于 Debian 的 Linux(例如 Ubuntu)中安装tcpdump ,我们可以使用apt-get 命令:
$ sudo apt-get update
$ sudo apt-get install -y tcpdump
或者,我们可以在 CentOS 等基于 RHEL 的 Linux 上使用yum执行安装:
$ sudo yum update
$ sudo yum install -y tcpdump
2.3. 一般语法
通常,tcpdump的语法可以表示为命令后跟选项列表和表达式:
tcpdump [OPTIONS] [expression]
OPTIONS参数是一个可选的标志列表,我们可以指定这些标志来改变tcpdump的不同方面。此外,expression是一个强大的结构,允许用户通过不同的属性进一步过滤数据包。
2.4. 基本用法
让我们使用默认配置运行tcpdump ,不带任何标志或表达式:
$ tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
10:33:18.583077 IP 927e94ccde39.54226 > 192.168.65.4.53: 39122+ AAAA? www.blogdemo.com. (34)
10:33:18.583082 IP 927e94ccde39.36545 > 192.168.65.4.53: 53932+ A? www.blogdemo.com. (34)
10:33:18.583450 IP 927e94ccde39.38845 > 192.168.65.4.53: 61341+ PTR? 4.65.168.192.in-addr.arpa. (43)
10:33:18.623951 IP 192.168.65.4.53 > 927e94ccde39.36545: 53932 3/0/0 A 104.26.12.74, A 172.67.72.45, A 104.26.13.74 (82)
10:33:18.624004 IP 192.168.65.4.53 > 927e94ccde39.54226: 39122 3/0/0 AAAA 2606:4700:20::ac43:482d, AAAA 2606:4700:20::681a:c4a, AAAA 2606:4700:20::681a:d4a (118)
10:33:18.624381 IP 927e94ccde39.35182 > 104.26.12.74.80: Flags [S], seq 3026253548, win 64240, options [mss 1460,sackOK,TS val 3916952268 ecr 0,nop,wscale 7], length 0
10:33:18.668779 IP 104.26.12.74.80 > 927e94ccde39.35182: Flags [S.], seq 452853775, ack 3026253549, win 65535, options [mss 1460,wscale 2,eol], length 0
10:33:18.668809 IP 927e94ccde39.35182 > 104.26.12.74.80: Flags [.], ack 1, win 502, length 0
10:33:18.668873 IP 927e94ccde39.35182 > 104.26.12.74.80: Flags [P.], seq 1:81, ack 1, win 502, length 80: HTTP: GET / HTTP/1.1
10:33:18.671819 IP 104.26.12.74.80 > 927e94ccde39.35182: Flags [.], ack 81, win 65535, length 0
10:33:18.691618 IP 104.26.12.74.80 > 927e94ccde39.35182: Flags [P.], seq 1:610, ack 81, win 65535, length 609: HTTP: HTTP/1.1 301 Moved Permanently
10:33:18.691628 IP 927e94ccde39.35182 > 104.26.12.74.80: Flags [.], ack 610, win 501, length 0
当我们不指定接口时,tcpdump将监听系统接口列表中编号最低的接口。在本例中,它选择eth0作为监听接口。然后,它捕获并打印以控制通过接口的任何数据包。
从输出中,我们可以看到每一行中网络数据包的详细信息。让我们更深入地研究一个示例数据包转储:
10:33:18.583077 IP 927e94ccde39.54226 > 192.168.65.4.53: 39122+ AAAA? www.blogdemo.com. (34)
从输出中,我们可以确定捕获此数据包的时间。除此之外,我们知道这个数据包是一个IP数据包,因为协议显示在时间戳旁边。
此外,我们从转储中得知此数据包源自端口54226上的主机927e94ccde39,并且它正向端口53上的**192.168.65.4发送。
3. 网络接口选项
3.1. 列出系统接口
我们可以使用*-D*标志查询系统上可用的接口列表 :
$ tcpdump -D
1.eth0 [Up, Running]
2.eth1 [Up, Running]
3.lo [Up, Running, Loopback]
4.any (Pseudo-device that captures on all interfaces) [Up, Running]
5.bluetooth-monitor (Bluetooth Linux Monitor) [none]
6.nflog (Linux netfilter log (NFLOG) interface) [none]
7.nfqueue (Linux netfilter queue (NFQUEUE) interface) [none]
8.tunl0 [none]
9.ip6tnl0 [none]
正如我们所见,tcpdump还显示了每个接口的状态。除了实际的网络接口之外,tcpdump还创建了一个名为*“any”的伪设备。**通过侦听这个伪设备any*,tcpdump将捕获通过所有接口的数据包。**
3.2. 指定接口
在具有多个接口的系统上,我们可以使用*-i*标志选择要收听的接口:
$ tcpdump -i wlan0
上面的命令在接口wlan0上启动tcpdump。此外,我们可以使用伪设备any捕获所有接口的数据包:
$ tcpdump -i any
4. 格式化时间戳
在每个数据包转储输出中,tcpdump在第一列附加一个时间戳以指示捕获数据包的时间。tcpdump支持使用*-t*标志格式化此时间戳输出。
4.1. 抑制时间戳信息
为了防止tcpdump打印任何时间戳信息,我们可以指定-t*标志*:
$ tcpdump -t
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP centos-box.intra.40600 > 927e94ccde39.443: Flags [P.], seq 1584919446:1584919451, ack 1644285291, win 502, options [nop,nop,TS val 1654074382 ecr 2691638716], length 5
IP 927e94ccde39.443 > centos-box.intra.40600: Flags [.], ack 5, win 510, options [nop,nop,TS val 2693653313 ecr 1654074382], length 0
4.2. 以纪元时间打印时间戳
我们还可以使用*-tt*标志在纪元(1970 年 1 月 1 日 00:00:00 UTC)之后以秒为单位打印时间戳:
$ tcpdump -tt
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
1615623341.099481 IP centos-box.intra.40600 > 927e94ccde39.443: Flags [P.], seq 1584919451:1584919456, ack 1644285291, win 502, options [nop,nop,TS val 1654246252 ecr 2693653313], length 5
1615623341.099494 IP 927e94ccde39.443 > centos-box.intra.40600: Flags [.], ack 5, win 510, options [nop,nop,TS val 2693825183 ecr 1654246252], length 0
从输出中,我们可以观察到时间戳分辨率下降到微秒级别。
4.3. 在时间增量中打印时间戳
我们可以使用*-ttt*标志根据增量输出时间戳。具体来说,tcpdump将在每一行打印当前转储和上一个转储之间的时间差:
$ tcpdump -ttt
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
00:00:00.000000 IP centos-box.intra.40600 > 927e94ccde39.443: Flags [P.], seq 1584919456:1584919461, ack 1644285291, win 502, options [nop,nop,TS val 1654379130 ecr 2693825183], length 5
00:00:00.000014 IP 927e94ccde39.443 > centos-box.intra.40600: Flags [.], ack 5, win 510, options [nop,nop,TS val 2693958061 ecr 1654379130], length 0
在上面的示例中,我们可以很容易地推断出第一个和第二个数据包之间的时间差为 14 微秒。
4.4. 打印带日期的时间戳
最后,我们可以使用*-tttt*标志打印时间戳和日期:
$ tcpdump -tttt
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
2021-03-13 08:20:05.370345 IP centos-box.intra.40600 > 927e94ccde39.443: Flags [P.], seq 1584919461:1584919466, ack 1644285291, win 502, options [nop,nop,TS val 1654510522 ecr 2693958061], length 5
2021-03-13 08:20:05.370400 IP 927e94ccde39.443 > centos-box.intra.40600: Flags [.], ack 5, win 510, options [nop,nop,TS val 2694089454 ecr 1654510522], length 0
5. 将数据包转储保存到文件
tcpdump还提供了几个标志,允许我们将数据包转储写入文件。
5.1. 写入文件
要将数据包转储写入文件,我们可以使用标志-w*后跟文件名*:
$ tcpdump -w packet-captured.pcap
当我们将转储写入文件时,tcpdump将不再将转储打印到标准输出。
5.2. 限制每个文件的大小
我们可以使用-C*标志限制每个文件的大小*。该标志接受一个整数值,表示每个文件的大小限制(以百万字节为单位):
$ tcpdump -w out.pcap -C 2
在上面的示例中,tcpdump会将捕获的数据包写入文件out.pcap中。一旦文件大小达到 2MB,此后每增加 2MB,它会将后续数据包保存到新文件out.pcap1、out.pcap2、out.pcap3等中。
5.3. 按时间间隔旋转保存文件
使用-G*标志,tcpdump以指定的时间间隔将转储保存到新文件中*。例如,我们可以每五秒轮换一次保存文件:
$ tcpdump -w out-%Y%m%d-%H%M%S.pcap -G 5
在上面的示例中,我们根据strftime 格式动态命名我们的文件。如果文件名指定为每个指定时间间隔不变,则先前的保存文件将被覆盖。
6. 以监控模式运行
在 IEEE 802.11 WiFi 接口上,监控模式 允许接口捕获在无线通道上接收到的所有数据包。此外,它甚至可以在不关联或链接到特定接入点的情况下嗅探数据包。
要在监控模式下的接口上运行tcpdump ,我们可以使用-I*标志*:
$ tcpdump -I
但是,请注意并非所有接口都支持监控模式。如果我们尝试在不支持它的接口上运行监控模式,tcpdump将输出一条错误消息:
$ tcpdump -i eth0 -I
tcpdump: eth0: That device doesn't support monitor mode
7. 其他有用的选项
7.1. 抑制地址查找
默认情况下,tcpdump会自动解析主机地址的名称。这可能是不可取的,因为它会导致 DNS 查找的网络开销。我们可以使用*-n*标志抑制查找:
$ tcpdump -n
7.2. 数据包方向
tcpdump捕获接口的传入和传出流量。我们可以使用-Q标志后跟方向值in、out或inout来捕获特定方向的数据包**。例如,我们可以只捕获接口eth0上的传出数据包:
$ tcpdump -i eth0 -Q out
7.3. 打印包号
我们可以使用*-#标志使tcpdump*在每个输出行中显示数据包编号:
$ tcpdump -#
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
1 10:33:50.254707 IP 927e94ccde39.55667 > 192.168.65.4.53: 36710+ AAAA? www.blogdemo.com. (34)
2 10:33:50.254897 IP 927e94ccde39.49841 > 192.168.65.4.53: 19808+ A? www.blogdemo.com. (34)
3 10:33:50.255044 IP 927e94ccde39.58436 > 192.168.65.4.53: 37800+ PTR? 4.65.168.192.in-addr.arpa. (43)
正如我们所见,每条输出行现在都有一个数字。该数字按顺序运行,并提供到目前为止捕获的数据包数量的指示。
8. 表情
除了我们可以使用的无数选项标志外,tcpdump还提供了一组我们可以指定为最终参数的语法 。使用表达式,我们可以构建一个规则集,该规则集将根据数据包的属性(例如协议)过滤数据包。
8.1. 语法结构
通常,表达式由原语和限定符组成:
[qualifier...] qualifier primitive [and|or|not] [primitive...]
基元通常是 number 或 string。这些原语本身没有意义。为了赋予这些原语以意义,我们将在它们之前加上一个或多个限定词。
语法中有三种不同的限定符——即type、dir和proto。类型限定符指定原语的类型。例如,如果原语80与类型**port一起指定,则原语值80代表端口号80。type限定符的可能值为host、net、port和portrange。如果没有指定类型限定符,则假定值host用于表达式。
限定符dir指定数据包的方向。此限定符的一些可能值是src、dst、src 或 dst以及src 和 dst。
除此之外,限定符proto代表要匹配的数据包的协议。此限定符的可能值包括ether、ip、ip6、arp、tcp和udp。
最后,语法还包含诸如and、or和not 之类的词,它们允许我们组合原语来构建复杂的表达式。它们的符号表示如*&&、||* ,和*!*也被表达式解析器识别。
让我们看一些例子。
8.2. 按主机过滤数据包
过滤数据包的最简单方法之一是按其主机进行过滤。具体来说,我们可以使用host语法捕获与特定主机关联的数据包:
$ tcpdump 'host www.blogdemo.com'
上面的命令只会转储来自或去往www.blogdemo.com 的数据包。
8.3. 按端口过滤数据包
我们还可以使用限定符端口按端口号过滤数据包:
$ tcpdump 'port 80'
上面的命令只捕获来自或去往端口 80 的任何数据包。此外,我们可以使用src或dst指定方向。例如,如果我们只想捕获源字段为端口 80 的数据包,我们可以在表达式前加上src:
$ tcpdump 'src port 80'
除此之外,限定符portrange允许我们指定我们希望从中捕获数据包的端口号范围:
$ tcpdump 'portrange 80-90'
使用上面的表达式,tcpdump捕获任何落在 80 到 90 端口范围内的数据包。
8.4. 按网络过滤数据包
使用net限定符,我们可以根据数据包所属的网络过滤数据包。例如,我们可以捕获来自192.168.0.1/16网络的数据包:
$ tcpdump 'net 192.168'
当我们省略最后两个字节时,tcpdump会自动将网络掩码*/16*应用于网络。
也可以使用掩码限定符显式指定网络掩码:
$ tcpdump 'net 192.168.0.1 mask 255.255.0.0'
这两个不同的表达式最终构造了相同的过滤器。
8.5. 按协议过滤数据包
要按协议过滤数据包,我们可以使用限定符proto后跟协议名称。例如,我们可以只转储 UDP 数据包:
$ tcpdump 'proto udp'
该工具为更常见的协议提供了一些快捷方式,例如tcp、udp和 icmp。例如,上面的命令可以只用tcp表达式重写:
$ tcpdump 'udp'
8.6. 其他有用的表达方式
使用语法less或greater,我们可以根据数据包长度过滤数据包。例如,只抓取长度小于 40 的数据包:
$ tcpdump 'less 40'
另一方面,仅捕获长度大于 40 的数据包:
$ tcpdump 'greater 40'
我们可以使用限定符inbound和 outbound按方向过滤数据包,而不是使用标志。例如,要仅捕获传入的数据包,我们可以使用 inbound语法:
$ tcpdump 'inbound'
同样,我们可以使用语法outbound只转储传出数据包:
$ tcpdump 'outbound'
8.7. 逻辑语法
tcpdump支持诸如and、or和not 之类的逻辑结构,这让我们可以构建更复杂的规则集。例如,我们可以构建一个过滤器,只捕获来自主机www.blogdemo.com 或 www.google.com 的流量:
$ tcpdump 'src host www.blogdemo.com or www.google.com'
此外,我们可以构建一个过滤器,使用and运算符在端口 443 上捕获来自www.blogdemo.com 的数据包:
$ tcpdump 'host www.blogdemo.com and port 443'
最后,not运算符可用于对表达式取反。例如,我们可以捕获除来自192.168.0.1/16网络的数据包之外的所有数据包:
$ tcpdump 'not net 192.168'