荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: georgehill (清风浮云 人生), 信区: Linux
标  题: snort源码分析(5)(转寄)
发信站: BBS 荔园晨风站 (Tue Oct 17 13:58:28 2000), 站内信件

【 以下文字转载自 georgehill 的信箱 】
【 原文由 georgehill.bbs@smth.org 所发表 】
发信人: shuke (莫失莫忘), 信区: Security
标  题: snort源码分析(5)(转寄)
发信站: BBS 水木清华站 (Fri Oct 13 11:20:55 2000)


    Proprocess函数很短,首先调用预处理规则处理数据包p,然后调用检测
函数Detect进行规则匹配实现检测,如果实现匹配,那么调用函数CallOutput
Plugins根据输出规则进行报警或日志。函数如下:

void Preprocess(Packet *p)
{
   PreprocessFuncNode *idx;

   do_detect = 1;
   idx = PreprocessList;  //指向预处理规则链表头

   while(idx != NULL)  //调用预处理函数处理包p
   {
      idx->func(p);
      idx = idx->next;
   }

   if(!p->frag_flag && do_detect)
   {
      if(Detect(p))  //调用检测函数
      {
         CallOutputPlugins(p);  //如果匹配,根据规则输出
      }
   }
}

    尽管这个函数很简洁,但是在第1行我们看到定义了ProprocessFuncNode
结构类型的指针,所以下面,我们不得不开始涉及到snort的各种复杂
的数据结构。前面的分析,我一直按照程序运行的调用顺序,忽略了许多函
数(其实有不少非常重要),以期描述出snort执行的主线,避免因为程序中
大量的调用关系而产生混乱。到现在,我们还没有接触到snort核心的数据结构
和算法。有不少关键的问题需要解决:规则是如何静态描述的?运行时这些
规则按照什么结构动态存储?每条规则的处理函数如何被调用?snort给了
我们提供了非常好的方法。

    snort一个非常成功的思想是利用了plugin机制,规则处理函数并非固定在
源程序中,而是根据每次运行时的参数设定,从规则文件中读入规则,再把每个
规则所需要的处理函数挂接到链表上。实际检测时,遍历这些链表,调用链表上
相应的函数来分析。

    snort主要的数据结构是链表,几乎都是链表来链表去。我们下面做个总的
介绍。

    我们有必要先回过头来,看一看main函数中对规则初始化时涉及到的一些
数据结构。

    在main函数初始化规则的时候,先建立了几个链表,全局变量定义如下
(plugbase.c中):

KeywordXlateList *KeywordList;
PreprocessKeywordList *PreprocessKeywords;
PreprocessFuncNode *PreprocessList;
OutputKeywordList *OutputKeywords;
OutputFuncNode *OutputList;

    这几种结构的具体定义省略。这一初始化的过程把snort中预定义的关键
字和处理函数按类别连接在不同的链表上。然后,在解析规则文件的时候,
如果一条规则的选项中包含了某个关键字,就会从上边初始化好的对应的链表
中查找,把必要的信息和处理函数添加到表示这条规则的节点(用RuleTreeNode
类型来表示,下面详述)的特定域(OptTreeNode类型)中。

    同时,main函数中初始化规则的最后,对指定的规则文件进行解析。在最
高的层次上,有3个全局变量保存规则(rules.c):

ListHead Alert;      /* Alert Block Header */
ListHead Log;        /* Log Block Header */
ListHead Pass;       /* Pass Block Header */

    这几个变量是ListHead类型的,正如名称所说,指示链表头。Alert中登记
了需要报警的规则,Log中登记了需要进行日志的规则,Pass中登记的规则在处
理过程忽略(不进行任何处理)。ListHead定义如下:

typedef struct _ListHead
{
   RuleTreeNode *TcpList;
   RuleTreeNode *UdpList;
   RuleTreeNode *IcmpList;
} ListHead;

    可以看到,每个ListHead结构中有三个指针,分别指向处理Tcp/Udp/Icmp包
规则的链表头。这里又出现了新的结构RuleTreeNode,为了说明链表的层次关系,
下面列出RuleTreeNode的定义,但是忽略了大部分域:

typedef struct _RuleTreeNode
{
   RuleFpList *rule_func;

   ...... //忽略

   struct _RuleTreeNode *right;

   OptTreeNode *down;   /* list of rule options to associate with this
                           rule node */

} RuleTreeNode;

    RuleTreeNode中包含上述3个指针域,分别又能形成3个链表。RuleTreeNode*
类型的right指向下一个RuleTreeNode,相当于普通链表中的next域,只不过这里
用right来命名。这样就形成了规则链表。

    RuleFpList类的指针rule_func记录的是该规则的处理函数的链表。一条规则
有时候需要调用多个处理函数来分析。所以,有必要做成链表。我们看看下面的
定义,除了next域,还有一个函数指针:

typedef struct _RuleFpList
{
   /* rule check function pointer */
   int (*RuleHeadFunc)(Packet *, struct _RuleTreeNode *, struct _RuleFpList *);

   /* pointer to the next rule function node */
   struct _RuleFpList *next;

} RuleFpList;

    第3个指针域是OptTreeNode类的指针down,该行后面的注释说的很清楚,这是
与这个规则节点相联系的规则选项的链表。很不幸,OptTreeNode的结构也相当复
杂,而且又引出了几个新的链表。忽略一些域,OptTreeNode定义如下:

typedef struct _OptTreeNode
{
   /* plugin/detection functions go here */
   OptFpList *opt_func;

   /* the ds_list is absolutely essential for the plugin system to work,
      it allows the plugin authors to associate "dynamic" data structures
      with the rule system, letting them link anything they can come up
      with to the rules list */
   void *ds_list[512];   /* list of plugin data struct pointers */

   .......//省略了一些域

   struct _OptTreeNode *next;

} OptTreeNode;

    next指向链表的下一个节点,无需多说。OptFpList类型的指针opt_func指向
选项函数链表,同前面说的RuleFpList没什么大差别。值得注意的是指针数组
ds_list,用来记录该条规则中涉及到的预定义处理过程。每个元素的类型是void*。
在实际表示规则的时候,ds_list被强制转换成不同的预定义类型。
--

      垆边人似月,皓腕凝霜雪


※ 来源:·BBS 水木清华站 smth.org·[FROM: 166.111.69.59]
--
※ 转载:·BBS 荔园晨风站 bbs.szu.edu.cn·[FROM: 192.168.1.115]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店