您当前的位置:首页 > 计算机 > 编程开发 > Other

从PCAP简单提取HTTP数据

时间:04-02来源:作者:点击数:

为了追查现网的声音卡顿和噪音问题,做了一些抓包。但是我们协议当时还没有采用WebSocket,而且采用了双工的HTTP,想从里面提取音频不太容易,而且更主要的是还需要和包时间进行分析,分析卡顿问题。我的设想是提取TCP包内容,解析HTTP协议并提取音频数据,根据包时间和间隔,填充需要的静音数据进去,最终保存一个音频文件。

音频部分目前是PCM格式,而且也是很规律标准的320字节,不需要编解码,直接写文件即可。比较麻烦的是抓包文件,可以人工处理的是进行流过滤,单个流保存一个文件,这样稍微简单点。而且在协议解析部分,之前在项目中已经实现过HTTP协议的解析,剩余的就是从抓包文件里面提取时间和TCP数据了。

PCAP文件解析

PCAP文件可以用libpcap库进行解析,感觉其实也没这必要,根据pcap文件格式直接进行解析,并从中提取出帧头、IP头、TCP头和数据。

PCAP文件大致是由文件头和一帧帧数据包构成,文件头的C结构定义如下

typedef struct pcap_header
{
    uchar8_t   magic[4];
    uint16_t   version_major;
    uint16_t   version_minor;
    int32_t    thiszone;      /*时区修正*/
    uint32_t   sigfigs;       /*精确时间戳*/
    uint32_t   snaplen;       /*抓包最大长度*/
    uint32_t   linktype;      /*链路类型*/
} pcap_header_t;

其中,magic是文件起始,值依次为0xd40xc30xb20xa1,表明文件是PCAP文件,其他字段见说明。

提取了文件头之后,就可以循环提取数据包了,数据包头的C结构定义如下

typedef struct pcap_packet_header
{
    uint32_t   seconds;     /*秒数*/
    uint32_t   u_seconds;   /*毫秒数*/
    uint32_t   caplen;      /*数据包长度*/
    uint32_t   len;         /*文件数据包长度*/
} pcap_packet_header_t;

读取之后,后面len长度的数据就是包数据了,而且我们需要的时间也在这个头结构中。

TCP数据解析

数据和时间我们已经可以正常提取了,然后剩下的就是提取TCP数据,直接用帧报头结构、IP头结构、TCP头结构映射过去即可(C指针就是这么强大)。

typedef struct frame_header
{ 
    uint8_t DstMAC[6]; //目的MAC地址
    uint8_t SrcMAC[6]; //源MAC地址
    u_short FrameType; //帧类型
} frame_header_t;
typedef struct ip_header
{ 
    uint8_t Ver_HLen;       //版本+报头长度
    uint8_t TOS;            //服务类型
    uint16_t TotalLen;       //总长度
    uint16_t ID;            //标识
    uint16_t Flag_Segment;   //标志+片偏移
    uint8_t TTL;            //生存周期
    uint8_t Protocol;       //协议类型
    uint16_t Checksum;       //头部校验和
    uint32_t SrcIP;         //源IP地址
    uint32_t DstIP;         //目的IP地址
} ip_header_t;
typedef struct tcp_header
{ 
    uint16_t SrcPort; //源端口
    uint16_t DstPort; //目的端口
    uint32_t SeqNO; //序号
    uint32_t AckNO; //确认号
    uint8_t HeaderLen; //数据报头的长度(4 bit) + 保留(4 bit)
    uint8_t Flags; //标识TCP不同的控制消息
    uint16_t Window; //窗口大小
    uint16_t Checksum; //校验和
    uint16_t UrgentPointer;  //紧急指针
}tcp_header_t;

这里面在实践中发现了2个问题。

  • 帧头不对
  • TCP头长度可变

帧头不对的问题是这样的,在正常抓包后,解析帧头是标准的定义如上,但是某些抓包却不是这样的,后来仔细对比发现不对的地方在wireshark里面显示的是linux cooked capture意思大概就是由于抓包采用了any,某些包没有报头,只能统一伪造包头了,这个需要注意下,伪造报头大概是16个字节,此次不再展示定义了,具体的相关知识可以百度。

TCP头长度不对其实是开始的理解不对,在TCP的定义里面有个头长度,根据这个头长度解析即可,因为TCP头可能还有其他数据,上面的定义只是最基础的结构,还要根据某些值来判断后续数据,因此根据TCP头里面的长度跳过头才是正确的做法。另外长度这个长度字段只有4bit,不是简单取值即可,这个真实长度是需要进行再计算获取的,大概这么计算,具体细节自行百度

uint8_t len = pData->HeaderLen;
len = (len >> 4 ) * 4;

注意这里面超过一个字节的数字需要大小端转换,网络包都是大端字节序。

剩下的就是HTTP解析和音频补偿和保存了,可以采用项目现有代码实现。

结语

后面再回头看看,PCAP抓包文件格式还是挺简单的了,完全没有必要使用libpcap解析,而且自己解析还可以顺便了解下协议相关知识,也还是有好处的。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门