一份快速实用的 tcpdump 命令参考手册

对于 tcpdump 的使用,大部分管理员会分成两类。有一类管理员,他们熟知  tcpdump 和其中的所有标记;另一类管理员,他们仅了解基本的使用方法,剩下事情都要借助参考手册才能完成。出现这种情况的原因在于, tcpdump 是一个相当高级的命令,使用的时候需要对网络的工作机制有相当深入的了解。

在今天的文章中,我想提供一个快速但相当实用的 tcpdump 参考。我会谈到基本的和一些高级的使用方法。我敢肯定我会忽略一些相当酷的命令,欢迎你补充在评论部分。

在我们深入了解以前,最重要的是了解  tcpdump 是用来做什么的。 tcpdump 命令用来保存和记录网络流量。你可以用它来观察网络上发生了什么,并可用来解决各种各样的问题,包括和网络通信无关的问题。除了网络问题,我经常用 tcpdump 解决应用程序的问题。如果你发现两个应用程序之间无法很好工作,可以用  tcpdump  观察出了什么问题。 tcpdump 可以用来抓取和读取数据包,特别是当通信没有被加密的时候。

基础知识

了解 tcpdump ,首先要知道 tcpdump中使用的标记(flag)。在这个章节中,我会涵盖到很多基本的标记,这些标记在很多场合下会被用到。

不转换主机名、端口号等

通常情况下, tcpdump  会尝试查找和转换主机名和端口号。

你可以通过 -n 标记关闭这个功能。我个人总是使用这个标记,因为我喜欢使用 IP 地址而不是主机名,主机名和端口号的转换经常会带来困扰。但是,知道利用  tcpdump  转换或者不转换的功能还是相当有用的,特别是有些时候,知道源流量(source traffic)来自哪个服务器是相当重要的。

增加详细信息

增加一个简单 -v 标记,输出会包含更多信息,例如一个 IP 包的生存时间(ttl, time to live)、长度和其他的选项。

tcpdump  的详细信息有三个等级,你可以通过在命令行增加 v 标记的个数来获取更多的信息。通常我在使用 tcpmdump 的时候,总是使用最高等级的详细信息,因为我希望看到所有信息,以免后面会用到。

指定网络接口

通常情况下,如果不指定网络接口, tcpdump  在运行时会选择编号最低的网络接口,一般情况下是 eth0,不过因系统不同可能会有所差异。

你可以用 -i 标记来指定网络接口。在大多数 Linux 系统上,any 这一特定的网络接口名用来让  tcpdump  监听所有的接口。我发现这在排查服务器(拥有多个网络接口)的问题特别有用,尤其是牵扯到路由的时候。

写入文件

tcpdump  运行结果会输出在屏幕上。

但很多时候,你希望把  tcpdump  的输出结果保存在文件中,最简单的方法就是利用 -w 标记。如果你后续还会检查这些网络数据,这样做就特别有用。将这些数据存成一个文件的好处,就是你可以多次读取这个保存下来的文件,并且可以在这个网络流量的快照上使用其它标记或者过滤器(我们后面会讨论到)。

通常这些数据被缓存而不会被写入文件,直到你用 CTRL+C 结束 tcpdump 命令的时候。

读取文件

一旦你将输出存成文件,就必然需要读取这个文件。要做到这点,你只需要在 -r 标记后指定这个文件的存放路径。

一个小提醒,如果你熟悉 wireshark 这类网络诊断工具,也可以利用它们来读取  tcpdump  保存的文件。

指定抓包大小

较新版本的  tcpdump  通常可以截获 65535 字节,但某些情况下你不需要截获默认大小的数据包。运行  tcpdump  时,你可以通过 -s 标记来指定快照长度。

指定抓包数量

tcpdump  会一直运行,直至你用 CTRL+C 让它退出。

你也可以通过 -c 标记后面加上抓包的数量,让  tcpdump  在抓到一定数量的数据包后停止操作。当你不希望看到  tcpdump  的输出大量出现在屏幕上,以至于你无法阅读的时候,就会希望使用这个标记。当然,通常更好的方法是借助过滤器来截获特定的流量。

基础知识汇总

你可以将以上这些基础的标记组合起来使用,来让  tcpdump  提供你所需要的信息。

过滤器

介绍完基础的标记后,我们该介绍过滤器了。 tcpdump  可以通过各式各样的表达式,来过滤所截取或者输出的数据。我在这篇文章里会给出一些简单的例子,以便让你们了解语法规则。你们可以查询  tcpdump  帮助中的 pcap-filter 章节,了解更为详细的信息。

查找特定主机的流量

运行上述命令, tcpdump  会像前面一样把结果输出到屏幕上,不过只会显示源 IP 或者目的 IP 地址是 10.0.3.1 的数据包。通过增加主机 10.0.3.1 参数,我们可以让  tcpdump  过滤掉源和目的地址不是 10.0.3.1 的数据包。

只显示源地址为特定主机的流量

前面的例子显示了源和目的地址是 10.0.3.1 的流量,而上面的命令只显示数据包源地址是 10.0.3.1 的流量。这是通过在 host 前面增加 src 参数来实现的。这个额外的过滤器告诉  tcpdump  查找特定的源地址。 反过来通过 dst 过滤器,可以指定目的地址。

过滤源和目的端口

通过类似 and 操作符,你可以在  tcpdump  上使用更为复杂的过滤器描述。这个就类似 if 语句,你就这么想吧。这个例子中,我们使用 and 操作符告诉  tcpdump  只输出端口号是 22 和 60738 的数据包。这点在分析网络问题的时候很有用,因为可以通过这个方法来关注某一个特定会话(session)的数据包。

你可以用两种方式来表示 and 操作符,and 或者 && 都可以。我个人倾向于两个都使用,特别要记住在使用 && 的时候,要用单引号或者双引号包住表达式。在 BASH 中,你可以使用 && 运行一个命令,该命令成功后再执行后面的命令。通常,最好将表达式用引号包起来,这样会避免不预期的结果,特别当过滤器中有一些特殊字符的时候。

查找两个端口号的流量

你可以用 or 或者 || 操作符来过滤结果。在这个例子中,我们使用 or 操作符去截获发送和接收端口为 80 或 443 的数据流。这在 Web 服务器上特别有用,因为服务器通常有两个开放的端口,端口号 80 表示 http 连接,443 表示 https。

查找两个特定端口和来自特定主机的数据流

前面的例子用来排查多端口的协议问题,是非常有效的。如果 Web 服务器的数据流量相当大, tcpdump  的输出可能有点混乱。我们可以通过增加 host 参数进一步限定输出。在这种情况下,我们通过把 or 表达式放在括号中来保持 or 描述。

在一个过滤器中,你可以多次使用括号。在下面的例子中,下面命令可以限定截获满足如下条件的数据包:发送或接收端口号为 80 或 443,主机来源于 10.0.3.169 或者 10.0.3.1,且目的地址是 10.0.3.246。

理解输出结果

打开  tcpdump  的所有选项去截获网络流量是相当困难的,但一旦你拿到这些数据你就要对它进行解读。在这个章节,我们将涉及如何判断源/目的 IP 地址,源/目的端口号,以及 TCP 协议类型的数据包。当然这些是相当基础的,你从  tcpdump  里面获取的信息也远不止这些。不过这篇文章主要是粗略的介绍,我们会关注在这些基础知识上。我建议你们可以通过帮助页获取更为详细的信息。

判断源和目的地址

判断源和目的地址和端口号相当简单。

从上面的输出,我们可以看到源 IP 地址是 10.0.3.246,源端口号是 56894, 目的 IP 地址是 192.168.0.92,端口号是 22。一旦你理解  tcpdump  格式后,这些信息很容易判断。如果你还没有猜到格式,你可以按照 src-ip.src-port > dest-ip.dest-port: Flags[S] 格式来分析。源地址位于 > 前面,后面则是目的地址。你可以把 > 想象成一个指向目的地址的箭头符号。

判断数据包类型

从上面的例子,我们可以判断这个数据包是一个 SYN 数据包。我们是通过  tcpdump  输出中的 [S] 标记字段得出这个结论,不同类型的数据包有不同类型的标记。不需要深入了解 TCP 协议中的数据包类型,你就可以通过下面的速查表来加以判断。

  • [S] – SYN (开始连接)
  • [.] – 没有标记
  • [P] – PSH (数据推送)
  • [F] – FIN (结束连接)
  • [R] – RST (重启连接)

在这个版本的  tcpdump  输出中,[S.] 标记代表这个数据包是 SYN-ACK 数据包。

不好的例子

上面显示了一个不好的通信例子,在这个例子中“不好”,代表通信没有建立起来。我们可以看到 10.0.3.246 发出一个 SYN 数据包给 主机 192.168.0.92,但是主机并没有应答。

好的例子

好的例子应该向上面这样,我们看到典型的 TCP 3次握手。第一数据包是 SYN 包,从主机 10.0.3.246 发送给 主机192.168.0.110,第二个包是 SYN-ACK 包,主机192.168.0.110 回应 SYN 包。最后一个包是一个 ACK 或者 SYN – ACK – ACK 包,是主机 10.0.3.246 回应收到了 SYN – ACK 包。从上面看到一个 TCP/IP 连接成功建立。

数据包检查

用十六进制和 ASCII 码打印数据包

排查应用程序网络问题的通常做法,就是用  tcpdump  的 -XX 标记打印出 16 进制和 ASCII 码格式的数据包。这是一个相当有用的命令,它可以让你看到源地址,目的地址,数据包类型以及数据包本身。但我不是这个命令输出的粉丝,我认为它太难读了。

只打印 ASCII 码格式的数据包

我倾向于只打印 ASCII 格式数据,这可以帮助我快速定位数据包中发送了什么,哪些是正确的,哪些是错误的。你可以通过 -A 标记来实现这一点。

从上面的输出,你可以看到我们成功获取了一个 http 的 GET 请求包。如果网络通信没有被加密,用人类可阅读的格式打出包中数据,对于解决应用程序的问题是很有帮助。如果你排查一个网络通信被加密的问题,打印包中数据就不是很有用。不过如果你有证书的话,你还是可以使用 ssldump 或者 wireshark

非 TCP 数据流

虽然这篇文章主要采用 TCP 传输来讲解  tcpdump ,但是  tcpdump  绝对不是只能抓 TCP 数据包。它还可以用来获取其他类型的数据包,例如 ICMP、 UDP 和 ARP 包。下面是一些简单的例子,说明  tcpdump  可以截获非 TCP 数据包。

ICMP 数据包

UDP 数据包

如果你觉得有好例子进一步说明  tcpdump  命令,请在评论中补充。

打赏支持我翻译更多好文章,谢谢!

打赏译者

打赏支持我翻译更多好文章,谢谢!

任选一种支付方式

3 15 收藏 评论

关于作者:至秦

Linux,Networking 个人主页 · 我的文章 · 53 ·  

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部