1. 普通解析
Wireshark啟動時,所有解析器進行初始化和注冊。要注冊的信息包括協議名稱、各個字段的信息、過濾用的關鍵字、要關聯的下層協議與端口(handoff)等。在解析過程,每個解析器負責解析自己的協議部分, 然后把上層封裝數據傳遞給后續協議解析器,這樣就構成一個完整的協議解析鏈條。
解析鏈條的最上端是Frame解析器,它負責解析pcap幀頭。后續該調用哪個解析器,是通過上層協議注冊handoff信息時寫在當前協議的hash表來查找的。
例如,考慮ipv4解析器有一個hash表,里面存儲的信息形如下表。當它解析完ipv4首部后,就可以根據得到的協議號字段,比如6,那么它就能從此hash表中找到后續解析器tcp。
| 協議號 | 解析器指針 |
| 6 | *tcp |
| 17 | *udp |
| …… | |
Wireshark中實際的解析表有3種,分別是字符串表,整數表和啟發式解析表。如下圖所示:

下面以ip協議為例,說明一下它的注冊過程。
相關的重要數據結構與全局變量如下。
proto.c
/* Name hashtables for fast detection of duplicate names */ static GHashTable* proto_names = NULL; static GHashTable* proto_short_names = NULL; static GHashTable* proto_filter_names = NULL; /** Register a new protocol. @param name the full name of the new protocol @param short_name abbreviated name of the new protocol @param filter_name protocol name used for a display filter string @return the new protocol handle */ int proto_register_protocol(const char *name, const char *short_name, const char *filter_name);
三個全局的哈希表分別用於保存協議名稱、協議縮略名和用於過濾器的協議名。
packet.c:
struct dissector_table { GHashTable *hash_table; GSList *dissector_handles; const char *ui_name; ftenum_t type; int base; }; static GHashTable *dissector_tables = NULL; /* * List of registered dissectors. */ static GHashTable *registered_dissectors = NULL; static GHashTable *heur_dissector_lists = NULL; /* Register a dissector by name. */ dissector_handle_t register_dissector(const char *name, dissector_t dissector, const int proto); /** A protocol uses this function to register a heuristic sub-dissector list. * Call this in the parent dissectors proto_register function. * * @param name the name of this protocol * @param list the list of heuristic sub-dissectors to be registered */ void register_heur_dissector_list(const char *name, heur_dissector_list_t *list); /* a protocol uses the function to register a sub-dissector table */ dissector_table_t register_dissector_table(const char *name, const char *ui_name, const ftenum_t type, const int base);
dissector_tables可以說是“哈希表的哈希表”,它以解析表名為鍵(如“ip.proto”),以dissector_table結構指針為值。在dissector_table中的哈希表以無符號數的指針為鍵(如協議號,為指針是glib hash表API的參數要求),以解析器handle為值;heur_dissector_lists是啟發式解析相關的東西,這個問題留待以后研究;registered_dissectors是解析器哈希表,它以解析器名為鍵(如”ip”),以解析器句柄為值。
packet.h:
typedef struct dissector_table *dissector_table_t;
packet-ip.c:
static dissector_table_t ip_dissector_table;
proto_register_ip函數中:
proto_ip = proto_register_protocol("Internet Protocol Version 4", "IPv4", "ip"); ... /* subdissector code */ ip_dissector_table = register_dissector_table("ip.proto", "IP protocol", FT_UINT8, BASE_DEC); register_heur_dissector_list("ip", &heur_subdissector_list); ... register_dissector("ip", dissect_ip, proto_ip); register_init_routine(ip_defragment_init); ip_tap = register_tap("ip");
register_dissector_table這個函數在packet.c中,在此函數內,創建了名為“ip.proto”的哈希表。解析ip協議后,會查詢這個表,找出下一個解析器,並將后續數據的解析移交給它。
packet-ip.c,dissect_ip函數內:
dissector_try_uint_new(ip_dissector_table, nxt, next_tvb, pinfo,
parent_tree, TRUE, iph)
packet.c:
/* Look for a given value in a given uint dissector table and, if found, call the dissector with the arguments supplied, and return TRUE, otherwise return FALSE. */ gboolean dissector_try_uint_new(dissector_table_t sub_dissectors, const guint32 uint_val, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const gboolean add_proto_name, void *data)
在dissector_try_uint_new函數中,會找到協議號對應的解析器句柄,並使用它解析其余數據。
2. 啟發式(heuristic)解析
//TODO
3. 參考
Wireshark開發指南第6章"How wireshark works"
