从pcap文件中解析网络数据包

1:pcap文件格式

pcap文件主要包含了三个部分,pcap文件头,数据包头,数据包内容。在磁盘上的存储格式为

文件头 + 数据包头[0] + 数据包内容[0] + 数据包头[1] + 数据包内容[1] + … +数据包头[N] + 数据包内容[N]
在这里插入图片描述
每一部分包含的内容如下
在这里插入图片描述
Pcap文件头:保存着文件的读取方式,版本号等信息,解析数据包只需要关注magic字段。

  • Magic:4Bytes, pcap文件标识,用于识别文件并确定字节顺序。0xA1B2C3D4用来表示按照原来的顺序读取,0xD4C3B2A1表 示下面的字节都要交换顺序读取。一般会采用0xD4C3B2A1,即所有字节都需要交换顺序读取。
  • version_major: 2Bytes, 主版本号,一般为 0x0200【实际上因为交换读取顺序,所以计算机看到的应该是 0x0002】
  • version_minor: 2Bytes, 次版本号,一般为 0x0400【计算机看到的应该是 0x0004】
  • timezoon: 4Bytes, 当地的标准时间,如果用的是GMT则全零,一般都直接写 0000 0000
  • sigfigs: 4Bytes, 时间戳的精度,设置为全零即可
  • snaplen: 4Bytes, 最大的存储长度,如果想把整个包抓下来,设置为 ffff 0000,但一般来说 ff7f 0000就足够了【计算机看到的应该是 0000 ff7f 】
  • linktype: 4Bytes, 链路类型,一般为Ethernet 即0x1。

数据包头:pkt_hdr保存了数据包被捕获时候的时间戳和数据包长度。

  • tv_sec:时间戳秒字段
  • tv_usec:时间戳微妙字段
  • caplen:捕获的数据包的长度(保存在pcap文件中的长度)单位是 Byte。
  • len:离线数据长度:实际数据帧的长度,一般不大于caplen,多数情况下和Caplen数值相等。

数据内容: pkt_content里面保存着网络上捕获的原始数据帧。长度为数据包头里面的caplen长度。
[以太网帧格式] (https://www.cnblogs.com/lifan3a/articles/6649970.html)

2:从pcap文件中读取以太网数据包

1:读取pcap文件头(24 Bytes),从文件头magic字段中确定文件读取方式。

  • 如果为0xA1B2C3D4则按照正常顺序读取,如果为0xD4C3B2A1则按照交换顺序读取以读取文件头中的linktype字段为例,如果文件头第20-23字节为0x01 0x00 0x00 0x00,则0xA1B2C3D4正常顺序读取的结果为0x01000000(32 bit),0xD4C3B2A1交换顺序读取的结果为0x00000001
  • 交换顺序读取
    在这里插入图片描述
    D4 C3 B2 A1交换顺序读取linktype:把[0x01 0x00 0x00 0x00]解释为0x00 00 00 01(十进制:1)
  • 正常顺序读取
    在这里插入图片描述
    A1 B2 C3 D4正常顺序读取linktype: 把[0x00 0x00 0x00 0x01]解释为0x00 00 00 01(十进制:1)

2:读取一个数据包头(16 Bytes) header_0 ,确定紧接着这个数据包头后面的数据包内容content_0内容的长度caplen_0。

  • 数据包头里面第8-11字节为caplen字段,即数据包的长度。例如 ”0x42 0x05 0x00 0x00” 按照0xD4C3B2A1交换顺序读取的结果为caplen_0 = 1346,如果按照0xA1B2C3D4正常顺序存储那么 ”0x00 0x00 0x05 0x42” 才会被解析为caplen_0 = 1346。
  • 交换顺序读取
    在这里插入图片描述
    D4 C3 B2 A1交换顺序读取caplen: 将[0x42 0x05 0x00 0x00]为0x00 00 05 42(十进制:1346)
    D4 C3 B2 A1交换顺序读取len: 将[0x42 0x05 0x00 0x00]为0x00 00 05 42(十进制:1346)
  • 正常顺序读取
    在这里插入图片描述
    A1 B2 C3 D4正常顺序读取caplen: 将[0x00 0x00 0x05 0x42]为0x00 00 05 42(十进制:1346)
    A1 B2 C3 D4正常顺序读取len: 将[0x00 0x00 0x05 0x42]为0x00 00 05 42(十进制:1346)

3:读取数据包内容

第2步中已经解析出了header_0中的caplen,那么我们读取caplen个字节长度content_0, header_0描述的数据包内容即为content_0。

  • 例如header_0的caplen为1346,那么我们读取1346字节数据,这1346字节数据即为content_0的内容。

4:反复执行第2步和第3步,直到文件结束。

3:c语言代码实现

void test_pcap_file_read()
{
	unsigned char pcap_file_header[24] = { 0 };/*file header 24 bytes*/
	unsigned char pkt_hdr[16] = { 0 };/*pkt_hdr 16 bytes*/
	unsigned char udp_pkt_data[4096] = { 0 };/*content*/
	int len = 0;
	int pkt_cnt = 0;
	bool isLittleEndian = false;/*big endian*/

	FILE *pInFile = fopen("Test.pcap", "rb");/*open pcap file*/
	if (NULL == pInFile)
	{
		return;
	}
	if (1 != fread(pcap_file_header, 24, 1, pInFile))/*read pcap file header*/
	{
		fclose(pInFile);
	}
	/*交换顺序读取*/
	if ((0xD4 == pcap_file_header[0]) && (0xC3 == pcap_file_header[1]) && (0xB2 == pcap_file_header[2]) && (0xA1 == pcap_file_header[3]))
	{
		isLittleEndian = true;
	}

	while (1)
	{
		if (1 != fread(pkt_hdr, 16, 1, pInFile))/*read a pkt_hdr 16 bytes*/
		{
			break;
		}

		if (isLittleEndian)/*get the pktcontent's length in the file following the pkt_hdr*/
		{
			len = (int(pkt_hdr[11]) << 24) + int((pkt_hdr[10]) << 16) + int((pkt_hdr[9]) << 8) + int(pkt_hdr[8]);
		}
		else
		{
			len = (int(pkt_hdr[8]) << 24) + int((pkt_hdr[9]) << 16) + int((pkt_hdr[10]) << 8) + int(pkt_hdr[11]);
		}
		/*read the length bytes from file, this is the pktcontent*/
		if (1 != fread(udp_pkt_data, len, 1, pInFile))
		{
			break;
		}
		pkt_cnt++;
	}
	printf("Total %d packets found\n", pkt_cnt);
	fclose(pInFile);
}

4 参考链接:

pcap文件格式: https://blog.csdn.net/u013793399/article/details/51474831
pcap包文件头: https://blog.csdn.net/yhangleo/article/details/8484597

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值