SNORT源码分析.doc

上传人:豆**** 文档编号:33465003 上传时间:2022-08-11 格式:DOC 页数:16 大小:73.50KB
返回 下载 相关 举报
SNORT源码分析.doc_第1页
第1页 / 共16页
SNORT源码分析.doc_第2页
第2页 / 共16页
点击查看更多>>
资源描述

《SNORT源码分析.doc》由会员分享,可在线阅读,更多相关《SNORT源码分析.doc(16页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。

1、如有侵权,请联系网站删除,仅供学习与交流SNORT源码分析【精品文档】第 16 页SNORT源码分析(转自SMTH) Snort作为一个轻量级的网络入侵检测系统,在实际中应用可能会有些力不从心,但如果想了解研究IDS的工作原理,仔细研究一下它的源码到是非常不错.首先对snort做一个概括的评论。 从工作原理而言,snort是一个NIDS。注:基于网络的入侵检测系统(NIDS)在网络的一点被动地检查原始的网络传输数据。通过分析检查的数据包,NIDS匹配入侵行为的特征或者从网络活动的角度检测异常行为。 网络传输数据的采集利用了工具包libpcap。snort对libpcap采集来的数据进行分析,从

2、而判断是否存在可疑的网络活动。 从检测模式而言,snort基本上是误用检测(misuse detection)。注:该方法对已知攻击的特征模式进行匹配,包括利用工作在网卡混杂模式下的嗅探器被动地进行协议分析,以及对一系列数据包解释分析特征。顺便说一句,另一种检测是异常检测(anomaly detection)。具体实现上,仅仅是对数据进行最直接最简单的搜索匹配,并没有涉及更复杂的入侵检测办法。 尽管snort在实现上没有什么高深的检测策略,但是它给我们提供了一个非常 优秀的公开源代码的入侵检测系统范例。我们可以通过对其代码的分析,搞清IDS 究竟是如何工作的,并在此基础上添加自己的想法。 sn

3、ort的编程风格非常优秀,代码阅读起来并不困难,整个程序结构清晰,函 数调用关系也不算复杂。但是,snort的源文件不少,函数总数也很多,所以不太 容易讲清楚。因此,最好把代码完整看一两遍,能更清楚点。 * * 下面看看snort的整体结构。展开snort压缩包,有约50个c程序和头文件,另有约30个其它文件(工程、数据或者说明文件)。注:这里用的是snort-1.6-beta7。snort-1.6.3不在手边,就用老一点的版本了,差别不大。下面对源代码文件分组说明。 snort.c(.h)是主程序所在的文件,实现了main函数和一系列辅助函数。 decode.c(.h)把数据包层层剥开,确定

4、该包属于何种协议,有什么特征。并 标记到全局结构变量pv中。 log.c(.h)实现日志和报警功能。snort有多种日志格式,一种是按tcpdump二进制的格式存储,另一种按snort编码的ascii格式存储在日志目录下,日志目录的名字根据外主机的ip地址命名。报警有不同的级别和方式,可以记录到syslog中,或者记录到用户指定的文件,另外还可以通过unix socket发送报警消息,以及利用SMB向Windows系统发送winpopup消息。 mstring.c(.h)实现字符串匹配算法。在snort中,采用的是Boyer-Moore算法。算法书上一般都有。 plugbase.c(.h)实现

5、了初始化检测以及登记检测规则的一组函数。snort中的检测规则以链表的形式存储,每条规则通过登记(Register)过程添加到链表中。 response.c(.h)进行响应,即向攻击方主动发送数据包。这里实现了两种响应。一种是发送ICMP的主机不可到达的假信息,另一种针对TCP,发送RST包,断开连接。 rule.c(.h)实现了规则设置和入侵检测所需要的函数。规则设置主要的作用是 把一个规则文件转化为实际运作中的规则链表。检测函数根据规则实施攻击特征的检测。 sp_*_check.c(.h)是不同类型的检测规则的具体实现。很容易就可以从文件名得知所实现的规则。例如,sp_dsize_chec

6、k针对的是包的数据大小,sp_icmp_type_check针对icmp包的类型,sp_tcp_flag_check针对tcp包的标志位。不再详述。 spo_*.c(.h)实现输出(output)规则。spo_alert_syslog把事件记录到syslog中;spo_log_tcpdump利用libpcap中的日志函数,进行日志记录。 spp_*.c(.h)实现预处理(preprocess)规则。包括http解码(即把http请求中的%XX这样的字符用对应的ascii字符代替,避免忽略了恶意的请求)、最小片断检查(避免恶意利用tcp协议中重组的功能)和端口扫描检测。 * 下面描述main函数

7、的工作流程。先来说明两个结构的定义。 在snort.h中,定义了两个结构:PV和PacketCount。PV用来记录命令行参数,snort根据这些命令行参数来确定其工作方式。PV类型的全局变量pv用来实际记录具体工作方式。结构定义可以参看snort.h,在下边的main函数中,会多次遇到pv中各个域的设定,到时再一个一个解释。 结构PacketCount用来统计流量,每处理一个数据包,该结构类型的全局变量pc把对应的域加1。相当于一个计数器。 接下来解释main函数。 初始化设定一些缺省值;然后解析命令行参数,根据命令行参数,填充结构变量pv;根据pv的值(也就是解析命令行的结果)确定工作方式

8、,需要注意: 如果是运行在Daemon方式,通过GoDaemon函数,创建守护进程,重定向标准输入输出,实现daamon状态,并结束父进程。 snort可以实时采集网络数据,也可以从文件读取数据进行分析。这两种情况并没有本质区别。如果是读取文件进行分析(并非直接从网卡实时采集来的),以该文件名作为libpcap的函数OpenPcap的参数,打开采集过程;如果是从网卡实时采集,就把网卡接口作为OpenPcap的参数,利用libpcap的函数打开该网卡接口。在unix中,设备也被看作是文件,所以这和读取文件分析没有多大的差别。 接着,指定数据包的拆包函数。不同的数据链路网络,拆包的函数也不同。利用

9、函数SetPktProcessor,根据全局变量datalink的值,来设定不同的拆包函数。例如,以太网,拆包函数为DecodeEthPkt;令牌环网,拆包函数为DecodeTRPkt,等等。这些Decode*函数,在decode.c中实现。 如果使用了检测规则,那么下面就要初始化这些检测规则,并解析规则文件,转化成规则链表。规则有三大类:预处理(preprocessor),插件(plugin),输出插件(outputplugin)。这里plugin就是具体的检测规则,而outputplugin是定义日志和报警方式的规则。 然后根据报警模式,设定报警函数;根据日志模式,设定日志函数;如果指定了

10、能够进行响应,就打开raw socket,准备用于响应。 最后进入读取数据包的循环,pcap_loop对每个采集来的数据包都用ProcessPacket函数进行处理,如果出现错误或者到达指定的处理包数(pv.pkt_cnt定义),就退出该函数。这里ProcessPacket是关键程序, 最后,关闭采集过程。 * 现在看看snort如何实现对数据包的分析和检测入侵的。 在main函数的最后部分有如下语句,比较重要: /* Read all packets on the device. Continue until cnt packets read */ if(pcap_loop(pd, pv.p

11、kt_cnt, (pcap_handler)ProcessPacket, NULL) sf.rfile != NULL) n = pcap_offline_read(p, cnt, callback, user); else /* * XXX keep reading until we get something * (or an error occurs) */ do /do循环 n = pcap_read(p, cnt, callback, user); while (n = 0); if (n 0) cnt -= n; if (cnt func(p); idx = idx-next; i

12、f(!p-frag_flag & do_detect) if(Detect(p) /调用检测函数 CallOutputPlugins(p); /如果匹配,根据规则输出 尽管这个函数很简洁,但是在第1行我们看到定义了ProprocessFuncNode 结构类型的指针,所以下面,我们不得不开始涉及到snort的各种复杂 的数据结构。前面的分析,我一直按照程序运行的调用顺序,忽略了许多函 数(其实有不少非常重要),以期描述出snort执行的主线,避免因为程序中 大量的调用关系而产生混乱。到现在,我们还没有接触到snort核心的数据结构 和算法。有不少关键的问题需要解决:规则是如何静态描述的?运行时

13、这些 规则按照什么结构动态存储?每条规则的处理函数如何被调用?snort给了 我们提供了非常好的方法。 snort一个非常成功的思想是利用了plugin机制,规则处理函数并非固定在 源程序中,而是根据每次运行时的参数设定,从规则文件中读入规则,再把每个 规则所需要的处理函数挂接到链表上。实际检测时,遍历这些链表,调用链表上 相应的函数来分析。 snort主要的数据结构是链表,几乎都是链表来链表去。我们下面做个总的 介绍。 我们有必要先回过头来,看一看main函数中对规则初始化时涉及到的一些 数据结构。 在main函数初始化规则的时候,先建立了几个链表,全局变量定义如下 (plugbase.c中

14、): KeywordXlateList *KeywordList; PreprocessKeywordList *PreprocessKeywords; PreprocessFuncNode *PreprocessList; OutputKeywordList *OutputKeywords; OutputFuncNode *OutputList; 这几种结构的具体定义省略。这一初始化的过程把snort中预定义的关键 字和处理函数按类别连接在不同的链表上。然后,在解析规则文件的时候, 如果一条规则的选项中包含了某个关键字,就会从上边初始化好的对应的链表 中查找,把必要的信息和处理函数添加到表示

15、这条规则的节点(用RuleTreeNode 类型来表示,下面详述)的特定域(OptTreeNode类型)中。 同时,main函数中初始化规则的最后,对指定的规则文件进行解析。在最 高的层次上,有3个全局变量保存规则(rules.c): ListHead Alert; /* Alert Block Header */ ListHead Log; /* Log Block Header */ ListHead Pass; /* Pass Block Header */ 这几个变量是ListHead类型的,正如名称所说,指示链表头。Alert中登记 了需要报警的规则,Log中登记了需要进行日志的规则

16、,Pass中登记的规则在处 理过程忽略(不进行任何处理)。ListHead定义如下: typedef struct _ListHead RuleTreeNode *TcpList; RuleTreeNode *UdpList; RuleTreeNode *IcmpList; ListHead; 可以看到,每个ListHead结构中有三个指针,分别指向处理Tcp/Udp/Icmp包规则的链表头。这里又出现了新的结构RuleTreeNode,为了说明链表的层次关系,下面列出RuleTreeNode的定义,但是忽略了大部分域: typedef struct _RuleTreeNode RuleFpL

17、ist *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记录的是该规则的处理函数的链表。一条

18、规则有时候需要调用多个处理函数来分析。所以,有必要做成链表。我们看看下面的定义,除了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类的指

19、针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 associat

20、e dynamic data structures with the rule system, letting them link anything they can come up with to the rules list */ void *ds_list512; /* list of plugin data struct pointers */ ./省略了一些域 struct _OptTreeNode *next; OptTreeNode; next指向链表的下一个节点,无需多说。OptFpList类型的指针opt_func指向 选项函数链表,同前面说的RuleFpList没什么大差别

21、。值得注意的是指针数组 ds_list,用来记录该条规则中涉及到的预定义处理过程。每个元素的类型是void*.在实际表示规则的时候,ds_list被强制转换成不同的预定义类型。 - Proprocess函数很短,首先调用预处理规则处理数据包p,然后调用检测 函数Detect进行规则匹配实现检测,如果实现匹配,那么调用函数CallOutput Plugins根据输出规则进行报警或日志。函数如下: void Preprocess(Packet *p) PreprocessFuncNode *idx; do_detect = 1; idx = PreprocessList; /指向预处理规则链表头

22、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执行的主线,避免因为程序中 大量的调用关系

23、而产生混乱。到现在,我们还没有接触到snort核心的数据结构 和算法。有不少关键的问题需要解决:规则是如何静态描述的?运行时这些 规则按照什么结构动态存储?每条规则的处理函数如何被调用?snort给了 我们提供了非常好的方法。 snort一个非常成功的思想是利用了plugin机制,规则处理函数并非固定在 源程序中,而是根据每次运行时的参数设定,从规则文件中读入规则,再把每个 规则所需要的处理函数挂接到链表上。实际检测时,遍历这些链表,调用链表上 相应的函数来分析。 snort主要的数据结构是链表,几乎都是链表来链表去。我们下面做个总的 介绍。 我们有必要先回过头来,看一看main函数中对规则初

24、始化时涉及到的一些 数据结构。 在main函数初始化规则的时候,先建立了几个链表,全局变量定义如下 (plugbase.c中): KeywordXlateList *KeywordList; PreprocessKeywordList *PreprocessKeywords; PreprocessFuncNode *PreprocessList; OutputKeywordList *OutputKeywords; OutputFuncNode *OutputList; 这几种结构的具体定义省略。这一初始化的过程把snort中预定义的关键 字和处理函数按类别连接在不同的链表上。然后,在解析规则

25、文件的时候, 如果一条规则的选项中包含了某个关键字,就会从上边初始化好的对应的链表 中查找,把必要的信息和处理函数添加到表示这条规则的节点(用RuleTreeNode 类型来表示,下面详述)的特定域(OptTreeNode类型)中。 同时,main函数中初始化规则的最后,对指定的规则文件进行解析。在最 高的层次上,有3个全局变量保存规则(rules.c): ListHead Alert; /* Alert Block Header */ ListHead Log; /* Log Block Header */ ListHead Pass; /* Pass Block Header */ 这几个

26、变量是ListHead类型的,正如名称所说,指示链表头。Alert中登记 了需要报警的规则,Log中登记了需要进行日志的规则,Pass中登记的规则在处 理过程忽略(不进行任何处理)。ListHead定义如下: typedef struct _ListHead RuleTreeNode *TcpList; RuleTreeNode *UdpList; RuleTreeNode *IcmpList; ListHead; 可以看到,每个ListHead结构中有三个指针,分别指向处理Tcp/Udp/Icmp包规则的链表头。这里又出现了新的结构RuleTreeNode,为了说明链表的层次关系,下面列出R

27、uleTreeNode的定义,但是忽略了大部分域: 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域,只不过这里

28、用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 nod

29、e */ 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

30、 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_list512; /* list of plugin data struct pointers */ ./省略了一些域 struct _OptTreeNode *next; OptTreeNode; next指向链表的下一个节点,无需多说。OptFpList类型的指针opt_func指向选项函数链表,同前面说的RuleFpList没什么大差别。值得注意的是指针数组 ds_list,用来记录该条规则中涉及到的预定义处理过程。每个元素的类型是void*。在实际表示规则的时候,ds_list被强制转换成不同的预定义类型。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 教育专区 > 高考资料

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知得利文库网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号-8 |  经营许可证:黑B2-20190332号 |   黑公网安备:91230400333293403D

© 2020-2023 www.deliwenku.com 得利文库. All Rights Reserved 黑龙江转换宝科技有限公司 

黑龙江省互联网违法和不良信息举报
举报电话:0468-3380021 邮箱:hgswwxb@163.com