OpenDPI-1.3.0源代码分析

来源:互联网 发布:西班牙 旅游 知乎 编辑:程序博客网 时间:2024/05/16 15:34
目前在实验室主要是弄这个,所以就分析了一下源代码。
水平有限,所以肯定有错的啦,如果谁发现错误的话欢迎及时告诉我OpenDPI-1.3.0源代码分析

============================================================================

OpenDPI-1.3.0源代码分析:

1.       OpenDPI_demo中的main函数:

OpenDPI-1.3.0源代码分析

main函数主要由七个子函数组成,他们分别为:

1.1   parseOptions:处理给定的参数,比如运行时指定的:-f ./http.pcap,分析参数是否正确。该函数不是非常重要,但如果我们改写程序时想要程序能有新的功能,可以在这里添加类似开关的代码,如定义一些宏。

1.2   setupDetection:非常重要的初始化函数,其会的初始化整个程序的最重要的数据结构:ipoque_struct,所有协议的回调函数都是在这里进行绑定的,下面两个函数会的进行重点分析:

OpenDPI-1.3.0源代码分析

除了初始化ipoque_struct外,还会的给几个全局变量分配内存,这些全局变量包括:

osdpi_ids:所有id对应的变量,每个id用来连接一个IP与一个表示该IPID

osdpi_flows:所有flow对应的变量,每个flows用来连接一个flow与一个表示该flowKEY

protocol_counter,protocol_counter_bytes:与协议相关的计数器,类型为数组

1.3   openPcapFile:常规的打开pcap文件

1.4   runPcapLoop:处理pcap的主循环,这个程序的灵魂,其会的最终通过回调函数来调用各个协议的分析函数。

1.5   closePcapFile:常规的关闭pcap文件

1.6   printResults:输出统计结果的数据,请注意观察下面的两个循环:

OpenDPI-1.3.0源代码分析

你会发现最终我们的结果存在与prot_long_str,protocol_counter,protocol_counter_bytes以及osdpi_flows这几个全局变量中,所以这几个变量我们在分析的时候需要着重分析。这些全局变量的初始化详见1.2

1.7   terminateDetection:处理程序的善后工作,比如free掉我们在1.2里建立的那几个全局变量。换句话说,如果我们在程序运行中间使用了ctrl+c中断了程序,那么就会造成内存泄漏。

2.       setupDetection()

2.1   该函数为整个程序的初始化设定函数,所有回调函数的绑定,全局变量的定义都来自这个函数。下面我们来分析一下其几个重要的函数调用

2.2   ipoque_init_detection_module

OpenDPI-1.3.0源代码分析

该函数:

返回值:一个ipoque_detection_module_struct的指针,其指向的对象为该程序的核心数据结构。整个程序有且只有一个该结构

参数1tick_per_second 这里的实参为1000,指每秒的时钟滴答(具体干什么用的不清楚,好像是用来说明cpu每秒多少个时钟滴答的)

参数2ipoque_malloc,指定的用来分配内存的类似于malloc的函数

参数3ipoque_debug_printf,指定的用来进行debug下的print的函数

总的来说,该函数就是用malloc函数分配了一个ipoque_detection_module_struct,该结构体中的许多成员被设定成了默认值。并返回指向该结构体的指针。注意,该函数并未让该结构体绑定回调函数。

2.3   ipoque_set_protocol_detection_bitmask2

OpenDPI-1.3.0源代码分析

所有的回调函数都有该函数进行绑定,大部分标志位(bitmask)的处理,也由该函数进行初始化。

下面进行具体的分析

2.3.1          调用IPOQUE_BITMASK_SET,使所有标志位使能:

OpenDPI-1.3.0源代码分析

2.3.2          一个size

OpenDPI-1.3.0源代码分析

这里的callback_buffer_size是指的回调函数的个数,为了安全起见我们现在先设置其为0,其作用可以见我下面要分析的runPcapLoop函数

2.3.3          接下来就是具体协议的绑定了,你会的看到非常多的ifndef这样的预处理语句:

OpenDPI-1.3.0源代码分析

终于,我们在这里就能看到期待已久的与具体协议有关的内容了。让我们来看一下他到底做了些什么:

OpenDPI-1.3.0源代码分析

注意IPOQUE_COMPARE_PROTOCOL_TO_BITMASK这个宏,在这里他的意思是:如果在detection_bitmask中设置了IPOQUE_PROTOCOL_MPEG这个标志位,那么就跳转到hack_do_http_detection去进行处理。正如之前看到的,detection_bitmask应该被设置为全1了,所以其会转到hack_do_http_detection

注意,该函数在hack_to_http_detection之前会有许多的这样的语句,因为这些协议都可以视为需要使用http_detection,所以只要有一个这样的协议定义了,就得执行http_detection

再来看看hack_to_http_detection到底做了什么吧:

OpenDPI-1.3.0源代码分析

首先,当然是绑定具体的处理函数啦。这些处理函数到底做了什么我们先不管,以后我会的花大量的时间分析这些处理函数,这里我们先看看其接下来做了什么。

Ipq_selection_bitmask是指如果这些协议被定义了的话,如果我们需要使用被绑定的ipoque_search_http_tcp函数,我们就需要该packetIPV4或者IPV6,且需要拥有PAYLOAD才行。这个在我们分析完runPcapLoop后你就会清楚它是干啥的了。

接下来是对于标志位的处理:

detection_bitmask:需要detectiveprotocol

excluded_protocol_bitmask:排除在外不需要detectiveprotocol

这两个标志位在runPcapLoop就能看到其作用了,这需要与osdpi_flows连起来看才行。

hack_do_http_detection的最后,我们看到了一句:

OpenDPI-1.3.0源代码分析

嗯,终于对于http的回调函数以及一些标志位的设置告一段落了。http之所以这么长是由于有太多的协议都会使用他,所以对于这些协议,我们都得用http的处理函数去处理一遍

然后其它的协议就是依样画葫芦了,比如接下来的SSL

OpenDPI-1.3.0源代码分析

嗯,先是判定这个协议要不要检测,然后绑定回调函数,设置这个函数在什么时候要用,然后设置那几个标志位。是的,接下来的大部分初始化函数就只是做了这么几件事罢了,直到一些新的代码的出现:

OpenDPI-1.3.0源代码分析

正如注释说的一样,下面是为一些特殊的packet绑定的回调函数,这些特殊的packet主要有四种:

OpenDPI-1.3.0源代码分析

其做的事情也很简单,callback_buffer不是一个大杂烩嘛,那大杂烩总归有点乱,干脆再细分下好了。于是这里就把callback_buffer又细分成了四个函数,最终我们可以看到,在runPcapLoop中调用的也只是这四个函数罢了。Callback_buffer已经可以功成身退了。

2.3.4          绑定玩回调函数这个大头后,接下来做的就是一些很简单的事了,比如:

OpenDPI-1.3.0源代码分析

就是初始化osdpi_flows这个全局变量,MAX_OSDPI_FLOWS在这里是200000,也就是说我们的程序最多也就只能跟踪200000条流,所以如果处理一个巨大的pacp包,这个数字可能需要适当的加大。

其它的初始化代码比较简单,就不细说了。

3.       runPcapLoop

终于轮到核心函数出场了,虽然是核心函数,但其实它并没有做什么事,真正重要的事情都让那些回调函数给做了,其不过是组织协调一些那些回调函数罢了。

3.1   pcap_loop

OpenDPI-1.3.0源代码分析

一开始用的是pcaploop函数,老套路,没什么好讲的。如果对这四个参数不熟悉的话建议上网查一查,但与我们这个程序关系不大。

3.2   pcap_packet_callback

这个函数的前半部分,主要是对pcap传过来的packet做些分析,然后其会的调用packet_processing

3.3   packet_processing

这个函数算是倒数第二个重要的函数了,所以我会的仔细的分析一下

3.3.1          先初始化要用的变量:

OpenDPI-1.3.0源代码分析

3.3.2          然后通过ip地址,用get_id这个函数,查找全局变量osdpi_ids,找到或者建立一个与指定ip地址相关联的id

OpenDPI-1.3.0源代码分析

3.3.3          然后通过对packet进行分析,找到或者建立与这个packet对应的全局变量osdpi_flows中的flow

OpenDPI-1.3.0源代码分析

有兴趣的同学可以看看ipoque_unique_flow_ipv4_and_6_struct这个结构体,看看OpenDPI是怎么定义一个flow的:

OpenDPI-1.3.0源代码分析

3.3.4          只处理unfragmentedpacket,如果这个packet符合所有条件,那么最终会的调用ipoque_detection_process_packet来完成最后要做的事:

OpenDPI-1.3.0源代码分析

注意一下这几行代码,ipoque_detection_process_packet会的返回检测到的协议的类型,相应的全局变量protocol_counterprotocol_counter_bytes就会增加,然后该packet所对应的flow的类型就会被设定。

3.3.5          ipoque_detection_process_packet

终于轮到这个函数出场了,我们先来看看这个函数的参数:

OpenDPI-1.3.0源代码分析

参数1ipoque_struct,嗯,就是那个核心的结构体。最核心的结构体出现在最核心的函数里一点也不让人意外

参数2flow,嗯,就是该packet对应的全局变量的那个表示flow的结构体,后者存在的目的就是为了表示该packet的一些设计flow的信息,出现在这里也完全不令人意外

参数3packet,这个肯定得有,没有的话就不用分析了

参数4:指明packet的长度,谁叫packet是个指针呢

参数5current_tick,我还是不知道这是干嘛的,只知道和时间有关(这个程序里和时间有关的东西我理解的都不是很好)

参数6和参数7:这两个其实是一样的,都是全局变量表示的osdpi_ids,嗯,和参数2一样,出现在这里理所应当。

既然参数我们看的都差不多懂了(除了current_tick没懂,其它参数也就只能是这么几个了,OpenDPI真的没啥其它东西可做参数了),那么分析起来就容易多了:

第一个遇到的重要函数是:ipq_init_packet_header

OpenDPI-1.3.0源代码分析

他初始化了ipoque_struct->packet这个成员,并把flow中的一些信息复制到了该成员中(即让ipoque_struct->packet继承其所属的flow中的packet前辈的记忆)

然后遇到第二个重要的函数:ipoque_connection_tracking

OpenDPI-1.3.0源代码分析

这个函数主要设置ipoque_struct中的packetflow的状态,有很大一部分代码和tcp的状态有关,可以详细的看一看

然后,设置ipq_selction packet bitmask,该标志位来源的依据主要来自之前对于flowpacket的分析(ipoque_connection_tracking

换句话说,该标志位表明这个packet拥有何种属性(如是否为IP?是否为IPV4?是否有PAYLOAD?)

接下来是一句非常关键的语句:

OpenDPI-1.3.0源代码分析

packet->detected_protocol_stack[0]

如果这个packet不是属于一个flow的(低于四层),那么在ipq_init_packet_header中,其会的被设置为IPOQUE_PROTOCOL_UNKNOWN

OpenDPI-1.3.0源代码分析

否则,则来自于flow的继承:

OpenDPI-1.3.0源代码分析

最后,当这一切都处理好了之后,就是四个for循环了:

OpenDPI-1.3.0源代码分析

这个的意思现在再看的话就很明白不过了吧:

第一行:需要为tcp

第二行:需要payload非空

第三行:开始调用has_payload的回调函数们

第四行:进行判断,判定有无必要对这个packet调用回调函数:比如这个packetIPV6的,但是某个has_payload的回调函数所对应的协议是绝对没有IPV6的,那么就不用大费周章的去调用了。

 

 

整个OpenDPIdemo差不多就分析到这里,下个礼拜开始看具体的协议。


=============================================================

貌似图片顺序有些问题。。。等有空再弄吧。。。嘿嘿

0 0
原创粉丝点击