【wireshark】協議解析


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"

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM