【转】【翻译】Wireshark:添加一个基础的解析器(2)

标签: 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_typeett_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。我们假设它依照网络字节顺序,所以将最后一个参数设为FALSETRUE表示"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以记录数据包解析的位置。将这些额外的代码块放入合适的位置,整个协议就可以得到全面的解析。

你可能感兴趣的:(【转】【翻译】Wireshark:添加一个基础的解析器(2))