俞 皓,黄益彬
(国网电力科学研究院,江苏 南京 211106)
协议解析技术是网络开发及应用中的关键技术之一。目前业界协议解析软件种类繁多,如Wildpackets、Wireshark[1-2](前身 Ethereal)等,这类软件能够支持绝大多数常用协议的解析,但如果遇到自定义协议或者新协议时,则无法正常解析。少量解析软件可通过其自带的插件[3]进行新协议的注册及处理(如图1所示),或者提供二次编程接口进行新协议的定制开发,但由于涉及软件代码的复杂性,其开发难度大,难以轻松扩展。本文通过设计一种基于协议描述语言的协议解析方法,大幅降低了协议添加的难度,使得新协议可以方便扩展。
图1 一般软件的新协议添加流程
网络协议由多个层次构成,每一层的解析需要3个元素:(1)指向协议头的头部指针;(2)该层协议的长度,包括头部(head)与负载(payload)部分;(3)标明下一层协议的类型(最上层除外)。
对于每一层协议而言,解析的方法基本类同。首先读取一定长度的数据字段得到数据内容;之后,或是继续进行同样的操作(所取的长度可不同),或是需要根据上一步得到的数据值,决定对后续的字段进行何种操作;最后依次循环直到读取至整个报文的结尾为止[4]。
协议解析的方式存在上述固定模式,一般情况下,可以通过某种方式对其进行循环解析。但由于协议种类数量庞大,且每一种协议都有自身的特殊性,其协议头部长度并不固定,多数需要通过其中一些域的值来进一步确定是否有其它数据选项,实际编写时需要考虑的因素过多,无法用简单的通用方式实现循环解析。
针对1.1节描述的问题,解决思路是,通过定义一种协议描述语言PDL(Protocol Description Language),将协议格式以及内容按照定义好的格式描述出来,并开发一种对PDL的协议解析引擎,则可对相应协议进行解析。对于一个新的自定义协议,仅需通过PDL进行描述,即可完成对此新协议的解析工作(如图2所示),如果描述语言的定义简单清晰,则新协议的添加工作将大幅简化,同时有利于代码的自动生成[5-6]。
图2 使用协议描述语言时新协议的添加
对于一个报文的解析,可以看作是对一个字段集合S的解析。首先将S分解为子字段S1,S2,S3,…,Sn,设S的总长为L,对于任意给定的子字段Si,只要确定每一段的长度Li,就可按照Li的值逐段解析。值得注意的是,Li的长度并不都是定长,有可能是变长;另外根据Si的不同取值,可能会出现可选数据字段 Si-j,如图 3 所示。
图3 报文解析遇到的问题
通过对上述报文解析过程的分析,可以看出报文解析主要面临2个问题,其一是数据字段变长的表示问题;其二是可选字段出现分支的问题。PDL重点解决上述2个问题,并对整个描述语言的基本元素做相应定义。
鉴于XML文本格式的扩展性与泛用性,以下使用XML格式对协议描述语言进行描述。
如图4所示,PDL文件需要先定义根节点<PDL>,用于描述版本信息。根节点以下是所有的协议节点<protocol>,在每一个协议中用<format>节点描述协议报文格式,完成对协议的解析。
图4 PDL结构图
对于每一个报文的解析流程为:根据实际报文内容,从物理层的某个<protocol>节点开始逐层解析,通过<format>节点中的字段值获取下一层的协议种类,根据取得的协议种类跳转到下一层的<protocol>节点,继续解析,直至报文结束。
2.2.1 定长描述词
报文解析最大的难点之一是数据字段变长时长度的处理问题。针对此问题,PDL在<format>节点中定义2类元素:定长元素<fixed>类,如表1所示;变长元素<variable>类,如表2所示。
表1 定长元素部分示例
定长元素<fixed>必须具备的属性有名字和长度,其中名字通过name元素进行唯一标识,长度拥有多种处理方式,其一是以字节(byte)作单位,其二是以位(bit)作单位,无论哪种方式,都通过size元素来指定大小。定义完成后,name字段的变量即被分配相同大小的空间,图5所示即为定长元素的使用范例。
图5 定长元素用法示例
从图5右边的描述语句可看出,Fixed表示该语句描述的是定长字段,byte表示以字节作单位,size=2表示读取这个字段时将分配2个字节的长度空间,最后将分配的字节空间给a1,并把该字段的值赋给a1。下面的Fixed-bit语句同理。另外还可通过Fixed-32bit、Fixed-4word变换后缀形式来指定基础长度。
2.2.2 变长描述词
变长元素<variable>同样必须具备名字以及长度属性,名字依然使用name表示,长度通过length指定。变长元素需要考虑的情况较多,表2总结了几种常见的变长表示方法。下面将分别举例对每一种用法进行介绍。
表2 变长元素部分示例
(1)Runtime。
这里定义了一种变长元素Runtime,它的长度需要通过程序在运行过程中计算获取。其中frame是一个全局变量,它保存了在解析链路层时记录的帧长,sizeof(frame)代表整个帧的长度,offset代表当前已解析部分的尾部指针,$offset则为当前偏移量。在第二行语句中v2的长度还需根据v1的长度再次进行运算。
(2)Regular。
这里定义了一种通过正则表达式表示的变长元素Regular,它首先通过相关的正则表达式函数库对正则表达式进行处理,之后再通过该表达式对变长字段进行匹配操作。类似的需求有很多,比如在处理HTTP协议头部第一行时,会有如下字段:
GET http://www.aaa.com/index.html HTTP/1.1
此时通过以下代码可将HTTP协议头部的元素分离出来:
其中“x20”是 ASCII码[7]的空格,“x47”是反斜杠。经过上述语句处理后,method中储存“GET”,URL 中储存“http://www.aaa.com/index.html”,proto中储存“HTTP”,version中储存“1.1”。
(3)Line。
这里定义了一种变长元素Line,它会获取直到下一个换行标识符出现前的所有内容。值得注意的是在不同的操作系统中换行标识符也不同,比如Unix like操作系统[8]中是“ ”,而 Windows下是“ ”。
(4)Rest。
这里定义了一种变长字段Rest,它对于处理报文头部外负载部分的字段很有帮助,它会获取从当前指针开始直到整个报文结束的全部内容。
(5)Token。
这里定义了2种带标记(token)的变长元素Token以及Tokenbetween,在第一行语句的描述中,Token元素会获取从当前指针开始直到token(x20,即空格)出现为止的字段,将它交给command;在下一行语句中,Tokenbetween则从当前指针开始查找3C即“<”符号,之后找到3E,即“>”符号,将这2个符号之中的内容记录下来交给Email。
(6)Custom。
这里定义了一种变长元素Custom,它提供了一种自定义格式的方法,用户可以根据自己的需求,对特殊的格式自由定义,以达到更好的处理效果。
2.3.1 Switch-case
报文解析的另一个难点是可选字段出现分支的处理问题。针对此问题,PDL使用条件判断表达式进行处理。根据一般高级程序语言的惯例,使用switchcase、if-else、loop即可描述所有情况。这里使用()表示判断条件,使用{}表示对满足条件所执行的语句进行的区域划分,下面将分别举例说明。
图6 Switch-case语句图例
如图6所示,当文件读到Switch这条语句时,会根据之前ProtoType变量的值进行分支处理,以便指定下一层(NextProto)是何种协议,其中“#”符号是PDL定义的一种特殊的表示协议类型的符号,用于协议定位。
2.3.2 if-else
图7 if-else语句图例
如图7所示,当执行完语句A后,可能会有可选字段出现,此时是否出现可选字段需要根据req字段的值来确定,当 req字段的值为“0x3333”或者“0x7777”时,则会增加2个size为1的字段 code和stat。
2.3.3 循环语句
对于loop循环语句,首先需要确定一个截止条件比如运行的次数或者截止的标识符,另外需要使用类似C语言中的break和continue做跳出处理,否则处理情况会变得十分复杂。
在解决了报文解析主要面临的两大问题后,接下来需要对PDL的基本元素做一些定义。同一般高级语言的定义一样,协议描述语言PDL主要包括数据类型、变量、函数[9]以及操作符表达式(如表3所示)。
表3 操作符表项说明
2.4.1 数据类型
这里定义了3种基本数据类型:数字型、内存型(包括字符串)、协议型。
(1)数字型是最简单的数据类型,所有可以运算的数值都是数字型数据。
(2)内存型数据也较为简单。在变量中直接储存的原始协议字段数据即是内存型数据,如果它是字符串,那么可以直接使用,如果是数字且需要对数字进行运算,则需要使用如buf2int()这样的函数将其转换成数字型。
(3)协议型数据是一种PDL所特有的数据类型,在图6的例子中出现过,其中的nextproto=“#tcp”,就是将TCP协议型数据变量赋予nextproto,使用“#”对协议型数据进行标识。处理完这层协议后,程序将自动定位到TCP协议的描述模块中,继续对下一层协议进行解析。
2.4.2 变量
变量使用“$”+“变量名”来表示,以下是一些预定义的变量。
$offset:记录了整个报文偏移量,每次处理完一个新的字段,处理程序会马上对此值进行更新;
$protooffset:对于当前协议的偏移量,一旦处理完一层新协议,则立即置0;
$linktype:记录目前处理的包是属于哪个链路层类型,以便决定处理包的顺序[10];
$prevproto:记录了当前协议所承载的上层协议;
$nextproto:记录了当前协议所包含的下层协议,该值只有在处理完当前的协议层后才被记录,因为无法在未处理前就知道下层的协议;
$timestamp:系统时间戳。
在一般的协议解析过程中,每一个字段都使用name对变量声明,“name=”后的名称即变量名,因此在同一个协议中,每一个名称必须是唯一的。
对于非预定义或没有在协议解析过程中出现的变量,可通过<Assign-variable>对变量进行自定义。
自定义的变量必须使用size字段指定分配值的大小,使用value字段指定分配的初始值。
2.4.3 函数表达式
最后是函数部分,PDL需要内置一些字符的处理及转换函数辅助进行操作。
buf2int():将buf变量转换成整形变量;
int2buf():与上述相反;
ascii2int():将ASCII码值转换成整形变量;
changebyteorder():字节序反转,因为网络协议一般都是网络序的,一些X86等架构的字节序与网络序相反[11];
sizeof():取指定字段的长度。
在设计好协议解析描述语言后,需要开发一种协议解析引擎对协议解析描述语言进行解释。
图8 协议解析器运行流程
图8所示是一种模块化的协议解析引擎设计思路,其中上半部分完成协议描述语言数据库的维护和协议规则的解析工作,并且提供了与数据包解析软件的接口;下半部分接收相应的数据包原始数据输入。
第2节中涉及的协议描述语言PDL,通过XML等形式以在线或者离线的方式存储于协议语言数据库文件中。协议解析引擎首先初始化,检查协议语言的格式,之后生成程序运行所需要的全局变量,然后根据原始协议数据包中的数据查询不同的协议解析规则进行逐层解析,最后根据不同的协议类型,按照协议数据库文件中自定义的输出格式进行输出。
IEC-104协议(以下简称104协议)是电网调度自动化系统中运用最广泛的协议之一。但目前对104协议的研究多以对协议本身的解释为主,协议内容的具体解析实现较少。在著名协议解析软件Wireshark中也仅做到对104协议的识别,而无法对其具体内容进行解析。
图9 IEC-104报文格式状态转换
通过对104协议报文的格式进行分析,首先按图9所示状态设计出协议解析描述文件,之后加入协议数据库文件中,使用该协议解析引擎对104报文的通信内容进行解析。
解析后的结果将生成一份概要解析文档与一份详细解析文档,图10和图11就是针对104协议中某S 帧[12]的解析结果。
图10 概要解析文档部分输出内容
概要解析文档的部分内容如图10所示。可以看出,这一文档同描述语言一样,由XML格式输出,效率较高,它记录了整个报文从物理层到应用层的基本信息概况。
图11 详细解析文档部分输出内容
详细解析文档的部分内容如图11所示。可以看出,这一文档详细分析了该104报文S帧的数据,不仅记录了十六进制的原始数据字串,还对每个字段根据协议描述语言中自定义的输出格式做了详细描述。
本文设计了一种协议描述语言PDL,解决了协议分析时遇到的主要问题,并定义了一般描述语言所必备的元素。基于PDL所开发的协议解析器,经过多种协议的测试验证,均可准确解析,证明本文设计的协议描述语言PDL具有良好的适应性及优秀的扩展性。今后,在PDL与协议解析引擎的交互问题上,还需要进一步地开展研究和优化。
:
[1]罗青林,徐克付,臧文羽,等.Wireshark环境下的网络协议解析与验证方法[J].计算机工程与设计,2011,32(3):700-704.
[2]李雪峰,张春芳.Wireshark网络协议解析原理与新协议添加方法[J].软件导刊,2011,10(12):105-107.
[3]闵捷峰.Lua脚本语言介绍[J].游戏创造,2007(8):18-20.
[4]董立,赵永恒.基于编译技术的协议解析方法[J].计算机工程,2007,33(21):66-68.
[5]冯茜.基于MDA的UML状态机代码生成技术研究与实现[D].西安:西安电子科技大学,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].通讯和计算机:中英文版,2012,8(9):920-928.
[8]维基百科.类 Unix系统[EB/OL].http://zh.wikipedia.org/wik i/Unix-like,2013-09-27.
[9]王丽,刘剑.基于高级程序设计语言语句的语法分析器设计和实现[J].硅谷,2012(6):57-59.
[10]金丽君.基于数据链路层的包过滤及数据重组处理技术研究和应用[D].苏州:苏州大学,2012.
[11]维基百科.字节序[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,远动设备及系统第5-104部分:传输规约采用标准传输协议子集IEC60870-5-101网络访问[S].
[13]傅钦翠,陈剑云.基于FSM的IEC60870-5-104规约的实现[J].继电器,2008,36(10):45-48.
[14]高占盈.应用于协议栈开发的状态机生成器的设计与实现[D].西安:西安电子科技大学,2010.