1. 簡介
2. Wireshark功能模塊
下圖給出了wireshark功能模塊:
a) GTK1/2
處理用戶的輸入輸出顯示,源碼在gtk目錄.
b) Core
核心模塊,通過函數調用將其他模塊連接在一起,源碼在根目錄
c) Epan
wireshark Packetage Analyzing,包分析引擎,源碼在epan目錄
l Protocol-Tree:保存數據包的協議信息,wireshark的協議結構採用樹形結構,解析協議報文時只需要從根節點通過函數句柄依次調用各層解析函數即可。
l Dissectors:在epan/dissector目錄下,各種協議解碼器,支持700+種協議解析,對於每種協議,解碼器都能識別出協議字段(field),並顯示出字段值(field value)由於網絡協議種類很多,爲了使協議和協議間層次關係明顯,對數據流裏的各個層次的協議能夠逐層處理,wireshark系統採用了協議樹的方式。
l Plugins:一些協議解碼器以插件形式實現,源碼在plugins目錄
l Display-Filters:顯示過濾引擎,源碼在epan/dfilter目錄
d) Capture
捕包引擎,利用libpcap/WinPcap從底層抓取網絡數據包,libpcap/WinPcap提供了通用的抓包接口,能從不同類型的網絡接口(包括以太網,令牌環網,ATM網等)獲取數據包。
e) Wiretap
從文件中讀取數據包,支持多種文件格式,源碼在wiretap目錄
f) Win-/libpcap
Wireshark抓包時依賴的庫文件
wireshark功能模塊
3. wireshark流程分析
1) 初始化
Wireshark的初始化包括一些全局變量的初始化、協議分析引擎的初始化和Gtk相關初始化,顯示Ethereal主窗口,等待用戶進一步操作。重點就是Epan模塊的初始化。
Epan初始化:
n tvbuff初始化:全局變量tvbuff_mem_chunk指向用memchunk分配的固定大小的空閒內存塊,每個內存塊是tvbuff_t結構,從空閒內存塊中取出後,用來保存原始數據包。
n 協議初始化:
u 全局變量:
l proto_names
l proto_short_names
l proto_filter_names
以上三個全局變量主要用來判斷新註冊的協議名是否重複,如果重複,給出提示信息,在協議解析過程中並沒有使用。
u 協議註冊:
l 註冊協議:將三個參數分別註冊給proto_names、proto_short_names、proto_filter_names三個全局變量中,
l 註冊字段,需要在wireshark協議樹顯示的報文內容字段。
l 協議解析表
u Handoff註冊
l 將協議與父協議節點關聯起來
n Packet(包)初始化
u 全局變量:
l frame_handle:協議解析從frame開始,層層解析,直到所有的協議都解析完爲止。frame_handle保存了frame協議的handle。
l data_handle:有的協議無法從frame開始,那麼就從data開始。原理同frame。
n 讀配置文件preference
n 讀capture filter和display filter文件,分別保存在全局變量capture_filter和display_filter中。
n 讀disabled protocols文件,保存全局變量global_disabled_protos和disabled_protos中
n 初始化全局變量cfile
u Cfile是個重要的變量,數據類型爲capture file,它保存了數據包的所有信息,
2) 處理流程
Wireshark初始化完成以後進入實際處理階段,主程序創建抓包進程,捕包進程和主程序是通過PIPE進行傳遞數據的,主程序把抓取的數據寫入臨時文件,通過函數add_packet_to_packet_list將數據包加入包列表。處理時,主程序從列表中選取一個數據包,提取該數據包中的數據填寫在數據結構中,最後調用協議解析函數epan_dissect_run進行處理,從epan_dissect_run開始,是實際的協議解析過程,
下面以HTTP協議報文爲例,流程如下:
a) 解析frame層
調用函數dissect_frame對frame層進行解析,並在協議樹上填充相應字段信息。函數最後會判斷是否有上層協議封裝,如果有則調用函數dissector_try_port在協議樹上查找對應的解析函數,這裏函數dissector_try_port根據pinfo->fd->lnk_t查找對應的上層協議處理函數,pinfo->fd->lnk_t值爲1,上層封裝協議爲以太網協議,全局結構體指針變量dissector_handle當前的協議解析引擎句柄置爲dissect_eth_maybefcs,至此,frame層解析結束。
g) 解析以太網層
函數call_dissector_work根據dissector_handle調用frame上層協議解析函數dissect_eth_maybefcs對以太網層進行解析,並在協議樹上填充相應字段,包括目的MAC地址和以太網上層協議類型等信息。函數最後會判斷是否有上層協議封裝,如果有則調用函數dissector_try_port在協議樹上查找對應的解析函數,這裏函數dissector_try_port根據etype查找對應的上層協議處理函數,以太網字段etype爲0800的報文是ip報文,上層封裝協議爲IP協議,全局結構體指針變量dissector_handle當前的協議解析引擎句柄置爲dissect_ip,至此,以太網層解析結束。
h) 解析IP層
函數call_dissector_work根據dissector_handle調用以太網上層協議解析函數dissect_ip對以太網層進行解析,並在協議樹上填充相應字段,包括版本號,源地址,目的地址等信息。函數最後會判斷是否有上層協議封裝,如果有則調用函數dissector_try_port在協議樹上查找對應的解析函數,這裏函數dissector_try_port根據nxt (nxt = iph->ip_p)查找對應的上層協議處理函數,以太網字段nxt爲06的報文是TCP報文,上層封裝協議爲TCP協議,全局結構體指針變量dissector_handle當前的協議解析引擎句柄置爲dissect_tcp,至此,IP層解析結束。
i) 解析TCP層
函數call_dissector_work根據dissector_handle調用以太網上層協議解析函數dissect_tcp對TCP層進行解析,包括對TCP頭的解析和選項字段的解析,並在協議樹上填充相應字段,包括源端口,目的端口,標誌位等信息。函數最後會判斷是否有上層協議封裝,如果有則調用函數dissector_try_port在協議樹上查找對應的解析函數,這裏函數dissector_try_port根據port查找對應的上層協議處理函數,將源端口和目的端口分別賦值給low_port和high_port,根據low_port和high_port分別匹配上層協議解析函數,port爲80的報文是HTTP報文,上層封裝協議爲HTTP協議,全局結構體指針變量dissector_handle當前的協議解析引擎句柄置爲dissect_http,至此,TCP層解析結束。
j) 解析HTTP層
至此wireshark進入應用層協議檢測階段,wireshark解析dissect_http函數中註冊的字段,並提取相應的字段值添加到協議樹中,應用層的具體解析流程將在下面介紹。HTTP協議具體函數調用過程參見:
重要的數據結構
struct _epan_dissect_t {
tvbuff_t *tvb;//用來保存原始數據包
proto_tree *tree;//協議樹結構
packet_info pi;// 包括各種關於數據包和協議顯示的相關信息
};
/** Each proto_tree, proto_item is one of these. */
typedef struct _proto_node {
struct _proto_node *first_child;//協議樹節點的第一個子節點指針
struct _proto_node *last_child; //協議樹節點的最後一個子節點指針
struct _proto_node *next; //協議樹節點的下一個節點指針
struct _proto_node *parent;//父節點指針
field_info *finfo;//保存當前協議要顯示的地段
tree_data_t *tree_data;//協議樹信息
} proto_node;
typedef struct _packet_info {
const char *current_proto; //當前正在解析的協議名稱
column_info *cinfo; //wireshark顯示的信息
frame_data *fd;//現在分析的原始數據指針
union wtap_pseudo_header *pseudo_header;//frame類型信息
GSList *data_src; /*frame層信息 */
address dl_src; /* 源MAC */
address dl_dst; /*目的MAC */
address net_src; /* 源IP */
address net_dst; /*目的IP */
address src; /*源IP */
address dst; /*目的IP */
guint32 ethertype; /*以太網類型字段*/
guint32 ipproto; /* IP協議類型*/
guint32 ipxptype; /* IPX 包類型 */
guint32 mpls_label; /* MPLS包標籤*/
circuit_type ctype;
guint32 circuit_id; /*環路ID */
const char *noreassembly_reason; /* 重組失敗原因*/
gboolean fragmented; /*爲真表示未分片*/
gboolean in_error_pkt; /*錯誤包標誌*/
port_type ptype; /*端口類型 */
guint32 srcport; /*源端口*/
guint32 destport; /*目的端口*/
guint32 match_port; /*進行解析函數匹配時的匹配端口*/
const char *match_string; /*調用子解析引擎時匹配的協議字段指針*/
guint16 can_desegment; /* 能否分段標誌*/
guint16 saved_can_desegment;
int desegment_offset; /*分段大小*/
#define DESEGMENT_ONE_MORE_SEGMENT 0x0fffffff
#define DESEGMENT_UNTIL_FIN 0x0ffffffe
guint32 desegment_len;
guint16 want_pdu_tracking;
guint32 bytes_until_next_pdu;
int iplen; /*IP包總長*/
int iphdrlen; /*IP頭長度*/
int p2p_dir;
guint16 oxid; /* next 2 fields reqd to identify fibre */
guint16 rxid; /* channel conversations */
guint8 r_ctl; /* R_CTL field in Fibre Channel Protocol */
guint8 sof_eof;
guint16 src_idx; /* Source port index (Cisco MDS-specific) */
guint16 dst_idx; /* Dest port index (Cisco MDS-specific) */
guint16 vsan; /* Fibre channel/Cisco MDS-specific */
/* Extra data for DCERPC handling and tracking of context ids */
guint16 dcectxid; /* Context ID (DCERPC-specific) */
int dcetransporttype;
guint16 dcetransportsalt; /* fid: if transporttype==DCE_CN_TRANSPORT_SMBPIPE */
#define DECRYPT_GSSAPI_NORMAL 1
#define DECRYPT_GSSAPI_DCE 2
guint16 decrypt_gssapi_tvb;
tvbuff_t *gssapi_wrap_tvb;
tvbuff_t *gssapi_encrypted_tvb;
tvbuff_t *gssapi_decrypted_tvb;
gboolean gssapi_data_encrypted;
guint32 ppid; /* SCTP PPI of current DATA chunk */
guint32 ppids[MAX_NUMBER_OF_PPIDS]; /* The first NUMBER_OF_PPIDS PPIDS which are present * in the SCTP packet*/
void *private_data; /* pointer to data passed from one dissector to another */
/* TODO: Use emem_strbuf_t instead */
GString *layer_names; /* layers of each protocol */
guint16 link_number;
guint8 annex_a_used;
guint16 profinet_type; /* the type of PROFINET packet (0: not a PROFINET packet) */
void *profinet_conv; /* the PROFINET conversation data (NULL: not a PROFINET packet) */
void *usb_conv_info;
void *tcp_tree; /* proto_tree for the tcp layer */
const char *dcerpc_procedure_name; /* Used by PIDL to store the name of the current dcerpc procedure */
struct _sccp_msg_info_t* sccp_info;
guint16 clnp_srcref; /* clnp/cotp source reference (can't use srcport, this would confuse tpkt) */
guint16 clnp_dstref; /* clnp/cotp destination reference (can't use dstport, this would confuse tpkt) */
guint16 zbee_cluster_id; /* ZigBee cluster ID, an application-specific message identifier that
* happens to be included in the transport (APS) layer header.
*/
guint8 zbee_stack_vers; int link_dir; /* 3GPP messages are sometime different UP link(UL) or Downlink(DL)*/
} packet_info;