Tcpdump使用

Tcpdump使用

Tcpdump 是信息安全领域常用的嗅探和网络分析工具,大部分 Linux 发行版都内置了 Tcpdump 工具。如果没有,也可以直接使用对应的包管理器进行安装(如:$ sudo apt-get install tcpdump 和 $ sudo yum install tcpdump)

1、命令选项

-i any:监听所有网络接口

-i eth0:监听指定的网络接口(eth0)

-D:列出所有可用的网络接口

-n:不解析主机名

-nn:不解析主机名和端口名

-q:输出较少的信息

-t:更便于阅读的时间戳输出

-tttt:最便于阅读的时间戳输出

-X:以 HEX 和 ASCII 模式输出数据包的内容

-XX:与 -X 选项相同,同时还输出 ethernet 头

-v, -vv, -vvv:输出更多数据包的信息

-c:获取到指定数目的数据包后就停止

-s:定义 snaplength (size) ,-s0 表示获取全部

-S:输出绝对序列号

-e:获取 ethernet 头信息

-E:通过提供 key 来解密 IPSEC 流量

二、表达式

通过表达式可以对各种不同类型的网络流量进行过滤,以获取到需要的信息。这也是 tcpdump强大功能的一个体现。主要有 3 种类型的表达式:

  • Type(类型)选项包括 host(主机名,域名,IP 地址) 、net(子网) 和 port(端口)
  • Direction(方向)选项包括 src 和 dst 以及它们的组合
  • Proto(协议)包括 tcp 、udp 、ICMP、ether  和 arp

三、应用实例

指定网络接口:

tcpdump -i <dev>

Tcpdump使用
-i 指定监听接口

ens33是centos7系统中第一张的网卡设备名称

原始信息输出模式:

tcpdump -ttttnnvvS -i <dev>

Tcpdump使用

更详细的输出,不解析主机名和端口名,使用绝对序列号,方便阅读的时间戳

通过IP地址过滤:

tcpdump host <IP>

Tcpdump使用

192.168.1.11是同网段的另外一台服务器

HEX 输出

tcpdump -nnvXSs 0

Tcpdump使用

抓取一个HEX格式的icpm包

通过源地址和目标地址进行过滤(源地址:src 目标地址:dst)

tcpdump src 192.168.1.11 -i ens33

Tcpdump使用
src

tcpdump dst 192.168.1.11 -i ens33

Tcpdump使用
dst

通过子网进行过滤

tcpdump net 192.168.1.0/24

Tcpdump使用
tcpdump net

监听指定端口号

tcpdump dst port 22 -i ens33

Tcpdump使用
tcpdump port

抓取ens33网卡接口目标地址端口为22的包

指定协议

tcpdmp icmp -i ens33

Tcpdump使用
tcpdmp icmp

端口范围 tcpdump portrange 1-65535

Tcpdump使用
tcpdump portrange

通过包大小过滤(通过length查看)

tcpdump less 32

tcpdump greater 64

查找 http 包

查找 user-agent 信息

tcpdump -vvAls0 | grep 'User-Agent:'

查找只是 GET 请求的流量

tcpdump -vvAls0 | grep 'GET'

查找 http 客户端 IP

tcpdump -vvAls0 | grep 'Host:'

查询客户端 cookie

tcpdump -vvAls0 | grep 'Set-Cookie|Host:|Cookie:'

查找 DNS 流量

tcpdump -vvAs0 port 53

四、高级功能

1. 逻辑运算符

可以通过命令选项的不同组合(使用逻辑运算符)完成更复杂的任务。运算符包括以下3种:

  • AND(and 或 &)
  • OR(or 或 ||)
  • EXCEPT (not 或 !)

tcpdump port 22 and src 192.168.1.11 -i ens33

Tcpdump使用

即捕捉从指定主机(192.168.1.11)发出,且目标端口为 22 的所有网络数据

tcpdump src net 192.168.1.0/24 and dst net 192.168.0.0/24 or 192.168.2.0/24

Tcpdump使用

即捕捉从指定子网(192.168.1.0/24)发送到目标子网(192.168.0.0/24 和 192.168.2.0/24)的所有网络数据

2. 指定 TCP 标志位(Flags)

tcpdump 'tcp[13] & 32!=0' 所有 URGENT (URG) 包
tcpdump 'tcp[13] & 16!=0' 所有 ACKNOWLEDGE (ACK) 包
tcpdump 'tcp[13] & 8!=0' 所有 PUSH (PSH) 包
tcpdump 'tcp[13] & 4!=0' 所有 RESET (RST) 包
tcpdump 'tcp[13] & 2!=0' 所有 SYNCHRONIZE (SYN) 包
tcpdump 'tcp[13] & 1!=0' 所有 FINISH (FIN) 包
tcpdump 'tcp[13]=18' 所有 SYNCHRONIZE/ACKNOWLEDGE (SYNACK) 包

其他指定标志位的方式如:

tcpdump 'tcp[tcpflags] == tcp-syn'
tcpdump 'tcp[tcpflags] == tcp-fin'

一些特殊的用法

tcpdump 'tcp[13] = 6' RST 和 SYN 同时启用的数据包(不正常)
tcpdump 'tcp[32:4] = 0x47455420' 获取 http GET 请求的文本

Tcpdump使用

tcpdump 'tcp[(tcp[12]>>2):4] = 0x5353482D' 获取任何端口的 ssh 连接(通过 banner 信息)

Tcpdump使用

tcpdump 'ip[8] < 10' ttl 小于 10 的数据包(出现问题或 traceroute 命令)

Tcpdump使用


tcpdump 'ip[6] & 128 != 0' 非常有可能是黑客入侵的情况

五、核心结构模板以及标准案例解读

核心结构模板

无论查什么网络问题,先跑这条命令,它能看到最核心的 TCP 交互逻辑。

sudo tcpdump -i eth0 -nn -S host <目标IP>
  • 把 <目标IP> 换成你要排查的那个客户端 IP(比如 192.168.1.220)。
  • 把 eth0 换成你服务器的网卡名(如果不确定,就用 ip addr 看一眼,通常是第一个非 lo 的网卡)。
  • 先不要加任何过滤条件(如 port, flags 等),先看全貌,再用人眼过滤。

返回格式:

[时间戳] IP [源IP].[源端口] > [目的IP].[目的端口]: Flags [标志位], seq [序列号], ack [确认号], win [窗口大小], length [数据长度]: [应用层摘要]
字段示例值含义与人话解读
时间戳10:37:46.604735发生的时间。用来计算两个包之间隔了多久(减法运算)。
方向192...220 > 172...124谁发给谁。箭头左边是发送方,右边是接收方。
Flags[S]最关键! 表示包的类型。
• [S]: SYN (发起连接)
• [S.]: SYN+ACK (同意连接)
• [.]: ACK (纯确认/心跳)
• [P.]: PUSH (有真实数据,如 HTTP 请求)
• [F.]: FIN (我要断开连接)
seq3029259600序列号。你可以把它想象成“快递单号”,保证数据包顺序不错乱。一般不用细看数值,除非丢包。
ack(第一行没有)确认号。表示“我收到了你之前的哪个包”。
(注意:只有带 ACK 标志的包才有这个字段)
length0数据载荷长度。
• 0: 纯控制包(握手、挥手、空确认)。
• >0: 里面藏着真实数据(如 HTML 代码、图片数据)。
摘要HTTP: GET /...tcpdump 智能识别出的应用层内容。如果是 HTTP,它会直接显示请求方法;如果是 HTTPS,这里通常为空或显示 TLS 相关。

案例一:标准 HTTP 访问分析

假如172.16.1.124部署了一个 nginx 服务,192.168.1.220 成功进行 curl 访问,在172.16.1.124使用此抓包命令结果如下

root@sh-cen-test:~# sudo tcpdump -i eth0 -nn -S host 192.168.1.220
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
11:09:40.190804 IP 192.168.1.220.59596 > 172.16.1.124.80: Flags [S], seq 1645009870, win 64240, options [mss 1460,sackOK,TS val 1914913400 ecr 0,nop,wscale 7], length 0
11:09:40.190833 IP 172.16.1.124.80 > 192.168.1.220.59596: Flags [S.], seq 4035228215, ack 1645009871, win 65160, options [mss 1460,sackOK,TS val 4133407660 ecr 1914913400,nop,wscale 7], length 0
11:09:40.200955 IP 192.168.1.220.59596 > 172.16.1.124.80: Flags [.], ack 4035228216, win 502, options [nop,nop,TS val 1914913410 ecr 4133407660], length 0
11:09:40.200991 IP 192.168.1.220.59596 > 172.16.1.124.80: Flags [P.], seq 1645009871:1645009946, ack 4035228216, win 502, options [nop,nop,TS val 1914913410 ecr 4133407660], length 75: HTTP: GET / HTTP/1.1
11:09:40.201014 IP 172.16.1.124.80 > 192.168.1.220.59596: Flags [.], ack 1645009946, win 509, options [nop,nop,TS val 4133407670 ecr 1914913410], length 0
11:09:40.201268 IP 172.16.1.124.80 > 192.168.1.220.59596: Flags [P.], seq 4035228216:4035229078, ack 1645009946, win 509, options [nop,nop,TS val 4133407670 ecr 1914913410], length 862: HTTP: HTTP/1.1 200 OK
11:09:40.211256 IP 192.168.1.220.59596 > 172.16.1.124.80: Flags [.], ack 4035229078, win 496, options [nop,nop,TS val 1914913420 ecr 4133407670], length 0
11:09:40.211461 IP 192.168.1.220.59596 > 172.16.1.124.80: Flags [F.], seq 1645009946, ack 4035229078, win 496, options [nop,nop,TS val 1914913420 ecr 4133407670], length 0
11:09:40.211498 IP 172.16.1.124.80 > 192.168.1.220.59596: Flags [F.], seq 4035229078, ack 1645009947, win 509, options [nop,nop,TS val 4133407680 ecr 1914913420], length 0
11:09:40.221479 IP 192.168.1.220.59596 > 172.16.1.124.80: Flags [.], ack 4035229079, win 496, options [nop,nop,TS val 1914913430 ecr 4133407680], length 0

第一阶段:TCP 三次握手(建立连接)

第 1 行:客户端发起请求 (SYN)

11:09:40.190804 IP 192.168.1.220.59596 > 172.16.1.124.80: Flags [S], seq 1645009870, win 64240, options [...], length 0
  • 11:09:40.190804: 时间点 A。
  • 192.168.1.220.59596 > 172.16.1.124.80: 客户端 (220) 的随机端口 59596 发给服务器 (124) 的 80 端口。
  • Flags [S]: SYN。意思是“你好,我想建立连接”。
  • seq 1645009870: 初始序列号。这是客户端说的第一句话的编号。
  • length 0: 没有实际数据,只是打个招呼。

第 2 行:服务器同意并回应 (SYN-ACK)

11:09:40.190833 IP 172.16.1.124.80 > 192.168.1.220.59596: Flags [S.], seq 4035228215, ack 1645009871, win 65160, options [...], length 0
  • 11:09:40.190833: 时间点 B。
    • 计算: B – A = 29 微秒。服务器反应极快。
  • 172.16.1.124.80 > 192.168.1.220.59596: 服务器回给客户端。
  • Flags [S.]: SYN + ACK。意思是“收到你的请求了,我也同意建立连接”。
  • ack 1645009871: 确认号。注意它是 seq + 1。表示“我期待你下一个包的编号是 1645009871”。
  • length 0: 依然没有业务数据。

第 3 行:客户端最终确认 (ACK)

11:09:40.200955 IP 192.168.1.220.59596 > 172.16.1.124.80: Flags [.], ack 4035228216, win 502, options [...], length 0
  • 11:09:40.200955: 时间点 C。
    • 计算: C – B = 约 10ms。这通常是网络往返延迟。
  • Flags [.]: ACK。意思是“好的,连接建立了”。
  • ack 4035228216: 确认服务器的序列号 (4035228215 + 1)。
  • length 0: 纯确认包。
  • 此时,TCP 连接正式打通。

第二阶段:HTTP 业务交互(传输数据)

第 4 行:客户端发送 HTTP 请求 (PUSH)

11:09:40.200991 IP 192.168.1.220.59596 > 172.16.1.124.80: Flags [P.], seq 1645009871:1645009946, ack 4035228216, win 502, length 75: HTTP: GET / HTTP/1.1
  • 11:09:40.200991: 紧接着第 3 行,几乎同时发出。
  • Flags [P.]: PUSH + ACK。意思是“这里有重要数据,请立即处理,不要缓冲”。
  • length 75: 数据包里有 75 字节的真实内容。
  • HTTP: GET / HTTP/1.1: 关键信息! tcpdump 帮你解析出来了,这是一个 HTTP GET 请求,访问根路径 /。

第 5 行:服务器确认收到请求 (ACK)

11:09:40.201014 IP 172.16.1.124.80 > 192.168.1.220.59596: Flags [.], ack 1645009946, win 509, options [...], length 0
  • Flags [.]: 纯 ACK。
  • ack 1645009946: 确认收到了客户端发来的那 75 字节数据 (1645009871 + 75 = 1645009946)。
  • 含义: “请求我收到了,正在处理中…”

第 6 行:服务器返回 HTTP 响应 (PUSH)

11:09:40.201268 IP 172.16.1.124.80 > 192.168.1.220.59596: Flags [P.], seq 4035228216:4035229078, ack 1645009946, win 509, length 862: HTTP: HTTP/1.1 200 OK
  • 11:09:40.201268: 时间点 D。
    • 计算: D – (第4行时间) = 约 0.27ms。Nginx 处理速度极快。
  • Flags [P.]: 推送数据。
  • length 862: 返回了 862 字节的数据(HTML 内容)。
  • HTTP: HTTP/1.1 200 OK: 关键信息! 状态码 200,表示成功。

第 7 行:客户端确认收到响应 (ACK)

11:09:40.211256 IP 192.168.1.220.59596 > 172.16.1.124.80: Flags [.], ack 4035229078, win 496, options [...], length 0
  • Flags [.]: 纯 ACK。
  • 含义: “网页内容我收到了。”

第三阶段:TCP 四次挥手(断开连接)

第 8 行:客户端发起断开 (FIN)

11:09:40.211461 IP 192.168.1.220.59596 > 172.16.1.124.80: Flags [F.], seq 1645009946, ack 4035229078, win 496, options [...], length 0
  • Flags [F.]: FIN + ACK。意思是“我没话说了,我要挂电话了”。
  • 背景: HTTP/1.1 短连接模式下,客户端拿到数据后通常会主动关闭连接。

第 9 行:服务器同意断开 (FIN)

11:09:40.211498 IP 172.16.1.124.80 > 192.168.1.220.59596: Flags [F.], seq 4035229078, ack 1645009947, win 509, options [...], length 0
  • Flags [F.]: FIN + ACK。意思是“好的,我也挂了”。

第 10 行:客户端最后确认 (ACK)

11:09:40.221479 IP 192.168.1.220.59596 > 172.16.1.124.80: Flags [.], ack 4035229079, win 496, options [...], length 0
  • Flags [.]: 最后的 ACK。
  • 含义: 连接彻底销毁。资源释放。

判断方法

以后你运行 sudo tcpdump -i eth0 -nn -S host <IP> 后,只需要盯着这三个地方看:

  1. 看开头:有没有 [S] 和 [S.]?
    • 有 -> 网络通了。
    • 没有 -> 防火墙或服务挂了。
  2. 看中间:有没有 HTTP: ...?
    • 有 200 OK -> 业务正常。
    • 有 500/502/504 -> 后端代码或配置错了。
    • 只有 [P.] 但没有 HTTP 摘要 -> 可能是 HTTPS(加密了看不清)或者非 HTTP 协议。
  3. 看结尾:有没有 [F.]?
    • 有 -> 优雅关闭,一切正常。
    • 突然没了 -> 可能是网络中断或进程崩溃。

案例二:k8s 集群 Pod 因网段冲突导致部分客户端连接重置

故障现象:集群内某 Pod 服务在接收特定网段(172.16.x.x)客户端请求时,出现 curl: (56) Recv failure: Connection reset by peer 错误,而其他网段客户端访问正常。

用户提供的网络抓包结果:

正常返回的抓包结果 :
-------------------------------------------------------------------------------------
root@xxxx:/mnt/workspace# tcpdump -i any port 8000 -nn -vv
tcpdump: data link type LINUX_SLL2
tcpdump: listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
11:36:43.073824 eth0 In IP (tos 0x0, ttl 64, id 42158, offset 0, flags [DF], proto TCP (6), length 60)
172.17.255.172.37724 > 109.22.116.121.8000: Flags [S], cksum 0x05ec (correct), seq 2194617501, win 64240, options [mss 1460,sackOK,TS val 2439036523 ecr 0,nop,wscale 7], length 0
11:36:43.073841 eth0 Out IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
109.22.116.121.8000 > 172.17.255.172.37724: Flags [S.], cksum 0x8d7c (incorrect -> 0x6574), seq 519108248, ack 2194617502, win 65535, options [mss 1460,sackOK,TS val 1366701142 ecr 2439036523,nop,wscale 9], length 0
11:36:43.076287 eth0 In IP (tos 0x0, ttl 64, id 42159, offset 0, flags [DF], proto TCP (6), length 52)
172.17.255.172.37724 > 109.22.116.121.8000: Flags [.], cksum 0x9249 (correct), seq 1, ack 1, win 502, options [nop,nop,TS val 2439036526 ecr 1366701142], length 0
11:36:43.076316 eth0 In IP (tos 0x0, ttl 64, id 42160, offset 0, flags [DF], proto TCP (6), length 135)
172.17.255.172.37724 > 109.22.116.121.8000: Flags [P.], cksum 0x643e (correct), seq 1:84, ack 1, win 502, options [nop,nop,TS val 2439036526 ecr 1366701142], length 83
11:36:43.076320 eth0 Out IP (tos 0x0, ttl 64, id 51921, offset 0, flags [DF], proto TCP (6), length 52)
109.22.116.121.8000 > 172.17.255.172.37724: Flags [.], cksum 0x8d74 (incorrect -> 0x9369), seq 1, ack 84, win 128, options [nop,nop,TS val 1366701145 ecr 2439036526], length 0
11:36:43.077450 eth0 Out IP (tos 0x0, ttl 64, id 51922, offset 0, flags [DF], proto TCP (6), length 196)
109.22.116.121.8000 > 172.17.255.172.37724: Flags [P.], cksum 0x8e04 (incorrect -> 0x4091), seq 1:145, ack 84, win 128, options [nop,nop,TS val 1366701146 ecr 2439036526], length 144
11:36:43.079823 eth0 In IP (tos 0x0, ttl 64, id 42161, offset 0, flags [DF], proto TCP (6), length 52)
172.17.255.172.37724 > 109.22.116.121.8000: Flags [.], cksum 0x9160 (correct), seq 84, ack 145, win 501, options [nop,nop,TS val 2439036529 ecr 1366701146], length 0
11:36:43.079921 eth0 In IP (tos 0x0, ttl 64, id 42162, offset 0, flags [DF], proto TCP (6), length 52)
172.17.255.172.37724 > 109.22.116.121.8000: Flags [F.], cksum 0x915e (correct), seq 84, ack 145, win 501, options [nop,nop,TS val 2439036530 ecr 1366701146], length 0
11:36:43.079967 eth0 Out IP (tos 0x0, ttl 64, id 51923, offset 0, flags [DF], proto TCP (6), length 52)
109.22.116.121.8000 > 172.17.255.172.37724: Flags [F.], cksum 0x8d74 (incorrect -> 0x92d0), seq 145, ack 85, win 128, options [nop,nop,TS val 1366701148 ecr 2439036530], length 0
11:36:43.082341 eth0 In IP (tos 0x0, ttl 64, id 42163, offset 0, flags [DF], proto TCP (6), length 52)
172.17.255.172.37724 > 109.22.116.121.8000: Flags [.], cksum 0x9159 (correct), seq 85, ack 146, win 501, options [nop,nop,TS val 2439036532 ecr 1366701148], length 0

=====================================================================================

异常返回curl: (56) Recv failure: Connection reset by peer 的抓包结果:
-------------------------------------------------------------------------------------
root@xxxx:/mnt/workspace# tcpdump -i any port 8000 -nn -vv
tcpdump: data link type LINUX_SLL2
tcpdump: listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
11:38:08.840019 eth0 In IP (tos 0x0, ttl 64, id 45690, offset 0, flags [DF], proto TCP (6), length 60)
172.16.239.105.55812 > 109.22.116.121.8000: Flags [S], cksum 0xbc38 (correct), seq 3328610606, win 64240, options [mss 1460,sackOK,TS val 1628725726 ecr 0,nop,wscale 7], length 0
11:38:08.840036 veth1 Out IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
109.22.116.121.8000 > 172.16.239.105.55812: Flags [S.], cksum 0x7d38 (incorrect -> 0x33a9), seq 107218837, ack 3328610607, win 65535, options [mss 1460,sackOK,TS val 570315638 ecr 1628725726,nop,wscale 9], length 0
11:38:08.843471 eth0 In IP (tos 0x0, ttl 64, id 45691, offset 0, flags [DF], proto TCP (6), length 52)
172.16.239.105.55812 > 109.22.116.121.8000: Flags [.], cksum 0x607e (correct), seq 1, ack 1, win 502, options [nop,nop,TS val 1628725729 ecr 570315638], length 0
11:38:08.843508 eth0 In IP (tos 0x0, ttl 64, id 45692, offset 0, flags [DF], proto TCP (6), length 135)
172.16.239.105.55812 > 109.22.116.121.8000: Flags [P.], cksum 0x3273 (correct), seq 1:84, ack 1, win 502, options [nop,nop,TS val 1628725729 ecr 570315638], length 83
11:38:08.843512 veth1 Out IP (tos 0x0, ttl 64, id 23716, offset 0, flags [DF], proto TCP (6), length 52)
109.22.116.121.8000 > 172.16.239.105.55812: Flags [.], cksum 0x7d30 (incorrect -> 0x619d), seq 1, ack 84, win 128, options [nop,nop,TS val 570315642 ecr 1628725729], length 0
11:38:08.844396 veth1 Out IP (tos 0x0, ttl 64, id 23717, offset 0, flags [DF], proto TCP (6), length 196)
109.22.116.121.8000 > 172.16.239.105.55812: Flags [P.], cksum 0x7dc0 (incorrect -> 0x10bf), seq 1:145, ack 84, win 128, options [nop,nop,TS val 570315643 ecr 1628725729], length 144
11:38:08.847233 veth1 In IP (tos 0x0, ttl 63, id 0, offset 0, flags [DF], proto TCP (6), length 40)
172.16.239.105.55812 > 109.22.116.121.8000: Flags [R], cksum 0xe1a8 (correct), seq 3328610690, win 0, length 0
11:38:09.048616 eth0 In IP (tos 0x0, ttl 64, id 45693, offset 0, flags [DF], proto TCP (6), length 135)
172.16.239.105.55812 > 109.22.116.121.8000: Flags [P.], cksum 0x31a5 (correct), seq 1:84, ack 1, win 502, options [nop,nop,TS val 1628725935 ecr 570315638], length 83
11:38:09.048621 veth1 Out IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 40)
109.22.116.121.8000 > 172.16.239.105.55812: Flags [R], cksum 0x2b98 (correct), seq 107218838, win 0, length 0

分析过程

先简化这段日志,并进行初步分析:

案例一:正常客户端 (172.17.255.172)

特征:流量走物理网卡 eth0,握手、传输、关闭全过程完整。

11:36:43.073824 eth0 In  IP 172.17.255.172.37724 > 109.22.116.121.8000: Flags [S], ... length 0
11:36:43.073841 eth0 Out IP 109.22.116.121.8000 > 172.17.255.172.37724: Flags [S.], ... length 0
11:36:43.076287 eth0 In  IP 172.17.255.172.37724 > 109.22.116.121.8000: Flags [.], ack 1, ... length 0
11:36:43.076316 eth0 In  IP 172.17.255.172.37724 > 109.22.116.121.8000: Flags [P.], seq 1:84, ... length 83: HTTP: GET /
11:36:43.076320 eth0 Out IP 109.22.116.121.8000 > 172.17.255.172.37724: Flags [.], ack 84, ... length 0
11:36:43.077450 eth0 Out IP 109.22.116.121.8000 > 172.17.255.172.37724: Flags [P.], seq 1:145, ... length 144: HTTP: HTTP/1.1 200 OK
11:36:43.079823 eth0 In  IP 172.17.255.172.37724 > 109.22.116.121.8000: Flags [.], ack 145, ... length 0
11:36:43.079921 eth0 In  IP 172.17.255.172.37724 > 109.22.116.121.8000: Flags [F.], ... length 0
... (后续优雅关闭)

案例二:异常客户端 (172.16.239.105)

特征:流量被劫持至虚拟网卡 veth1,并在数据传输阶段出现 RST。

11:38:08.840019 eth0 In  IP 172.16.239.105.55812 > 109.22.116.121.8000: Flags [S], ... length 0
11:38:08.840036 veth1 Out IP 109.22.116.121.8000 > 172.16.239.105.55812: Flags [S.], ... length 0
11:38:08.843471 eth0 In  IP 172.16.239.105.55812 > 109.22.116.121.8000: Flags [.], ack 1, ... length 0
11:38:08.843508 eth0 In  IP 172.16.239.105.55812 > 109.22.116.121.8000: Flags [P.], seq 1:84, ... length 83: HTTP: GET /
11:38:08.843512 veth1 Out IP 109.22.116.121.8000 > 172.16.239.105.55812: Flags [.], ack 84, ... length 0
11:38:08.844396 veth1 Out IP 109.22.116.121.8000 > 172.16.239.105.55812: Flags [P.], seq 1:145, ... length 144: HTTP: HTTP/1.1 200 OK
11:38:08.847233 veth1 In  IP 172.16.239.105.55812 > 109.22.116.121.8000: Flags [R], ... length 0  <-- 关键异常点
11:38:09.048616 eth0 In  IP 172.16.239.105.55812 > 109.22.116.121.8000: Flags [P.], ... length 83 (重传)
11:38:09.048621 veth1 Out IP 109.22.116.121.8000 > 172.16.239.105.55812: Flags [R], ... length 0

第一步:对比“正常”与“异常”的抓包差异

步骤正常流程 (172.17.x.x)异常流程 (172.16.x.x)差异点分析
1. SYNClient -> Server [S]Client -> Server [S]一致,连接发起正常
2. SYN-ACKServer -> Client [S.] (via eth0)Server -> Client [S.] (via veth1)疑点1:回包网卡不同!正常走 eth0,异常走 veth1。
3. ACKClient -> Server [.]Client -> Server [.]一致,握手完成
4. Data ReqClient -> Server [P.] (HTTP GET)Client -> Server [P.] (HTTP GET)一致,请求已发出
5. Data RespServer -> Client [P.] (200 OK, via eth0)Server -> Client [P.] (200 OK, via veth1)疑点2:响应数据也走了 veth1。说明服务器确实处理了请求并回了包。
6. Close/ResetClient -> Server [F.] (优雅关闭)Client -> Server [R] (强制重置)核心故障点:客户端突然发送 RST。
7. Retry–Client -> Server [P.] (重传)
Server -> Client [R]
二次确认:服务器也回了 RST。

初步推断:

  1. 应用层没问题:服务器收到了请求,并且发出了 200 OK 响应(见异常日志第 6 行 length 144)。所以不是 后端服务挂了。
  2. 网络路径有问题:正常流量走 eth0(物理/主网卡),异常流量走 veth1(虚拟网卡/容器网卡)。
  3. 连接被强行切断:客户端在收到响应后(或同时)发送了 RST,导致连接中断。

第二步:深入分析“为什么走 veth1?”

这是解题的关键钥匙。为什么同一个服务器 IP (109.22.116.121),给不同客户端回包时,走的网卡不一样?

于是查看用户提供的路由表:

服务端执行 ip route show

default via 109.22.127.253 dev eth0 onlink       # 默认路由走 eth0
172.16.0.0/16 via 169.254.1.1 dev veth1 onlink   # ⚠️ 关键路由:172.16.0.0/16 走 veth1
169.254.1.1 dev veth1 scope link
  • 正常客户端 (172.17.255.172):
    • 源 IP 是 172.17.x.x。
    • 服务器回包时,目的 IP 是 172.17.255.172。
    • 查路由表:没有匹配 172.17.0.0/16 的特定路由,因此命中 default 路由。
    • 结果:数据包从 eth0 发出,经过正常的互联网/内网网关返回客户端。✅ 正常。
  • 异常客户端 (172.16.239.105):
    • 源 IP 是 172.16.239.105。
    • 服务器回包时,目的 IP 是 172.16.239.105。
    • 查路由表:匹配到了 172.16.0.0/16 via 169.254.1.1 dev veth1。
    • 结果:数据包被强制从 veth1 发出,发往网关 169.254.1.1。❌ 异常路径。

推论:
服务器认为 172.16.239.105 是一个“内部特殊网段”的地址,所以试图通过 veth1 这个虚拟接口把它送出去,而不是走正常的公网/内网网关 eth0。

关联:该路由由 ACK 集群的 Terway CNI 插件自动下发,用于处理集群内部 Service IP 的通信。

根因分析

  1. 路由劫持:当 DSW 服务器需要向客户端 172.16.239.105 回包时,内核查找路由表,匹配到更精确的 172.16.0.0/16 路由,而非默认路由。因此,数据包被强制发送至 veth1 接口,进入集群内部的 CNI 网络通道。
  2. 网段冲突:ACK 集群的 Service CIDR 配置为 172.16.0.0/16。而异常客户端的真实 IP 网段 172.16.239.0/24 恰好落在此范围内。
  3. CNI 丢弃/重置:
    • 数据包进入 Terway CNI 插件后,插件检查目标 IP 172.16.239.105。
    • 由于该 IP 并非集群内真实的 Pod IP 或 Service IP,CNI 插件无法找到对应的转发规则。
    • CNI 插件判定该目标不可达,遂丢弃数据包,并可能向源地址发送 ICMP 错误或触发 TCP 复位机制。
  4. 客户端行为:客户端内核收到网络层的错误反馈(如 ICMP Host Unreachable 或非法 TCP 状态),判定连接失效,主动发送 RST 包终止连接,导致上层应用报 Connection reset by peer。

问题处理后一些疑点解答:流量从 eth0 入,veth1 出还怎么三次握手?

Linux 路由是基于目的 IP 的,不分进出一致性。 进来可以走 eth0,出去可以走 veth1,只要路由表这么指,内核就这么干。握手阶段的包可能被“侥幸”送达。 在 ACK 集群的 Terway 模式下,veth1 连接的虚拟交换机通常具备将流量转发回 VPC 的能力。如果 CNI 插件在握手阶段没有做严格的“白名单校验”,SYN-ACK 包就能通过 VPC 网络绕回客户端。
真正的断裂点在“业务数据”阶段。 往往是因为 CNI 插件对长连接或数据包的校验更严格,如果它发现这个连接的目标 IP 不在其管理的 Pod/Service 列表中,它可能在数据传输阶段才判定为“非法连接”并丢弃后续包,或者因为 MTU、分片、状态跟踪等问题,导致大数据包(HTTP 响应)在 veth1 通道中被丢弃,而小包(SYN/ACK)却能通过。

形象比喻整个过程:

  • eth0 是大门,veth1 是通往“内部禁区”的侧门。
  • 客人(Client)从大门进来打招呼(SYN)。
  • 主人(Server)通过侧门(veth1)扔出一张名片(SYN-ACK)。因为侧门外面的走廊(VPC 网络)是连通的,客人捡到了名片。
  • 客人以为关系建立了,从大门递进来一份合同(HTTP GET)。
  • 主人处理完,想通过侧门把签好的合同扔出去。
  • 但是,侧门口的保安(CNI 插件)这次仔细看了收件人地址,发现:“这人不是我们小区的(非 Pod/Service IP)”,于是把合同撕了(DROP)。
  • 客人在外面等不到回音,生气地挂了电话(RST)。

发布者:LJH,转发请注明出处:https://www.ljh.cool/4999.html

赞 (0)
LJH的头像LJH
上一篇 2022年7月28日 下午7:48
下一篇 2022年8月23日 下午2:22

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注