2、网络流量基础:TCP/IP协议栈回顾、数据包结构、PCAP文件格式解析

好,咱们正式开始第二讲。说实话,很多搞安全的朋友,一上来就急着分析攻击流量,结果连数据包长什么样都说不清楚。我个人习惯是,先把地基打牢。这一章,我们就来聊聊网络流量的那些“底层逻辑”。

2.1 TCP/IP协议栈:别把它想得太复杂

TCP/IP协议栈,说白了就是一套“网络通信的规矩”。你想想看,两台电脑要说话,总得有个统一的语言吧?这个协议栈就是那个语言。

它分四层,我习惯从上往下记:

  • 应用层:你直接用的软件,比如浏览器(HTTP)、邮件客户端(SMTP)、(自定义协议)。这一层只管“我要发什么内容”。
  • 传输层:负责“怎么可靠地发”。TCP保证不丢包,UDP只管快。我在项目中遇到过,有人用UDP传重要数据,结果丢包了还不知道,排查了半天。
  • 网络层:负责“路怎么走”。IP协议在这里,它决定数据包从你的电脑到服务器,中间要经过哪些路由器。
  • 网络接口层:负责“物理上怎么传”。比如网线、Wi-Fi信号,还有MAC地址。
我的小技巧: 分析异常流量时,我通常先看传输层。因为大部分攻击(比如SYN Flood、端口扫描)都藏在这一层。应用层的内容可能被加密,但传输层的“行为特征”是藏不住的。

2.2 数据包结构:拆开来看,其实很简单

一个网络数据包,就像一封信。信封上写着地址(IP头),里面还有一层信封写着怎么确认收到(TCP头),最里面才是信纸(数据)。

咱们重点看两个最常用的头:IP头和TCP头。

2.2.1 IP头(网络层)

IP头里最重要的几个字段,我列个表给你看:

字段 长度(位) 说明
版本号 4 IPv4还是IPv6。现在大部分还是IPv4。
源IP地址 32 谁发的。比如192.168.1.100
目的IP地址 32 发给谁。比如8.8.8.8
协议号 8 上层是什么协议。6代表TCP,17代表UDP。
生存时间(TTL) 8 防止数据包在网络里无限循环。每过一个路由器减1,减到0就丢弃。

嗯,这里要注意:TTL值在异常流量分析里很有用。我曾经遇到过一种攻击,攻击者伪造源IP,但TTL值没改好,一看就知道是假的。因为正常Windows发的包TTL是128,Linux是64,攻击者伪造的包TTL是255,明显不对劲。

2.2.2 TCP头(传输层)

TCP头更关键,因为大部分攻击都跟它有关。核心字段如下:

字段 长度(位) 说明
源端口 16 发起方的端口,比如浏览器随机分配一个高位端口。
目的端口 16 目标服务的端口,比如HTTP是80,HTTPS是443。
序列号(SEQ) 32 保证数据顺序。第一次握手时随机生成。
确认号(ACK) 32 告诉对方“我收到你的数据了,下一个该发这个序号”。
标志位 9 最常用的:SYN(发起连接)、ACK(确认)、FIN(结束)、RST(重置)。
避坑指南: 我曾经在分析一个DDoS攻击时,发现攻击流量里全是SYN包,但没有ACK包。这就是典型的SYN Flood攻击——只握手不完成,把服务器的连接队列塞满。你只要看到大量SYN包没有对应的SYN-ACK,基本可以断定是攻击。

2.3 PCAP文件格式解析:你每天都在用的东西

做流量分析,离不开PCAP文件。Wireshark、tcpdump抓下来的包,默认就是PCAP格式。说白了,它就是一个“数据包的容器”,把抓到的每个包按顺序存起来。

PCAP文件的整体结构,我画个图给你描述一下:

+-------------------+
|  全局文件头 (24字节)  |
+-------------------+
|  数据包1头 (16字节)  |
|  数据包1数据         |
+-------------------+
|  数据包2头 (16字节)  |
|  数据包2数据         |
+-------------------+
|  ...               |
+-------------------+

全局文件头只有24字节,但信息量很大。我挑几个重要的说:

  • Magic Number(4字节):固定为0xA1B2C3D4。如果字节序反了,就是0xD4C3B2A1。这用来判断文件是大端还是小端。
  • Major Version / Minor Version(各2字节):版本号,目前主流是2.4。
  • Timezone(4字节):时区偏移。说实话,这个字段在实际中经常不准,我一般忽略它。
  • Snaplen(4字节):每个包最大抓取长度。比如设为65535,就是抓完整包;设为96,就只抓前96字节。
  • Link Type(4字节):链路层类型。1代表以太网,最常见的。如果是Linux的loopback接口,值是0。

每个数据包的头是16字节,记录了这个包的基本信息:

struct pcap_pkthdr {
    struct timeval ts;  // 时间戳,8字节(秒+微秒)
    bpf_u_int32 caplen; // 实际抓取的长度(4字节)
    bpf_u_int32 len;    // 原始包的长度(4字节)
};

这里有个坑:caplen和len可能不一样。如果Snaplen设得小,caplen就是Snaplen的值,但len是原始包的真实长度。我在写解析工具时,曾经忘了处理这个差异,结果读出来的数据全是截断的,排查了半天才发现。

警告: 不要直接拿文本编辑器打开PCAP文件!里面全是二进制数据,你会看到一堆乱码。用Wireshark或者编程解析才是正道。我见过有人用记事本打开PCAP,然后问我“为什么全是乱码”——嗯,这是个经典笑话。

2.4 实战:用Python解析PCAP文件

光说不练假把式。咱们写几行Python代码,手动解析一个PCAP文件。这样你就能真正理解它的结构了。

import struct

def parse_pcap(filepath):
    with open(filepath, 'rb') as f:
        # 读取全局文件头
        magic = struct.unpack('<I', f.read(4))[0]
        if magic == 0xA1B2C3D4:
            print("字节序:大端")
        elif magic == 0xD4C3B2A1:
            print("字节序:小端")
        else:
            print("不是合法的PCAP文件")
            return
        
        # 跳过其他全局头字段
        f.read(20)  # 版本、时区、snaplen、链路类型
        
        packet_count = 0
        while True:
            # 读取数据包头
            header_data = f.read(16)
            if len(header_data) < 16:
                break  # 文件结束
            
            # 解析时间戳和长度
            ts_sec, ts_usec, caplen, orig_len = struct.unpack('<IIII', header_data)
            print(f"包 {packet_count}: 时间={ts_sec}.{ts_usec:06d}, "
                  f"抓取长度={caplen}, 原始长度={orig_len}")
            
            # 跳过数据部分(这里不解析具体内容)
            f.read(caplen)
            packet_count += 1
        
        print(f"共解析 {packet_count} 个数据包")

# 使用示例
# parse_pcap('example.pcap')

这段代码虽然简单,但能让你看到PCAP文件的“骨架”。你想想看,Wireshark那么强大的工具,底层也就是这样一层层解析的。只不过它把每个字段都展示出来了。

我的建议: 刚开始学的时候,别急着用现成的库(比如scapy)。自己手写一遍解析代码,哪怕只解析IP头和TCP头,你对数据包的理解会深很多。我当年就是这么过来的,现在看任何PCAP文件,脑子里都能自动“拆包”。

2.5 本章小结

这一章我们干了三件事:

  1. 回顾了TCP/IP四层模型,重点放在传输层和网络层。
  2. 拆解了IP头和TCP头的关键字段,特别是那些跟攻击检测相关的(TTL、标志位)。
  3. 解析了PCAP文件格式,从全局头到数据包头,最后用Python代码验证了理解。

下一章,我们会正式进入异常流量分析的核心——如何用机器学习模型识别攻击。但请记住,没有今天这些基础,后面的模型再厉害也是空中楼阁。嗯,先把地基打牢,咱们慢慢来。