解析pcap文件及读取实现源码

 

pcap文件的格式为:

  文件头    24字节
  数据报头 + 数据报  数据包头为16字节,后面紧跟数据报
  数据报头 + 数据报  ......
pcap.h里定义了文件头的格式
struct pcap_file_header {
        bpf_u_int32 magic;
        u_short version_major;
        u_short version_minor;
        bpf_int32 thiszone;    
        bpf_u_int32 sigfigs;   
        bpf_u_int32 snaplen;   
        bpf_u_int32 linktype;  
};

Pcap文件头24B各字段说明:

Magic:4B:0×1A 2B 3C 4D:用来识别文件自己和字节顺序。0xa1b2c3d4用来表示按照原来的顺序读取,0xd4c3b2a1表示下面的字节都要交换顺序读取。一般,我们使用0xa1b2c3d4
Major:2B,0×02 00:当前文件主要的版本号
Minor:2B,0×04 00当前文件次要的版本号
ThisZone:4B 时区。GMT和本地时间的相差,用秒来表示。如果本地的时区是GMT,那么这个值就设置为0.这个值一般也设置为0 SigFigs:4B时间戳的精度;全零
SnapLen:4B最大的存储长度(该值设置所抓获的数据包的最大长度,如果所有数据包都要抓获,将该值设置为65535; 例如:想获取数据包的前64字节,可将该值设置为64)
LinkType:4B链路类型
常用类型:
0           BSD loopback devices, except for later OpenBSD
1            Ethernet, and Linux loopback devices
6            802.5 Token Ring
7            ARCnet
8            SLIP
9            PPP
10           FDDI
100         LLC/SNAP-encapsulated ATM
101         “raw IP”, with no link
102         BSD/OS SLIP
103         BSD/OS PPP
104         Cisco HDLC
105         802.11
108         later OpenBSD loopback devices (with the AF_value in network byte order)
113         special Linux “cooked” capture
114         LocalTalk


Packet 包头和Packet数据组成
字段说明:
Timestamp:时间戳高位,精确到seconds(值是自从January 1, 1970 00:00:00 GMT以来的秒数来记)
Timestamp:时间戳低位,精确到microseconds (数据包被捕获时候的微秒(microseconds)数,是自ts-sec的偏移量)
Caplen:当前数据区的长度,即抓取到的数据帧长度,由此可以得到下一个数据帧的位置。
Len:离线数据长度 网络中实际数据帧的长度,一般不大于caplen,多数情况下和Caplen数值相等。
(例如,实际上有一个包长度是1500 bytes(L en=1500),但是因为在Global Header的 snaplen=1300有限制,所以只能抓取这个包的前1300个字节,这个时候, Caplen = 1300 )
Packet 数据:即 Packet(通常就是链路层的数据帧)具体内容,长度就是Caplen,这个长度的后面,就是当前PCAP文件中存放的下一个Packet数据包,也就 是说:PCAP文件里面并没有规定捕获的Packet数据包之间有什么间隔字符串,下一组数据在文件中的起始位置。我们需要靠第一个Packet包确定。 最后,Packet数据部分的格式其实就是标准的网路协议格式了可以任何网络教材上找得到。



//
//  pcap.h
//  pcaptest
//
//  Created by zc on 12-1-24.
//  Copyright 2012年 __MyCompanyName__. All rights reserved.
//
 
#ifndef pcaptest_pcap_h
#define pcaptest_pcap_h
 
typedef unsigned int  bpf_u_int32;
typedef unsigned short  u_short;
typedef int bpf_int32;
 
/*
 Pcap文件头24B各字段说明:
 Magic:4B:0x1A 2B 3C 4D:用来标示文件的开始
 Major:2B,0x02 00:当前文件主要的版本号     
 Minor:2B,0x04 00当前文件次要的版本号
 ThisZone:4B当地的标准时间;全零
 SigFigs:4B时间戳的精度;全零
 SnapLen:4B最大的存储长度    
 LinkType:4B链路类型
 常用类型:
  0            BSD loopback devices, except for later OpenBSD
 1            Ethernet, and Linux loopback devices
 6            802.5 Token Ring
 7            ARCnet
 8            SLIP
 9            PPP
 */
typedef struct pcap_file_header {
	bpf_u_int32 magic;
	u_short version_major;
	u_short version_minor;
	bpf_int32 thiszone;    
	bpf_u_int32 sigfigs;   
	bpf_u_int32 snaplen;   
	bpf_u_int32 linktype;  
}pcap_file_header;
 
/*
 Packet 包头和Packet数据组成
 字段说明:
 Timestamp:时间戳高位,精确到seconds     
 Timestamp:时间戳低位,精确到microseconds
 Caplen:当前数据区的长度,即抓取到的数据帧长度,由此可以得到下一个数据帧的位置。
 Len:离线数据长度:网络中实际数据帧的长度,一般不大于caplen,多数情况下和Caplen数值相等。
 Packet 数据:即 Packet(通常就是链路层的数据帧)具体内容,长度就是Caplen,这个长度的后面,就是当前PCAP文件中存放的下一个Packet数据包,也就 是说:PCAP文件里面并没有规定捕获的Packet数据包之间有什么间隔字符串,下一组数据在文件中的起始位置。我们需要靠第一个Packet包确定。
 */
 
typedef struct  timestamp{
	bpf_u_int32 timestamp_s;
	bpf_u_int32 timestamp_ms;
}timestamp;
 
typedef struct pcap_header{
	timestamp ts;
	bpf_u_int32 capture_len;
	bpf_u_int32 len;
 
}pcap_header;
 
 
void prinfPcapFileHeader(pcap_file_header *pfh);
void printfPcapHeader(pcap_header *ph);
void printPcap(void * data,size_t size);
 
#endif



//
//  pcap.c
//  pcaptest
//
//  Created by zc on 12-1-24.
//  Copyright 2012年 __MyCompanyName__. All rights reserved.
//
 
#include <stdio.h>
#include "pcap.h"
 
void prinfPcapFileHeader(pcap_file_header *pfh){
	if (pfh==NULL) {
		return;
	}
	printf("=====================\n"
		   "magic:0x%0x\n"
		   "version_major:%u\n"
		   "version_minor:%u\n"
		   "thiszone:%d\n"
		   "sigfigs:%u\n"
		   "snaplen:%u\n"
		   "linktype:%u\n"
		   "=====================\n",
		   pfh->magic,
		   pfh->version_major,
		   pfh->version_minor,
		   pfh->thiszone,
		   pfh->sigfigs,
		   pfh->snaplen,
		   pfh->linktype);
}
 
void printfPcapHeader(pcap_header *ph){
	if (ph==NULL) {
		return;
	}
	printf("=====================\n"
		   "ts.timestamp_s:%u\n"
		   "ts.timestamp_ms:%u\n"
		   "capture_len:%u\n"
		   "len:%d\n"
		   "=====================\n",
		   ph->ts.timestamp_s,
		   ph->ts.timestamp_ms,
		   ph->capture_len,
		   ph->len);
 
 
}
 
void printPcap(void * data,size_t size){
	unsigned  short iPos = 0;
	//int * p = (int *)data;
	//unsigned short* p = (unsigned short *)data;
	if (data==NULL) {
		return;
	}
 
	printf("\n==data:0x%x,len:%lu=========",data,size);
 
	for (iPos=0; iPos < size/sizeof(unsigned short); iPos++) {
		//printf(" %x ",(int)( * (p+iPos) ));
		//unsigned short a = ntohs(p[iPos]);
 
		unsigned short a = ntohs( *((unsigned short *)data + iPos ) );
		if (iPos%8==0) printf("\n");
		if (iPos%4==0) printf(" ");
 
		printf("%04x",a);
 
 
	}
	/*
	 for (iPos=0; iPos <= size/sizeof(int); iPos++) {
		//printf(" %x ",(int)( * (p+iPos) ));
		int a = ntohl(p[iPos]);
 
		//int a = ntohl( *((int *)data + iPos ) );
		if (iPos %4==0) printf("\n");
 
		printf("%08x ",a);
 
 
	}
	 */
	printf("\n============\n");
}



//
//  main.c
//  pcaptest
//
//  Created by zc on 12-1-24.
//  Copyright 2012年 __MyCompanyName__. All rights reserved.
//
 
#include <stdio.h>
#include <arpa/inet.h>
#include "pcap.h"
 
#define PCAP_FILE "ping.pcap"
#define MAX_ETH_FRAME 1514
#define ERROR_FILE_OPEN_FAILED -1
#define ERROR_MEM_ALLOC_FAILED -2
#define ERROR_PCAP_PARSE_FAILED -3
 
 
int main (int argc, const char * argv[])
{
 
	printf("sizeof:int %lu,unsigned int %lu,char %lu,unsigned char %lu,short:%lu,unsigned short:%lu\n",
		    sizeof(int),sizeof(unsigned int),sizeof(char),sizeof(unsigned char),sizeof(short),sizeof(unsigned short));
 
	pcap_file_header  pfh;
	pcap_header  ph;
	int count=0;
	void * buff = NULL;
	int readSize=0;
	int ret = 0;
 
	FILE *fp = fopen(PCAP_FILE, "rw");
 
	if (fp==NULL) {
		fprintf(stderr, "Open file %s error.",PCAP_FILE);
		ret = ERROR_FILE_OPEN_FAILED;
		goto ERROR;
	}
 
	fread(&pfh, sizeof(pcap_file_header), 1, fp);	
	prinfPcapFileHeader(&pfh);
	//fseek(fp, 0, sizeof(pcap_file_header));
 
	buff = (void *)malloc(MAX_ETH_FRAME);
	for (count=1; ; count++) {
		memset(buff,0,MAX_ETH_FRAME);
		//read pcap header to get a packet
		//get only a pcap head count .
		readSize=fread(&ph, sizeof(pcap_header), 1, fp);
		if (readSize<=0) {
			break;
		}
		printfPcapHeader(&ph);
 
 
		if (buff==NULL) {
			fprintf(stderr, "malloc memory failed.\n");
			ret = ERROR_MEM_ALLOC_FAILED;
			goto ERROR;
		}
 
		//get a packet contents.
		//read ph.capture_len bytes.
		readSize=fread(buff,1,ph.capture_len, fp);
		if (readSize != ph.capture_len) {
			free(buff);
			fprintf(stderr, "pcap file parse error.\n");
			ret = ERROR_PCAP_PARSE_FAILED;
			goto ERROR;
		}
		printPcap(buff, ph.capture_len);
 
 
		printf("===count:%d,readSize:%d===\n",count,readSize);
 
		if (feof(fp) || readSize <=0 ) { 
			break;
		}
	}
 
ERROR:
	//free
	if (buff) {
		free(buff);
		buff=NULL;
	} 
	if (fp) {
		fclose(fp);
		fp=NULL;
	}	
 
    return ret;
}



Makefile


objects = main.o pcap.o
 
pcaptest : $(objects)
	gcc -o pcaptest  $(objects)
 
main.o:pcap.h
pcap.o:pcap.h
 
.PHONY : clean
clean :
	rm pcaptest  $(objects)


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值