俞 皓,黃益彬
(國(guó)網(wǎng)電力科學(xué)研究院,江蘇 南京 211106)
協(xié)議解析技術(shù)是網(wǎng)絡(luò)開(kāi)發(fā)及應(yīng)用中的關(guān)鍵技術(shù)之一。目前業(yè)界協(xié)議解析軟件種類(lèi)繁多,如Wildpackets、Wireshark[1-2](前身 Ethereal)等,這類(lèi)軟件能夠支持絕大多數(shù)常用協(xié)議的解析,但如果遇到自定義協(xié)議或者新協(xié)議時(shí),則無(wú)法正常解析。少量解析軟件可通過(guò)其自帶的插件[3]進(jìn)行新協(xié)議的注冊(cè)及處理(如圖1所示),或者提供二次編程接口進(jìn)行新協(xié)議的定制開(kāi)發(fā),但由于涉及軟件代碼的復(fù)雜性,其開(kāi)發(fā)難度大,難以輕松擴(kuò)展。本文通過(guò)設(shè)計(jì)一種基于協(xié)議描述語(yǔ)言的協(xié)議解析方法,大幅降低了協(xié)議添加的難度,使得新協(xié)議可以方便擴(kuò)展。
圖1 一般軟件的新協(xié)議添加流程
網(wǎng)絡(luò)協(xié)議由多個(gè)層次構(gòu)成,每一層的解析需要3個(gè)元素:(1)指向協(xié)議頭的頭部指針;(2)該層協(xié)議的長(zhǎng)度,包括頭部(head)與負(fù)載(payload)部分;(3)標(biāo)明下一層協(xié)議的類(lèi)型(最上層除外)。
對(duì)于每一層協(xié)議而言,解析的方法基本類(lèi)同。首先讀取一定長(zhǎng)度的數(shù)據(jù)字段得到數(shù)據(jù)內(nèi)容;之后,或是繼續(xù)進(jìn)行同樣的操作(所取的長(zhǎng)度可不同),或是需要根據(jù)上一步得到的數(shù)據(jù)值,決定對(duì)后續(xù)的字段進(jìn)行何種操作;最后依次循環(huán)直到讀取至整個(gè)報(bào)文的結(jié)尾為止[4]。
協(xié)議解析的方式存在上述固定模式,一般情況下,可以通過(guò)某種方式對(duì)其進(jìn)行循環(huán)解析。但由于協(xié)議種類(lèi)數(shù)量龐大,且每一種協(xié)議都有自身的特殊性,其協(xié)議頭部長(zhǎng)度并不固定,多數(shù)需要通過(guò)其中一些域的值來(lái)進(jìn)一步確定是否有其它數(shù)據(jù)選項(xiàng),實(shí)際編寫(xiě)時(shí)需要考慮的因素過(guò)多,無(wú)法用簡(jiǎn)單的通用方式實(shí)現(xiàn)循環(huán)解析。
針對(duì)1.1節(jié)描述的問(wèn)題,解決思路是,通過(guò)定義一種協(xié)議描述語(yǔ)言PDL(Protocol Description Language),將協(xié)議格式以及內(nèi)容按照定義好的格式描述出來(lái),并開(kāi)發(fā)一種對(duì)PDL的協(xié)議解析引擎,則可對(duì)相應(yīng)協(xié)議進(jìn)行解析。對(duì)于一個(gè)新的自定義協(xié)議,僅需通過(guò)PDL進(jìn)行描述,即可完成對(duì)此新協(xié)議的解析工作(如圖2所示),如果描述語(yǔ)言的定義簡(jiǎn)單清晰,則新協(xié)議的添加工作將大幅簡(jiǎn)化,同時(shí)有利于代碼的自動(dòng)生成[5-6]。
圖2 使用協(xié)議描述語(yǔ)言時(shí)新協(xié)議的添加
對(duì)于一個(gè)報(bào)文的解析,可以看作是對(duì)一個(gè)字段集合S的解析。首先將S分解為子字段S1,S2,S3,…,Sn,設(shè)S的總長(zhǎng)為L(zhǎng),對(duì)于任意給定的子字段Si,只要確定每一段的長(zhǎng)度Li,就可按照Li的值逐段解析。值得注意的是,Li的長(zhǎng)度并不都是定長(zhǎng),有可能是變長(zhǎng);另外根據(jù)Si的不同取值,可能會(huì)出現(xiàn)可選數(shù)據(jù)字段 Si-j,如圖 3 所示。
圖3 報(bào)文解析遇到的問(wèn)題
通過(guò)對(duì)上述報(bào)文解析過(guò)程的分析,可以看出報(bào)文解析主要面臨2個(gè)問(wèn)題,其一是數(shù)據(jù)字段變長(zhǎng)的表示問(wèn)題;其二是可選字段出現(xiàn)分支的問(wèn)題。PDL重點(diǎn)解決上述2個(gè)問(wèn)題,并對(duì)整個(gè)描述語(yǔ)言的基本元素做相應(yīng)定義。
鑒于XML文本格式的擴(kuò)展性與泛用性,以下使用XML格式對(duì)協(xié)議描述語(yǔ)言進(jìn)行描述。
如圖4所示,PDL文件需要先定義根節(jié)點(diǎn)<PDL>,用于描述版本信息。根節(jié)點(diǎn)以下是所有的協(xié)議節(jié)點(diǎn)<protocol>,在每一個(gè)協(xié)議中用<format>節(jié)點(diǎn)描述協(xié)議報(bào)文格式,完成對(duì)協(xié)議的解析。
圖4 PDL結(jié)構(gòu)圖
對(duì)于每一個(gè)報(bào)文的解析流程為:根據(jù)實(shí)際報(bào)文內(nèi)容,從物理層的某個(gè)<protocol>節(jié)點(diǎn)開(kāi)始逐層解析,通過(guò)<format>節(jié)點(diǎn)中的字段值獲取下一層的協(xié)議種類(lèi),根據(jù)取得的協(xié)議種類(lèi)跳轉(zhuǎn)到下一層的<protocol>節(jié)點(diǎn),繼續(xù)解析,直至報(bào)文結(jié)束。
2.2.1 定長(zhǎng)描述詞
報(bào)文解析最大的難點(diǎn)之一是數(shù)據(jù)字段變長(zhǎng)時(shí)長(zhǎng)度的處理問(wèn)題。針對(duì)此問(wèn)題,PDL在<format>節(jié)點(diǎn)中定義2類(lèi)元素:定長(zhǎng)元素<fixed>類(lèi),如表1所示;變長(zhǎng)元素<variable>類(lèi),如表2所示。
表1 定長(zhǎng)元素部分示例
定長(zhǎng)元素<fixed>必須具備的屬性有名字和長(zhǎng)度,其中名字通過(guò)name元素進(jìn)行唯一標(biāo)識(shí),長(zhǎng)度擁有多種處理方式,其一是以字節(jié)(byte)作單位,其二是以位(bit)作單位,無(wú)論哪種方式,都通過(guò)size元素來(lái)指定大小。定義完成后,name字段的變量即被分配相同大小的空間,圖5所示即為定長(zhǎng)元素的使用范例。
圖5 定長(zhǎng)元素用法示例
從圖5右邊的描述語(yǔ)句可看出,F(xiàn)ixed表示該語(yǔ)句描述的是定長(zhǎng)字段,byte表示以字節(jié)作單位,size=2表示讀取這個(gè)字段時(shí)將分配2個(gè)字節(jié)的長(zhǎng)度空間,最后將分配的字節(jié)空間給a1,并把該字段的值賦給a1。下面的Fixed-bit語(yǔ)句同理。另外還可通過(guò)Fixed-32bit、Fixed-4word變換后綴形式來(lái)指定基礎(chǔ)長(zhǎng)度。
2.2.2 變長(zhǎng)描述詞
變長(zhǎng)元素<variable>同樣必須具備名字以及長(zhǎng)度屬性,名字依然使用name表示,長(zhǎng)度通過(guò)length指定。變長(zhǎng)元素需要考慮的情況較多,表2總結(jié)了幾種常見(jiàn)的變長(zhǎng)表示方法。下面將分別舉例對(duì)每一種用法進(jìn)行介紹。
表2 變長(zhǎng)元素部分示例
(1)Runtime。
這里定義了一種變長(zhǎng)元素Runtime,它的長(zhǎng)度需要通過(guò)程序在運(yùn)行過(guò)程中計(jì)算獲取。其中frame是一個(gè)全局變量,它保存了在解析鏈路層時(shí)記錄的幀長(zhǎng),sizeof(frame)代表整個(gè)幀的長(zhǎng)度,offset代表當(dāng)前已解析部分的尾部指針,$offset則為當(dāng)前偏移量。在第二行語(yǔ)句中v2的長(zhǎng)度還需根據(jù)v1的長(zhǎng)度再次進(jìn)行運(yùn)算。
(2)Regular。
這里定義了一種通過(guò)正則表達(dá)式表示的變長(zhǎng)元素Regular,它首先通過(guò)相關(guān)的正則表達(dá)式函數(shù)庫(kù)對(duì)正則表達(dá)式進(jìn)行處理,之后再通過(guò)該表達(dá)式對(duì)變長(zhǎng)字段進(jìn)行匹配操作。類(lèi)似的需求有很多,比如在處理HTTP協(xié)議頭部第一行時(shí),會(huì)有如下字段:
GET http://www.aaa.com/index.html HTTP/1.1
此時(shí)通過(guò)以下代碼可將HTTP協(xié)議頭部的元素分離出來(lái):
其中“x20”是 ASCII碼[7]的空格,“x47”是反斜杠。經(jīng)過(guò)上述語(yǔ)句處理后,method中儲(chǔ)存“GET”,URL 中儲(chǔ)存“http://www.aaa.com/index.html”,proto中儲(chǔ)存“HTTP”,version中儲(chǔ)存“1.1”。
(3)Line。
這里定義了一種變長(zhǎng)元素Line,它會(huì)獲取直到下一個(gè)換行標(biāo)識(shí)符出現(xiàn)前的所有內(nèi)容。值得注意的是在不同的操作系統(tǒng)中換行標(biāo)識(shí)符也不同,比如Unix like操作系統(tǒng)[8]中是“ ”,而 Windows下是“ ”。
(4)Rest。
這里定義了一種變長(zhǎng)字段Rest,它對(duì)于處理報(bào)文頭部外負(fù)載部分的字段很有幫助,它會(huì)獲取從當(dāng)前指針開(kāi)始直到整個(gè)報(bào)文結(jié)束的全部?jī)?nèi)容。
(5)Token。
這里定義了2種帶標(biāo)記(token)的變長(zhǎng)元素Token以及Tokenbetween,在第一行語(yǔ)句的描述中,Token元素會(huì)獲取從當(dāng)前指針開(kāi)始直到token(x20,即空格)出現(xiàn)為止的字段,將它交給command;在下一行語(yǔ)句中,Tokenbetween則從當(dāng)前指針開(kāi)始查找3C即“<”符號(hào),之后找到3E,即“>”符號(hào),將這2個(gè)符號(hào)之中的內(nèi)容記錄下來(lái)交給Email。
(6)Custom。
這里定義了一種變長(zhǎng)元素Custom,它提供了一種自定義格式的方法,用戶可以根據(jù)自己的需求,對(duì)特殊的格式自由定義,以達(dá)到更好的處理效果。
2.3.1 Switch-case
報(bào)文解析的另一個(gè)難點(diǎn)是可選字段出現(xiàn)分支的處理問(wèn)題。針對(duì)此問(wèn)題,PDL使用條件判斷表達(dá)式進(jìn)行處理。根據(jù)一般高級(jí)程序語(yǔ)言的慣例,使用switchcase、if-else、loop即可描述所有情況。這里使用()表示判斷條件,使用{}表示對(duì)滿足條件所執(zhí)行的語(yǔ)句進(jìn)行的區(qū)域劃分,下面將分別舉例說(shuō)明。
圖6 Switch-case語(yǔ)句圖例
如圖6所示,當(dāng)文件讀到Switch這條語(yǔ)句時(shí),會(huì)根據(jù)之前ProtoType變量的值進(jìn)行分支處理,以便指定下一層(NextProto)是何種協(xié)議,其中“#”符號(hào)是PDL定義的一種特殊的表示協(xié)議類(lèi)型的符號(hào),用于協(xié)議定位。
2.3.2 if-else
圖7 if-else語(yǔ)句圖例
如圖7所示,當(dāng)執(zhí)行完語(yǔ)句A后,可能會(huì)有可選字段出現(xiàn),此時(shí)是否出現(xiàn)可選字段需要根據(jù)req字段的值來(lái)確定,當(dāng) req字段的值為“0x3333”或者“0x7777”時(shí),則會(huì)增加2個(gè)size為1的字段 code和stat。
2.3.3 循環(huán)語(yǔ)句
對(duì)于loop循環(huán)語(yǔ)句,首先需要確定一個(gè)截止條件比如運(yùn)行的次數(shù)或者截止的標(biāo)識(shí)符,另外需要使用類(lèi)似C語(yǔ)言中的break和continue做跳出處理,否則處理情況會(huì)變得十分復(fù)雜。
在解決了報(bào)文解析主要面臨的兩大問(wèn)題后,接下來(lái)需要對(duì)PDL的基本元素做一些定義。同一般高級(jí)語(yǔ)言的定義一樣,協(xié)議描述語(yǔ)言PDL主要包括數(shù)據(jù)類(lèi)型、變量、函數(shù)[9]以及操作符表達(dá)式(如表3所示)。
表3 操作符表項(xiàng)說(shuō)明
2.4.1 數(shù)據(jù)類(lèi)型
這里定義了3種基本數(shù)據(jù)類(lèi)型:數(shù)字型、內(nèi)存型(包括字符串)、協(xié)議型。
(1)數(shù)字型是最簡(jiǎn)單的數(shù)據(jù)類(lèi)型,所有可以運(yùn)算的數(shù)值都是數(shù)字型數(shù)據(jù)。
(2)內(nèi)存型數(shù)據(jù)也較為簡(jiǎn)單。在變量中直接儲(chǔ)存的原始協(xié)議字段數(shù)據(jù)即是內(nèi)存型數(shù)據(jù),如果它是字符串,那么可以直接使用,如果是數(shù)字且需要對(duì)數(shù)字進(jìn)行運(yùn)算,則需要使用如buf2int()這樣的函數(shù)將其轉(zhuǎn)換成數(shù)字型。
(3)協(xié)議型數(shù)據(jù)是一種PDL所特有的數(shù)據(jù)類(lèi)型,在圖6的例子中出現(xiàn)過(guò),其中的nextproto=“#tcp”,就是將TCP協(xié)議型數(shù)據(jù)變量賦予nextproto,使用“#”對(duì)協(xié)議型數(shù)據(jù)進(jìn)行標(biāo)識(shí)。處理完這層協(xié)議后,程序?qū)⒆詣?dòng)定位到TCP協(xié)議的描述模塊中,繼續(xù)對(duì)下一層協(xié)議進(jìn)行解析。
2.4.2 變量
變量使用“$”+“變量名”來(lái)表示,以下是一些預(yù)定義的變量。
$offset:記錄了整個(gè)報(bào)文偏移量,每次處理完一個(gè)新的字段,處理程序會(huì)馬上對(duì)此值進(jìn)行更新;
$protooffset:對(duì)于當(dāng)前協(xié)議的偏移量,一旦處理完一層新協(xié)議,則立即置0;
$linktype:記錄目前處理的包是屬于哪個(gè)鏈路層類(lèi)型,以便決定處理包的順序[10];
$prevproto:記錄了當(dāng)前協(xié)議所承載的上層協(xié)議;
$nextproto:記錄了當(dāng)前協(xié)議所包含的下層協(xié)議,該值只有在處理完當(dāng)前的協(xié)議層后才被記錄,因?yàn)闊o(wú)法在未處理前就知道下層的協(xié)議;
$timestamp:系統(tǒng)時(shí)間戳。
在一般的協(xié)議解析過(guò)程中,每一個(gè)字段都使用name對(duì)變量聲明,“name=”后的名稱即變量名,因此在同一個(gè)協(xié)議中,每一個(gè)名稱必須是唯一的。
對(duì)于非預(yù)定義或沒(méi)有在協(xié)議解析過(guò)程中出現(xiàn)的變量,可通過(guò)<Assign-variable>對(duì)變量進(jìn)行自定義。
自定義的變量必須使用size字段指定分配值的大小,使用value字段指定分配的初始值。
2.4.3 函數(shù)表達(dá)式
最后是函數(shù)部分,PDL需要內(nèi)置一些字符的處理及轉(zhuǎn)換函數(shù)輔助進(jìn)行操作。
buf2int():將buf變量轉(zhuǎn)換成整形變量;
int2buf():與上述相反;
ascii2int():將ASCII碼值轉(zhuǎn)換成整形變量;
changebyteorder():字節(jié)序反轉(zhuǎn),因?yàn)榫W(wǎng)絡(luò)協(xié)議一般都是網(wǎng)絡(luò)序的,一些X86等架構(gòu)的字節(jié)序與網(wǎng)絡(luò)序相反[11];
sizeof():取指定字段的長(zhǎng)度。
在設(shè)計(jì)好協(xié)議解析描述語(yǔ)言后,需要開(kāi)發(fā)一種協(xié)議解析引擎對(duì)協(xié)議解析描述語(yǔ)言進(jìn)行解釋。
圖8 協(xié)議解析器運(yùn)行流程
圖8所示是一種模塊化的協(xié)議解析引擎設(shè)計(jì)思路,其中上半部分完成協(xié)議描述語(yǔ)言數(shù)據(jù)庫(kù)的維護(hù)和協(xié)議規(guī)則的解析工作,并且提供了與數(shù)據(jù)包解析軟件的接口;下半部分接收相應(yīng)的數(shù)據(jù)包原始數(shù)據(jù)輸入。
第2節(jié)中涉及的協(xié)議描述語(yǔ)言PDL,通過(guò)XML等形式以在線或者離線的方式存儲(chǔ)于協(xié)議語(yǔ)言數(shù)據(jù)庫(kù)文件中。協(xié)議解析引擎首先初始化,檢查協(xié)議語(yǔ)言的格式,之后生成程序運(yùn)行所需要的全局變量,然后根據(jù)原始協(xié)議數(shù)據(jù)包中的數(shù)據(jù)查詢不同的協(xié)議解析規(guī)則進(jìn)行逐層解析,最后根據(jù)不同的協(xié)議類(lèi)型,按照協(xié)議數(shù)據(jù)庫(kù)文件中自定義的輸出格式進(jìn)行輸出。
IEC-104協(xié)議(以下簡(jiǎn)稱104協(xié)議)是電網(wǎng)調(diào)度自動(dòng)化系統(tǒng)中運(yùn)用最廣泛的協(xié)議之一。但目前對(duì)104協(xié)議的研究多以對(duì)協(xié)議本身的解釋為主,協(xié)議內(nèi)容的具體解析實(shí)現(xiàn)較少。在著名協(xié)議解析軟件Wireshark中也僅做到對(duì)104協(xié)議的識(shí)別,而無(wú)法對(duì)其具體內(nèi)容進(jìn)行解析。
圖9 IEC-104報(bào)文格式狀態(tài)轉(zhuǎn)換
通過(guò)對(duì)104協(xié)議報(bào)文的格式進(jìn)行分析,首先按圖9所示狀態(tài)設(shè)計(jì)出協(xié)議解析描述文件,之后加入?yún)f(xié)議數(shù)據(jù)庫(kù)文件中,使用該協(xié)議解析引擎對(duì)104報(bào)文的通信內(nèi)容進(jìn)行解析。
解析后的結(jié)果將生成一份概要解析文檔與一份詳細(xì)解析文檔,圖10和圖11就是針對(duì)104協(xié)議中某S 幀[12]的解析結(jié)果。
圖10 概要解析文檔部分輸出內(nèi)容
概要解析文檔的部分內(nèi)容如圖10所示。可以看出,這一文檔同描述語(yǔ)言一樣,由XML格式輸出,效率較高,它記錄了整個(gè)報(bào)文從物理層到應(yīng)用層的基本信息概況。
圖11 詳細(xì)解析文檔部分輸出內(nèi)容
詳細(xì)解析文檔的部分內(nèi)容如圖11所示。可以看出,這一文檔詳細(xì)分析了該104報(bào)文S幀的數(shù)據(jù),不僅記錄了十六進(jìn)制的原始數(shù)據(jù)字串,還對(duì)每個(gè)字段根據(jù)協(xié)議描述語(yǔ)言中自定義的輸出格式做了詳細(xì)描述。
本文設(shè)計(jì)了一種協(xié)議描述語(yǔ)言PDL,解決了協(xié)議分析時(shí)遇到的主要問(wèn)題,并定義了一般描述語(yǔ)言所必備的元素?;赑DL所開(kāi)發(fā)的協(xié)議解析器,經(jīng)過(guò)多種協(xié)議的測(cè)試驗(yàn)證,均可準(zhǔn)確解析,證明本文設(shè)計(jì)的協(xié)議描述語(yǔ)言PDL具有良好的適應(yīng)性及優(yōu)秀的擴(kuò)展性。今后,在PDL與協(xié)議解析引擎的交互問(wèn)題上,還需要進(jìn)一步地開(kāi)展研究和優(yōu)化。
:
[1]羅青林,徐克付,臧文羽,等.Wireshark環(huán)境下的網(wǎng)絡(luò)協(xié)議解析與驗(yàn)證方法[J].計(jì)算機(jī)工程與設(shè)計(jì),2011,32(3):700-704.
[2]李雪峰,張春芳.Wireshark網(wǎng)絡(luò)協(xié)議解析原理與新協(xié)議添加方法[J].軟件導(dǎo)刊,2011,10(12):105-107.
[3]閔捷峰.Lua腳本語(yǔ)言介紹[J].游戲創(chuàng)造,2007(8):18-20.
[4]董立,趙永恒.基于編譯技術(shù)的協(xié)議解析方法[J].計(jì)算機(jī)工程,2007,33(21):66-68.
[5]馮茜.基于MDA的UML狀態(tài)機(jī)代碼生成技術(shù)研究與實(shí)現(xiàn)[D].西安:西安電子科技大學(xué),2011.
[6]Risso F,Baldi M.NetPDL:An extensible XML-based language for packet header description[J].Computer Networks,2006,50(5):688-706.
[7]Maeda K.Comparative survey of object serialization techniques and the programming supports[J].通訊和計(jì)算機(jī):中英文版,2012,8(9):920-928.
[8]維基百科.類(lèi) Unix系統(tǒng)[EB/OL].http://zh.wikipedia.org/wik i/Unix-like,2013-09-27.
[9]王麗,劉劍.基于高級(jí)程序設(shè)計(jì)語(yǔ)言語(yǔ)句的語(yǔ)法分析器設(shè)計(jì)和實(shí)現(xiàn)[J].硅谷,2012(6):57-59.
[10]金麗君.基于數(shù)據(jù)鏈路層的包過(guò)濾及數(shù)據(jù)重組處理技術(shù)研究和應(yīng)用[D].蘇州:蘇州大學(xué),2012.
[11]維基百科.字節(jié)序[EB/OL].http://zh.Wikipedia.org/wiki/%E5%AD%97%E8%8A%82%E5%BA%8F,2013-11-27.
[12]DL/T634.5104-2009/IEC60870-5-104:2006,遠(yuǎn)動(dòng)設(shè)備及系統(tǒng)第5-104部分:傳輸規(guī)約采用標(biāo)準(zhǔn)傳輸協(xié)議子集IEC60870-5-101網(wǎng)絡(luò)訪問(wèn)[S].
[13]傅欽翠,陳劍云.基于FSM的IEC60870-5-104規(guī)約的實(shí)現(xiàn)[J].繼電器,2008,36(10):45-48.
[14]高占盈.應(yīng)用于協(xié)議棧開(kāi)發(fā)的狀態(tài)機(jī)生成器的設(shè)計(jì)與實(shí)現(xiàn)[D].西安:西安電子科技大學(xué),2010.