发明内容
本发明的目的在于克服现有技术中所存在的数据包解析系统扩展性较差的不足,提供一种可提高扩展性的网络数据包解析方法。
为了实现上述发明目的,本发明提供了以下技术方案:
一种网络数据包解析方法,包括如下步骤:
1)、根据协议的协议结构,生成所述协议的协议脚本,并存储;
2)、根据协议脚本生成语句表和逻辑树;
3)、载入待解析的数据包,获取待解析的数据包的协议名称,根据协议名称查找相应的协议脚本,并获取相应的语句表和逻辑树,对待解析的数据包进行解析,输出解析结果。
根据本发明实施例,所述步骤1)中生成协议脚本的方法是:按照协议结构中各字段的顺序,将各字段的属性载入协议脚本中。
进一步的,所述协议脚本中的每条语句由语句类型关键字和语句属性组成,所述语句类型关键字表明语句的类型,语句属性为各字段的属性,所述语句的类型包括字段描述语句、判断语句和循环语句,所述判断语句包括if、elseif、else和endif语句,所述循环语句包括do和while语句。
根据本发明实施例,所述步骤2)中生成语句表的方法是:
2-11):根据协议脚本中语句的语句类型关键字确定语句的类型;
2-12):取得语句中的各个属性,并存储在对应的语句类中,然后将该语句类记录到语句表中,并对语句类进行编号。一个语句类对应协议脚本中的一行语句,即一个语句类存储一条语句中所有的属性,语句表由多个语句类组成,一个语句类占语句表的一行。
根据本发明实施例,所述步骤2)中生成逻辑树的方法是:从语句表头至语句表尾,顺序扫描语句表,对语句表中的判断语句和循环语句进行分析,确定判断语句的执行顺序和对应的执行条件,确定循环语句的循环体和循环条件,建立所述逻辑树。
进一步的,生成逻辑树包括步骤:
2-21):扫描整个语句表,按照单一语句块、判断语句块和循环语句块三种语句块类型,将整个语句表分解为若干个语句块B1,B2,…,Bn,n为自然数;
2-22):将若干个语句块B1,B2,…,Bn中的每一个语句块存储到逻辑树的根节点下。
2-23):将若干个语句块B1,B2,…,Bn中的判断语句块和循环语句块分解成单一类型的语句块,然后将每一个单一类型的语句块存储到逻辑树相应的子节点下,完成逻辑树建立;
其中,若一段连续的语句不包括if、elseif、else和endif语句,也不包括do和while语句,则称这个语句块为单一语句块;判断语句块为:if语句和对应的endif语句,以及之间包含的一段连续的语句,称为判断语句块;do语句和对应的while语句,以及之间包含的一段连续语句,称为循环语句块。
进一步的,所述步骤2-23)将若干个语句块B1,B2,…,Bn中的判断语句块和循环语句块分解成单一类型的语句块,然后将每一个单一类型的语句块存储到逻辑树相应的子节点下,方法是:
2-23-1):对于判断语句块,则以最外层if语句、elseif语句、else语句和endif语句为分隔符,将该判断语句块中所有的语句分解成若干个带执行条件的子语句块,并将所述若干个带执行条件的语句块存储到该判断语句块的子节点下,且将各自的判断条件也存储在该子节点下;
对于循环语句块,则将do语句和while语句之间的语句作为一个带循环条件的语句块,并将所述带循环条件的语句块存储到该循环语句块的子节点下,同时将循环条件也存储在该子节点下;
2-23-2):将经过步骤2-23-1)分解后的语句块中不是单一类型的语句块,按照单一语句块、判断语句块和循环语句块三种类型进行分解,将分解得到的语句块存储在分解前相应语句块的子节点下;
2-23-3):循环步骤2-23-1)至2-23-2),直到逻辑树中的每一个叶子节点中的语句块都为单一语句块。
根据本发明实施例,所述步骤3)中,获取待解析的数据包中每层协议的协议名称,查找各协议的协议脚本,并获取所述协议的语句表和逻辑树。
根据本发明实施例,所述步骤3)中,对待解析的数据包进行解析的方法是:从逻辑树的根节点开始,顺序进入各个子节点,根据子节点中的判断条件和循环条件,确定语句的执行顺序,并从语句表中获取语句的各个属性,然后根据语句的各个属性从数据包中取出相应的数据,获取数据包的各字段解码。
进一步的,顺序进入各个子节点,获取当前子节点中的各个语句块的语句块信息,本步骤中,
B-1:若语句块为单一语句块,则根据语句块中的各条语句的编号,顺序地从语句表中取得各条语句相应的各个属性,然后根据各条语句的各个属性从数据包中取出相应的数据,获取数据包的各字段解码;
B-2:若语句块为判断语句块,则对该子节点中存储的各个语句块的判断条件进行判定,第一个满足条件的语句块即为当前应该执行的语句块,再根据此语句块的类型执行B-1或B-2或B-3;
B-3:若语句块为循环语句块,则首先执行该语句块中的语句,然后判断语句块中存储的循环条件是否满足,若满足则再次执行该语句块的子节点中的语句块中的语句,直到循环条件不满足为止。此处所述执行语句块中的语句的含义是,根据此语句块的类型执行B-1或B-2或B-3。
每种类型的语句都定义了对应的操作函数,根据取得的语句的类型,调用对应的操作函数,根据语句的各个属性即可从数据包中取得不同长度的数据,获取数据包的具体字段解码。
与现有技术相比,本发明的有益效果:
1、本发明网络数据包解析方法,首先根据协议的协议结构生成协议脚本,再根据协议脚本生成语句表和逻辑树,最后利用语句表和逻辑树对数据包进解析。添加新协议的解码时只需要添加新协议的协议脚本,而协议脚本的添加不必需要专业的程序员执行,任何了解新协议的协议名称和协议结构的普通用户都可完成新协议的添加,新协议添加方便,扩展性强。
2、通过私有协议用户书写私有协议的协议脚本,本发明方法可以完成私有协议数据包解析。由于协议脚本中对于私有协议的协议结构进行了详细的说明,在解析私有协议数据包时,只需要根据语句表中各语句的属性,从数据包中对应的位置获取数据,即可完成私有协议数据包解析。
具体实施方式
下面结合试验例及具体实施方式对本发明作进一步的详细描述。但不应将此理解为本发明上述主题的范围仅限于以下的实施例,凡基于本发明内容所实现的技术均属于本发明的范围。
参考图1,本发明提供的一种网络数据包解析方法,包括步骤:
S100:根据协议的协议结构生成相应的协议脚本,所述协议的协议结构即是指遵循该协议传输的数据包的头部结构,所述协议脚本中包括协议名称和协议结构。
本步骤中,所述协议脚本由多条语句组成,一条语句为一行,每条语句由语句类型关键字和语句属性组成。语句类型关键字表明了协议脚本中各语句的类型,协议脚本中语句的类型包括protocol语句、#语句、comment语句等,如表1所示。不同类型语句的语句属性不同,例如,字段描述语句(即#语句),语句属性为数据包头部结构中各字段的属性,数据包头部结构中各字段的属性包括字段名、字段显示名、字段长度(所述字段长度表明该字段在数据包中的长度)和类型。又例如,move语句,语句属性为移动的字节数。协议脚本中第一行语句为协议名称描述语句,然后按照数据包头部结构中各字段的顺序,将各字段的属性载入协议脚本中。
表1
例如,IPv6协议的协议脚本中的前两行语句为:
[protocol:IPv6]
#version,"版本[Version]:",1:0:4,netdec
其中,第一语句行中“protocol”为语句类型关键字,“IPv6”为协议名称。第二行语句中“#”为语句类型关键字,“Version”为字段名,“版本[Version]:”为字段显示名,“1:0:4”为字段长度,即数据包中第一个字节的头四位,“netdec”为类型,即十进制整数。
S200:将生成的每个协议的协议脚本解析为语句表和逻辑树,并存储;
S300:传入待解析的数据包,获取数据包的协议名称,然后在已存储的所有协议脚本中查找该协议的协议脚本,并获取该协议的语句表和逻辑树,对数据包进行解析;
S400:输出解析结果。
参考图2,所述步骤S200中将生成的每个协议的协议脚本解析为语句表和逻辑树,并存储的操作包括步骤:
S201:读取第一个协议脚本。
S202:解析当前协议脚本,包括步骤:
ⅰ:读取协议脚本中的第一条语句。
ⅱ:根据当前语句中的语句类型关键字确定当前语句的类型。
ⅲ:对当前语句进行解析,取得当前语句中的各个属性,并存储在对应的语句类中,然后将该语句类插入到语句表中,并对语句类进行编号。一个语句类对应协议脚本中的一行语句,即一个语句类存储一条语句中所有的属性,语句表由多个语句类组成,一个语句类占语句表的一行。
ⅳ:进入协议脚本中的下一条语句,返回步骤ⅱ,循环执行步骤ⅱ~ⅳ。
例如TCP协议的协议脚本中的第二行语句为:
#srcport,"Source Port:|Src:",2,port
该语句是遵循TCP协议传输的数据包头部结构中的第一个字段描述语句,其中字段名为srcport,字段显示名为Source Port,字段长度为2(2个字节),类型为port(端口号),字段名、字段显示名、字段长度和类型即为该字段描述语句需要存储的属性,即语句表中对应的语句类中存储了srcport,"Source Port:|Src:",2,port这四个属性。
S203:从语句表头至语句表尾,顺序扫描语句表,对语句表中的判断语句(if\elseif\else\endif)、循环语句(do\while)进行分析,确定判断语句的执行顺序和对应的执行条件,确定循环语句的循环体和循环条件,建立逻辑树。
有些协议的协议结构是固定的,这样的结构比较简单,多个字段描述语句即可将协议结构描述清楚。但有些协议是不固定的,例如TCP协议,其协议结构中,前20个字节的字段内容是固定不变的,但在不同的传输情况下,后面字段是变化的,不同的传输情况将出现不同的字段。参考图8,为TCP协议包括TCP选项内容的某个数据包,由图8中可见,选项1和选项2下的字段是一样的,但选项3至选项5下的字段都不相同,此时就需要使用循环语句和判断语句来描述这种不同传输情况出现不同字段的可变结构,即协议脚本中包含判断语句和循环语句。
判断语句的执行顺序和对应的执行条件构成一种逻辑结构,循环语句的循环体和循环条件的也构成一种逻辑结构,多个判断语句和循环语句构成的多个逻辑结构构成逻辑树。
逻辑树建立的方法是:
Ⅰ、扫描整个语句表,按照单一语句块、判断语句块和循环语句块三种语句块类型,将整个语句表分解为若干个语句块B1,B2,…,Bn,n为自然数。
其中,所述单一语句块为:若一段连续的语句不包括if、elseif、else和endif语句,也不包括do和while语句,则称这个语句块为单一语句块。判断语句块为:if语句和对应的endif语句以及之间包含的一段连续的语句,称为判断语句块。循环语句块为:do语句和对应的while语句,以及之间包含的一段连续语句,称为循环语句块。
举例,一段包含循环语句和判断语句的协议脚本如下:
①#num,“number”,2,dec
②if num>10
③set times=3
④endif
⑤set i=1
⑥do
⑦#roueaddr,"Route Address:|Address:",4,ipv4
⑧#preflev,"Preference Level:|Preference:",4,hex
⑨set i=i+1
⑩while times<i
根据该协议脚本解析的语句表中,第①行和第⑤行均为单一语句块,第②行至第④行为一个判断语句块,第⑥六行至第⑩行为一个循环语句块。需要说明的是,协议脚本中的每一条语句前面不带有编号,此处给协议脚本中的每一条语句进行编号,是为了方便阐述单一语句块、判断语句块和循环语句块。
Ⅱ、将若干个语句块B1,B2,…,Bn中的每一个语句块插入(即存储)到逻辑树的根节点中。
Ⅲ、将语句块Bi(i=1,2,3,…,n)分解成单一类型的语句块(单一语句块或循环语句块或判断语句块),然后将每一个单一类型的语句块插入到逻辑树相应的子节点中,完成逻辑树建立,其方法是:
若语句块Bi为判断语句块,则以最外层if语句、elseif语句、else语句和endif语句为分隔符,将语句块Bi中所有的语句分割成若干个带执行条件的语句块b1,b2,…,bn,分别插入到语句块Bi的子节点中,且将各自的判断条件也存储在该子节点中。由于判断语句和循环语句是可以相互嵌套的,所以判断语句块中可能包含有循环语句块,循环语句块中可能包含有判断语句块,因此语句块b1,b2,…,bn中,并不一定每个语句块都是单一类型的语句块,即虽然语句块b1,b2,…,bn为单一语句块或者判断语句块或者循环语句块,但判断语句块和循环语句块中可能包含有单一语句块和/或判断语句块和/或循环语句块,因此继续对子语句块b1,b2,…,bn中不是单一类型的语句块,仍然按照单一语句块、判断语句块和循环语句块三种类型进行分解,将分解后得到的语句块插入到分解前的语句块的子节点中。以此类推,继续将不是单一类型的语句块进行分解,直到逻辑树的每一个叶子节点中的语句块都为单一语句块。根据判断语句块和循环语句块的定义,if语句和对应的endif语句之间的一段连续的语句中,可能其中部分语句组成单一语句块或循环语句块,其中部分语句组成判断语句块。根据循环语句块的定义,do语句和对应的while语句之间的一段连续语句中,可能其中部分语句组成单一语句块或判断语句块,其中部分语句组成循环语句块。所述单一类型的语句块的含义是,一个类型的语句块(单一语句块或判断语句块或循环语句块)中不包含其他类型的语句块。
若Bi为循环语句块,则将do语句和while语句之间的语句作为一个带循环条件的语句块Cn,将Cn插入到语句块Bi的子节点中,同时将循环条件也存储在该子节点中。由于判断语句和循环语句是可以嵌套的,所以语句块Cn并不一定都是单一类型的语句块。若Cn不是单一类型的循环语句块,则继续对Cn按照单一语句块、判断语句块和循环语句块三种类型进行分解,分解得到的语句块插入到Cn的子节点中。以此类推,继续将不是单一类型的语句块进行分解,直到逻辑树的每一个叶子节点的语句块都为单一语句块。
需要说明的是,逻辑树中的根节点和子节点只记录语句块中各语句类在语句表中的编号,并不保存具体的语句内容。
S204:将语句表和逻辑树以当前协议脚本中第一行语句记录的协议名称为关键字,存储在协议表中。协议表中的每一项关键字对应一个协议脚本。
S205:读入下一个协议脚本,重复步骤S202:~S205,直到所有的协议脚本解析并存储完毕。
参考图3,所述步骤S300中,对数据包进行解析的操作包括步骤:
S301:传入待解析的数据包,从数据包中获取协议级数和每一级协议的协议名称。从数据包中获取协议级数和每一级协议的协议名称通过数据包协议识别方法实现,为现有技术,此处不作赘述。
S302:取得数据包中当层协议的协议名称,在已存储的协议脚本中查找该协议的协议脚本是否存在,如果存在则进入步骤S303,否则放弃对数据包当层协议进行解析,直接进入步骤S306。
S303:获取当层协议的语句表和逻辑树。
S304:根据逻辑树中的判断条件和循环条件,确定语句的执行顺序,并从语句表中获取语句的各个属性,然后根据语句的各个属性从数据包中取出相应的数据,获取数据包的各字段解码。具体操作如下:
A.从逻辑树的根节点开始,顺序进入各个子节点。
B.获取当前子节点中的各个语句块的语句块信息。本步骤中,
B-1:若语句块为单一语句块,则根据语句块中的各条语句的编号,顺序地从语句表中取得各条语句相应的各个属性,然后根据各条语句的各个属性从数据包中取出相应的数据,获取数据包的各字段解码。每种类型的语句都定义了对应的操作函数,根据取得的语句的类型,调用对应的操作函数,根据语句的各个属性即可从数据包中取得不同长度的数据,获取数据包的具体字段解码。
B-2:若语句块为判断语句块,则对该子节点中存储的各个语句块的判断条件进行判定,第一个满足条件的语句块即为当前应该执行的语句块,再根据此语句块的类型执行B-1或B-2或B-3。需要说明的是,在数据包解析时,判断条件中的变量或者字段名是有数据的,能够完成判断条件的判定。例如判断条件ifnum>10,在数据包解析时,在执行本判断条之前num已经解码完成,会得到一个数字(比如是5),那么可对这条判断进行判定,判定结果为不满足条件。
B-3:若语句块为循环语句块,则首先执行该语句块中的语句,然后判断子节点中存储的循环条件是否满足,若满足则再次执行该语句块的子节点的语句块中的语句,直到循环条件不满足为止。此处所述执行语句块中的语句的含义是,根据此语句块的类型执行B-1或B-2或B-3。
S305:将当前协议层数据的解析结果存储起来。
S306:获取下一层协议的协议名称,返回步骤S302,重复步骤S302~S306,直到所有的协议层数据都被解析完毕。
本发明网络数据包解析方法,需要添加新协议的解码时只需要添加新协议的协议脚本,而协议脚本的添加不必需要专业的程序员执行,只要是了解新协议的协议名称和协议结构的普通用户都可完成新协议的添加,便于添加新协议,扩展性强。
下面列举两个具体应用实例来说明本发明网络数据包解析方法。
实例1:常用协议IPv6数据包的解析。
IPv6协议数据包的解析步骤如下:
(1)根据IPv6的协议结构,所述协议结构是指利用该协议进行传输的数据包的头部结构,书写IPv6的协议脚本。
IPv6是常用协议,数据包头部结构是已知的,如图4所示。
IPv6协议的数据包头部结构长度固定为40个字节,如图4所示,每一行为4个字节,一共10行。根据数据包头部结构写出IPv6的协议脚本如下:
[protocol:IPv6]
#version,"版本[Version]:",1:0:4,netdec
#traffic_class,"优先级[Traffic Class]:",2:4:8,netdec
#flow_label,"流标签[Flow Label]:",4:12:20,netdec
move4
#payload_len,"负载数据长度[Payload Length]:",2,dec
#next_header,"上层协议[Next Header]:",1,dec
#hop_limit,"跳数[Hop Limit]:",1,dec
#srcadd,"源地址[Source Address]:",16,ipv6
#desadd,"目的地址[Destination Address]:",16,ipv6
协议脚本中对协议结构中的每个字段进行了顺序的具体描述,例如,#version,"版本[Version]:",1:0:4,netdec语句表示,字段名为Version,字段显示名为版本[Version],字段长度为1:0:4,表示取数据包中第一个字节的头四位,类型为netdec,表示十进制整数。又例如,move4语句表示向后移动4个字节。因为根据协议结构,字段Version、traffic_class和flow_label在数据包中的长度不是整数个字节,所以从数据包中读取Version、traffic_class和flow_label字段的数据后,需要向后移动4个字节才能正确获取payload_len、next_header等字段的字段长度。
(2)解析并存储IPv6的协议脚本。
分行读取协议脚本,一行为一个完整的语句,根据语句中的语句类型关键字确定语句的类型,再按照语句的类型获取语句的各个属性,并存储在对应的语句类中,接着将此语句类插入到语句表中。例如第二行,由语句类型关键字“#”判断出当前语句的类型为字段描述语句,接着取得此语句中的各个属性分别为:字段名(version),字段显示名(版本[Version]:),长度(1:0:4),类型(netdec),并将各个属性存储在对应的语句类中,再将此语句类插入到语句表中。继续读入下一条语句,重复上述操作,直到协议脚本的全部语句解析后的语句类都插入到语句表中。
接着对语句表进行顺序扫描,对语句表中的判断语句(if\elseif\else\endif)、循环语句(dow\hile)进行分析,形成逻辑树。
(3)传入需要解析的IPv6数据包,对其进行解析。
由于IPv6协议的结构比较简单,协议脚本中不包含判断语句和循环语句,因此由逻辑树确定的语句执行顺序为从语句表头到语句表尾顺序执行。依次从语句表头到语句表尾获取对应的语句,并依次顺序获取该语句的字段解码。例如第二句,取得该语句表示的字段的各个属性分别为:字段名(version),显示名(版本[Version]:),长度(1:0:4),类型(netdec)。1:0:4表示在数据包中取数据的位置和长度,即第一个字节的头四位,数据包中第一个字节的头四位转换为十进制整数(netdec)显示,即为解析得到的第一个字段“version”的字段解码。
最后输出数据包中包含的所有语句的解析结果,如图5所示。
有些用户在使用网络传输数据的过程中会自定义一些私有协议,针对不公开的私有协议,传统的数据包解析方法无法对私有协议数据包进行解析,而本发明方法可以完成私有协议数据包解析。熟悉私有协议结构的用户书写私有协议的协议脚本,由于协议脚本中对于每个语句的类型和语句属性都进行了详细说明,例如每个字段的字段名,字段显示名,长度以及类型属性都进行了详细的说明,在解析私有协议数据包时,只需要将各个字段的信息提取出来,然后根据位置和长度,从数据包中对应的位置获取数据,然后按照说明的类型和显示名显示出解析结果,即可完成私有协议数据包解析。
下面通过一个应用实例来说明本发明方法解析私有协议数据包的具体流程。
实例2:对某私有协议数据包的解析。
例如某公司自己定义了一套服务器和客户端之间通信的私有协议,用于传输该公司需要的数据,利用该私有协议传输的数据包的头部结构如图6所示,此协议头部结构一共12个字节,分为五个字段。
该私有协议数据包的解析步骤如下:
(1)根据数据包的头部结构,加载该私有协议的协议脚本如下:
[protocol:myprotocol]
#payload_len,"负载长度[PayloadLength]:",2,dec
#port,"端口号[Port]:",2,port
#command,"命令号[Command]:",2,dec
#index,"序号[Index]:",2,dec
#server_ip,"服务器IP[Server IP]:",4,ipv4
(2)解析并存储该私有协议的协议脚本。
分行读取协议脚本,一行为一个完整的语句,根据语句类型关键字确定语句的类型,再按照语句的类型获取语句的各个属性,并存储在对应的语句类中,接着将此语句类插入到语句表中。例如第二行,由语句类型关键字“#”判断出当前语句的类型为字段描述语句,接着取得此语句中的各个属性分别为,字段名(payload_len),字段显示名(负载长度[PayloadLength]:),长度(2),类型(dec),并存储在对应的语句类中,再将此语句类插入到语句表中。继续读入下一条语句,重复上述操作,直到协议的全部语句解析后的语句类都插入到语句表中。
接着对语句表进行顺序扫描,对语句表中的判断语句(if\elseif\else\endif)、循环语句(dow\hile)进行分析,形成逻辑树。
(3)传入需要解析的myprotocol数据包,对其进行解析。
由于列举的该私有协议的结构比较简单,协议脚本中不包含判断语句和循环语句,因此由逻辑树确定的语句执行顺序为从语句表头到语句表尾顺序执行。依次从语句表头到语句表尾获取对应的语句,并依次顺序获取该语句的字段解码。例如第二句,取得该语句表示的字段的各个属性分别为:段名(payload_len),字段显示名(负载长度[PayloadLength]:),长度(2),类型(dec)。2表示数据的位置和长度,即数据包的头两个字节,并以十进制整数显示,显示名为“负载长度[PayloadLength]:”,即为解析得到的字段“payload_len”的字段解码。
最后输出数据包中包含的所有语句的解析结果,如图7所示。