2012-02-14 57 views
1

我想解析C中的pcap文件。我不想使用libpcap。但由於某種原因,我無法。你知道我該怎麼做?這裏是我的嘗試:代碼中的一些錯誤 - libpcap

fseek(f,24,0); 
while(count<20)//reading 20 packets 
{ 
    fread(header,sizeof(struct pcap_pkthdr),1,f); 
    //after this I'm printing values header fields 
    fseek(f,ntohl(header->caplen),1); 
    count++; 
} 

輸出與libpcap不一樣。

回答

4

struct pcap_pkthdr不是定義pcap文件中包頭格式的結構;它是定義使用libpcap或WinPcap提供給程序的包頭格式的結構。

限定在PCAP文件分組報頭的格式的結構是NOT中任PCAP的包括文件,因爲libpcap的/ WinPcap的規定,讀取這些標頭的例程,並將它們轉換爲必要pcap_pkthdr頭。與struct pcap_pkthdr不同,在pcap文件中,數據包標頭中的時間戳總是具有32位「秒」字段和32位「微秒」字段,即使在time_tstruct timeval中的tv_sec值爲64位的系統上也是如此。

即,結構是由

struct pcap_timeval { 
    bpf_int32 tv_sec;   /* seconds */ 
    bpf_int32 tv_usec;   /* microseconds */ 
}; 


struct pcap_sf_pkthdr { 
    struct pcap_timeval ts;  /* time stamp */ 
    bpf_u_int32 caplen;   /* length of portion present */ 
    bpf_u_int32 len;   /* length this packet (off wire) */ 
}; 

struct pcap_sf_pkthdr其中是該文件中的結構中定義。

還要注意的是,如果你從文件中讀取一個struct pcap_sf_pkthdr,你將不得不字節交換ts.tv_sects.tv_useccaplenlenIF寫入文件的機器,其字節順序從機器上不同的你正在閱讀文件。簡單的ntohl()不是工作 - 例如,如果您的文件被寫入與您正在讀取它的同一臺機器上,則不需要進行字節交換。

ONLY方式,使這項工作將文件頭,而不是僅僅跳過它fseek()。如果文件頭中的「幻數」的值爲0xa1b2c3d4,則不需要進行任何字節交換;如果它的值爲0xd4c3b2a1,則需要對文件頭和struct pcap_sf_pkthdr中的值進行字節交換。請注意,ntohl()htonl()不是字節交換,如果您運行在一個大型機器上,如PowerPC/Power架構機器或MIPS機器或IBM大型機或....

請注意,並非所有的捕獲文件都將是pcap文件;如果他們是pcap-NG文件,他們必須以完全不同的方式閱讀。 Libpcap 1.1和更高版本知道如何讀取pcap-NG文件(libpcap/WinPcap API功能不足以處理所有 pcap-NG文件,但它可以處理僅包含一個部分的pcap-NG文件並且只有來自一個網絡適配器的數據包,並且libpcap 1.1和更高版本可以讀取這些數據包)。我建議,就像放鬆建議一樣,你使用libpcap/WinPcap讀取捕獲文件,而不是編寫自己的代碼來完成它。

+0

我檢查了這個pcap文件的幻數。它出來是0xa1b2c3d4。所以這意味着我不需要從你的解釋中進行字節交換。但是,當我打印第一個數據包的caplen的值時,它出現爲0x1050d300,而snaplen爲0xffff。這怎麼可能?我在這裏做錯了什麼? – user1192671 2012-02-15 08:16:51

+0

對於* that *文件,您不需要字節交換;對於其他文件,您可能需要。至於caplen,根據我的例子,你* DID *修改你的代碼來讀入'struct pcap_sf_pkthdr',而不是'struct pcap_pkthdr',對吧?如果沒有,那就這樣做。 – 2012-02-15 22:13:30

+0

雅,我的壞!得到它的工作! – user1192671 2012-02-16 05:16:46

0

嘗試類似的東西:

struct dump_pcap_pkthdr { 
struct   timeval ts; /* time stamp */ 
unsigned int caplen;  /* length of portion present */ 
unsigned int len;  /* length this packet (off wire) */ 
}; 

struct dump_pcap_file_header { 
unsigned int magic; 
unsigned short version_major; 
unsigned short version_minor; 
int    thiszone; /* gmt to local correction */ 
unsigned int sigfigs; /* accuracy of timestamps */ 
unsigned int snaplen; /* max length saved portion of each pkt */ 
unsigned int linktype; /* data link type (LINKTYPE_*) */ 
}; 


static void read_pcap_file(char *file) 
{ 
int fd = -1; 
struct dump_pcap_pkthdr packet_header = {0}; 
struct dump_pcap_file_header pcap_header = {0}; 

fd = open(file, O_RDONLY); 
if(fd < 0) { 
    printf("Fail open file: %s\n", file); 
    return; 
} 

if(read(fd, &pcap_header, sizeof(pcap_header)) != sizeof(pcap_header)) { 
    printf("Failed to read TCPDump Header from file: %s\n", file); 
    return; 
} 

while(1) 
{ 
    r = read(fd, &packet_header, sizeof(packet_header)); 
    if(r != sizeof(packet_header)) 
     break; 

    //print data   

    lseek(fd, packet_header.caplen, SEEK_CUR); 
} 

close(fd); 
} 
+0

它與我的實現相同,rigt? – user1192671 2012-02-14 11:53:04

+0

上述代碼無法正常工作。它在第一次循環後退出。我懷疑lseek(caplen)有什麼問題。你能告訴我發生了什麼事嗎? – user1192671 2012-02-14 12:51:23

+0

您使用非標準函數而不是C標準函數的任何特定原因? – Lundin 2012-02-14 13:30:04

1

確保您正確處理PCAP文件格式的存儲方式。因爲編譯器可以自由地在結構字段之間插入填充,這將使得磁盤中的字節與內存中的字節不匹配,所以直接從磁盤加載整個結構幾乎不是安全的。

我建議你使用官方的圖書館,因爲那些問題已經被照顧到了。

+0

從我觀察到的情況來看,當我將caplen添加到文件指針時,它會在第一次後退出。所以我想可能是我不得不將它轉換爲主機字節順序。所以我用ntohl(caplen),但沒有任何區別。 – user1192671 2012-02-14 14:03:35