這一節是本系列教程的結尾了,內容也比較簡單,主要是對網路協議進行分析,其實學過計算機網路的同學完全可以略過
在整個專案中需要有乙個標頭檔案存放各層協議的頭部定義,我把它們放在了head.h中,這個標頭檔案都有什麼呢,首先放幾個關於協議的巨集定義,這樣可以讓整個程式顯得更加清晰:
1之後就是存放協議的頭部定義了,對照著頭部定義,用合適的型別定義各個字段,比如ip協議頭:/*網路層協議型別 */2
#define ip 0x0800
3#define arp 0x0806
4#define rarp 0x8035 56
/*傳輸層型別 */7
#define icmp 0x01
8#define igmp 0x02
9#define tcp 0x06
10#define egp 0x08
11#define udp 0x11
12#define ipv6 0x29
13#define ospf 0x59
1 typedef struct當然有些位置的意義是小於乙個位元組大小的,比如tcp協議中的標誌位欄位,有urg,ack,psh,rst,syn,fin,這些在之後用&&運算可以方便求得ip_address
2ip_address;89
/*ipv4 首部
*/10 typedef struct
ip_header
11ip_header;
當資料報被pcap_next_ex()函式捕獲後,我們需要其中的兩個引數,pcap_next_ex()函式原型如下:
1第乙個引數是乙個已開啟的捕捉例項,也就是之前我們選擇的介面卡,第二個引數是乙個結構體,其中內容有:int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **);
1因為在某些情況下你不能保證捕獲的包是完整的,例如乙個包長1480,但是你捕獲到1000的時候,可能因為某些原因就中止捕獲了,所以caplen是記錄實際捕獲的包長,也就是1000,而len就是1480。第三個引數就是資料報的內容後兩個引數是對我們有用的,將其傳遞到顯示資料報概略的函式showpacketlist中struct
pcap_pkthdr
2
每當捕獲以個資料報,需要進行儲存,在mfc中可以用carray,carray是乙個動態陣列,它的用法是:carrayvar1;前乙個引數是指定儲存在陣列中的物件的型別,後乙個引數是指定用於訪問儲存在陣列中物件的引數型別。其實這兩個引數一般是一樣的型別,程式中儲存每次抓包的pkt_header和pkt_data就用如下carray表示:
carraycarray類的一些常用成員函式有:getat返回在給定索引上的值;add增加乙個元素;getsize獲得此陣列中的元素數struct pcap_pkthdr *,const
struct pcap_pkthdr *>m_pktheaders;
carray
m_pktdatas;
儲存完捕獲的資料報,就可以利用pkt_data的資訊來分析資料報,在分析資料報中的資料時注意,資料報的資料是按照小端模式儲存的,對於大於1位元組的內容需要用noths或是nothl進行轉化(前者對應short,後者對應long)。舉乙個例子,比如數字0x12 34 56 78在記憶體中的表示形式為:0x78 | 0x56 | 0x34 | 0x12 ,這時就需要noths來轉化為正確的順序。顯示資料報概要的函式部分**如下:
1 ethernet_header *eh;就這樣陷入一層一層的分析中,對於資料報的詳細分析,也就是在樹形結構中顯示的**也與次類似,不做分析。2 eh = (ethernet_header *)pkt_data;
3 str.format(_t("
%x:%x:%x:%x:%x:%x
"),eh->saddr.byte1,eh->saddr.byte2,eh->saddr.byte3,eh->saddr.byte4,eh->saddr.byte5,eh->saddr.byte6);
4 m_list1.setitemtext(ncount,2
,str);
5 str.format(_t("
%x:%x:%x:%x:%x:%x
"),eh->daddr.byte1,eh->daddr.byte2,eh->daddr.byte3,eh->daddr.byte4,eh->daddr.byte5,eh->daddr.byte6);
6 m_list1.setitemtext(ncount,3
,str);
7 str.format(_t("
%ld"),pheader->len);
8 m_list1.setitemtext(ncount,4
,str);9/*
處理網路層
*/10
switch(ntohs(eh->type))11{
12case
ip:13
{14 ip_header *ih;
15const u_char *ip_data;
16 ip_data=pkt_data+14
;17 ih = (ip_header *)ip_data;
18 u_int ip_len;//
ip首部長度
19 ip_len = (ih->ver_ihl & 0xf) * 4
;20 str.format(_t("
%d.%d.%d.%d
"),ih->saddr.byte1,ih->saddr.byte2,ih->saddr.byte3,ih->saddr.byte4);
21 m_list1.setitemtext(ncount,6
,str);
22 str.format(_t("
%d.%d.%d.%d
"),ih->saddr.byte1,ih->saddr.byte2,ih->saddr.byte3,ih->saddr.byte4);
23 m_list1.setitemtext(ncount,7
,str);
24/*
處理傳輸層
*/25
switch(ih->type)26{
27case tcp:
在統計部分,除了有統計各種資料報的數目外,還有一部分是流量分析:
這一部分的實現也比較簡單,對於某些常用的軟體,都是通過固定埠進行資料傳輸的,比如qq 預設採用 udp 通訊方式,埠 8000,8001。如果 udp 的兩個埠不通,會自動轉換到 tcp 80 埠或者 tcp 443 埠進行通訊。 qq 同時也支援 http **模式及 sock5**模式。阿里旺旺採用 tcp 通訊方式,預設登入埠為 16000,當 16000 埠不通時,則跳轉到 443 埠進行通訊。所以通過對固定埠的監聽,可以知道哪些軟體產生了流量(這樣做並不完美,有興趣的可以分析應用層協議)
1寫在最後:if(ntohs( th->sport ) == 0x3e80 || ntohs( th->dport ) == 0x3e80) //
阿里旺旺流量為tcp埠16000
2 m_wangcount++;
3if(ntohs( th->sport ) == 0x747 || ntohs( th->dport ) == 0x747) //
msn流量為tcp埠1863
4 m_msncount++;
編寫乙個makefile
什麼是makefile?對於大多數的windows程式設計師來講,makefile可能不是那麼重要,因為windows的ide都為程式設計師做好了這個工作。但是在linux下程式設計,會不會寫makefile,從側面上說明乙個人是否具備完成大型工程的能力。makefile的作用 makefile是用...
編寫乙個webpack loader
loader是一種打包的方案,webpack預設只識別js結尾的檔案,當遇到其他格式的檔案後,webpack並不知道如何去處理。此時,我們可以定義一種規則,告訴webpack當他遇到某種格式的檔案後,去求助於相應的loader。新建loaders資料夾並建立三個loaders檔案 remove co...
如何編寫乙個 XML Schema
看看這個名為 shiporder.xml 的 xml 文件 george bush john adams oxford street london uk empire burlesque special edition 110.90 hide your heart 19.90 說明 上面的xml文件...