解析pcap文件及讀取實現源碼


轉自:http://imzc.net/archives/181/%E8%A7%A3%E6%9E%90pcap%E6%96%87%E4%BB%B6%E5%8F%8A%E6%BA%90%E7%A0%81/

下面pcap文件格式介紹是在網上轉的,根據理解,寫了個程序來進行解析pcap文件,后續再實現合並pcap功能(wireshark已經自帶命令行合並pcap文件工具,在這里只是為了分析pcap文件和學習)。
==========================
默認的*.pcap文件保存格式。

Pcap文件頭24B各字段說明:

Magic:4B:0x1A 2B 3C 4D:用來標示文件的開始
Major:2B,0×02 00:當前文件主要的版本號
Minor:2B,0×04 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
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
Timestamp:時間戳低位,精確到microseconds
Caplen:當前數據區的長度,即抓取到的數據幀長度,由此可以得到下一個數據幀的位置。
Len:離線數據長度 網絡中實際數據幀的長度,一般不大於caplen,多數情況下和Caplen數值相等。
Packet  數據: 即 Packet(通常就是鏈路層的數據幀)具體內容,長度就是Caplen,這個長度的后面,就是當前PCAP文件中存放的下一個Packet數據包,也就 是說:PCAP文件里面並沒有規定捕獲的Packet數據包之間有什么間隔字符串,下一組數據在文件中的起始位置。我們需要靠第一個Packet包確定。 最后,Packet數據部分的格式其實就是標准的網路協議格式了可以任何網絡教材上找得到。
===========================
我的實現:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//
//  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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//
//  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");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//
//  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:

1
2
3
4
5
6
7
8
9
10
11
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)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM