一、概述
1.1 网络故障排查方法论
网络故障排查是运维工程师最核心的技能之一。当应用出现连接超时、响应延迟、数据丢包等问题时,网络抓包分析是最直接、最有效的诊断手段。通过捕获和分析网络数据包,工程师可以精确还原通信过程,定位问题发生在哪一层、哪个环节。
tcpdump和Wireshark是网络抓包领域最经典、最强大的两个工具。tcpdump是命令行的packet analyzer,适合快速捕获和初步过滤;Wireshark是图形化的protocol analyzer,适合深度分析和问题定位。两者配合使用,可以应对从简单到复杂的各种网络故障场景。
根据SharkFest和Packet Pushers的联合调研,2025年网络工程师日常工作中,76%的故障排查需要使用抓包分析;在复杂的微服务架构中,这个比例达到89%。然而,能熟练使用这两个工具的工程师不足30%,能进行深度协议分析的不足15%。本文将从一线运维工程师的视角,系统讲解tcpdump和Wireshark的配合使用技巧,提供可直接复用的脚本和案例。
1.2 证据链:网络故障与抓包分析
| 故障类型 |
占比 |
抓包解决率 |
平均排查时间 |
| 连接超时 |
34% |
92% |
8分钟 |
| 响应延迟 |
27% |
85% |
15分钟 |
| 数据丢包 |
18% |
88% |
12分钟 |
| DNS异常 |
12% |
95% |
5分钟 |
| 加密握手失败 |
9% |
78% |
20分钟 |
数据来源:Packet Pushers Network Troubleshooting Survey 2025,样本量N=2500
关键结论:抓包分析可以解决超过85%的网络层故障,平均可将排查时间从小时级压缩到分钟级。
1.3 本文结构
第一部分:tcpdump命令行详解
├── 基础语法与常用选项
├── 过滤器表达式
├── 进阶捕获技巧
└── 性能优化与常见错误
第二部分:Wireshark高级功能
├── 界面布局与快捷键
├── 过滤器语法
├── 统计与专家信息
└── 追踪流与导出
第三部分:典型故障场景
├── TCP连接问题
├── HTTP/HTTPS问题
├── DNS解析问题
└── 应用层协议问题
第四部分:自动化与脚本
├── 自动抓包触发
├── 批量包分析
└── 报告生成
第五部分:最佳实践
├── 抓包点选择
├── 性能与存储
└── 团队协作规范
二、tcpdump命令行详解
2.1 基础语法与常用选项
2.1.1 tcpdump核心选项速查
tcpdump [ -adeflnNOpqRStuUvxX ] [ -c count ] [ -C file_size ] [ -F file ]
[ -i interface ] [ -m module ] [ -r file ] [ -s snaplen ]
[ -T type ] [ -w file ] [ -E algo:secret ] [ expression ]
常用选项说明:
| 选项 |
说明 |
示例 |
| -i |
指定网卡 |
tcpdump -i eth0 |
| -i any |
监听所有网卡 |
tcpdump -i any |
| -c |
捕获数据包数量 |
tcpdump -c 100 |
| -w |
写入文件 |
tcpdump -w capture.pcap |
| -r |
读取文件 |
tcpdump -r capture.pcap |
| -n |
不解析域名 |
tcpdump -n |
| -nn |
不解析端口和服务 |
tcpdump -nn |
| -v |
详细输出 |
tcpdump -v |
| -vv |
更详细 |
tcpdump -vv |
| -X |
十六进制和ASCII显示 |
tcpdump -X |
| -s |
捕获长度 |
tcpdump -s 0 (完整) |
2.1.2 基础捕获脚本
#!/bin/bash
# tcpdump_basics.sh
# tcpdump基础使用演示脚本
set -e
echo "===== tcpdump 基础使用 ====="
# 1. 捕获指定网卡的所有数据包
echo -e "\n[示例1] 捕获eth0网卡的前100个包"
echo "命令: tcpdump -i eth0 -c 100 -n"
echo "说明: -i指定网卡, -c捕获数量, -n不解析域名"
sudo tcpdump -i eth0 -c 100 -n 2>/dev/null | head -20
# 2. 捕获TCP流量
echo -e "\n[示例2] 只捕获TCP流量"
echo "命令: tcpdump -i eth0 tcp -c 50"
sudo tcpdump -i eth0 tcp -c 50 -n 2>/dev/null | head -15
# 3. 捕获特定端口流量
echo -e "\n[示例3] 捕获80端口(HTTP)流量"
echo "命令: tcpdump -i eth0 port 80 -c 20"
sudo tcpdump -i eth0 port 80 -c 20 -n 2>/dev/null | head -15
# 4. 捕获特定主机流量
echo -e "\n[示例4] 捕获与192.168.1.100通信的流量"
echo "命令: tcpdump -i eth0 host 192.168.1.100 -c 20"
sudo tcpdump -i eth0 host 192.168.1.100 -c 20 -n 2>/dev/null | head -15
# 5. 捕获并保存到文件
echo -e "\n[示例5] 保存捕获到文件"
CAPTURE_FILE="/tmp/capture_$(date +%Y%m%d_%H%M%S).pcap"
echo "命令: tcpdump -i eth0 -w $CAPTURE_FILE -c 1000"
timeout 5 sudo tcpdump -i eth0 -w "$CAPTURE_FILE" -c 100 2>/dev/null &
sleep 3
if [ -f "$CAPTURE_FILE" ]; then
echo "文件大小: $(du -h "$CAPTURE_FILE" | cut -f1)"
echo "包数量: $(sudo tcpdump -r "$CAPTURE_FILE" 2>/dev/null | wc -l)"
fi
echo -e "\n===== 基础演示完成 ====="
2.1.3 输出格式解析
tcpdump的标准输出格式:
时间戳 协议 源地址.端口 -> 目标地址.端口 [标志位] 其他信息
---------------- ---- ------------------- ------------------- ----- --------------------
21:23:45.123456 IP 192.168.1.10.443 -> 192.168.1.100.54321 Flags [P.], ack 123, win 502, length 1420
21:23:45.123789 IP 192.168.1.100.54321 -> 192.168.1.10.443 Flags [.], ack 14563, win 501, length 0
TCP标志位说明:
| 标志 |
说明 |
含义 |
| S |
SYN |
连接建立请求 |
| F |
FIN |
连接关闭请求 |
| P |
PSH |
数据推送 |
| R |
RST |
复位连接 |
| . |
ACK |
确认应答 |
2.2 过滤器表达式
2.2.1 BPF过滤语法
tcpdump使用Berkeley Packet Filter (BPF)语法,支持三种原语类型:类型限定、方向限定、协议限定。
类型限定:
host <ip> - 特定主机
net <cidr> - 网络段
port <port> - 端口
portrange <p1-p2> - 端口范围
方向限定:
src <qualifier> - 源限定
dst <qualifier> - 目标限定
协议限定:
ip, tcp, udp, icmp, arp, etc.
2.2.2 复合过滤表达式
#!/bin/bash
# tcpdump_filters.sh
# tcpdump过滤器表达式演示
set -e
echo "===== tcpdump 过滤器表达式 ====="
# 常用过滤场景
declare -A FILTER_SCENARIOS=(
["HTTP流量"]="tcp port 80 or tcp port 8080"
["HTTPS流量"]="tcp port 443"
["SSH流量"]="tcp port 22"
["DNS流量"]="udp port 53 or tcp port 53"
["MySQL流量"]="tcp port 3306"
["Redis流量"]="tcp port 6379"
["HTTP POST请求"]="tcp port 80 and tcp[tcpflags] & tcp-ack != 0 and (tcp[20:4] = 0x504f5354)"
["TCP SYN包"]="tcp[tcpflags] & tcp-syn != 0"
["TCP RST包"]="tcp[tcpflags] & tcp-rst != 0"
["大于1000字节的包"]="greater 1000"
["特定子网流入"]="src net 192.168.1.0/24"
["特定子网流出"]="dst net 192.168.1.0/24"
["非ICMP流量"]="ip and not icmp"
["非本地流量"]="ip and not net 127.0.0.1"
)
for scenario in "${!FILTER_SCENARIOS[@]}"; do
echo -e "\n[场景] $scenario"
echo "过滤表达式: ${FILTER_SCENARIOS[$scenario]}"
echo "验证命令: sudo tcpdump -i lo -n '${FILTER_SCENARIOS[$scenario]}' -c 1 2>/dev/null"
done
# 逻辑运算符
echo -e "\n===== 逻辑运算符 ====="
echo "and / && - 逻辑与"
echo "or / || - 逻辑或"
echo "not / ! - 逻辑非"
echo "括号() - 优先级控制"
# 高级过滤示例
echo -e "\n===== 高级过滤示例 ====="
echo -e "\n[1] 捕获源端口大于1024的SSH流量"
echo "tcpdump 'tcp port 22 and src port > 1024'"
echo -e "\n[2] 捕获包含特定字符串的HTTP请求"
echo "tcpdump -i eth0 'tcp port 80 and (tcp[20:4] = 0x47455420 or tcp[20:4] = 0x504f5354)'"
echo -e "\n[3] 捕获TTL小于10的ICMP包"
echo "tcpdump 'icmp and ip[8] < 10'"
echo -e "\n[4] 捕获TCP窗口大小为0的包(可能表示缓冲区满)"
echo "tcpdump 'tcp[14:2] = 0'"
echo -e "\n[5] 捕获设置了URG标志的TCP包"
echo "tcpdump 'tcp[tcpflags] & tcp-urg != 0'"
2.2.3 常用过滤脚本库
#!/bin/bash
# network_filter_lib.sh
# 网络故障排查常用过滤脚本库
set -e
# 加载常用过滤函数
source /dev/stdin << 'EOF'
# 输出带颜色的诊断信息
info() { echo -e "\033[1;34m[INFO]\033[0m $1"; }
warn() { echo -e "\033[1;33m[WARN]\033[0m $1"; }
error() { echo -e "\033[1;31m[ERROR]\033[0m $1"; }
# 1. TCP连接状态分析
analyze_tcp_connections() {
local interface=${1:-eth0}
local duration=${2:-10}
info "TCP连接状态分析 (捕获${duration}秒)..."
echo -e "\n=== SYN包统计 ==="
sudo tcpdump -i "$interface" "tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0" -c 10 -nn 2>/dev/null
echo -e "\n=== SYN-ACK包统计 ==="
sudo tcpdump -i "$interface" "tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack != 0" -c 10 -nn 2>/dev/null
echo -e "\n=== RST包统计 ==="
sudo tcpdump -i "$interface" "tcp[tcpflags] & tcp-rst != 0" -c 10 -nn 2>/dev/null
echo -e "\n=== FIN包统计 ==="
sudo tcpdump -i "$interface" "tcp[tcpflags] & tcp-fin != 0" -c 10 -nn 2>/dev/null
}
# 2. HTTP流量分析
analyze_http_traffic() {
local interface=${1:-eth0}
local host=${2:-""}
info "HTTP流量分析..."
if [ -n "$host" ]; then
FILTER="tcp port 80 or tcp port 8080 and host $host"
else
FILTER="tcp port 80 or tcp port 8080"
fi
echo -e "\n=== HTTP请求方法统计 ==="
sudo tcpdump -i "$interface" "$FILTER and tcp[tcpflags] & tcp-push != 0" -nn 2>/dev/null | \
awk '{print $NF}' | sort | uniq -c | sort -rn | head -10
echo -e "\n=== HTTP状态码分布 ==="
sudo tcpdump -i "$interface" "$FILTER" -nn -vv 2>/dev/null | \
grep -oE "Http.*[0-9]{3}" | awk '{print $NF}' | sort | uniq -c | sort -rn
}
# 3. DNS查询分析
analyze_dns_queries() {
local interface=${1:-eth0}
local duration=${2:-5}
info "DNS查询分析 (捕获${duration}秒)..."
echo -e "\n=== DNS查询 ==="
sudo timeout "$duration" tcpdump -i "$interface" "udp port 53" -nn 2>/dev/null | head -30
echo -e "\n=== DNS响应码统计 ==="
sudo timeout "$duration" tcpdump -i "$interface" "udp port 53" -nn 2>/dev/null | \
grep -oE "QUERY|NOERROR|NXDOMAIN|SERVFAIL" | sort | uniq -c | sort -rn
}
# 4. 延迟分析
analyze_latency() {
local interface=${1:-eth0}
local target=${2:-8.8.8.8}
info "延迟分析 (ping目标: $target)..."
echo -e "\n=== Ping统计 ==="
ping -c 10 "$target" 2>&1 | tail -2
echo -e "\n=== TCP延迟采样 ==="
sudo tcpdump -i "$interface" "host $target and tcp" -nn 2>/dev/null | \
awk '{print $1}' | while read ts; do
echo "${ts#*.}"
done | head -20
}
# 5. 包大小分布
analyze_packet_sizes() {
local interface=${1:-eth0}
info "包大小分布分析..."
echo -e "\n=== 包大小统计 ==="
sudo tcpdump -i "$interface" -nn 2>/dev/null | \
awk '{print NF, $0}' | sort -n | \
awk '{print $NF}' | \
grep -oE "[0-9]+" | sort -n | \
awk 'BEGIN {b[0]=0;b[1]=0;b[2]=0;b[3]=0;b[4]=0;b[5]=0} {
if ($1 < 64) b[0]++
else if ($1 < 128) b[1]++
else if ($1 < 256) b[2]++
else if ($1 < 1024) b[3]++
else if ($1 < 1518) b[4]++
else b[5]++
} END {
print " <64B:", b[0]
print " 64-127B:", b[1]
print " 128-255B:", b[2]
print " 256-1023B:", b[3]
print " 1024-1517B:", b[4]
print " >1518B:", b[5]
}'
}
# 6. 连接数统计
analyze_connection_count() {
local interface=${1:-eth0}
info "活动连接数统计..."
echo -e "\n=== 按源IP统计连接数 ==="
sudo tcpdump -i "$interface" -nn 2>/dev/null | \
awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c | sort -rn | head -10
echo -e "\n=== 按目标端口统计 ==="
sudo tcpdump -i "$interface" -nn 2>/dev/null | \
grep -oE "(\.[0-9]+\.[0-9]+)->" | grep -oE "[0-9]+" | sort | uniq -c | sort -rn | head -10
}
# 7. 丢包检测
detect_packet_loss() {
local interface=${1:-eth0}
info "丢包检测分析..."
echo -e "\n=== 重传包分析 ==="
sudo tcpdump -i "$interface" "tcp[tcpflags] & tcp-ack != 0" -nn 2>/dev/null | \
grep -E "retransmission|duplicate" | head -10
echo -e "\n=== Seq号跳跃分析 ==="
echo "检查是否有Seq号跳跃(可能表示丢包)"
}
# 8. TCP窗口分析
analyze_tcp_window() {
local interface=${1:-eth0}
info "TCP窗口分析..."
echo -e "\n=== 零窗口检测 ==="
sudo tcpdump -i "$interface" "tcp[tcpflags] & tcp-ack != 0" -nn 2>/dev/null | \
awk '/win 0/ {print $0}' | head -10
echo -e "\n=== 小窗口检测 ==="
sudo tcpdump -i "$interface" "tcp[tcpflags] & tcp-ack != 0" -nn 2>/dev/null | \
awk '/win [0-9]{1,3}/ {print $0}' | head -10
}
EOF
# 执行演示
echo "===== 过滤脚本库演示 ====="
analyze_tcp_connections lo 3
analyze_dns_queries lo 3
2.3 进阶捕获技巧
2.3.1 条件触发捕获
#!/bin/bash
# conditional_capture.sh
# 条件触发式抓包脚本
set -e
CAPTURE_DIR="/var/log/captures"
mkdir -p "$CAPTURE_DIR"
echo "===== 条件触发式抓包 ====="
# 1. 基于错误的自动捕获
auto_capture_on_error() {
local interface=${1:-eth0}
local error_threshold=${2:-5}
local capture_duration=${3:-30}
echo "监控 $interface 上的错误,阈值: $error_threshold errors/$capture_duration 秒"
# 监控TCP重传
echo -e "\n[1] 启动TCP重传监控..."
(
while true; do
RETRANS_COUNT=$(sudo tcpdump -i "$interface" "tcp[tcpflags] & tcp-retransmission" 2>/dev/null | \
awk '{print $1}' | sort | uniq -c | wc -l)
if [ "$RETRANS_COUNT" -gt "$error_threshold" ]; then
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
CAPTURE_FILE="$CAPTURE_DIR/retrans_$TIMESTAMP.pcap"
echo "检测到TCP重传激增,开始捕获..."
sudo tcpdump -i "$interface" -w "$CAPTURE_FILE" -c 10000 &
CAPTURE_PID=$!
sleep "$capture_duration"
kill "$CAPTURE_PID" 2>/dev/null
echo "捕获已保存: $CAPTURE_FILE"
fi
sleep "$capture_duration"
done
) &
MONITOR_PID=$!
echo "监控进程PID: $MONITOR_PID"
echo "停止监控: kill $MONITOR_PID"
}
# 2. 基于延迟的自动捕获
auto_capture_on_latency() {
local interface=${1:-eth0}
local latency_threshold=${2:-100} # ms
local target=${3:-8.8.8.8}
echo "监控到 $target 的延迟,阈值: ${latency_threshold}ms"
(
while true; do
LATENCY=$(ping -c 1 -W 1 "$target" 2>/dev/null | \
grep "time=" | awk -F'time=' '{print $2}' | awk '{print $1}')
if [ -n "$LATENCY" ] && (( $(echo "$LATENCY > $latency_threshold" | bc -l) )); then
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
CAPTURE_FILE="$CAPTURE_DIR/latency_$TIMESTAMP.pcap"
echo "检测到延迟升高 (${LATENCY}ms),开始捕获..."
sudo tcpdump -i "$interface" -w "$CAPTURE_FILE" -c 5000 &
CAPTURE_PID=$!
sleep 10
kill "$CAPTURE_PID" 2>/dev/null
echo "捕获已保存: $CAPTURE_FILE"
fi
sleep 5
done
) &
}
# 3. 基于特定事件的捕获
capture_on_specific_event() {
local interface=${1:-eth0}
local event_pattern=${2:-"RST"}
local capture_duration=${3:-60}
echo "监控包含 '$event_pattern' 的包,捕获时长: ${capture_duration}s"
(
while true; do
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
CAPTURE_FILE="$CAPTURE_DIR/event_${event_pattern}_$TIMESTAMP.pcap"
echo "开始捕获..."
sudo tcpdump -i "$interface" -w "$CAPTURE_FILE" -c 1000 2>/dev/null &
CAPTURE_PID=$!
sleep "$capture_duration"
kill "$CAPTURE_PID" 2>/dev/null
wait "$CAPTURE_PID" 2>/dev/null
# 检查是否捕获到目标事件
EVENTS=$(sudo tcpdump -r "$CAPTURE_FILE" 2>/dev/null | grep -c "$event_pattern" || echo 0)
if [ "$EVENTS" -gt 0 ]; then
echo "捕获到 $EVENTS 个 '$event_pattern' 事件"
echo "文件: $CAPTURE_FILE"
break
else
echo "未捕获到目标事件,继续..."
rm -f "$CAPTURE_FILE"
fi
done
) &
}
# 4. 环形缓冲区捕获
ring_buffer_capture() {
local interface=${1:-eth0}
local ring_size=${2:-10} # 文件数量
local file_size=${3:-100} # MB
local total_size=$((ring_size * file_size))
echo "环形缓冲区捕获: $ring_size 个文件,每个 ${file_size}MB,总计 ${total_size}MB"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
PREFIX="$CAPTURE_DIR/ring_${TIMESTAMP}"
sudo tcpdump -i "$interface" \
-w "${PREFIX}_%Y%m%d%H%M%S.pcap" \
-C "$file_size" \
-W "$ring_size" \
-Z root &
echo "捕获进程已启动"
echo "前缀: $PREFIX"
echo "停止: pkill -f 'tcpdump.*$PREFIX'"
}
# 5. 并行捕获(多网卡同时)
parallel_capture() {
local interfaces=("eth0" "eth1" "lo")
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
echo "并行捕获: ${interfaces}"
for iface in "${interfaces[@]}"; do
CAPTURE_FILE="$CAPTURE_DIR/parallel_${iface}_$TIMESTAMP.pcap"
echo "启动 $iface 捕获: $CAPTURE_FILE"
sudo tcpdump -i "$iface" -w "$CAPTURE_FILE" -c 1000 2>/dev/null &
done
echo "所有接口捕获已启动"
echo "停止所有: pkill -f 'tcpdump.*parallel'"
}
# 主菜单
case "${1:-demo}" in
retrans)
auto_capture_on_error eth0 5 30
;;
latency)
auto_capture_on_latency eth0 100 8.8.8.8
;;
event)
capture_on_specific_event eth0 "RST" 60
;;
ring)
ring_buffer_capture eth0 10 100
;;
parallel)
parallel_capture
;;
demo|*)
echo "===== 条件触发捕获演示 ====="
echo "用法: $0 {retrans|latency|event|ring|parallel}"
echo ""
echo "示例:"
echo " $0 retrans # TCP重传时自动捕获"
echo " $0 latency # 延迟升高时自动捕获"
echo " $0 event # 检测到RST时捕获"
echo " $0 ring # 环形缓冲区持续捕获"
echo " $0 parallel # 多网卡并行捕获"
;;
esac
2.3.2 远程抓包与传输
#!/bin/bash
# remote_capture.sh
# 远程抓包与安全传输脚本
set -e
REMOTE_HOST=${REMOTE_HOST:-""}
REMOTE_USER=${REMOTE_USER:-"root"}
CAPTURE_DIR="/var/log/captures"
echo "===== 远程抓包系统 ====="
# 1. SSH远程抓包(实时传输)
remote_capture_stream() {
local host=$1
local interface=${2:-eth0}
local filter=${3:-"tcp"}
local count=${4:-1000}
echo "远程抓包: $host:$interface"
echo "过滤器: $filter"
echo "包数量: $count"
# 通过SSH远程执行tcpdump,结果通过管道传输
ssh "$REMOTE_USER@$host" "sudo tcpdump -i $interface -n -c $count '$filter'" 2>/dev/null | head -50
}
# 2. 远程抓包并保存到本地
remote_capture_save() {
local host=$1
local interface=${2:-eth0}
local filter=${3:-"tcp"}
local local_file=$4
echo "远程抓包并保存到本地: $local_file"
# 使用SSH隧道 + tcpdump
ssh "$REMOTE_USER@$host" "sudo tcpdump -i $interface -n -w - '$filter'" 2>/dev/null | \
sudo tee "$local_file" > /dev/null &
echo "捕获中... Ctrl+C 停止"
wait
}
# 3. 使用SCP安全传输抓包文件
transfer_capture_file() {
local remote_file=$1
local local_dir=${2:-$CAPTURE_DIR}
local host=$3
local filename=$(basename "$remote_file")
local timestamp=$(date +%Y%m%d_%H%M%S)
echo "传输抓包文件: $host:$remote_file -> $local_dir/${timestamp}_$filename"
scp "$REMOTE_USER@$host:$remote_file" "$local_dir/${timestamp}_$filename"
echo "传输完成: $local_dir/${timestamp}_$filename"
echo "文件大小: $(du -h "$local_dir/${timestamp}_$filename" | cut -f1)"
}
# 4. 远程抓包自动化脚本(在远程主机上执行)
generate_remote_script() {
local output_file="/tmp/remote_capture_$$.sh"
cat > "$output_file" << 'REMOTE_EOF'
#!/bin/bash
# 远程抓包代理脚本
# 在远程主机上执行
INTERFACE=${1:-eth0}
FILTER=${2:-"tcp"}
COUNT=${3:-1000}
OUTPUT_DIR="/var/log/captures"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
OUTPUT_FILE="$OUTPUT_DIR/capture_${TIMESTAMP}.pcap"
# 确保输出目录存在
mkdir -p "$OUTPUT_DIR"
# 执行抓包
echo "开始抓包: $(date)"
tcpdump -i "$INTERFACE" -n -w "$OUTPUT_FILE" -c "$COUNT" "$FILTER" 2>&1
# 计算文件大小
if [ -f "$OUTPUT_FILE" ]; then
SIZE=$(du -h "$OUTPUT_FILE" | cut -f1)
echo "抓包完成: $(date)"
echo "文件: $OUTPUT_FILE"
echo "大小: $SIZE"
echo "包数量: $(tcpdump -r "$OUTPUT_FILE" 2>/dev/null | wc -l)"
else
echo "抓包失败"
exit 1
fi
REMOTE_EOF
chmod +x "$output_file"
echo "远程脚本已生成: $output_file"
}
# 5. WireGuard隧道抓包
wireguard_capture() {
local wg_interface=${1:-wg0}
local target_host=$2
echo "WireGuard隧道抓包: $wg_interface -> $target_host"
# 监控WireGuard接口
sudo tcpdump -i "$wg_interface" -nn -c 100 2>/dev/null | head -30
# 同时抓取物理网卡
echo -e "\n同时抓取物理网卡..."
sudo tcpdump -i eth0 "host $target_host" -nn -c 100 2>/dev/null | head -30
}
# 菜单
case "${1:-menu}" in
stream)
remote_capture_stream "$REMOTE_HOST" eth0 tcp 100
;;
save)
remote_capture_save "$REMOTE_HOST" eth0 tcp "/tmp/remote_capture.pcap"
;;
transfer)
transfer_capture_file "/var/log/captures/capture.pcap" "$CAPTURE_DIR" "$REMOTE_HOST"
;;
generate)
generate_remote_script
;;
menu|*)
echo "用法: $0 {stream|save|transfer|generate}"
;;
esac
2.4 性能优化与常见错误
2.4.1 tcpdump性能优化
#!/bin/bash
# tcpdump_performance.sh
# tcpdump性能优化与最佳实践
set -e
echo "===== tcpdump 性能优化 ====="
# 1. 内核缓冲区优化
optimize_kernel_buffer() {
echo "[1] 内核缓冲区优化"
# 查看当前缓冲区大小
echo "当前环形缓冲区大小:"
ifconfig eth0 2>/dev/null | grep -E "ring" || ip link show eth0 | grep -E "ring"
# 设置更大的缓冲区(需要root)
echo "设置缓冲区..."
# ifconfig eth0 txqueuelen 10000
# ip link set eth0 txqueuelen 10000
}
# 2. BPF优化
optimize_bpf() {
echo -e "\n[2] BPF过滤器优化"
echo "BPF优化原则:"
echo " 1. 尽量在捕获前过滤,减少内核拷贝"
echo " 2. 使用精确的协议和端口过滤"
echo " 3. 避免在过滤器中使用函数调用"
echo " 4. 优先匹配低层协议"
echo -e "\n示例对比:"
echo " 低效: tcpdump 'ip and tcp and port 80'"
echo " 高效: tcpdump 'tcp port 80'"
echo -e "\nBPF编译器验证:"
echo "使用 -ddd 选项查看编译后的BPF指令"
}
# 3. 快照长度优化
optimize_snaplen() {
echo -e "\n[3] 快照长度优化"
echo "默认快照长度: 262144 bytes (262KB)"
echo "优化建议:"
echo " - 使用 -s 0 自动选择合适长度"
echo " - 只需要头部时: -s 68 (TCP/IP头)"
echo " - UDP诊断: -s 512"
echo " - 完整包: -s 65535"
echo -e "\n示例:"
echo " sudo tcpdump -i eth0 -s 68 -c 100 'tcp port 80'"
}
# 4. 多核并行处理
optimize_multicore() {
echo -e "\n[4] 多核并行处理"
echo "使用pf_ring加速:"
echo " 1. 安装PF_RING: apt install pf_ring"
echo " 2. 加载驱动: modprobe pf_ring"
echo " 3. 使用pfcount替代tcpdump"
echo -e "\n使用dpdk优化:"
echo " dpdk-pdump工具支持DPDK加速抓包"
}
# 5. 捕获文件压缩
optimize_compression() {
echo -e "\n[5] 捕获文件压缩"
echo "方法1: 使用 gzip 实时压缩"
echo " sudo tcpdump -i eth0 -w - | gzip > capture.pcap.gz"
echo -e "\n方法2: 使用管道输出到压缩工具"
echo " sudo tcpdump -i eth0 -nn -c 1000 | gzip > capture.txt.gz"
}
# 6. 常见错误避免
echo -e "\n[6] 常见错误避免"
cat << 'EOF'
错误1: 捕获的文件无法打开
原因: 写入时使用了管道但格式不对
解决: 确保使用 -w 选项写入文件
错误2: 捕获不到任何包
原因: 网卡混杂模式未启用、过滤器语法错误
解决: 使用 ip link set eth0 promisc 启用混杂
错误3: 捕获性能差,丢包严重
原因: 缓冲区不足、过滤器太复杂
解决: 增加缓冲区、优化过滤器
错误4: 文件过大
原因: 未限制包数量或文件大小
解决: 使用 -c count, -C size, -W count 限制
错误5: 权限问题
原因: 普通用户无法直接访问网卡
解决: sudo 运行,或设置 pcap 组权限
EOF
# 执行优化检查
echo -e "\n===== 当前系统状态 ====="
optimize_kernel_buffer
optimize_bpf
optimize_snaplen
echo -e "\n===== 优化完成 ====="
三、Wireshark高级功能
3.1 界面布局与快捷键
3.1.1 Wireshark界面布局
┌─────────────────────────────────────────────────────────────────────────────┐
│ Menu Bar (菜单栏) │
├─────────────────────────────────────────────────────────────────────────────┤
│ Main Toolbar (主工具栏) [Start] [Stop] [Open] [Save] [Print] [Find] ... │
├───────────────────────────────────┬─────────────────────────────────────────┤
│ Filter Toolbar (过滤器工具栏) │ Interface List (接口列表) │
│ ip.addr == 192.168.1.100 │ □ eth0 [Start] │
├───────────────────────────────────┴─────────────────────────────────────────┤
│ │
│ Packet List Pane (包列表面板) - 主区域 │
│ ┌──────┬────────┬──────────┬────────────┬─────────────┬────────────────┐ │
│ │ No. │ Time │ Source │ Destination│ Protocol │ Length │ Info │ │
│ ├──────┼────────┼──────────┼────────────┼─────────────┼────────────────┤ │
│ │ 1 │ 0.000 │ 192.168 │ 8.8.8.8 │ DNS │ 72 │ ... │ │
│ │ 2 │ 0.023 │ 8.8.8.8 │ 192.168 │ DNS │ 104 │ ... │ │
│ └──────┴────────┴──────────┴────────────┴─────────────┴────────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ Packet Details Pane (包详情面板) │
│ ┌─ Frame 1 ─────────────────────────────────────────────────────────────┐ │
│ │ Ethernet II, Src: ..., Dst: ... │ │
│ │ ► Internet Protocol Version 4, Src: 192.168.1.100, Dst: 8.8.8.8 │ │
│ │ ► User Datagram Protocol, Src Port: 54321, Dst Port: 53 │ │
│ │ ► Domain Name System (query) │ │
│ └──────────────────────────────────────────────────────────────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ Packet Bytes Pane (包字节面板) │
│ ┌─ 0000 │ 45 00 00 48 01 23 40 00 40 11 a1 b7 c0 a8 01 64 │ │
│ │ 0010 │ c0 a8 01 01 d4 35 00 35 00 34 12 34 01 00 00 01 │ │
│ └──────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
│ Status Bar (状态栏) │
│ [Capturing: eth0] [Packets: 1000] [Displayed: 500] [Marked: 0] [Dropped: 0]│
└─────────────────────────────────────────────────────────────────────────────┘
3.1.2 常用快捷键速查
| 快捷键 |
功能 |
说明 |
| Ctrl+F |
查找包 |
搜索包列表 |
| Ctrl+G |
跳转到包 |
转到指定包号 |
| Ctrl+B |
查找字节 |
在十六进制中搜索 |
| Ctrl+Shift+B |
查找字符串 |
搜索字符串 |
| F5 |
开始捕获 |
重新开始抓包 |
| Ctrl+E |
停止捕获 |
停止抓包 |
| Ctrl+O |
打开文件 |
打开抓包文件 |
| Ctrl+S |
保存文件 |
保存当前捕获 |
| Ctrl+W |
关闭文件 |
关闭当前文件 |
| Tab |
展开选中 |
展开当前字段 |
| Enter |
展开/折叠 |
切换展开状态 |
| +/= |
放大时间 |
增加时间精度 |
| - |
缩小时间 |
减少时间精度 |
| Ctrl++ |
下一面板 |
跳到包详情 |
| Ctrl+0-9 |
书签 |
设置/跳转到书签 |
| Ctrl+M |
标记包 |
标记/取消标记 |
| Ctrl+Shift+M |
标记所有 |
标记所有匹配包 |
| Ctrl+D |
忽略包 |
忽略当前包 |
| Ctrl+Shift+D |
取消忽略 |
取消忽略 |
| Ctrl+T |
设置时间参考 |
设置时间参考点 |
| T |
下一个时间参考 |
跳转到下一个时间参考 |
| : |
过滤器输入框 |
快速输入过滤器 |
3.2 过滤器语法
3.2.1 捕获过滤器与显示过滤器
捕获过滤器(Capture Filter) - 在抓包时生效,减少捕获数据量
语法: <protocol> <direction> <host(s)> <value> <port>
示例: tcp dst port 80 and host 192.168.1.100
显示过滤器(Display Filter) - 在分析时生效,不丢失原始数据
语法: <protocol>.<field> <operator> <value>
示例: ip.addr == 192.168.1.100 and tcp.port == 80
3.2.2 显示过滤器操作符
| 操作符 |
说明 |
示例 |
| == |
等于 |
ip.addr == 192.168.1.1 |
| != |
不等于 |
ip.addr != 192.168.1.1 |
| > |
大于 |
tcp.len > 1000 |
| < |
小于 |
tcp.len < 100 |
| >= |
大于等于 |
tcp.window_size >= 8192 |
| <= |
小于等于 |
tcp.window_size <= 8192 |
| contains |
包含 |
http.request.uri contains "/api" |
| matches |
正则匹配 |
http.host matches ".*.example.com" |
| and / && |
逻辑与 |
ip.addr == 192.168.1.1 and tcp.port == 80 |
| or / |
|
逻辑或 |
tcp.port == 80 or tcp.port == 443 |
| not / ! |
逻辑非 |
not arp |
3.2.3 常用显示过滤器模板
#!/bin/bash
# wireshark_filters.sh
# Wireshark常用显示过滤器模板
set -e
echo "===== Wireshark 显示过滤器模板 ====="
declare -A FILTER_TEMPLATES=(
# HTTP相关
["HTTP请求"]="http.request"
["HTTP响应"]="http.response"
["HTTP POST"]="http.request.method == POST"
["HTTP GET"]="http.request.method == GET"
["404响应"]="http.response.code == 404"
["500错误"]="http.response.code == 500"
["特定URL"]="http.request.uri contains \"/api/v1\""
["特定Host"]="http.host == \"api.example.com\""
# TCP相关
["TCP重传"]="tcp.analysis.retransmission"
["TCP快速重传"]="tcp.analysis.fast_retransmission"
["TCP重复ACK"]="tcp.analysis.duplicate_ack"
["TCP零窗口"]="tcp.analysis.zero_window"
["TCP窗口满"]="tcp.analysis.window_full"
["TCP RST"]="tcp.flags.reset == 1"
["TCP SYN"]="tcp.flags.syn == 1"
["TCP FIN"]="tcp.flags.fin == 1"
# UDP相关
["DNS查询"]="dns.qry.name"
["DNS响应"]="dns.resp.name"
["NTP查询"]="ntp"
# IP相关
["源IP"]="ip.src == 192.168.1.100"
["目标IP"]="ip.dst == 192.168.1.100"
["IP段"]="ip.addr in {192.168.1.0/24}"
["TTL异常"]="ip.ttl < 10"
# 应用层
["SSH流量"]="ssh"
["MySQL查询"]="mysql.query"
["Redis命令"]="redis"
["HTTP2流量"]="http2"
["TLS握手"]="tls.handshake"
# 性能分析
["响应时间>1s"]="frame.time_delta > 1"
["大文件传输"]="tcp.len > 100000"
["异常包大小"]="frame.len > 1500"
)
# 生成过滤器文件
FILTER_FILE="/tmp/wireshark_filters.txt"
echo "# Wireshark Display Filter Templates" > "$FILTER_FILE"
echo "# Generated: $(date)" >> "$FILTER_FILE"
echo "" >> "$FILTER_FILE"
for name in "${!FILTER_TEMPLATES[@]}"; do
printf "%-30s | %s\n" "$name" "${FILTER_TEMPLATES[$name]}" >> "$FILTER_FILE"
done
echo "过滤器文件已生成: $FILTER_FILE"
cat "$FILTER_FILE"
# 导出为Wireshark配置文件
CONF_FILE="/tmp/dfilter_dfilters"
cat > "$CONF_FILE" << 'EOF'
# Wireshark Display Filter Expressions
# Copy to ~/.config/wireshark/dfilter_dfilters
[HTTP]
http.request=HTTP request
http.response=HTTP Response
http.request.method==POST=HTTP POST
http.request.method==GET=HTTP GET
http.response.code==404=HTTP 404
http.response.code==500=HTTP 500
[TCP]
tcp.analysis.retransmission=TCP Retransmission
tcp.flags.reset==1=TCP RST
tcp.flags.syn==1=TCP SYN
tcp.flags.fin==1=TCP FIN
tcp.analysis.zero_window=TCP Zero Window
[IP]
ip.addr==192.168.1.100=Local Host
ip.ttl<10=Low TTL
[DNS]
dns.qry.name=DNS Query
dns.resp.name=DNS Response
EOF
echo -e "\nWireshark配置文件已生成: $CONF_FILE"
3.3 统计与专家信息
3.3.1 统计分析工具
#!/bin/bash
# wireshark_stats.sh
# Wireshark统计分析自动化
set -e
PCAP_FILE=${1:-""}
if [ -z "$PCAP_FILE" ]; then
echo "用法: $0 <pcap文件>"
echo "使用示例: $0 /tmp/capture.pcap"
exit 1
fi
if [ ! -f "$PCAP_FILE" ]; then
echo "文件不存在: $PCAP_FILE"
exit 1
fi
echo "===== Wireshark 统计分析 ====="
echo "分析文件: $PCAP_FILE"
echo "文件大小: $(du -h "$PCAP_FILE" | cut -f1)"
echo "包数量: $(tshark -r "$PCAP_FILE" 2>/dev/null | wc -l)"
# 使用tshark进行统计分析
echo -e "\n[1] 协议分布"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
tshark -r "$PCAP_FILE" -q -z io,phs 2>/dev/null | head -20
echo -e "\n[2] IP地址统计"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "最活跃的源IP (Top 10):"
tshark -r "$PCAP_FILE" -q -z ip_src_stat,10 2>/dev/null
echo -e "\n[3] TCP会话统计"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
tshark -r "$PCAP_FILE" -q -z conv,tcp 2>/dev/null | head -20
echo -e "\n[4] HTTP请求统计"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
tshark -r "$PCAP_FILE" -q -z http_req,ref 2>/dev/null | head -20
echo -e "\n[5] HTTP状态码分布"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
tshark -r "$PCAP_FILE" -Y "http.response" -q -z http_srv,stat 2>/dev/null | head -20
echo -e "\n[6] TCP问题分析"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "重传包:"
tshark -r "$PCAP_FILE" -Y "tcp.analysis.retransmission" -q 2>/dev/null | wc -l
echo "重复ACK:"
tshark -r "$PCAP_FILE" -Y "tcp.analysis.duplicate_ack" -q 2>/dev/null | wc -l
echo "零窗口:"
tshark -r "$PCAP_FILE" -Y "tcp.analysis.zero_window" -q 2>/dev/null | wc -l
echo -e "\n[7] 专家信息摘要"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
tshark -r "$PCAP_FILE" -q -z expert 2>/dev/null | grep -A2 "Error\|Warning" | head -30
echo -e "\n[8] 包长度分布"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
tshark -r "$PCAP_FILE" -q -z ptype,addr 2>/dev/null | head -10
echo -e "\n===== 分析完成 ====="
3.3.2 专家信息解读
Wireshark的专家信息(Expert Information)是自动分析协议问题的核心功能,分为以下级别:
| 级别 |
颜色 |
说明 |
常见原因 |
| Error |
红色 |
严重问题 |
畸形包、解密失败 |
| Warning |
黄色 |
警告 |
重传、重复ACK、窗口满 |
| Note |
青色 |
注意 |
连接建立/关闭、Keepalive |
| Chat |
灰色 |
对话信息 |
正常协议交互 |
常见专家信息解读:
[Error] Malformed Packet
原因: 包格式损坏或无法解析
排查: 检查该包的原始数据,确认是否被抓包损坏
[Warning] TCP Retransmission
原因: 包在网络中丢失或延迟
排查: 检查丢包位置、分析网络拥塞或路径问题
[Warning] TCP duplicate ACK
原因: 接收端未收到期望的包
排查: 可能是重传或乱序
[Warning] TCP Zero Window
原因: 接收端缓冲区满
排查: 检查接收端应用状态
[Warning] TCP Window Full
原因: 发送端已达到接收端窗口限制
排查: 评估滑动窗口机制
[Note] Connection finish (FIN)
原因: 正常连接关闭
排查: 分析连接生命周期
[Note] Connection reset (RST)
原因: 连接被重置
排查: 检查是否异常断开
3.4 追踪流与导出
3.4.1 追踪流脚本
#!/bin/bash
# trace_stream.sh
# 追踪流与数据导出脚本
set -e
PCAP_FILE=${1:-""}
if [ ! -f "$PCAP_FILE" ]; then
echo "用法: $0 <pcap文件>"
exit 1
fi
OUTPUT_DIR="/tmp/wireshark_extract"
mkdir -p "$OUTPUT_DIR"
echo "===== 追踪流与数据导出 ====="
echo "输入文件: $PCAP_FILE"
echo "输出目录: $OUTPUT_DIR"
# 1. 追踪TCP流
trace_tcp_stream() {
local src_ip=$1
local dst_ip=$2
local src_port=$3
local dst_port=$4
echo -e "\n[1] 追踪TCP流: $src_ip:$src_port -> $dst_ip:$dst_port"
local filter="tcp.stream eq $(( RANDOM % 100 ))"
tshark -r "$PCAP_FILE" -Y "$filter" -w "$OUTPUT_DIR/tcp_stream_${src_port}_${dst_port}.pcap" 2>/dev/null
# 导出为文本
tshark -r "$PCAP_FILE" -Y "$filter" -T fields -e data 2>/dev/null | \
xxd -r -p > "$OUTPUT_DIR/tcp_data_${src_port}_${dst_port}.bin"
}
# 2. 追踪HTTP流
trace_http_stream() {
echo -e "\n[2] 追踪HTTP流"
# 提取所有HTTP请求
echo "HTTP请求:"
tshark -r "$PCAP_FILE" -Y "http.request" -T fields \
-e http.request.method \
-e http.host \
-e http.request.uri 2>/dev/null | head -20
# 提取所有HTTP响应
echo -e "\nHTTP响应:"
tshark -r "$PCAP_FILE" -Y "http.response" -T fields \
-e http.response.code \
-e http.host 2>/dev/null | head -20
# 导出完整HTTP流
tshark -r "$PCAP_FILE" -Y "http" -w "$OUTPUT_DIR/http_streams.pcap" 2>/dev/null
}
# 3. 提取HTTP对象
extract_http_objects() {
echo -e "\n[3] 提取HTTP对象 (图片、文件等)"
# 使用editcap或chaosreader提取
if command -v chaosreader &> /dev/null; then
chaosreader "$PCAP_FILE" -d "$OUTPUT_DIR/http_objects" 2>/dev/null
echo "HTTP对象已提取到: $OUTPUT_DIR/http_objects"
else
echo "提示: 安装 chaosreader 以提取HTTP对象"
echo " apt install chaosreader"
fi
}
# 4. 追踪DNS流
trace_dns_stream() {
echo -e "\n[4] 追踪DNS查询"
echo "DNS查询:"
tshark -r "$PCAP_FILE" -Y "dns.qry.name" -T fields \
-e dns.qry.name \
-e dns.qry.type \
-e ip.src 2>/dev/null | head -30
echo -e "\nDNS响应:"
tshark -r "$PCAP_FILE" -Y "dns.resp.name" -T fields \
-e dns.resp.name \
-e dns.a \
-e ip.dst 2>/dev/null | head -30
# 导出DNS流量
tshark -r "$PCAP_FILE" -Y "dns" -w "$OUTPUT_DIR/dns_streams.pcap" 2>/dev/null
}
# 5. 提取TLS会话
trace_tls_stream() {
echo -e "\n[5] 提取TLS会话"
# 提取TLS握手信息
tshark -r "$PCAP_FILE" -Y "tls.handshake" -T fields \
-e ip.src \
-e tls.handshake.type \
-e tls.handshake.version \
-e x509sat.printableString 2>/dev/null | head -30
}
# 6. 导出为CSV
export_to_csv() {
echo -e "\n[6] 导出为CSV格式"
local csv_file="$OUTPUT_DIR/packet_data.csv"
tshark -r "$PCAP_FILE" -T fields \
-e frame.number \
-e frame.time \
-e ip.src \
-e ip.dst \
-e tcp.srcport \
-e tcp.dstport \
-e _ws.col.Protocol \
-e frame.len \
-e tcp.len \
-e tcp.flags \
-E separator=',' > "$csv_file"
echo "CSV已导出: $csv_file"
echo "行数: $(wc -l < "$csv_file")"
}
# 7. 导出payload数据
extract_payloads() {
echo -e "\n[7] 导出应用层Payload"
# 提取HTTP body
tshark -r "$PCAP_FILE" -Y "http" -T fields \
-e http.file_data 2>/dev/null | head -10
# 提取自定义端口数据
echo -e "\n提取自定义端口(9000)数据:"
tshark -r "$PCAP_FILE" -Y "tcp.port == 9000" -T fields \
-e data 2>/dev/null | xxd -r -p | head -20
}
# 执行所有操作
trace_http_stream
trace_dns_stream
export_to_csv
echo -e "\n===== 导出完成 ====="
echo "输出目录: $OUTPUT_DIR"
ls -la "$OUTPUT_DIR"
四、典型故障场景与排查脚本
4.1 TCP连接问题
4.1.1 TCP三次握手问题
#!/bin/bash
# tcp_handshake_analysis.sh
# TCP三次握手问题分析脚本
set -e
PCAP_FILE=${1:-""}
echo "===== TCP三次握手分析 ====="
if [ -n "$PCAP_FILE" ] && [ -f "$PCAP_FILE" ]; then
echo "分析文件: $PCAP_FILE"
else
echo "执行实时捕获分析..."
CAPTURE_FILE="/tmp/handshake_$(date +%Y%m%d_%H%M%S).pcap"
echo "捕获文件: $CAPTURE_FILE"
echo "捕获5秒TCP流量..."
sudo tcpdump -i any "tcp" -w "$CAPTURE_FILE" -c 100 2>/dev/null &
sleep 5
PCAP_FILE="$CAPTURE_FILE"
fi
# 1. 分析SYN包
echo -e "\n[1] SYN包统计"
echo "发送SYN但未收到SYN-ACK:"
tshark -r "$PCAP_FILE" -Y "tcp.flags.syn == 1 and tcp.flags.ack == 0" -T fields \
-e ip.src \
-e tcp.srcport \
-e ip.dst \
-e tcp.dstport 2>/dev/null | \
while IFS=$'\t' read src sport dst dport; do
echo " $src:$sport -> $dst:$dport (SYN未响应)"
done | head -20
# 2. 分析SYN-ACK包
echo -e "\n[2] SYN-ACK包统计"
echo "收到SYN-ACK:"
tshark -r "$PCAP_FILE" -Y "tcp.flags.syn == 1 and tcp.flags.ack == 1" -T fields \
-e ip.src \
-e tcp.srcport \
-e ip.dst \
-e tcp.dstport 2>/dev/null | head -10
# 3. 分析握手延迟
echo -e "\n[3] 握手延迟分析"
echo "SYN -> SYN-ACK 延迟 > 100ms:"
tshark -r "$PCAP_FILE" -Y "tcp.flags.syn == 1 and tcp.flags.ack == 0" -T fields \
-e frame.time_delta_displayed \
-e ip.src \
-e ip.dst \
-e tcp.srcport 2>/dev/null | awk -F'\t' '$1 > 0.1 {print}' | head -10
# 4. 分析连接失败原因
echo -e "\n[4] 连接失败分析"
echo "RST包(连接被拒绝):"
tshark -r "$PCAP_FILE" -Y "tcp.flags.reset == 1" -T fields \
-e ip.src \
-e tcp.srcport \
-e ip.dst \
-e tcp.dstport 2>/dev/null | head -10
# 5. TCP窗口问题
echo -e "\n[5] TCP窗口问题"
echo "零窗口包:"
tshark -r "$PCAP_FILE" -Y "tcp.window_size == 0" -T fields \
-e ip.src \
-e tcp.window_size \
-e ip.dst 2>/dev/null | head -10
echo -e "\n===== 分析完成 ====="
4.1.2 TCP重传问题分析
#!/bin/bash
# tcp_retrans_analysis.sh
# TCP重传问题分析脚本
set -e
PCAP_FILE=${1:-""}
echo "===== TCP重传问题分析 ====="
if [ -n "$PCAP_FILE" ] && [ -f "$PCAP_FILE" ]; then
echo "分析文件: $PCAP_FILE"
else
echo "用法: $0 <pcap文件>"
exit 1
fi
# 1. 重传统计
echo -e "\n[1] 重传包统计"
echo "总重传包数:"
tshark -r "$PCAP_FILE" -Y "tcp.analysis.retransmission" 2>/dev/null | wc -l
echo -e "\n按源IP统计重传:"
tshark -r "$PCAP_FILE" -Y "tcp.analysis.retransmission" -T fields \
-e ip.src 2>/dev/null | sort | uniq -c | sort -rn | head -10
echo -e "\n按目标IP统计重传:"
tshark -r "$PCAP_FILE" -Y "tcp.analysis.retransmission" -T fields \
-e ip.dst 2>/dev/null | sort | uniq -c | sort -rn | head -10
# 2. 重传时序分析
echo -e "\n[2] 重传时序分析"
echo "首次重传延迟 > 200ms 的连接:"
tshark -r "$PCAP_FILE" -Y "tcp.analysis.retransmission" -T fields \
-e frame.time_delta_displayed \
-e ip.src \
-e ip.dst \
-e tcp.srcport \
-e tcp.dstport 2>/dev/null | \
awk -F'\t' '$1 > 0.2 {printf "%.3fs %s:%s -> %s:%s\n", $1, $2, $3, $4, $5}' | \
head -10
# 3. 快速重传分析
echo -e "\n[3] 快速重传分析"
echo "快速重传包数:"
tshark -r "$PCAP_FILE" -Y "tcp.analysis.fast_retransmission" 2>/dev/null | wc -l
# 4. 重复ACK分析
echo -e "\n[4] 重复ACK分析"
echo "重复ACK包数:"
tshark -r "$PCAP_FILE" -Y "tcp.analysis.duplicate_ack" 2>/dev/null | wc -l
echo -e "\n重复ACK最多的连接:"
tshark -r "$PCAP_FILE" -Y "tcp.analysis.duplicate_ack" -T fields \
-e ip.src \
-e ip.dst \
-e tcp.srcport \
-e tcp.dstport 2>/dev/null | sort | uniq -c | sort -rn | head -5
# 5. 重传模式分析
echo -e "\n[5] 重传模式分析"
echo "判断重传原因:"
# 计算重传率
TOTAL_TCP=$(tshark -r "$PCAP_FILE" -Y "tcp" 2>/dev/null | wc -l)
TOTAL_RETRANS=$(tshark -r "$PCAP_FILE" -Y "tcp.analysis.retransmission" 2>/dev/null | wc -l)
if [ "$TOTAL_TCP" -gt 0 ]; then
RETRANS_RATE=$(echo "scale=2; $TOTAL_RETRANS * 100 / $TOTAL_TCP" | bc)
echo "TCP重传率: ${RETRANS_RATE}%"
if (( $(echo "$RETRANS_RATE > 5" | bc -l) )); then
echo "[警告] 重传率超过5%,可能存在网络问题"
fi
fi
# 6. 建议
echo -e "\n[6] 诊断建议"
cat << 'EOF'
重传原因判断:
1. 单点重传 -> 可能是随机丢包,网络质量不稳定
2. 连续重传 -> 可能是网络拥塞或链路带宽不足
3. 特定时段重传 -> 可能是流量高峰或限速触发
4. 特定方向重传 -> 可能是对端处理能力问题
排查方向:
1. 检查网络设备CPU/内存是否正常
2. 检查链路带宽利用率
3. 检查是否有流量限速配置
4. 检查对端服务健康状态
EOF
echo -e "\n===== 分析完成 ====="
4.2 HTTP/HTTPS问题
4.2.1 HTTP问题诊断脚本
#!/bin/bash
# http_diagnosis.sh
# HTTP问题诊断脚本
set -e
PCAP_FILE=${1:-""}
echo "===== HTTP/HTTPS问题诊断 ====="
if [ -n "$PCAP_FILE" ] && [ -f "$PCAP_FILE" ]; then
echo "分析文件: $PCAP_FILE"
else
echo "用法: $0 <pcap文件>"
exit 1
fi
# 1. HTTP方法统计
echo -e "\n[1] HTTP方法统计"
tshark -r "$PCAP_FILE" -Y "http.request.method" -T fields \
-e http.request.method 2>/dev/null | sort | uniq -c | sort -rn
# 2. HTTP状态码分布
echo -e "\n[2] HTTP状态码分布"
tshark -r "$PCAP_FILE" -Y "http.response.code" -T fields \
-e http.response.code 2>/dev/null | sort | uniq -c | sort -rn
# 3. 错误响应分析
echo -e "\n[3] 错误响应详情"
echo "4xx错误:"
tshark -r "$PCAP_FILE" -Y "http.response.code >= 400 and http.response.code < 500" -T fields \
-e http.response.code \
-e http.host \
-e http.request.uri 2>/dev/null | head -20
echo -e "\n5xx错误:"
tshark -r "$PCAP_FILE" -Y "http.response.code >= 500" -T fields \
-e http.response.code \
-e http.host \
-e http.request.uri 2>/dev/null | head -20
# 4. 慢请求分析
echo -e "\n[4] 慢请求分析 (响应时间 > 1秒)"
tshark -r "$PCAP_FILE" -Y "http" -T fields \
-e frame.time_delta_displayed \
-e http.request.method \
-e http.host \
-e http.request.uri 2>/dev/null | \
awk -F'\t' '$1 > 1 {printf "%.3fs %s %s%s\n", $1, $2, $3, $4}' | \
sort -rn | head -20
# 5. HTTPS/TLS问题
echo -e "\n[5] TLS握手问题"
echo "TLS版本统计:"
tshark -r "$PCAP_FILE" -Y "tls.handshake.version" -T fields \
-e tls.handshake.version 2>/dev/null | sort | uniq -c | sort -rn
echo -e "\nTLS错误:"
tshark -r "$PCAP_FILE" -Y "tls.alert_message" -T fields \
-e ip.src \
-e tls.alert_message 2>/dev/null | head -10
echo -e "\nTLS证书问题:"
tshark -r "$PCAP_FILE" -Y "tls.handshake.type == 11" -T fields \
-e ip.src \
-e x509sat.printableString 2>/dev/null | head -10
# 6. 连接复用分析
echo -e "\n[6] HTTP连接复用分析"
echo "Keep-Alive连接:"
tshark -r "$PCAP_FILE" -Y "http.connection" -T fields \
-e http.connection 2>/dev/null | sort | uniq -c | sort -rn | head -10
# 7. 并发请求分析
echo -e "\n[7] 并发请求分析"
echo "同一主机并发请求数 (Top 10):"
tshark -r "$PCAP_FILE" -Y "http.request" -T fields \
-e http.host \
-e frame.number \
-e frame.time 2>/dev/null | \
awk -F'\t' '{print $1}' | sort | uniq -c | sort -rn | head -10
# 8. Transfer-Encoding分析
echo -e "\n[8] Transfer-Encoding分析"
echo "分块传输编码:"
tshark -r "$PCAP_FILE" -Y "http.transfer_encoding" -T fields \
-e http.transfer_encoding 2>/dev/null | sort | uniq -c
echo -e "\n===== 诊断完成 ====="
4.3 DNS解析问题
4.3.1 DNS问题诊断脚本
#!/bin/bash
# dns_diagnosis.sh
# DNS解析问题诊断脚本
set -e
PCAP_FILE=${1:-""}
echo "===== DNS解析问题诊断 ====="
if [ -n "$PCAP_FILE" ] && [ -f "$PCAP_FILE" ]; then
echo "分析文件: $PCAP_FILE"
else
echo "执行实时捕获..."
CAPTURE_FILE="/tmp/dns_$(date +%Y%m%d_%H%M%S).pcap"
sudo tcpdump -i any "port 53" -w "$CAPTURE_FILE" -c 500 2>/dev/null &
sleep 10
PCAP_FILE="$CAPTURE_FILE"
fi
# 1. DNS查询统计
echo -e "\n[1] DNS查询统计"
echo "查询类型分布:"
tshark -r "$PCAP_FILE" -Y "dns.qry.type" -T fields \
-e dns.qry.type 2>/dev/null | sort | uniq -c | sort -rn
# 2. 最常见查询
echo -e "\n[2] 最常见查询 (Top 20)"
tshark -r "$PCAP_FILE" -Y "dns.qry.name" -T fields \
-e dns.qry.name 2>/dev/null | sort | uniq -c | sort -rn | head -20
# 3. 响应码分析
echo -e "\n[3] DNS响应码分析"
echo "响应状态分布:"
tshark -r "$PCAP_FILE" -Y "dns.flags.rcode" -T fields \
-e dns.flags.rcode 2>/dev/null | sort | uniq -c | sort -rn
# 4. 失败查询分析
echo -e "\n[4] DNS失败查询分析"
echo "NXDOMAIN (域名不存在):"
tshark -r "$PCAP_FILE" -Y "dns.flags.rcode == 3" -T fields \
-e dns.qry.name \
-e ip.src 2>/dev/null | head -20
echo -e "\nSERVFAIL (服务器失败):"
tshark -r "$PCAP_FILE" -Y "dns.flags.rcode == 2" -T fields \
-e dns.qry.name \
-e ip.src 2>/dev/null | head -10
# 5. 解析延迟分析
echo -e "\n[5] DNS解析延迟分析"
echo "查询响应时间 > 500ms:"
tshark -r "$PCAP_FILE" -Y "dns" -T fields \
-e frame.time_delta_displayed \
-e dns.qry.name \
-e dns.resp.name 2>/dev/null | \
awk -F'\t' '$1 > 0.5 {printf "%.3fs %s -> %s\n", $1, $2, $3}' | \
sort -rn | head -15
# 6. DNS隧道检测
echo -e "\n[6] DNS隧道/异常检测"
echo "大量相同查询 (可能是隧道):"
tshark -r "$PCAP_FILE" -Y "dns.qry.type == 1" -T fields \
-e dns.qry.name 2>/dev/null | sort | uniq -c | \
awk '$1 > 50 {print}' | head -10
echo -e "\n异常长的子域名 (可能是隧道):"
tshark -r "$PCAP_FILE" -Y "dns" -T fields \
-e dns.qry.name 2>/dev/null | \
awk '{print length($1), $1}' | sort -rn | head -10
# 7. DNSSEC验证
echo -e "\n[7] DNSSEC验证状态"
tshark -r "$PCAP_FILE" -Y "dns.ds" -T fields \
-e dns.dnskey 2>/dev/null | wc -l
echo "DNSSEC记录数: $(tshark -r "$PCAP_FILE" -Y "dns.dnskey" 2>/dev/null | wc -l)"
# 8. 解析路径追踪
echo -e "\n[8] 解析路径追踪"
echo "查询 -> 响应 追踪:"
tshark -r "$PCAP_FILE" -Y "dns" -T fields \
-e dns.id \
-e dns.qry.name \
-e ip.src \
-e ip.dst 2>/dev/null | head -30
echo -e "\n===== 诊断完成 ====="
4.4 应用层协议问题
4.4.1 数据库协议分析
#!/bin/bash
# db_protocol_analysis.sh
# 数据库协议分析脚本
set -e
PCAP_FILE=${1:-""}
echo "===== 数据库协议分析 ====="
if [ -n "$PCAP_FILE" ] && [ -f "$PCAP_FILE" ]; then
echo "分析文件: $PCAP_FILE"
else
echo "用法: $0 <pcap文件>"
exit 1
fi
# 1. MySQL分析
echo -e "\n[1] MySQL协议分析"
echo "MySQL命令统计:"
tshark -r "$PCAP_FILE" -Y "mysql.query" -T fields \
-e mysql.query 2>/dev/null | cut -d' ' -f1 | sort | uniq -c | sort -rn | head -10
echo -e "\n慢查询 (执行时间 > 1s):"
tshark -r "$PCAP_FILE" -Y "mysql" -T fields \
-e frame.time_delta_displayed \
-e mysql.query 2>/dev/null | \
awk -F'\t' '$1 > 1 {printf "%.3fs %s\n", $1, $2}' | head -20
echo -e "\nMySQL错误:"
tshark -r "$PCAP_FILE" -Y "mysql.errcode" -T fields \
-e mysql.errcode \
-e mysql.errmsg 2>/dev/null | head -10
# 2. PostgreSQL分析
echo -e "\n[2] PostgreSQL协议分析"
echo "PostgreSQL命令统计:"
tshark -r "$PCAP_FILE" -Y "postgresql" -T fields \
-e postgresql.query 2>/dev/null | cut -d' ' -f1 | sort | uniq -c | sort -rn | head -10
# 3. Redis分析
echo -e "\n[3] Redis协议分析"
echo "Redis命令统计:"
tshark -r "$PCAP_FILE" -Y "redis" -T fields \
-e redis.command 2>/dev/null | sort | uniq -c | sort -rn | head -15
echo -e "\n大Key操作 (响应 > 1MB):"
tshark -r "$PCAP_FILE" -Y "redis" -T fields \
-e frame.len \
-e redis.keyspace \
-e redis.command 2>/dev/null | \
awk -F'\t' '$1 > 1000000 {printf "%.2fMB %s %s\n", $1/1024/1024, $2, $3}' | head -10
# 4. 连接分析
echo -e "\n[4] 数据库连接分析"
echo "连接建立统计:"
echo "MySQL:"
tshark -r "$PCAP_FILE" -Y "mysql.packet_length" 2>/dev/null | wc -l
echo "PostgreSQL:"
tshark -r "$PCAP_FILE" -Y "postgresql.packet_type" 2>/dev/null | wc -l
echo "Redis:"
tshark -r "$PCAP_FILE" -Y "redis" 2>/dev/null | wc -l
# 5. 性能问题
echo -e "\n[5] 性能问题汇总"
echo "总数据库查询数:"
echo "MySQL: $(tshark -r "$PCAP_FILE" -Y "mysql.query" 2>/dev/null | wc -l)"
echo "PostgreSQL: $(tshark -r "$PCAP_FILE" -Y "postgresql" 2>/dev/null | wc -l)"
echo "Redis: $(tshark -r "$PCAP_FILE" -Y "redis" 2>/dev/null | wc -l)"
echo -e "\n===== 分析完成 ====="
五、自动化与脚本
5.1 自动抓包触发
5.1.1 智能抓包脚本
#!/bin/bash
# smart_capture.sh
# 智能自动抓包脚本
set -e
CONFIG_FILE="/etc/network-capture.conf"
LOG_DIR="/var/log/captures"
mkdir -p "$LOG_DIR"
# 加载配置
load_config() {
if [ -f "$CONFIG_FILE" ]; then
source "$CONFIG_FILE"
else
# 默认配置
INTERFACE="eth0"
TRIGGER_ERRORS=5
TRIGGER_LATENCY=100
CAPTURE_DURATION=30
MAX_FILE_SIZE=100
fi
}
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_DIR/capture.log"
}
# 错误条件检测
detect_errors() {
local count=0
# 检测TCP错误
count=$(sudo tcpdump -i "$INTERFACE" "tcp[tcpflags] & tcp-rst != 0" -c 10 2>/dev/null | wc -l)
# 检测ICMP不可达
count=$((count + $(sudo tcpdump -i "$INTERFACE" "icmp[icmptype] == 3" -c 10 2>/dev/null | wc -l)))
echo $count
}
# 延迟检测
detect_latency() {
local target=${1:-"8.8.8.8"}
local latency=$(ping -c 1 -W 1 "$target" 2>/dev/null | \
grep "time=" | awk -F'time=' '{print $2}' | awk '{print $1}')
if [ -z "$latency" ]; then
echo "999"
else
echo "$latency"
fi
}
# 执行抓包
execute_capture() {
local trigger_type=$1
local capture_file="${LOG_DIR}/auto_${trigger_type}_$(date +%Y%m%d_%H%M%S).pcap"
log "触发抓包: $trigger_type"
log "保存到: $capture_file"
# 后台执行捕获
sudo tcpdump -i "$INTERFACE" \
-w "$capture_file" \
-C "$MAX_FILE_SIZE" \
-W 10 \
-c 10000 &
CAPTURE_PID=$!
log "捕获进程PID: $CAPTURE_PID"
# 等待指定时间
sleep "$CAPTURE_DURATION"
# 停止捕获
kill "$CAPTURE_PID" 2>/dev/null
wait "$CAPTURE_PID" 2>/dev/null
# 分析捕获文件
log "分析捕获文件..."
ANALYSIS_FILE="${capture_file%.pcap}_analysis.txt"
{
echo "===== 自动捕获分析报告 ====="
echo "触发类型: $trigger_type"
echo "捕获时间: $(date)"
echo "文件: $capture_file"
echo -e "\n[1] 协议分布"
tshark -r "$capture_file" -q -z io,phs 2>/dev/null | head -15
echo -e "\n[2] TCP问题"
echo "重传包: $(tshark -r "$capture_file" -Y 'tcp.analysis.retransmission' 2>/dev/null | wc -l)"
echo "RST包: $(tshark -r "$capture_file" -Y 'tcp.flags.reset==1' 2>/dev/null | wc -l)"
echo -e "\n[3] 统计摘要"
tshark -r "$capture_file" -q -z conv,tcp 2>/dev/null | head -10
} > "$ANALYSIS_FILE"
log "分析报告: $ANALYSIS_FILE"
}
# 主监控循环
main() {
load_config
log "===== 智能抓包监控启动 ====="
log "接口: $INTERFACE"
log "错误阈值: $TRIGGER_ERRORS"
log "延迟阈值: ${TRIGGER_LATENCY}ms"
while true; do
# 检测错误条件
ERRORS=$(detect_errors)
if [ "$ERRORS" -ge "$TRIGGER_ERRORS" ]; then
log "检测到错误激增: $ERRORS"
execute_capture "errors"
fi
# 检测延迟
LATENCY=$(detect_latency)
if (( $(echo "$LATENCY > $TRIGGER_LATENCY" | bc -l) )); then
log "检测到延迟升高: ${LATENCY}ms"
execute_capture "latency"
fi
sleep 10
done
}
# 信号处理
trap 'log "收到停止信号,退出..."; exit 0' SIGINT SIGTERM
# 运行
case "${1:-start}" in
start)
main
;;
stop)
pkill -f smart_capture.sh
log "已停止"
;;
*)
echo "用法: $0 {start|stop}"
;;
esac
5.2 批量包分析
#!/bin/bash
# batch_analysis.sh
# 批量抓包文件分析脚本
set -e
ANALYSIS_DIR=${1:-"/var/log/captures"}
echo "===== 批量抓包分析 ====="
echo "分析目录: $ANALYSIS_DIR"
if [ ! -d "$ANALYSIS_DIR" ]; then
echo "目录不存在: $ANALYSIS_DIR"
exit 1
fi
# 创建输出报告
REPORT_FILE="/tmp/batch_analysis_$(date +%Y%m%d_%H%M%S).html"
cat > "$REPORT_FILE" << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>批量抓包分析报告</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #4CAF50; color: white; }
.error { color: red; }
.warning { color: orange; }
.success { color: green; }
</style>
</head>
<body>
<h1>批量抓包分析报告</h1>
EOF
echo "<p>生成时间: $(date)</p>" >> "$REPORT_FILE"
echo "<p>分析目录: $ANALYSIS_DIR</p>" >> "$REPORT_FILE"
# 统计摘要
echo "<h2>文件列表</h2>" >> "$REPORT_FILE"
echo "<table>" >> "$REPORT_FILE"
echo "<tr><th>文件名</th><th>大小</th><th>包数</th><th>TCP重传</th><th>RST</th><th>问题级别</th></tr>" >> "$REPORT_FILE"
# 分析每个pcap文件
for pcap_file in $(find "$ANALYSIS_DIR" -name "*.pcap" -type f 2>/dev/null); do
filename=$(basename "$pcap_file")
filesize=$(du -h "$pcap_file" | cut -f1)
# 统计包数
packet_count=$(tshark -r "$pcap_file" 2>/dev/null | wc -l)
# 统计TCP问题
retrans=$(tshark -r "$pcap_file" -Y "tcp.analysis.retransmission" 2>/dev/null | wc -l)
rst=$(tshark -r "$pcap_file" -Y "tcp.flags.reset==1" 2>/dev/null | wc -l)
# 判断问题级别
if [ "$retrans" -gt 100 ] || [ "$rst" -gt 50 ]; then
level="<span class='error'>严重</span>"
elif [ "$retrans" -gt 20 ] || [ "$rst" -gt 10 ]; then
level="<span class='warning'>警告</span>"
else
level="<span class='success'>正常</span>"
fi
echo "<tr><td>$filename</td><td>$filesize</td><td>$packet_count</td><td>$retrans</td><td>$rst</td><td>$level</td></tr>" >> "$REPORT_FILE"
done
echo "</table>" >> "$REPORT_FILE"
# 总体统计
echo "<h2>总体统计</h2>" >> "$REPORT_FILE"
TOTAL_FILES=$(find "$ANALYSIS_DIR" -name "*.pcap" | wc -l)
TOTAL_SIZE=$(du -sh "$ANALYSIS_DIR" 2>/dev/null | cut -f1)
TOTAL_PACKETS=$(find "$ANALYSIS_DIR" -name "*.pcap" -exec tshark -r {} 2>/dev/null \; | wc -l)
cat >> "$REPORT_FILE" << EOF
<ul>
<li>文件总数: $TOTAL_FILES</li>
<li>总大小: $TOTAL_SIZE</li>
<li>总包数: $TOTAL_PACKETS</li>
</ul>
EOF
echo "</body></html>" >> "$REPORT_FILE"
echo "报告已生成: $REPORT_FILE"
echo "打开方式: firefox $REPORT_FILE"
六、最佳实践
6.1 抓包点选择
6.1.1 网络拓扑与抓包点
网络拓扑示例:
┌─────────┐ ┌─────────┐ ┌─────────┐
│ 客户端 │───▶│ L4 │───▶│ 服务器 │
│ │◀───│ 负载均衡 │◀───│ │
└─────────┘ └─────────┘ └─────────┘
│ │
│ │
▼ ▼
┌─────────────────────────────────────────┐
│ 抓包点选择指南 │
├─────────────────────────────────────────┤
│ 抓包点 │ 能看到的问题 │ 适用场景 │
├─────────────────────────────────────────┤
│ 客户端 │ 应用层问题 │ 端到端延迟 │
│ │ TLS问题 │ 协议兼容性 │
├─────────────────────────────────────────┤
│ 负载均衡 │ 连接分发问题 │ 健康检查 │
│ │ 流量不均 │ 端口映射 │
├─────────────────────────────────────────┤
│ 服务器网卡│ 服务层问题 │ 后端处理 │
│ │ 资源争用 │ 数据库延迟 │
├─────────────────────────────────────────┤
│ 交换机镜像│ 全网流量 │ 分布式问题 │
│ │ 流量分析 │ 性能监控 │
└─────────────────────────────────────────┘
6.1.2 不同场景的抓包策略
#!/bin/bash
# capture_strategy.sh
# 不同场景的抓包策略
set -e
echo "===== 网络抓包策略指南 ====="
# 场景1: 客户端到服务器延迟
scenario_client_to_server() {
echo -e "\n[场景1] 客户端到服务器延迟"
echo "推荐抓包点: 客户端 + 服务器端"
echo "过滤条件: host <目标IP> and tcp.port == <端口>"
echo ""
echo "客户端抓包命令:"
echo " sudo tcpdump -i eth0 -w client_capture.pcap 'host 192.168.1.100 and tcp.port 443'"
echo ""
echo "服务器抓包命令:"
echo " sudo tcpdump -i eth0 -w server_capture.pcap 'host 203.0.113.50 and tcp.port 443'"
}
# 场景2: 负载均衡问题
scenario_load_balancer() {
echo -e "\n[场景2] 负载均衡问题"
echo "推荐抓包点: 客户端 + 负载均衡器入口 + 后端服务器"
echo "过滤条件: tcp.port == 80 or tcp.port == 443"
echo ""
echo "分析要点:"
echo " 1. 对比客户端请求与负载均衡器收到的请求"
echo " 2. 检查负载均衡器到后端的连接分发"
echo " 3. 验证健康检查是否正常"
}
# 场景3: 数据库性能问题
scenario_database() {
echo -e "\n[场景3] 数据库性能问题"
echo "推荐抓包点: 应用服务器 + 数据库服务器"
echo "过滤条件: tcp.port == 3306 or tcp.port == 5432 or tcp.port == 6379"
echo ""
echo "分析要点:"
echo " 1. 查询响应时间"
echo " 2. 连接池耗尽"
echo " 3. 慢查询模式"
}
# 场景4: 微服务间通信
scenario_microservices() {
echo -e "\n[场景4] 微服务间通信问题"
echo "推荐抓包点: 每个服务的出入口"
echo "过滤条件: tcp.port == <服务端口>"
echo ""
echo "分析要点:"
echo " 1. 服务调用链追踪"
echo " 2. gRPC/HTTP2问题"
echo " 3. mTLS证书问题"
}
# 场景5: DNS问题
scenario_dns() {
echo -e "\n[场景5] DNS解析问题"
echo "推荐抓包点: DNS服务器或客户端"
echo "过滤条件: port 53"
echo ""
echo "分析要点:"
echo " 1. 查询响应时间"
echo " 2. NXDOMAIN模式"
echo " 3. DNS劫持检测"
}
# 场景6: TLS/SSL问题
scenario_tls() {
echo -e "\n[场景6] TLS/SSL问题"
echo "推荐抓包点: 客户端终止点"
echo "过滤条件: tcp.port == 443 and tls"
echo ""
echo "分析要点:"
echo " 1. 握手失败原因"
echo " 2. 证书验证"
echo " 3. 协议版本不匹配"
}
# 显示所有场景
scenario_client_to_server
scenario_load_balancer
scenario_database
scenario_microservices
scenario_dns
scenario_tls
echo -e "\n===== 策略指南结束 ====="
6.2 性能与存储
6.2.1 抓包存储策略
#!/bin/bash
# capture_storage.sh
# 抓包存储与生命周期管理
set -e
STORAGE_BASE="/var/log/captures"
RETENTION_DAYS=${RETENTION_DAYS:-30}
echo "===== 抓包存储管理 ====="
echo "存储目录: $STORAGE_BASE"
echo "保留天数: $RETENTION_DAYS"
# 创建目录结构
create_dirs() {
echo -e "\n[1] 创建目录结构"
mkdir -p "$STORAGE_BASE"/{daily,incidents,debug,archive}
echo "目录已创建:"
ls -la "$STORAGE_BASE"
}
# 自动清理
auto_cleanup() {
echo -e "\n[2] 清理过期文件"
find "$STORAGE_BASE" -name "*.pcap" -mtime +$RETENTION_DAYS -type f -delete
echo "已删除 ${RETENTION_DAYS} 天前的pcap文件"
find "$STORAGE_BASE/archive" -name "*.pcap.gz" -mtime +365 -type f -delete
echo "已删除 1 年前的压缩归档"
}
# 压缩归档
compress_old_files() {
echo -e "\n[3] 压缩归档"
find "$STORAGE_BASE/daily" -name "*.pcap" -mtime +7 -type f | while read file; do
gzip "$file"
echo "已压缩: $file"
done
}
# 存储使用统计
storage_stats() {
echo -e "\n[4] 存储统计"
echo "按目录大小:"
du -sh "$STORAGE_BASE"/* 2>/dev/null | sort -hr
echo -e "\n总大小:"
du -sh "$STORAGE_BASE" 2>/dev/null
echo -e "\n文件数量:"
find "$STORAGE_BASE" -name "*.pcap*" -type f | wc -l
}
# 告警阈值
check_threshold() {
echo -e "\n[5] 存储告警检查"
MAX_SIZE_GB=100
CURRENT_SIZE=$(du -sm "$STORAGE_BASE" 2>/dev/null | awk '{print $1}')
CURRENT_GB=$(echo "scale=2; $CURRENT_SIZE / 1024" | bc)
echo "当前使用: ${CURRENT_GB}GB / ${MAX_SIZE_GB}GB"
USAGE_PCT=$(echo "scale=0; $CURRENT_SIZE * 100 / ($MAX_SIZE_GB * 1024)" | bc)
if [ "$USAGE_PCT" -gt 90 ]; then
echo "[告警] 存储使用率超过90%,请清理"
elif [ "$USAGE_PCT" -gt 70 ]; then
echo "[警告] 存储使用率超过70%"
else
echo "[正常] 存储使用率正常"
fi
}
# 执行维护任务
main() {
create_dirs
auto_cleanup
compress_old_files
storage_stats
check_threshold
}
# 计划任务示例
# 0 2 * * * /usr/local/bin/capture_storage.sh # 每天凌晨2点执行
main
6.3 团队协作规范
6.3.1 抓包分析协作流程
#!/bin/bash
# capture_workflow.sh
# 抓包分析团队协作脚本
set -e
WORKFLOW_DIR="/var/log/captures/workflow"
TEMPLATE_DIR="/etc/capture-templates"
echo "===== 抓包分析协作流程 ====="
# 创建标准命名规范
naming_convention() {
echo -e "\n[1] 命名规范"
cat << 'EOF'
抓包文件命名:
{日期}_{场景}_{IP范围}_{捕获方向}_{序号}.pcap
示例:
20260328_http_api_192.168.1.0_client_001.pcap
20260328_tls_handshake_203.0.113.0_both_001.pcap
20260328_dns_resolve_8.8.8.8_server_001.pcap
分析报告命名:
{抓包文件}_analysis_{日期}.txt
示例:
20260328_http_api_192.168.1.0_client_001_analysis_20260328.txt
EOF
}
# 生成分析报告模板
generate_template() {
echo -e "\n[2] 分析报告模板"
local template_file="$WORKFLOW_DIR/analysis_template.txt"
cat > "$template_file" << 'EOF'
===== 网络抓包分析报告 =====
基本信息:
--------
文件名:
捕获时间:
捕获位置:
分析时间:
分析人员:
问题描述:
--------
[详细描述遇到的网络问题]
分析摘要:
--------
[总结发现的关键问题]
详细分析:
--------
1. 协议分布
2. 连接统计
3. 异常发现
4. 时间线
根本原因:
--------
[分析得出的根本原因]
建议措施:
--------
[针对问题的解决方案]
附件:
----
- 抓包文件: xxx.pcap
- 关键包截图: xxx.png
EOF
echo "模板已生成: $template_file"
}
# 导出协作包
export_bundle() {
local incident_id=$1
local output_dir=$2
echo -e "\n[3] 导出协作包"
echo "事件ID: $incident_id"
echo "输出目录: $output_dir"
mkdir -p "$output_dir"
# 复制相关抓包文件
cp "$WORKFLOW_DIR"/${incident_id}_*.pcap "$output_dir/" 2>/dev/null || true
# 复制分析报告
cp "$WORKFLOW_DIR"/${incident_id}_*.txt "$output_dir/" 2>/dev/null || true
# 复制截图
cp "$WORKFLOW_DIR"/${incident_id}_*.png "$output_dir/" 2>/dev/null || true
# 创建索引文件
cat > "$output_dir/README.txt" << EOF
事件 $incident_id 协作包
生成时间: $(date)
包含文件:
$(ls -la "$output_dir")
EOF
echo "协作包已导出: $output_dir"
}
# 导入审查
import_review() {
local bundle_dir=$1
echo -e "\n[4] 审查抓包协作包"
echo "目录: $bundle_dir"
# 检查必要文件
if [ ! -f "$bundle_dir"/*.pcap ]; then
echo "[错误] 缺少抓包文件"
return 1
fi
# 生成审查清单
cat > "$bundle_dir/review_checklist.txt" << 'EOF'
审查清单:
[ ] 抓包文件完整可读
[ ] 分析报告结构完整
[ ] 问题描述清晰
[ ] 根本原因分析合理
[ ] 建议措施可行
[ ] 截图清晰可辨
EOF
echo "审查清单已生成: $bundle_dir/review_checklist.txt"
}
naming_convention
generate_template
echo -e "\n===== 协作流程说明 ====="
echo "1. 捕获时使用标准命名"
echo "2. 分析后生成报告模板"
echo "3. 使用 export_bundle 导出协作包"
echo "4. 接收方使用 import_review 进行审查"
七、总结
7.1 核心要点回顾
tcpdump和Wireshark是企业网络故障排查的两大核心工具,各有优劣:
tcpdump优势:轻量、远程友好、适合自动化、高性能抓包
Wireshark优势:可视化、深度分析、统计强大、专家系统
两者配合使用的最佳实践:
- tcpdump负责捕获和预处理,Wireshark负责深度分析
- 使用BPF过滤减少数据量
- 熟练掌握显示过滤器是关键
- 统计功能和专家信息是快速定位问题的利器
- 自动化脚本可以大幅提升效率
7.2 证据链总结
| 技术点 |
效能数据 |
来源 |
| 抓包解决率 |
85%+ |
Packet Pushers 2025 |
| 排查时间节省 |
从小时到分钟 |
行业实践 |
| 协议分析准确率 |
>90% |
SharkFest统计 |
7.3 快速参考表
| 场景 |
tcpdump命令 |
Wireshark过滤器 |
| HTTP问题 |
tcpdump -i eth0 port 80 -w http.pcap |
http |
| TCP重传 |
tcpdump -i eth0 'tcp[tcpflags] & tcp-retransmission' |
tcp.analysis.retransmission |
| DNS问题 |
tcpdump -i eth0 port 53 -w dns.pcap |
dns |
| TLS握手 |
tcpdump -i eth0 port 443 -w tls.pcap |
tls.handshake |
| 延迟分析 |
tcpdump -i eth0 -tttt |
frame.time_delta |
更多网络抓包实战,尽在云栈社区的网络技术板块。