tcpdump
1. 基础抓包
1.1 简单抓包
# 这是最基础的命令,但在生产环境几乎没人这么用,因为刷屏太快根本看不清。
tcpdump -i eth0
1.2 加上常用参数
# -i eth0:指定网卡,用 `any` 可以监听所有网卡
# -nn:不解析主机名和端口名,直接显示IP和数字端口(提升性能)
# -tttt:显示人类可读的时间戳
tcpdump -i eth0 -nn -tttt
1.3 控制显示长度
# -s 0:抓包时不截断数据包,默认只抓前 68/96(?)字节
tcpdump -i eth0 -nn -tttt -s 0
1.4 限制抓包数量
# 测试时别让它无限抓下去,抓100个包后自动停止。
tcpdump -i eth0 -nn -tttt -s 0 -c 100
2. 过滤器,这才是tcpdump的灵魂
2.1 按端口过滤
# 抓取目的端口为80的HTTP流量
tcpdump -i eth0 -nn port 80
# 抓取MySQL流量
tcpdump -i eth0 -nn port 3306
# 端口范围过滤(抓1000-2000端口)
tcpdump -i eth0 -nn portrange 1000-2000
2.2 按主机过滤
# 抓取与特定服务器的所有通信
tcpdump -i eth0 -nn host 192.168.1.100
# 只抓源地址
tcpdump -i eth0 -nn src host 192.168.1.100
# 只抓目标地址
tcpdump -i eth0 -nn dst host 192.168.1.100
# 抓取整个网段
tcpdump -i eth0 -nn net 192.168.1.0/24
2.3 按协议过滤
# 只抓TCP包
tcpdump -i eth0 -nn tcp
# 只抓UDP包
tcpdump -i eth0 -nn udp
# 只抓ICMP包(ping)
tcpdump -i eth0 -nn icmp
2.4 逻辑组合,真正的威力
# (同时满足多个条件)- 抓取来自192.168.1.100且访问80端口的包
tcpdump -i eth0 -nn 'host 192.168.1.100 and port 80'
# (满足任一条件)- 抓取HTTP或HTTPS流量
tcpdump -i eth0 -nn 'port 80 or port 443'
# (排除某些流量)- 抓取除SSH外的所有流量
tcpdump -i eth0 -nn 'port not 22'
# 复杂组合- 抓取来自特定网段访问web服务的流量
# 注意:复杂表达式一定要加引号,否则shell会误解析。
tcpdump -i eth0 -nn 'src net 192.168.1.0/24 and (port 80 or port 443)'
3. 保存和读取
3.1 基础保存
# 生成的pcap文件可以用Wireshark打开,图形化分析更直观。
tcpdump -i eth0 -nn -w /tmp/capture.pcap
3.2 按大小切割文件
# 单个文件太大不好传输和分析,每个文件100MB,自动切割
# -C 参数单位是**MB**(1,000,000字节),会生成 `capture.pcap1`、`capture.pcap2`...
tcpdump -i eth0 -nn -w /tmp/capture.pcap -C 100
3.3 按数量循环覆盖
# 避免磁盘被撑爆,每个文件50MB,最多保留10个
# 最多占用500MB,超过10个文件后会覆盖最老的文件(从pcap0开始循环)
tcpdump -i eth0 -nn -w /tmp/capture.pcap -C 50 -W 10
3.4 按时间切割
# 每3600秒(1小时)切割一次,会保留24小时的数据,文件名自动带时间戳
tcpdump -i eth0 -nn -w /tmp/capture.pcap -G 3600 -W 24
3.5 带时间戳的文件名
#
tcpdump -nn -r /tmp/capture.pcap
# .com 读取时也可以加过滤条件,只显示符合条件的包,分析效率更高
tcpdump -nn -r /tmp/capture.pcap 'port 3306 and host 10.0.1.50'
4. 查看包内容,深入应用层
4.1 ASCII格式显示
# -A 参数会以ASCII显示包内容,适合查看HTTP请求和响应
tcpdump -i eth0 -nn -A port 80
4.2 十六进制显示
# -X 同时显示十六进制和ASCII,排查二进制协议时很有用。
tcpdump -i eth0 -nn -X port 80
4.3 只显示十六进制
# -x 只显示十六进制,不显示ASCII。
tcpdump -i eth0 -nn -x port 3306
4.4 增加详细程度
# -v、-vv、-vvv 三个级别,越多越详细,会显示TTL、IP选项、校验和等信息
tcpdump -i eth0 -nn -v port 80
5. TCP标志位过滤,排查连接问题
5.1 抓取SYN包(新连接请求)
# 只抓SYN包,不包括SYN-ACK。用来统计新建连接数
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0'
5.2 抓取SYN-ACK包
# 服务器回应客户端的SYN-ACK包
tcpdump -i eth0 -nn 'tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)'
5.3 抓取RST包(连接重置)
# RST包通常意味着连接异常关闭,是排查连接问题的关键
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-rst != 0'
5.4 抓取FIN包(正常关闭)
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-fin != 0'
5.5 抓取PSH包(立即推送数据)
# 应用层数据传输时会设置PSH标志
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-push != 0'
5.6 只看三次握手过程
tcpdump -i eth0 -nn 'tcp[tcpflags] & (tcp-syn|tcp-ack) != 0' -c 100
# 抓取100个三次握手相关的包(SYN、SYN-ACK、ACK)
6. HTTP协议深度过滤
6.1 抓取HTTP GET请求
# 原理:`tcp[12:1] & 0xf0) >> 2` 计算TCP头长度(字节),然后从TCP payload开始位置读取4字节,`0x47455420` 是 "GET " 的十六进制ASCII码(注意空格)
tcpdump -i eth0 -nn -A -s 0 'tcp port 80 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420)'
6.2 抓取HTTP POST请求
# .com - '0x504f5354' 是 "POST" 的十六进制(4字节)
tcpdump -i eth0 -nn -A -s 0 'tcp port 80 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354)'
6.3 抓取HTTP响应
# by - '0x48545450' 是 "HTTP" 的十六进制(4字节),匹配HTTP响应的开头
tcpdump -i eth0 -nn -A -s 0 'tcp port 80 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x48545450)'
6.4 抓取特定URL
# .com - 抓取包含/api/user的请求
# 配合grep使用,实时过滤URL
tcpdump -i eth0 -nn -A -s 0 'tcp port 80' | grep -i 'GET /api/user'
6.5 抓取特定User-Agent
# - 排查爬虫或特定客户端的请求
tcpdump -i eth0 -nn -A -s 0 'tcp port 80' | grep -i 'User-Agent: curl'
7. 高级过滤技巧
7.1 按包大小过滤
# 排查大包或小包攻击
# .com - 抓取大于1000字节的包
tcpdump -i eth0 -nn 'greater 1000'
# 抓取小于100字节的包
tcpdump -i eth0 -nn 'less 100'
7.2 抓取特定TTL的包
# .com - ip[8] 表示IP头的第8个字节,即TTL字段。用来追踪包的跳数
tcpdump -i eth0 -nn 'ip[8] = 64'
7.3 抓取分片的包
# - MTU不匹配时会产生分片,影响性能
tcpdump -i eth0 -nn 'ip[6:2] & 0x1fff != 0 or ip[6] & 0x20 != 0'
7.4 抓取带特定TCP选项的包
# .com - 抓取所有TCP头部长度大于20字节的包
tcpdump -i eth0 -nn 'tcp[12] & 0xf0 > 0x50'
7.5 抓取重传的包
# by - 通过序列号分析识别重传
# 统计目的IP和端口的ACK包频率,频繁重复出现的组合可能存在重传。
# 加班哥提醒:这只是简单的频率统计,真正的重传检测需要分析TCP序列号,建议用Wireshark的 `tcp.analysis.retransmission` 过滤器
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-ack != 0' -tttt | \
awk '{print $1, $2, $5}' | sort | uniq -c | sort -rn | head -20
8. 性能调优和注意事项
8.1 使用buffer避免丢包
# .com - 设置4MB的buffer(4096 KB)
# 高流量环境下,默认buffer可能导致丢包。`-B` 参数单位是KB
tcpdump -i eth0 -nn -B 4096 -w /tmp/capture.pcap
8.2 只抓包头,减少开销
# - 只抓前100字节
# 如果只需要分析包头(源IP、目的IP、端口等),不需要抓全包
tcpdump -i eth0 -nn -s 100 -w /tmp/headers.pcap
8.3 快速模式
# 立即显示抓到的包,不等待buffer满。
tcpdump -i eth0 -nn --immediate-mode
8.4 多网卡同时抓包
# by - '-i any' 监听所有网卡,包括lo(本地回环)
tcpdump -i any -nn port 80 -w /tmp/all_interfaces.pcap
8.5 排除本机流量
# .com
tcpdump -i eth0 -nn 'not host 127.0.0.1 and not host ::1'
8.6 抓包时不要让DNS查询干扰
# - 排除DNS流量,避免污染数据
tcpdump -i eth0 -nn 'port not 53' -w /tmp/no_dns.pcap
9. 实战案例
9.1 排查接口超时问题
# 后台运行,抓取与应用服务器10.0.1.50的8080端口通信
tcpdump -i eth0 -nn -s 0 -w /tmp/timeout_$(date +%Y%m%d_%H%M%S).pcap \
'host 10.0.1.50 and port 8080' &
#借助tshark
# 1. 检查RST包数量(异常断开)
tshark -r "XXX.pcap" -Y "tcp.flags.reset == 1" | wc -l
# 2. 检查TCP重传(网络问题)
tshark -r "XXX.pcap" -Y "tcp.analysis.retransmission" | wc -l
# 3. 检查慢响应(应用处理慢)
tshark -r "XXX.pcap" -Y "tcp.time_delta > 1" -T fields -e tcp.time_delta
# 4. 查看HTTP状态码分布
tshark -r "XXX.pcap" -Y "http" -T fields -e http.response.code | sort | uniq -c
9.2 排查SYN Flood攻击
# by - 统计每秒SYN包数量
# 如果每秒SYN包超过正常值几倍,可能遭受SYN Flood攻击
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-syn != 0' | \
awk '{print strftime("%Y-%m-%d %H:%M:%S", systime()), $3}' | \
awk '{count[$1" "$2]++} END {for (i in count) print i, count[i]}' | \
sort -k3 -rn
9.3 分析MySQL慢查询
# 抓取后用Wireshark分析,过滤 `mysql.query`,按响应时间排序,找出响应慢的SQL语句。也可以在tcpdump层面通过时间戳间隔初步判断慢查询
tcpdump -i eth0 -nn -s 0 -w /tmp/mysql.pcap 'port 3306 and host 10.0.2.100'
9.4 抓取Redis的GET/SET命令
# - 实时查看Redis操作
tcpdump -i eth0 -nn -A -s 0 'port 6379' | grep -E 'GET|SET'
9.5 排查网络丢包
在Wireshark里用 `tcp.analysis.retransmission` 和 `tcp.analysis.lost_segment` 过滤,查看重传和丢包情况
tcpdump -i eth0 -nn -tttt -vvv 'host 192.168.1.100' -w /tmp/loss.pcap
9.6 抓取HTTPS握手过程
虽然无法解密内容,但可以分析握手性能:
# by - 在Wireshark里过滤 `ssl.handshake`,分析TLS握手耗时
tcpdump -i eth0 -nn -s 0 'port 443' -w /tmp/tls_handshake.pcap
9.7 监控网卡流量
# 简易的流量监控脚本,每抓100个包就统计一次累计流量大小。
tcpdump -i eth0 -nn -tttt -l | \
awk '{bytes+=$NF} NR%100==0 {print systime(), bytes/1024/1024 "MB"; bytes=0}'
9.8 抓取特定时间段的流量
# 抓取60秒后自动停止
timeout 60 tcpdump -i eth0 -nn -w /tmp/1min.pcap
9.9 只抓取TCP握手失败的包
# 抓完包分析哪些SYN包没有对应的SYN-ACK,说明连接建立失败
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-syn != 0' -w /tmp/syn.pcap
9.10 抓取异常端口扫描
# 统计发送SYN包最多的源IP(以及每个IP的SYN包数量),识别端口扫描行为
tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0' | \
awk '{print $3}' | cut -d'.' -f1-4 | sort | uniq -c | sort -rn | head -10
10. 与其他工具配合
10.1 配合tshark(Wireshark命令行版)
# tshark的过滤语法比tcpdump强大,可以直接过滤HTTP字段
tshark -i eth0 -nn -Y 'http.request.method == "POST"' -T fields -e frame.time -e ip.src -e http.request.uri
10.2 配合Wireshark远程抓包
# 服务器上执行,实时传输到本地Wireshark分析
ssh user@server 'tcpdump -i eth0 -nn -s 0 -w - port 80' | wireshark -k -i -
10.3 配合termshark(终端版Wireshark)
# 需要先安装termshark
# 在终端里也能用类似Wireshark的TUI(文本用户界面),支持过滤、上下键浏览等功能
termshark -i eth0 -f 'port 80'
10.4 配合iftop看流量
# 一边抓包一边看实时流量。
tcpdump -i eth0 -nn 'port 80' &
iftop -i eth0 -f 'port 80'
11. 安全和权限
11.1 普通用户抓包
# tcpdump需要root权限或CAP_NET_RAW能力
# .com - 设置后普通用户也能抓包
sudo setcap cap_net_raw,cap_net_admin=eip /usr/sbin/tcpdump
11.2 脱敏处理
# 抓取生产环境流量时,可能包含敏感信息
# 只保存包头,不保存payload
# 或者可以先抓取,后用 `tcprewrite` 工具改写IP地址等信息
tcpdump -i eth0 -nn -s 96 -w /tmp/headers_only.pcap
11.3 加密传输pcap文件
# 边抓边加密,防止pcap文件泄露
tcpdump -i eth0 -nn -w - port 80 | gzip | openssl enc -aes-256-cbc -salt -out /tmp/capture.pcap.gz.enc
12. 调试tcpdump本身
12.1 查看编译后的过滤表达式
# 查看BPF字节码,用于验证过滤器是否按预期工作
tcpdump -d 'host 192.168.1.1 and port 80'
12.2 测试过滤表达式
# 对已有的pcap文件测试过滤条件
tcpdump -r /tmp/capture.pcap -d 'tcp port 80'
12.3 查看tcpdump版本和支持的链路类型
# -D 列出所有可用的网卡
tcpdump --version
tcpdump -D
13. 常见坑和解决方案
13.1 抓包文件太大打不开
# Wireshark打不开大于2GB的文件,用 `editcap` 切割,每10万个包切割成一个文件
editcap -c 100000 huge.pcap split.pcap
13.2 远程抓包时SSH断开
# 永远记得排除SSH端口,或者用screen/tmux
tcpdump -i eth0 -nn 'port not 22' -w /tmp/safe.pcap
screen -S tcpdump
tcpdump -i eth0 -nn -w /tmp/capture.pcap
# Ctrl+A+D 断开,ssh断了也继续运行
13.3 抓包导致CPU飙高
# 高流量环境下,tcpdump会消耗大量CPU
# - 降低优先级
nice -n 19 tcpdump -i eth0 -nn -w /tmp/capture.pcap
或者用更精确的过滤器,减少抓包数量。 采样抓包(利用IP校验和):
# - 利用IP校验和最后一位采样,约抓50%的包
#原理:IP头校验和(ip[10:2])的最后一位具有随机性,`ip[10] & 1 = 1` 只保留校验和最后一位为1的包,约占50%。可以调整位掩码实现不同采样率:
# 'ip[10] & 1 = 1':约50%
# 'ip[10] & 3 = 1':约25%
# 'ip[10] & 7 = 1':约12.5%
tcpdump -i eth0 -nn 'ip[10] & 1 = 1' -w /tmp/sample.pcap
13.4 磁盘写满
设置磁盘空间上限,最多占用500MB
tcpdump -i eth0 -nn -w /tmp/capture.pcap -C 50 -W 10
13.5 时间戳不准
# 使用高精度时间戳,纳秒级时间戳(需要较新版本tcpdump)
# 纳秒级精度,适合分析微秒级延迟。
# 加班哥提醒:并非所有系统和tcpdump版本都支持纳秒精度。
tcpdump -i eth0 -nn -tttt --time-stamp-precision=nano
14. 最后
tcpdump用途较广,总结了几条tcpdump使用原则:
生产环境抓包前一定要评估影响,高流量场景可能导致性能问题
永远不要在生产环境直接用
-A或-X查看内容,先保存到文件再离线分析远程抓包必须排除SSH端口,或者用screen/tmux防止断开
用
-C和-W限制文件大小,避免磁盘写满抓包时尽量加精确的过滤条件,减少无关流量干扰
敏感数据要脱敏处理,别因为抓包泄露用户信息
复杂分析用Wireshark,tcpdump适合快速定位问题
善用BPF语法,有助于写出正确有效的网络捕捉过滤器
抓包是手段不是目的更不是炫技,关键是分析出问题根因
定期清理历史pcap文件,别让你的服务器变成垃圾场