Transmission Control Protocol: https://en.wikipedia.org/wiki/Transmission_Control_Protocol
TCP 首部中 TCP Flags 位于第 14 个字节, 包含 8 个比特位。主要用作操控 TCP 状态机, 8 个比特位都表示特定功能, 分别为:
CWR & ECE: 用来配合做 congestion control,一般情况下和应用层关系不大。发送方的包 ECE 为 0 时,表示出现了 congestion。接收方回的包里 CWR 为 1 时,表示收到 congestion 信息并做了处理。
URG: 表示 TCP 包的紧急指针域有效。用来保证 TCP 连接不被中断,并且督促中间层设备要尽快处理这些数据。
ACK: 表示应答域有效。有两个取值 0 和 1,为 1 的时候表示应答域有效,反之为 0。
PSH: 表示 Push 操作。所谓 Push 操作就是指在数据包到达接收端以后,立即传送给应用程序, 而不是在缓冲区中排队。
RST: 表示连接复位请求。用来复位那些产生错误的连接,也被用来拒绝错误和非法的数据包。
SYN: 表示同步序号,用来建立连接。SYN 标志位和 ACK 标志位搭配使用,当连接请求的时候 SYN=1,ACK=0。连接被响应的时候 SYN=1,ACK=1。
FIN: 表示发送端已经达到数据末尾。也就是说双方的数据传送完成,没有数据可以传送了,发送 FIN 标志位的 TCP 数据包后,连接将被断开。
TCP Flags 用 RST 表示复位,用来表示异常关闭连接。发送 RST 包关闭连接时,不必等缓冲区的包都发出去,直接就丢弃缓存区的包发送 RST 包。而接收端收到 RST 包后,也不必发送 ACK 包来确认。主要有以下四种情况可能导致 RST:
排查请求异常断连, 应用日志显示为 Read ECONNRESET 其实日志内容已经告诉了问题原因, ECONNRESET 即收到了 TCP RST 报文。
Error: read ECONNRESET at TCP.onStreamRead (internal/stream_base_commons.js:200:27) {
errno: 'ECONNRESET',
code: 'ECONNRESET',
syscall: 'read',
name: 'ResponseError',
data: undefined,
path: '/mgw.htm',
status: -1,
headers: {},
res: {
status: -1,
statusCode: -1,
statusMessage: null,
headers: {},
size: 0,
aborted: false,
rt: 90360,
keepAliveSocket: false,
data: undefined,
requestUrls: [ 'http://google.com' ],
timing: null,
remoteAddress: '108.177.8.139',
remotePort: 80,
socketHandledRequests: 1,
socketHandledResponses: 0
}
}
登陆 CentOS or Fedora 服务器安装 tcpdump,正常情况 Linux & macOS 默认安装。
sudo yum install tcpdump
服务器内用 tcpdump 抓包, 数据倒入 out.pcap 文件内。
tcpdump -i any -w out.pcap
或者根据 IP 进行抓包。
tcpdump -i any host 8.8.8.8 -w out.pcap
out.pcap 文件导出, 权限限制情况下 scp 不可取。所以用 OSS 当媒介上传, 安装阿里云 OSS Client。
wget http://gosspublic.alicdn.com/ossutil/1.6.18/ossutil64
chmod 755 ossutil64
生成 OSS 相关配置文件。
./ossutil64 config -e oss-ap-southeast-1.aliyuncs.com -i ak-id -k ak-secret -L CH -c ./myconfig
上传 .pcap 文件至 OSS。
./ossutil64 cp out.pcap oss://oss-ap-southeast-1.aliyuncs.com/out.pcap --config-file ./myconfig
out.pcap 在 Wireshark 中打开进行分析。
通过 tcp.flags.reset == 1 过滤出 RST 异常数据包。
根据 IP 以及 Port 端口号 ip.src eq 121.0.26.95 or ip.dst eq 121.0.26.95 and tcp.port == 49688 过滤出,整体 TCP 传输报文。
数据报文进行分析, 首先进行 TCP 三次握手。
报文解析客户端到服务端数据报文, 2047 为帧号。
2048 帧,服务端的返回报文,每个报文都有对应的响应报文。
2057 帧后客户端 3s 没有返回,服务端超时,发送 RST 报文中止了链接。
原因为服务端发送 RST 报文中止请求导致。正常情况下中止是通过服务端发送 FIN 四次挥手结束的。
Written on December 23rd , 2018 by Gaius