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; }
4. 参考
Wireshark开发指南第6章"How wireshark works"