1. 抓包
捕獲從網絡適配器提取包,並將其保存到硬盤上.
訪問底層網絡適配器需要提升的權限,因此和底層網卡抓包的功能被封裝在dumpcap中,這是Wireshark中唯一需要特權執行的程序,代碼的其他部分(包括解析器,用戶界面等等)只需要普通用戶權限。
為了隱藏所有底層的機器依賴性,使用了libpcap/WinPcap庫.這此庫提供了從多種不同的網絡接口 類型(Ethernet, Token Ring,...)上捕獲包的通用接口.
2. 文件格式
Wireshark可以讀寫libpcap格式的捕獲文件,這是它的默認文件格式,被用於其他很多網絡捕獲工具, 如tcpdump.另外,Wireshark還可以讀寫其他網絡捕獲工具使用的多種不同的文件格式.wiretap庫, 和Wireshark一起開發,提供了讀寫所有這些文件格式的通用接口.如果你需要添加其他的捕獲文件格式,應從此處着手.
pcap文件的封裝格式如下圖所示。magic number的值對於以主機字節序寫入的文件來說是0x1a2b3c4d。
兩個重要struct見/wiretap/libpcap.h。
/* "libpcap" file header (minus magic number). */ struct pcap_hdr { unsigned short version_major; unsigned short version_minor; int thiszone; unsigned int sigfigs; unsigned int snaplen; unsigned int network; }; /* "libpcap" record header. */ struct pcaprec_hdr { unsigned int ts_sec; unsigned int ts_usec; unsigned int incl_len; unsigned int orig_len; };
3. 報文解析
當Wireshark從文件中載入包時,會解析每一個包.Wireshark嘗試探測包類型並盡可能地取得更多的包信息.然而此時,只需要顯示在報文列表窗格(packet list pane)的信息.
當用戶在包列表窗格中選擇特定的包時,它會被重新解析一次.此時,Wireshark嘗試取得每條信息並顯示在報文細節窗格(packet detail pane)中.
Wireshark支持多種文件格式,這是由wiretap目錄下代碼來實現的。簡單來說,在fire_access.c里有一個open_info結構體數組open_info_base,它的一部分如下:
static struct open_info open_info_base[] = { { "Pcap", OPEN_INFO_MAGIC, libpcap_open, "pcap", NULL, NULL }, { "PcapNG", OPEN_INFO_MAGIC, pcapng_open, "pcapng", NULL, NULL }, { "NgSniffer", OPEN_INFO_MAGIC, ngsniffer_open, NULL, NULL, NULL }, { "Snoop", OPEN_INFO_MAGIC, snoop_open, NULL, NULL, NULL }, { "IP Trace", OPEN_INFO_MAGIC, iptrace_open, NULL, NULL, NULL }, { "Netmon", OPEN_INFO_MAGIC, netmon_open, NULL, NULL, NULL }, { "Netxray", OPEN_INFO_MAGIC, netxray_open, NULL, NULL, NULL }, { "Radcom", OPEN_INFO_MAGIC, radcom_open, NULL, NULL, NULL }, { "Nettl", OPEN_INFO_MAGIC, nettl_open, NULL, NULL, NULL }, { "Visual", OPEN_INFO_MAGIC, visual_open, NULL, NULL, NULL }, { "5 Views", OPEN_INFO_MAGIC, _5views_open, NULL, NULL, NULL }, { "Network Instruments", OPEN_INFO_MAGIC, network_instruments_open, NULL, NULL, NULL }, { "Peek Tagged", OPEN_INFO_MAGIC, peektagged_open, NULL, NULL, NULL }, { "DBS Etherwatch", OPEN_INFO_MAGIC, dbs_etherwatch_open, NULL, NULL, NULL }, { "K12", OPEN_INFO_MAGIC, k12_open, NULL, NULL, NULL }, { "Catapult DCT 2000", OPEN_INFO_MAGIC, catapult_dct2000_open, NULL, NULL, NULL }, { "Aethra", OPEN_INFO_MAGIC, aethra_open, NULL, NULL, NULL }, { "BTSNOOP", OPEN_INFO_MAGIC, btsnoop_open, "log", NULL, NULL }, { "EYESDN", OPEN_INFO_MAGIC, eyesdn_open, NULL, NULL, NULL }, { "TNEF", OPEN_INFO_MAGIC, tnef_open, NULL, NULL, NULL }, { "MIME Files with Magic Bytes", OPEN_INFO_MAGIC, mime_file_open, NULL, NULL, NULL }, { "Lanalyzer", OPEN_INFO_HEURISTIC, lanalyzer_open, "tr1", NULL, NULL }, ... };
在file_access.c中的init_open_routines函數中,它被賦值給全局變量open_routines。
在file_access.c中的wtap_open_offline函數中,會遍歷此數組,直到其中的打開函數可以打開給定的文件。
switch ((*open_routines[i].open_routine)(wth, err, err_info)) { case -1: /* I/O error - give up */ wtap_close(wth); return NULL; case 0: /* No I/O error, but not that type of file */ break; case 1: /* We found the file type */ goto success; }