2. 分析TCP三次握手建立连接过程

任务目标

通过抓取TCP建立连接过程中的三个报文段(SYN、SYN-ACK、ACK),分析其TCP标志位、序号(SEQ)与确认号(ACK)的数值关系,并结合Wireshark的专家信息或状态统计,验证TCP三次握手的状态转换逻辑。

环境准备

  • Wireshark 4.x(或3.6+)
  • 本机回环接口(lo)或任意可用网卡
  • Python 3.8+(仅用于启动本地TCP服务,便于抓包)

抓包步骤

  1. 启动Wireshark,选择回环接口(lo)开始抓包。
  2. 在终端启动一个简单的TCP服务:python3 -m http.server 8080。
  3. 另开终端执行:curl http://127.0.0.1:8080/,随后立即停止Wireshark抓包。
  4. 在Wireshark过滤栏输入 tcp.port==8080,即可看到完整的握手报文。

关键代码:TCP三次握手状态验证脚本

以下Python脚本使用scapy库读取抓包文件(pcap/pcapng),自动提取三次握手的前三个TCP报文段,并输出标志位、序号、确认号及状态转换推断。若未安装scapy,先执行 pip install scapy。

from scapy.all import rdpcap, TCP, IP

def analyze_handshake(pcap_file):
    packets = rdpcap(pcap_file)
    handshake = []
    for pkt in packets:
        if TCP in pkt and pkt[TCP].dport == 8080 or (TCP in pkt and pkt[TCP].sport == 8080):
            flags = pkt[TCP].flags
            # 仅保留SYN、SYN-ACK、ACK(不含PSH等后续数据包)
            if flags & 0x02 or (flags & 0x10 and not flags & 0x02):
                handshake.append(pkt)
            if len(handshake) == 3:
                break

    if len(handshake) < 3:
        print("未捕获完整三次握手,请检查过滤条件")
        return

    # 报文1: SYN
    p1 = handshake[0]
    print(f"[1] {p1[IP].src}:{p1[TCP].sport} -> {p1[IP].dst}:{p1[TCP].dport}")
    print(f"    标志位: SYN={bool(p1[TCP].flags & 0x02)}, ACK={bool(p1[TCP].flags & 0x10)}")
    print(f"    SEQ={p1[TCP].seq}, ACK_num={p1[TCP].ack}")

    # 报文2: SYN-ACK
    p2 = handshake[1]
    print(f"[2] {p2[IP].src}:{p2[TCP].sport} -> {p2[IP].dst}:{p2[TCP].dport}")
    print(f"    标志位: SYN={bool(p2[TCP].flags & 0x02)}, ACK={bool(p2[TCP].flags & 0x10)}")
    print(f"    SEQ={p2[TCP].seq}, ACK_num={p2[TCP].ack}")

    # 报文3: ACK
    p3 = handshake[2]
    print(f"[3] {p3[IP].src}:{p3[TCP].sport} -> {p3[IP].dst}:{p3[TCP].dport}")
    print(f"    标志位: SYN={bool(p3[TCP].flags & 0x02)}, ACK={bool(p3[TCP].flags & 0x10)}")
    print(f"    SEQ={p3[TCP].seq}, ACK_num={p3[TCP].ack}")

    # 状态转换验证
    print("\n--- 状态转换验证 ---")
    print(f"客户端发送SYN后进入 SYN_SENT")
    print(f"服务端收到SYN,回复SYN-ACK后进入 SYN_RCVD")
    print(f"客户端收到SYN-ACK,发送ACK后进入 ESTABLISHED")
    print(f"服务端收到ACK后也进入 ESTABLISHED")

if __name__ == "__main__":
    import sys
    if len(sys.argv) != 2:
        print("用法: python3 analyze_handshake.py <抓包文件.pcap>")
    else:
        analyze_handshake(sys.argv[1])

运行与验证

  1. 将Wireshark保存的抓包文件(如 handshake.pcap)置于脚本同目录。
  2. 执行:python3 analyze_handshake.py handshake.pcap
  3. 观察输出,判定通过条件如下:
  • 报文1:仅SYN=1,ACK=0,SEQ为客户端初始序号(记为x),ACK_num=0。
  • 报文2:SYN=1且ACK=1,SEQ为服务端初始序号(记为y),ACK_num=x+1。
  • 报文3:SYN=0,ACK=1,SEQ=x+1,ACK_num=y+1。

若输出满足上述数值关系,则说明三次握手标志位与序号确认号逻辑正确,状态转换过程与TCP协议规范一致。

常见问题

  • 抓不到包:确认使用回环接口,且curl命令在抓包启动后执行。
  • 脚本输出不足3个报文:过滤条件可能混入了HTTP请求数据包,可手动在Wireshark中右键第一个SYN包,选择“追踪TCP流”,确认流的前三个报文即为握手包。
  • SEQ不是从0开始:现代操作系统启用随机初始序号(ISN),属正常现象,只需验证相对值(如ACK_num = SEQ+1)即可。
客户端 服务端 CLOSED ↓ SYN_SENT LISTEN ↓ SYN_RCVD ① SYN=1, ACK=0 SEQ=x, ACK_num=0 ② SYN=1, ACK=1 SEQ=y, ACK_num=x+1 ③ SYN=0, ACK=1 SEQ=x+1, ACK_num=y+1 ESTABLISHED ESTABLISHED