轉自: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
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) |