如何使用 tcpdump 捕获网络数据包
Environment
- Red Hat Enterprise Linux 3 及更新的版本
Issue
在对网络问题进行故障排除时,可能需要对数据包一级的进行行为进行分析。成功分析数据包通常取决于在第一时间获得正确的数据包数据。本文档解决了这个问题,同时为以下问题提供答案:
- 如何使用
tcpdump
捕获网络数据包? - 如何监控系统中的网络流量?
- 请推荐用于网络捕获的工具
Resolution
安装
tcpdump 包括在 RPM 软件包 tcpdump-<version>.<arch>.rpm
中。
tcpdump 示例
# tcpdump -s 0 -i {INTERFACE} -w {FILEPATH} [filter expression]
完成后,使用 ctrl+c
键终止 tcpdump
命令。
参数
- -s 是 snaplen 的一个选项。它告知
tcpdump
对于每个数据包应捕获的信息量(字节)。对于 RHEL 6 及更新版本所提供的 tcpdump,默认捕获每个数据包的 65535 个字节数据。对于之前的版本 (RHEL 5 和更早版本),tcpdump
默认捕获 68 个字节。68 个字节通常不足以有效执行任何类型的故障排除或诊断。如果不确定您的系统上的默认设置,请参阅tcpdump (8)
手册页并搜索 "snaplen"。如果要捕获网络数据包中的所有数据,在运行tcpdump
命令时使用 "-s 0" 选项,如上所示。当有大量网络流量时,或需要长时间捕获网络流量时,这可能并不是最佳选择。
在捕获数据包时,系统性能也很重要;如果系统没有足够的资源,tcpdump
也可能不会捕获所有数据包。要对 tcpdump
进行调整,建议将 snaplen 限制为可以捕获稍后进行分析所需的所有重要协议信息的最小数量。
实际需要的字节数取决于具体的问题。例如,如果您对 NFS v3 的问题进行故障排除,snaplen 为 256 通常就足够了,除非需要对 READDIR/READDIRPLUS 问题进行故障排除,在这种情况下,您可能需要 snaplen 为 0。对于 NFS v4,通常 snaplen 为 0。
-
-i 将 {INTERFACE} 替换为被调查流量的网络接口名称。您可以在各种类型的接口上捕获流量(物理接口、vlan、绑定、团队等),但在多数情况下,您应避免使用关键字 any。使用 any 将捕获来自所有接口的数据包,并可能导致在使用绑定、团队时重复捕获数据包数据。这会使故障排除变得更加复杂,因为不同的工具可能会将额外的数据包标记为重新传输的数据。如果您知道要与之通信的远程系统的地址,您可以使用
ip route get
来确定网络数据的源接口。# ip route get 10.16.29.55
10.16.29.55 via 10.16.47.254 dev eth0 src 10.16.46.34
cache
在上例中,源接口是 eth0
。这是您在 tcpdump
中传递给 -i
选项的接口名称。
如果需要同时在多个接口上运行 tcpdump
,请并行对每个接口运行单独的 tcpdump (写入不同文件)。
- 此处指定的 -w FILEPATH 应指向一个本地文件系统。这会避免
tcpdump
捕获不需要的流量。另外,请确保有足够的可用空间。如果已挂载到本地存储,建议使用/tmp
。为确保捕获的数据以二进制格式保存(强烈推荐的格式),文件名应以二进制扩展名结尾 (.cap、.pcap 等)。
过滤表达式
您可以使用表达式
在捕获数据包时对数据进行过滤。有关表达式
的详细信息,请参阅 pcap-filter
的 man page。另外,如果计划在捕获 vlan 接口数据时使用表达式,请参阅以下解决方案:"在指定了 VLAN 上的端口和接口时,为什么 tcpdump 没有捕获任何网络数据? "建议仅在完全必要的情况下使用过滤功能。使用过滤功能会为系统带更多压力,并会降低执行tcpdump
的服务器的性能。另外,它还通常会因为捕获的信息不足而无法有效进行分析。如果您必须使用过滤,请在上传用于进行分析的数据时,明确说明使用了哪些过滤,以及使用这些过滤的时间和原因。
有关 tcpdump
的详情,请参考手册页。
捕获提示
tcpdump
命令的语法相对简单,但为了捕获真正相关的网络流量以进行分析,建议遵循以下简单的规则:
- 在网络连接的两端(客户端和服务器端)同时运行数据包捕获
- 确保在问题发生时捕获数据包
- 确保捕获文件被保存在本地文件系统中
- 请注意在其中进行了数据捕获的系统的时区设置,以及与系统日志的关联
- 对难以重现的问题,或因为捕获文件太大而导致捕获过程无法完成的情况,使用滚动捕获
- 使用
tcpdump -s <bytes>
来限制对于每个数据包要保存的信息量 - 不要使用文本输出格式,而是使用二进制格式(文件的扩展名为 .cap, .pcap 等)
- 避免使用
tcpdump -i any
,确保您在正确的接口上进行捕获 - 如果可能,尽量避免使用捕获过滤,这可以避免有用的数据被过滤掉。但是,如果接口上有大量的网络数据,则不使用过滤可能并不可行,因为这可能会生成一个巨大的文件。如果需要使用过滤,请首先咨询红帽支持团队。当对一个特定主机或端口进行过滤时,需要注意不丢弃网络对话的一个方向。
- 红帽客户门户网站提供了一个应用程序,可以帮助生成相关语法(如果需要)。请查看 :https://access.redhat.com/labs/nptcpdump/
- 压缩 捕获文件(例如使用 gzip)
如何上传捕获
-
使用 '-r' 选项运行
tcpdump
命令,验证网络数据是否已被正确捕获。如果数据被正确捕获,这个命令的输出应会显示从客户端和服务器发送的数据包,类似于以下的 NFS 'getattr' 请求和响应示例:# tcpdump -r /tmp/client.cap
...
09:39:06.272688 IP 192.168.155.74.3337237041 > 192.168.155.2.nfs: 216 getattr fh 0,0/22
09:39:06.273342 IP 192.168.155.2.nfs > 192.168.155.74.3337237041: reply ok 88 getattr NON 2 ids 0/9 sz 0
09:39:06.273365 IP 192.168.155.3354014257 > 192.168.155.2.nfs: 220 getattr fh 0,0/22
09:39:06.273840 IP 192.168.155.2.nfs > 192.168.155.74.3354014257: reply ok 108 getattr NON 2 ids 0/9 sz 0 -
如果 trace 文件较大(几百 MB 甚至几 GB),使用
gzip
压缩这些文件。您可以使用其他压缩方法,如 bzip2,但有一些工具(如tshark
)可能无法读取这些数据它们,因此建议使用gzip
。# gzip /tmp/client.cap
# gzip /tmp/server.cap -
将客户端和服务器系统的压缩 trace 文件(
The):cap.gz
文件)附加到相关的支持问题单中,或上传到 Red Hat Global Support Services sFTP 服务器。
安装
-
确保在客户端和服务器系统上安装了
tcpdump
RPM。-
在 Red Hat Enterprise Linux 3 或 4 中,使用 'up2date' 命令:
# up2date -i tcpdump
-
在 Red Hat Enterprise Linux 5 或更高版本中,使用 'yum' 命令:
# yum install tcpdump
-
滚动捕获
有时,捕获可能需要在一段较长的时间内运行。在这种情况下,捕获文件会无限期地增长,这通常不是一个好的做法。而滚动捕获(rolling capture)会检查系统是否有足够的可用磁盘空间。参数 -w path -W n -C m
将指示 tcpdump
创建 "n" 个大小大约为 "m" MB 的文件。这些文件的名称从 path0 到 path(n-1)。当文件 pathX 的大小超过 m MB 时,会写入或重写 path(mod (X+1, n) 文件。因为在默认情况下,tcpdump
以 tcpdump
用户 ID 运行,因此此用户 ID 需要具有创建 pathX 文件所需的权限。使用 "-Z userID" 可以更改运行 tcpdump
命令的 ID。
务必要确保,文件大小、文件数量、以及循环使用文件的速度的组合可以保证在相关的事件发生时捕获并记录下相关的数据,并在适当的时间停止捕获过程,以避免记录的相关数据被覆盖。以下脚本可以帮助实现这个目的。它可以启动 tcpdump,然后在日志文件中出现触发的信息时停止它。
示例:./pcapLogwatch.sh eth0 5 250 /tmp dumpfilename.pcap "" /var/log/messages "Time has been changed"
SCRIPT NAME | DEVICE | NUMBER-OF-FILES | SIZE-OF-FILES | DUMP-DIRECTORY | DUMP-FILE-NAME | FILTER | LOG-FILE-NAME | TRIGGER-STRING |
---|---|---|---|---|---|---|---|---|
./pcapLogwatch.sh | eth0 | 5 | 250 | /tmp | dumpfilename.pcap | "" | /var/log/messages | "Time has been changed" |
其中:
DEVICE
=(eth0) 您从中捕获的接口 (#ip a)NUMBER-OF-FILES
=(5) 文件数SIZE-OF_FILES
=(250) 其中 250 为大小,单位为 MBDUMP-DIRECTORY
=(/tmp) 要转储到的目录DUMP-FILE-NAME
=(dumpfilename.pcap) 捕获文件的名称FILTER
= ("") tcpdump 过滤,可以是协议或 IPLOG-FILE-NAME
= (/var/log/messages) 用于监视触发器的文件TRIGGER-STRING
= (Time has been changed)在监视的文件中停止滚动捕获的错误消息
pcapLogwatch.sh
脚本:
#!/bin/sh
# pcaplogwatch.sh
# - capture packets until a given string is seen in a given logfile
#
# Usage:
# pcapLogwatch.sh DEVICE NUMBER-OF-FILES SIZE-OF-FILES DUMP-DIRECTORY DUMP-FILE-NAME FILTER LOG-FILE-NAME TRIGGER-STRING
#
#
if [ $# -ne 8 ]
then echo "Usage:"
echo pcapLogwatch.sh DEVICE NUMBER-OF-FILES SIZE-OF-FILES \
DUMP-DIRECTORY DUMP-FILE-NAME FILTER LOG-FILE-NAME \
TRIGGER-STRING
echo Where:
echo " DEVICE name of the device used for capturing packets"
echo " NUMBER-OF-FILES number of files in the capture ring"
echo " SIZE-OF-FILES size of each file (approximately)"
echo " DUMP-DIRECTORY directory to put the files"
echo " DUMP-FILE-NAME base name of the capture files"
echo " FILTER tcpdump filter string, may be \"\""
echo " LOG-FILE-NAME name of log file containing the trigger"
echo " TRIGGER-STRING when this string is seen tcpdump will be stopped"
exit
fi
# After setting the parameters below, this script will run
# a rolling packet capture until the string in $LOG_STRING
# is found in $LOG_FILE. Set the optional $DUMP_FILTER with
# whatever libpcap filter as needed.
# Interface to capture on:
DUMP_INTERFACE="$1"
# Number of capture files:
DUMP_NUM="$2"
# Size of capture files:
DUMP_SIZE="$3"
# Directory to save file to:
DUMP_DIR="$4"
# Filename to capture to:
DUMP_NAME="$5"
# libpcap Dump filter:
DUMP_FILTER="$6"
# Log file to monitor:
LOG_FILE="$7"
# String to match in LOG_FILE:
LOG_STRING="$8"
# Time to wait after LOG_STRING found
# until the dump is stopped (in seconds):
TIME_AFTER=1
mkdir -p "$DUMP_DIR"
chmod g+w "$DUMP_DIR"
chgrp tcpdump "$DUMP_DIR"
/usr/sbin/tcpdump -s 0 -w "$DUMP_DIR/$DUMP_NAME" -W "$DUMP_NUM" -C "$DUMP_SIZE" -i "$DUMP_INTERFACE" "$DUMP_FILTER" &DUMP_PID=$!
tail --follow=name --pid=$DUMP_PID -n 0 "$LOG_FILE" | awk "/$LOG_STRING/{system(\"sleep $TIME_AFTER; kill $DUMP_PID\")}" &
disown -a -h
exit 0
# END pcapLogwatch.sh
在特定情况下,事件不会马上被一个事件触发,需要一段时间后才会触发。在这种情况下,您可以运行以下命令。确保将接口 (eth0
) 改为您服务器上的相关接口名称:
# /usr/sbin/tcpdump -s 0 -w /tmp/reproduced_issue.pcap -W 4 -C 300 -i eth0
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.
Comments