2011-11-28 51 views
0

我寫了一個使用libpcap讀取捕獲文件的數據包讀取器。它讀取捕獲文件並將捕獲的數據上傳到MySQL數據庫。有時它似乎工作正常,而其他的則返回無效數據(例如,源IP和目的IP將相同,TCP端口都是垃圾)。我在一個虛擬的RHEL 5下運行它。這裏是我的代碼(對不起,如果它太長或不必要的複雜,這是我的第一次嘗試)。爲什麼我的數據包閱讀程序返回不正確的數據?

#include <arpa/inet.h> 
#include <net/ethernet.h> 

#include <netinet/ether.h> 
#include <netinet/if_ether.h> 
#include <netinet/in.h> 
#include <netinet/ip.h> 

#include "npc_tcp.h" 
#include "npc_udp.h" 

#include <ftw.h> 
#include <pcap.h> 
#include <stdio.h> 
#include <sys/stat.h> 
#include <regex.h> 
#include <string.h> 
#include <time.h> 

const int IPTYPE_TCP = 6; 
const int IPTYPE_UDP = 17; 

struct cap_data { 
    char ts[64]; 
    u_int16_t ether_type; 
    u_int16_t proto; 
    char *srcip; 
    char *dstip; 
    char *srcmac; 
    u_int16_t srcport; 
    u_int16_t dstport; 
    u_int8_t flags; 
    u_int capsize; 
}; 

int main(int argc, char **argv) { 

    //pcap 
    struct cap_data data; 
    struct pcap_pkthdr pkthdr; 
    const u_char *packet; 
    pcap_t *handle; 
    char *fname = argv[1]; 
    printf("%s\n", fname); 
    char errbuf[PCAP_ERRBUF_SIZE]; 
    handle = pcap_open_offline(fname, errbuf); 
    char buf[1000]; 

    while (packet = pcap_next(handle, &pkthdr)) { 

    int ether_flag; 
    struct ether_header *ether;  
    u_short ether_type;   

    ether = (struct ether_header *) packet; 
    data.ether_type = ntohs(ether->ether_type); 

    ether_flag = 1; 

    if (ether_flag) { 
     if (data.ether_type == ETHERTYPE_IP) { 
     struct ip *ip_hdr; 
     u_int length = pkthdr.len; 

     ip_hdr = (struct ip *)(packet + sizeof(struct ether_header)); 

     data.proto = ip_hdr->ip_p; 
     data.dstip = inet_ntoa(ip_hdr->ip_dst); 
     data.srcip = inet_ntoa(ip_hdr->ip_src); 

     if (data.proto == IPTYPE_TCP) { 
     struct tcphdr *tcp; 
     tcp = (struct tcphdr*)(packet + sizeof(struct ether_header) + 
       sizeof(struct ip)); 

     data.srcport = tcp->th_sport; 
     data.dstport = tcp->th_dport; 

     printf("%s %u %s %u\n\n", inet_ntoa(ip_hdr->ip_src), tcp->th_sport, inet_ntoa(ip_hdr->ip_dst), tcp->th_dport); 

     } else if (data.proto == IPTYPE_UDP) { 
     struct udphdr *udp; 
     udp = (struct udphdr *)(packet + sizeof(struct ether_header) + 
       sizeof(struct ip)); 
     data.srcport = udp->uh_sport; 
     data.dstport = udp->uh_dport; 

     printf("%s %u %s %u\n\n", inet_ntoa(ip_hdr->ip_src), udp->uh_sport, inet_ntoa(ip_hdr->ip_dst), udp->uh_dport); 

     } 
     } 
    } 
    }//while 

    pcap_close(handle); 

    return 0; 
} 

UPDATE:

此輸出..

source ip  port dest ip  port 

66.68.236.207 30151  66.68.236.207 47873 

172.22.162.235 60920 172.22.162.235 36175 

67.207.28.150 23007  67.207.28.150 22038 

172.22.162.235 60920 172.22.162.235 36175 

67.207.28.151 22038  67.207.28.151 23007 

65.55.87.43 20480  65.55.87.43 21764 

67.207.28.150 23007  67.207.28.150 22038 

的地址應該是不一樣的,端口號是錯誤的爲好。

我不知道在哪裏,甚至開始尋找我的代碼(至少對我來說)錯誤看起來是正確的。任何幫助,提示或建議將不勝感激。謝謝:)

+0

當然可以。將盡快發佈更新。但是,我正準備離開我的辦公室,因此可能要等到明天抱歉。 –

+1

您可以嘗試製作一個能夠解決相同問題的較短程序嗎?請參閱http://sscce.org。 –

+2

您是否嘗試過尋找在Wireshark的捕獲文件,看到什麼類型的分組是出現在你的程序出錯了吧?可能有其他數據包格式在那裏,你沒有正確處理。 – TJD

回答

1

兩個問題:

  1. INET_NTOA返回一個指向一個靜態緩衝區。
    當同一printf的內調用兩次,它將覆蓋相同的緩衝液。所以你最終打印相同的數據。
    使用inet_ntop代替,併爲每個調用單獨的緩衝器。

  2. 您應該使用ntohs和()的端口轉換打印前舉辦順序。

+0

對不起,花了這麼長的時間來接受你的答案。我實際上已經解決了這個問題,但忘了更新這個問題。 –

0

如果發生什麼事,叫pcap_open_offline()之後,你做

if (pcap_datalink(handle) != DLT_EN10MB) { 
    fprintf(stderr, "This program handles only Ethernet captures\n"); 
    return 2; 
} 
+0

這似乎不能解釋問題。他說他得到的數據無效,而不是錯誤信息。你是對的,限制程序爲10Mbps以太網是沒有意義的。 – ugoren

+0

收回我以前的評論。我誤解了這個意圖。 – ugoren

+0

實際上,DLT_EN10MB的名稱是歷史性的 - 它適用於所有*以太網速度,而不是10MB/s以太網。他編寫的程序已經侷限於以太網,因爲它假設每個數據包都以以太網報頭開始;該檢查是爲了確保程序在傳遞包*不包含以太網報頭的文件時失敗,而不是錯誤地解析這些包。 – 2012-01-02 01:48:37

相關問題