0 引言
當(dāng)前,國(guó)內(nèi)廠商對(duì)IEC 61850的開(kāi)發(fā)工作已經(jīng)從以制造報(bào)文規(guī)范(MMS)為核心的客戶/服務(wù)器(C/S)服務(wù)實(shí)現(xiàn)轉(zhuǎn)到面向通用對(duì)象的變電站事件(GOOSE)和IEC 61850-9-1/2的實(shí)現(xiàn)上來(lái)。GOOSE通信及其應(yīng)用是IEC 61850的一個(gè)亮點(diǎn),其出發(fā)點(diǎn)是功能的分布式實(shí)現(xiàn)口],GOOSE應(yīng)用的建立需要多方面配合,同時(shí)也是一個(gè)較為煩瑣的工程。在工程的調(diào)試過(guò)程中,對(duì)GOOSE報(bào)文的分析是一個(gè)必不可少的步驟,即檢查數(shù)據(jù)發(fā)送是否正確及其時(shí)間特性。因此,如果有一個(gè)簡(jiǎn)捷的工具來(lái)捕捉與分析IEC 61850報(bào)文,將會(huì)有助于工程調(diào)試的順利進(jìn)行。
WINPCAP(Windows packet capture)網(wǎng)絡(luò)開(kāi)發(fā)包是一個(gè)免費(fèi)、基于Windows平臺(tái)、訪問(wèn)網(wǎng)絡(luò)鏈路層的工業(yè)標(biāo)準(zhǔn)工具,它允許各種應(yīng)用程序繞過(guò)協(xié)議棧捕捉并傳送網(wǎng)絡(luò)數(shù)據(jù)包,同時(shí)還包括一些其他功能,如包過(guò)濾、網(wǎng)絡(luò)流量統(tǒng)計(jì)以及遠(yuǎn)程捕獲等?;谶@一開(kāi)發(fā)包,可以方便地開(kāi)發(fā)出GOOSE報(bào)文的捕捉工具,進(jìn)而根據(jù)ASN.1/BER對(duì)報(bào)文進(jìn)行解碼并分析。
本文介紹了如何基于WINPCAP開(kāi)發(fā)包開(kāi)發(fā)一個(gè)完整的GOOSE報(bào)文捕獲工具,以及整個(gè)設(shè)計(jì)思路和實(shí)現(xiàn)過(guò)程,并提出了一些可能的應(yīng)用。希望能夠?yàn)镮EC 61850標(biāo)準(zhǔn)在中國(guó)的推廣做出一些貢獻(xiàn)。
1 WINPCAP簡(jiǎn)介
1.1 內(nèi)部結(jié)構(gòu)
WINPCAP是一個(gè)Win32平臺(tái)下用于抓包和分析的系統(tǒng),其基本構(gòu)成如圖1所示。它包含一個(gè)運(yùn)行于操作系統(tǒng)內(nèi)核級(jí)的模塊,與網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)接口直接連接,這一模塊直接繞過(guò)了系統(tǒng)的協(xié)議棧。為了讓用戶程序使用內(nèi)核提供的功能,WINPCAP提供了多個(gè)編程接口分別封裝在2個(gè)不同的動(dòng)態(tài)鏈接庫(kù)packet.d11和wpcap.d11中。packet.dll提供一個(gè)底層的應(yīng)用程序接口(API),通過(guò)這個(gè)API可直接訪問(wèn)網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng),而獨(dú)立于Microsoft操作系統(tǒng);wpcap.dll是一個(gè)高層的強(qiáng)大捕獲程序庫(kù),與Unix下的libpcap兼容,它獨(dú)立于下層的網(wǎng)絡(luò)硬件和操作系統(tǒng)。
⑴通過(guò)接口函數(shù)pcap_findalldevs_ex枚舉所有可用的網(wǎng)絡(luò)設(shè)備。
⑵根據(jù)枚舉返回的網(wǎng)絡(luò)設(shè)備名稱打開(kāi)一個(gè)設(shè)備,對(duì)應(yīng)接口函數(shù)為pcap_open( )。
⑶如果需要,設(shè)置數(shù)據(jù)包的過(guò)濾條件,對(duì)應(yīng)接口函數(shù)為pcap_setfilter。
⑷捕獲原始的數(shù)據(jù)包,有2種方法:一種方法是以回調(diào)函數(shù)的方式由接口pcap_loop或pcap_dispatch完成,其基本方法是底層收集數(shù)據(jù)包,當(dāng)滿足一定的條件(timeout或者緩沖區(qū)滿),就調(diào)用回調(diào)函數(shù),把收集到的原始數(shù)據(jù)包通過(guò)數(shù)據(jù)緩存區(qū)交給用戶;另一種方法是pcap_next_ex( )的方法,每當(dāng)一個(gè)包到達(dá)以后,接口pcap_next_ex就會(huì)返回,返回的數(shù)據(jù)緩沖區(qū)中只包含一個(gè)包。
本文采用。pcap_next_ex的方法,并且設(shè)置了包過(guò)濾的條件,只捕獲類型為GOOSE的數(shù)據(jù)包,即EtherType為0x88的數(shù)據(jù)包。
2 程序設(shè)計(jì)與開(kāi)發(fā)
2.1 初始化
初始化工作包括2個(gè)部分:一是人機(jī)界面中協(xié)議數(shù)據(jù)單元(PDU)列表控件實(shí)例與GOOSE數(shù)據(jù)集列表控件實(shí)例的初始化,包括列名稱、列寬度等相關(guān)屬性;二是網(wǎng)絡(luò)設(shè)備的枚舉及顯示,枚舉可用設(shè)備的接口函數(shù)為pcap_findalldevs( ),調(diào)用方法如下:
If (pcap_findalldevs(&m_pAlldevs, errbuf)==-1) return FALSE;
如果成功地枚舉到可用的網(wǎng)絡(luò)設(shè)備,網(wǎng)絡(luò)設(shè)備的相關(guān)信息將返回到列表m_pAlldevs中,網(wǎng)絡(luò)設(shè)備的信息包括設(shè)備的唯一識(shí)別名稱及其可讀的描述內(nèi)容,然后將其顯示在一個(gè)下拉列表中供用戶選擇。
2.2 捕獲線程的建立和用戶的交互
網(wǎng)絡(luò)數(shù)據(jù)的捕獲需要為其單獨(dú)建立一個(gè)后臺(tái)工作線程。當(dāng)選定網(wǎng)絡(luò)設(shè)備后,點(diǎn)擊啟動(dòng)按鈕,就啟動(dòng)后臺(tái)工作線程。后臺(tái)工作線程與界面線程的交互通過(guò)消息機(jī)制來(lái)完成。在后臺(tái)工作線程中,首先通過(guò)接口函數(shù)pcap_open_live打開(kāi)網(wǎng)絡(luò)接口設(shè)備,然后調(diào)用接口函數(shù)pcap_next_ex啟動(dòng)網(wǎng)絡(luò)數(shù)據(jù)的捕捉。每當(dāng)捕捉到一個(gè)數(shù)據(jù)包時(shí),接口函數(shù)pcap_next_ex就會(huì)返回,然后啟動(dòng)一個(gè)GOOSE報(bào)文過(guò)濾機(jī)制,如果報(bào)文類型EtherType為0x88B8,則通過(guò)消息將數(shù)據(jù)回傳給界面線程。界面線程然后解碼,并將每一個(gè)捕獲到的GOOSE報(bào)文顯示到一個(gè)列表中。此時(shí),如果用戶點(diǎn)擊此條報(bào)文,系統(tǒng)將自動(dòng)將應(yīng)用協(xié)議數(shù)據(jù)單元(APDU)從報(bào)文中分離并解析,然后分別顯示。APDU的頭信息顯示在一個(gè)文本編輯框中,數(shù)據(jù)集的每一項(xiàng)單獨(dú)顯示在一個(gè)列表中。圖2顯示了程序的主要工作序列。
在后臺(tái)工作線程捕獲數(shù)據(jù)并回傳給界面線程時(shí),界面線程依照標(biāo)準(zhǔn)定義進(jìn)行解碼。圖3詳細(xì)描述了GOOSE PDU的構(gòu)成。本文采用面向?qū)ο蟮姆椒ǘx了3個(gè)數(shù)據(jù)結(jié)構(gòu),分別對(duì)應(yīng)不同層次的數(shù)據(jù)內(nèi)容。
對(duì)于ISO/IEC 8802-3幀結(jié)構(gòu),其幀頭部分長(zhǎng)度固定,通過(guò)一個(gè)結(jié)構(gòu)與其對(duì)應(yīng),其定義如下:
struct GOOSEFrame_Header //Byte Length 26
{
BYTE DMac[6];
BYTE SMac[6];
WORD TPID;
WORD TCI;
WORD Ethertype;
WORD APPID;
WORD Length;
WORD Reserved1;
WORD Reserved2;
struct GOOSEAPDU_Info
{
int iLength;
CString gocbRef;
int timeAllowedtoLive;
CString datSet;
CString goID;
CString t;
int stNum;
int sqNum;
BOOL test;
int confRev;
BOOL ndsCom;
int numDatSetEntries;
CList<DataSetEntry_Info, DataSetEntry_Info&>DataSetEntryList
}
對(duì)于數(shù)據(jù)集成員的信息,使用了模板類CList來(lái)保存數(shù)據(jù)集成員的信息,動(dòng)態(tài)分配內(nèi)存。其中,數(shù)據(jù)集部分的定義如下:
struct DataSetEntry_Info
{
int iIndex;
CString sType;
CString sValue;
CString sNote;
}
2.4 解碼與分析
幀頭部分的數(shù)據(jù)長(zhǎng)度固定,因而可以很容易地進(jìn)行解析并保存到結(jié)構(gòu)GOOSEFrame_Header的一個(gè)實(shí)例中。其中,幀頭中前12個(gè)字節(jié)依次與目標(biāo)媒體訪問(wèn)控制(MAC)地址和源MAC地址對(duì)應(yīng)。對(duì)于虛擬局域網(wǎng)(VLAN)部分,程序增加了有無(wú)VLAN標(biāo)志的自動(dòng)識(shí)別,不同的交換機(jī)對(duì)VLAN的處理不同,一些交換機(jī)會(huì)去掉VLAN標(biāo)識(shí),當(dāng)報(bào)文經(jīng)過(guò)交換機(jī)到達(dá)計(jì)算機(jī)的網(wǎng)絡(luò)端口時(shí),TPID與TCI標(biāo)志已經(jīng)由交換機(jī)去掉了;一些交換機(jī)會(huì)保留TPID與TCI標(biāo)志。
此外,還增加了一些相應(yīng)的可讀化功能,如源MAC地址的解析,直接將其轉(zhuǎn)換為IP地址或IED名稱,便于分析數(shù)據(jù)。
2.4.2 APDU的處理
如圖3所示,APDU依照TLV規(guī)則構(gòu)成。本文以一段代碼來(lái)說(shuō)明如何有效地進(jìn)行解碼。這里iIndex是指向pAPDUBufer緩存區(qū)當(dāng)前位置的一個(gè)索引,每解析一個(gè)字段信息,位置索引將自動(dòng)移到下一個(gè)字段的開(kāi)始。
//datSet
iIndex=iIndex+iLength+2;
iLength=pAPDUBufer[iIndex+1]; //length
for(i=0; i<iLength; i++) //value
sTemp[i]=pAPDUBufer[iIndex+2+i];
sTemp[i]=’\0’;
pAPDU→datSet=sTemp;
//goID
iIndex=iIndex+iLength+2;
iLength=pAPDUBufer[iIndex+1]; //length
for(i=0; i<iLength; i++) //value
sTemp[i]=pAPDUBufer[iIndex+2+i];
sTemp[i]=’\0’;
pAPDU→goID=sTemp;
2.4.3 數(shù)據(jù)集的解析
在數(shù)據(jù)集中,其成員的類型定義是多樣的,因而,在解析其成員數(shù)據(jù)時(shí)就需要判別Tag的值并分別處理,部分代碼如下:
switch(pDataSet[iIndex])
{
case 0x83: //boolean
Entry.sType=”BOOLEAN”;
iLength=pDataSet[ilndex+1];
if(pDataSet[iIndex+2]==0)
Entry.sValue=”FALSE”;
else
Entry.sValue=”TRUE”;
iIndex=iIndex+iLength+1:
Entry.sNote.Format(”Length:%d”, iLength);
break;
case 0x84: //bitstring
Entry.sType=”BITSTRING”;
iLength=pDataSet[iIndex+1]-1;
...
break;
⑴互斥量的使用
多線程編程需要注意的一個(gè)問(wèn)題是要嚴(yán)格避免多個(gè)線程同時(shí)對(duì)一個(gè)變量進(jìn)行訪問(wèn)。本系統(tǒng)中,后臺(tái)工作線程的終止是通過(guò)檢查一個(gè)標(biāo)志位m_bThreadStop的狀態(tài)來(lái)判斷是否要停止。如果界面線程給m_bThreadStop賦值為true,工作線程將退出運(yùn)行。后臺(tái)工作線程在每完成一次pcap_next_ex后檢查其值是否為true。然而,如果兩個(gè)線程同時(shí)對(duì)一個(gè)變量進(jìn)行訪問(wèn)并控制,可能會(huì)發(fā)生系統(tǒng)崩潰,因而要嚴(yán)格保證在任何時(shí)刻只能有一個(gè)訪問(wèn)。因此,程序利用了Windows系統(tǒng)的互斥量來(lái)實(shí)現(xiàn)互斥訪問(wèn),在界面線程和工作線程對(duì)其讀取或操作前,都需要通過(guò)一個(gè)臨界量來(lái)保證互斥操作,嚴(yán)格保證對(duì)m_bThreadStop的任何操作都在一個(gè)臨界區(qū)內(nèi)進(jìn)行,其代碼如下:
EnterCriticalSection(&m_csThreadStop)
m_bThreadStop=true
LeaveCriticalSection(&m_csThreadStop)
⑵人機(jī)界面
良好的人機(jī)界面設(shè)計(jì)是必不可少的。程序啟動(dòng)后自動(dòng)枚舉所有可用的網(wǎng)絡(luò)設(shè)備供用戶選擇,用戶通過(guò)下拉列表來(lái)選擇相應(yīng)的網(wǎng)卡,然后點(diǎn)擊開(kāi)始即可。此時(shí)開(kāi)始按鈕變?yōu)橥V拱粹o,如果要停止捕獲,點(diǎn)擊同一按鈕。對(duì)于捕獲到的GOOSE報(bào)文,在報(bào)文列表中直接點(diǎn)擊,對(duì)應(yīng)的解析將自動(dòng)完成并顯示在下部的文本框和列表中,文本框中顯示的是GOOSE報(bào)文的描述信息,對(duì)于數(shù)據(jù)集的內(nèi)容將單獨(dú)顯示在一個(gè)列表中。在界面的最底部是其他幾個(gè)輔助功能,如保存當(dāng)前捕獲的報(bào)文或者是打開(kāi)以往保存的報(bào)文。報(bào)文保存文件格式與其他捕捉工具兼容,本工具也可以打開(kāi)其他基于WINPCAP開(kāi)發(fā)的報(bào)文捕捉工具,如Ethereal保存的記錄文件。
3 結(jié)語(yǔ)
在一個(gè)基于IEC 61850通信的變電站自動(dòng)化系統(tǒng)中,WINPCAP有很大的用途?;赪INPCAP開(kāi)發(fā)包可以開(kāi)發(fā)出許多實(shí)用的工具。如下幾點(diǎn)應(yīng)用非常有實(shí)用價(jià)值:
⑴網(wǎng)絡(luò)流量日志?;贗EC 61850的變電站自動(dòng)化系統(tǒng)中,通信極為重要,在一些情況下,可能會(huì)發(fā)生網(wǎng)絡(luò)堵塞或中斷,或者是當(dāng)通過(guò)GOOSE信號(hào)跳閘,這時(shí)一個(gè)類似變電站故障錄波裝置的網(wǎng)路日志記錄工具就非常有應(yīng)用價(jià)值,它可以設(shè)計(jì)成實(shí)時(shí)捕捉網(wǎng)路報(bào)文并自動(dòng)存儲(chǔ)。當(dāng)網(wǎng)絡(luò)發(fā)生堵塞或其他問(wèn)題時(shí),可以調(diào)取日志用于事故的分析和診斷。
⑵GOOSE源仿真器。它可以依據(jù)配置SCL文件自動(dòng)生成GOOSE模型并發(fā)出GOOSE報(bào)文。這些報(bào)文直接繞過(guò)了協(xié)議棧,因而可以較容易實(shí)現(xiàn)。這一仿真器可以在設(shè)備的出廠測(cè)試中來(lái)驗(yàn)證相應(yīng)的功能是否正確等,以及進(jìn)行網(wǎng)絡(luò)流量仿真測(cè)試等。
⑶GOOSE數(shù)據(jù)分析??梢詫?duì)同一GOOSE源的報(bào)文建立時(shí)間軸,縱向比較數(shù)據(jù)的變化及其時(shí)標(biāo);可以檢測(cè)分析IED物理模型的變化及通過(guò)時(shí)標(biāo)來(lái)驗(yàn)證其時(shí)間響應(yīng)特性。
另外,GOOSE報(bào)文完全是明文傳輸,沒(méi)有任何加密,因而存在很大的安全隱患。盡管GOOSE通過(guò)一些措施來(lái)檢查其有效性,如序列號(hào),然而,非法用戶可以很容易截獲報(bào)文,然后騙過(guò)這一檢查來(lái)篡改相關(guān)數(shù)據(jù)值并重發(fā),因而必須考慮其安全問(wèn)題,對(duì)此需要深入研究。
與本文類似的商業(yè)報(bào)文捕捉軟件有很多,如Ethereal、Unica等。與本軟件相比,這些軟件的功能強(qiáng)大得多,也很成熟。本文試圖通過(guò)這個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明2個(gè)問(wèn)題:一是如何基于WINPCAP包開(kāi)發(fā)報(bào)文捕捉與應(yīng)用工具;二是如何根據(jù)標(biāo)準(zhǔn)定義對(duì)GOOSE報(bào)文進(jìn)行解碼并引出如上所述的其他GOOSE工具的開(kāi)發(fā)。解碼的過(guò)程也是一個(gè)很好的學(xué)習(xí)ASN.1與BER的過(guò)程。希望本文能夠促進(jìn)GOOSE應(yīng)用的開(kāi)發(fā)。
聯(lián)系客服