標簽: Wireshark
版權聲明:轉載時請以超鏈接形式標明文章原始出處和作者信息及本聲明
http://www.blogbus.com/shujiantang-logs/35858037.html
本文是Wireshark官方開發文檔9.2節《添加一個基礎的解析器》的翻譯
9.2.2. 解析協議細節
現在我們已經有了一個可以運用的簡單解析器,讓我們再為它添點兒什么吧。首先想到的應該就是標示數據包的有效信息了。解析器在這方面給我們提供了支持。
首先要做的事情是創建一個子樹以容納我們的解析結果。這會使協議的細節顯示得井井有條。現在解析器在兩種情況下被調用:其一,用于獲得數據包的概要信息;其二,用于獲得數據包的詳細信息。這兩種情況可以通過樹指針參數tree
來進行區分。如果樹指針為NULL
,我們只需要提供概要信息;反之,我們就需要拆解協議完成細節的顯示了。基于此,讓我們來增強這個解析器吧。
例 9.4. 插入數據包解析.
static void dissect_foo(tvbuff_t *tvb,packet_info *pinfo,proto_tree *tree)
{
if(check_col(pinfo->cinfo,COL_PROTOCOL))
{
col_set_str(pinfo->cinfo,COL_PROTOCOL,"FOO");
}
/* Clear out stuff in the info column */
if(check_col(pinfo->cinfo,COL_INFO))
{
col_clear(pinfo->cinfo,COL_INFO);
}
if(tree)
{
/* we are being asked for details */
proto_item *ti=NULL;
ti=proto_tree_add_item(tree,proto_foo,tvb,0,-1,FALSE);
}
}
這里我們為解析添加一個子樹。它將用于保管協議的細節,僅在必要時顯示這些內容。
我們還要標識被協議占據的數據區域。在我們的這種情況下,協議占據了傳入數據的全部,因為我們假設協議沒有封裝其它內容。因此,我們用
proto_tree_add_item
函數添加新的樹結點,將它添加到傳入的協議樹tree
中,用協議句柄proto_foo
標識它,用傳入的緩沖區tvb
作為數據,并將有效數據范圍的起點設為0
,長度設為-1
(表示緩沖區內的全部數據)。至于最后的參數FALSE
,我們暫且忽略。做了這個更改之后,在包明細面板區中應該會出現一個針對該協議的標簽;選擇該標簽后,在包字節面板區中包的剩余內容就會高亮顯示。
現在進入下一步,添加一些協議解析功能。在這一步我們需要構建一組幫助解析的表結構。這需要對proto_register_foo
函數做些修改。首先定義一組靜態數組。
例 9.5. 定義數據結構.
static hf_register_info hf[]=
{
{
&hf_foo_pdu_type,
{"FOO PDU Type","foo.type",FT_UINT8,BASE_DEC,NULL, 0x0,NULL,HFILL}
}
};
/* Setup protocol subtree array */
static gint *ett[]=
{
&ett_foo
};
接下來,在協議注冊代碼之后,我們對這些數組進行注冊。
例 9.6. 注冊數據結構.
proto_register_field_array(proto_foo,hf,array_length(hf));
proto_register_subtree_array(ett,array_length(ett));
變量hf_foo_pdu_type
和ett_foo
依然需要在文件頂部的某處予以聲明。
例 9.7. 解析器全局數據結構.
static int hf_foo_pdu_type=-1;
static gint ett_foo=-1;
現在我們就可以對協議細節的顯示做一番改善了。
例 9.8. 解析器開始數據包解析.
if(tree)
{
/* we are being asked for details */
proto_item *ti=NULL;
proto_tree *foo_tree=NULL;
ti=proto_tree_add_item(tree,proto_foo,tvb,0,-1,FALSE);
foo_tree=proto_item_add_subtree(ti,ett_foo);
proto_tree_add_item(foo_tree,hf_foo_pdu_type,tvb,0,1,FALSE);
}
協議的解析變得愈發有趣了。我們提取出協議的第一部分。數據包的首字節定義了foo協議的包類型。
函數
proto_item_add_subtree
的調用在協議樹中添加了一個子樹,我們就在這里進行細節解析。子樹的展開受控于變量ett_foo
。當您在協議間切換時,由它記錄子樹是否展開。正像您從下面的函數調用中看到的那樣,隨后的所有解析都會添加到該子樹中。函數
proto_tree_add_item
用于為子樹foo_tree
添加項,這次調用使用變量hf_foo_pdu_type
控制項格式。PDU(協議數據單元)類型是一個單字節數據,位于數據包的首字節,我們將有效數據范圍的起點設為0
,長度設為1
。我們假設它依照網絡字節順序,所以將最后一個參數設為FALSE
(TRUE
表示"little endian",FALSE
表示"big endian")。盡管對于單字節數據無所謂字節順序,但我們最好還是保持指定字節順序的良好習慣。如果詳細查看靜態數組中
hf_foo_pdu_type
的聲明,我們能夠獲悉定義的明細:
hf_foo_pdu_type
:節點索引。FOO PDU Type
:項標示。foo.type
:過濾字符串。我們可以在過濾框中輸入諸如foo.type=1
的結構。FT_UNIT8
:指定該項數據是一個8比特位的無符號整型。這和我們之前調用函數時設置的一字節有效數據是相一致的。BASE_DEC
:針對整型數據,指定將其作為十進制數顯示。當然視具體情況也可以設置為“BASE_HEX”(十六進制)和“BASE_OCT”(八進制),以使數據更易辨識。- 至于結構中余下的部分我們暫且忽略。
如果您現在安裝并試用這個插件,就會發現一些有用的東西了。
接下來讓我們完成這個簡單協議的解析工作吧。我們需要再添加一些hf數組成員和程序調用。
例 9.9. 完成數據包解析.
//添加到文件開始的某個地方,作為全局變量
static int hf_foo_flags=-1;
static int hf_foo_sequenceno=-1;
static int hf_foo_initialip=-1;
//添加到“proto_register_foo”函數中的“hf”數組中,作為數組的成員
{
&hf_foo_flags,
{"FOO PDU Flags","foo.flags",FT_UINT8,BASE_HEX,NULL,0x0,NULL,HFILL}
},
{
&hf_foo_sequenceno,
{"FOO PDU Sequence Number","foo.seqn",FT_UINT16,BASE_DEC,NULL,0x0,NULL,HFILL}
},
{
&hf_foo_initialip,
{"FOO PDU Initial IP","foo.initialip",FT_IPv4,BASE_NONE,NULL,0x0,NULL,HFILL}
},
//添加到“dissect_foo”函數中,實現數據包的解析
gint offset=0;
ti = proto_tree_add_item(tree,proto_foo,tvb,0,-1,FALSE);
foo_tree=proto_item_add_subtree(ti,ett_foo);
proto_tree_add_item(foo_tree,hf_foo_pdu_type,tvb,offset,1,FALSE);
offset+=1;
proto_tree_add_item(foo_tree,hf_foo_flags,tvb,offset,1,FALSE);
offset+=1;
proto_tree_add_item(foo_tree,hf_foo_sequenceno,tvb,offset,2,FALSE);
offset+=2;
proto_tree_add_item(foo_tree,hf_foo_initialip,tvb,offset,4,FALSE);
offset+=4;
- 這段代碼解析了這個簡單的虛構協議的全部內容。我們引入了一個新的變量
offset
以記錄數據包解析的位置。將這些額外的代碼塊放入合適的位置,整個協議就可以得到全面的解析。