opendpi 源码分析(二)

摘要:
它首先介绍了opendpi如何设置每个协议的处理,然后描述了如何处理每个包,最后是软件流程图。

先介绍opendpi如何设置各个协议的处理,然后介绍如何处理每一个包,最后是软件的流程图。

第一:首先看下要用到的重要的宏

opendpi 源码分析(二)第1张opendpi 源码分析(二)第2张View Code
#define IPOQUE_SAVE_AS_BITMASK(bitmask,value) (bitmask)=(((IPOQUE_PROTOCOL_BITMASK)1)<<(value))
#define IPOQUE_BITMASK_COMPARE(a,b) ((a) & (b))
#define IPOQUE_BITMASK_MATCH(x,y) ((x) == (y))


#define IPOQUE_BITMASK_COMPARE(a,b) ((a) & (b))
#define IPOQUE_COMPARE_PROTOCOL_TO_BITMASK(bmask,value) IPOQUE_BITMASK_COMPARE(bmask,IPOQUE_CONVERT_PROTOCOL_TO_BITMASK(value))

#define IPOQUE_CONVERT_PROTOCOL_TO_BITMASK(p) ( ((IPOQUE_PROTOCOL_BITMASK)1) << (p) )
#define IPOQUE_ADD_PROTOCOL_TO_BITMASK(bmask,value) IPOQUE_BITMASK_ADD(bmask,IPOQUE_CONVERT_PROTOCOL_TO_BITMASK(value))

#define IPOQUE_BITMASK_ADD(a,b) (a)|=(b)

#define IPOQUE_BITMASK_SET(a,b) (a)=(b)
#define IPOQUE_DEL_PROTOCOL_FROM_BITMASK(bmask,value) IPOQUE_BITMASK_DEL(bmask,IPOQUE_CONVERT_PROTOCOL_TO_BITMASK(value))
#define IPOQUE_BITMASK_DEL(a,b) (a)=((a) & (~(b)))

#define IPOQUE_BITMASK_SET_ALL(a) (a) = ((IPOQUE_PROTOCOL_BITMASK)0xFFFFFFFFFFFFFFFFULL)

#define IPOQUE_BITMASK_RESET(a) (a) = 0

然后是标识协议掩码的数据结构:

#if IPOQUE_MAX_SUPPORTED_PROTOCOLS >= 128
typedef
struct ipoque_protocol_bitmask_struct {
u64 bitmask[
3];
} ipoque_protocol_bitmask_struct_t;
#define IPOQUE_PROTOCOL_BITMASK struct ipoque_protocol_bitmask_struct

#elif IPOQUE_MAX_SUPPORTED_PROTOCOLS >= 64
typedef
struct ipoque_protocol_bitmask_struct {
u64 bitmask[
2];
} ipoque_protocol_bitmask_struct_t;
#define IPOQUE_PROTOCOL_BITMASK struct ipoque_protocol_bitmask_struct

#if IPOQUE_MAX_SUPPORTED_PROTOCOLS >= 128
typedef
struct ipoque_protocol_bitmask_struct {
u64 bitmask[
3];
} ipoque_protocol_bitmask_struct_t;
#define IPOQUE_PROTOCOL_BITMASK struct ipoque_protocol_bitmask_struct

#elif IPOQUE_MAX_SUPPORTED_PROTOCOLS >= 64
typedef
struct ipoque_protocol_bitmask_struct {
u64 bitmask[
2];
} ipoque_protocol_bitmask_struct_t;
#define IPOQUE_PROTOCOL_BITMASK struct ipoque_protocol_bitmask_struct

#else

#define IPOQUE_PROTOCOL_BITMASK u64

#endif


#ifndef u64
#define u64 unsigned long long
#endif
#ifndef u32
#define u32 unsigned int
#endif
#ifndef u16
#define u16 unsigned short
#endif
#ifndef u8
#define u8 unsigned char
#endif

我开始的时候一直以为 IPOQUE_PROTOCOL_BITMASK是整型,没想到是个结构体。

在函数ipoque_set_protocol_detection_bitmask2中开启了对某个固定协议的处理,比如这样就开启了所有协议来检测包:

// enable all protocols
IPOQUE_BITMASK_SET_ALL(all);
ipoque_set_protocol_detection_bitmask2(ipoque_struct,
&all);

在具体的一种协议的实现中是这样处理的,比如YAHOO:

opendpi 源码分析(二)第3张opendpi 源码分析(二)第4张View Code
#ifdef IPOQUE_PROTOCOL_YAHOO
if (IPOQUE_COMPARE_PROTOCOL_TO_BITMASK(*detection_bitmask, IPOQUE_PROTOCOL_YAHOO) != 0) {
ipoque_struct
->callback_buffer[a].func = ipoque_search_yahoo;
ipoque_struct
->callback_buffer[a].ipq_selection_bitmask = IPQ_SELECTION_BITMASK_PROTOCOL_TCP_OR_UDP;

IPOQUE_SAVE_AS_BITMASK(ipoque_struct
->callback_buffer[a].detection_bitmask, IPOQUE_PROTOCOL_UNKNOWN);
IPOQUE_ADD_PROTOCOL_TO_BITMASK(ipoque_struct
->callback_buffer[a].detection_bitmask, IPOQUE_PROTOCOL_YAHOO);
IPOQUE_SAVE_AS_BITMASK(ipoque_struct
->callback_buffer[a].excluded_protocol_bitmask, IPOQUE_PROTOCOL_YAHOO);

a
++;
}

而函数ipoque_search_yahoo就是存在于目录protocol中,对于YAHOO的具体检查,实现如下:

opendpi 源码分析(二)第5张opendpi 源码分析(二)第6张View Code
void ipoque_search_yahoo(struct ipoque_detection_module_struct *ipoque_struct)
{
struct ipoque_packet_struct *packet = &ipoque_struct->packet;
struct ipoque_flow_struct *flow = ipoque_struct->flow;


IPQ_LOG(IPOQUE_PROTOCOL_YAHOO, ipoque_struct, IPQ_LOG_DEBUG,
"search yahoo\n");

if (packet->payload_packet_len > 0 && flow->yahoo_detection_finished == 0) {
if (packet->tcp != NULL && packet->tcp_retransmission == 0) {
#ifdef IPOQUE_PROTOCOL_HTTP
if (packet->detected_protocol == IPOQUE_PROTOCOL_UNKNOWN
|| packet->detected_protocol == IPOQUE_PROTOCOL_HTTP)
#else
if (packet->detected_protocol == IPOQUE_PROTOCOL_UNKNOWN)
#endif
{
ipoque_search_yahoo_tcp(ipoque_struct);
}
}
else if (packet->udp != NULL) {
ipoque_search_yahoo_udp(ipoque_struct);
}
}
if (packet->payload_packet_len > 0 && flow->yahoo_detection_finished == 2) {
if (packet->tcp != NULL && packet->tcp_retransmission == 0) {
ipoque_search_yahoo_tcp(ipoque_struct);
}
}
}

这个函数检查了YAHOO是基于UDP还是TCP,还有没有payload长度是不是等于0.

这样就建立了一个匹配的模式数据库。

第二:对于每一个包,在这个函数中从pcap文件中获得:

// executed for each packet in the pcap file
static void pcap_packet_callback(u_char * args, const struct pcap_pkthdr *header, const u_char * packet)
然后在函数
// here the actual detection is performed
protocol = ipoque_detection_process_packet(ipoque_struct, ipq_flow, (uint8_t *) iph, ipsize, time, src, dst);

这是对每个包的具体处理,而返回值就是我们所想要知道的,这个包所属于的协议号。

在函数 ipoque_detection_process_packet中最重要的是如下的代码:

if (flow != NULL && ipoque_struct->packet.tcp != NULL) {
if (ipoque_struct->packet.payload_packet_len != 0) {
for (a = 0; a < ipoque_struct->callback_buffer_size_tcp_payload; a++) {
if ((ipoque_struct->callback_buffer_tcp_payload[a].ipq_selection_bitmask & ipq_selection_packet) ==
ipoque_struct
->callback_buffer_tcp_payload[a].ipq_selection_bitmask
&& IPOQUE_BITMASK_COMPARE(ipoque_struct->flow->excluded_protocol_bitmask,
ipoque_struct
->callback_buffer_tcp_payload[a].excluded_protocol_bitmask) == 0
&& IPOQUE_BITMASK_COMPARE(ipoque_struct->callback_buffer_tcp_payload[a].detection_bitmask,
detection_bitmask)
!= 0) {
ipoque_struct
->callback_buffer_tcp_payload[a].func(ipoque_struct);
}
}

首先判断了payload,而ipq_selection_packet依赖于下面的这些判断:

opendpi 源码分析(二)第7张opendpi 源码分析(二)第8张View Code
/* build ipq_selction packet bitmask */
ipq_selection_packet
= IPQ_SELECTION_BITMASK_PROTOCOL_COMPLETE_TRAFFIC;
if (ipoque_struct->packet.iph != NULL) {
ipq_selection_packet
|= IPQ_SELECTION_BITMASK_PROTOCOL_IP | IPQ_SELECTION_BITMASK_PROTOCOL_IPV4_OR_IPV6;

}
if (ipoque_struct->packet.tcp != NULL) {
ipq_selection_packet
|=
(IPQ_SELECTION_BITMASK_PROTOCOL_INT_TCP
| IPQ_SELECTION_BITMASK_PROTOCOL_INT_TCP_OR_UDP);

}
if (ipoque_struct->packet.udp != NULL) {
ipq_selection_packet
|=
(IPQ_SELECTION_BITMASK_PROTOCOL_INT_UDP
| IPQ_SELECTION_BITMASK_PROTOCOL_INT_TCP_OR_UDP);
}
if (ipoque_struct->packet.payload_packet_len != 0) {
ipq_selection_packet
|= IPQ_SELECTION_BITMASK_PROTOCOL_HAS_PAYLOAD;
}

if (ipoque_struct->packet.tcp_retransmission == 0) {
ipq_selection_packet
|= IPQ_SELECTION_BITMASK_PROTOCOL_NO_TCP_RETRANSMISSION;

}

excluded_protocol_bitmask是设置不需要检查的协议,我们上面已经设置为all。

detection_bitmask通过这样初始化:

opendpi 源码分析(二)第9张opendpi 源码分析(二)第10张View Code
#define IPOQUE_CONVERT_PROTOCOL_TO_BITMASK(p) ( ((IPOQUE_PROTOCOL_BITMASK)1) << (p) )
IPOQUE_SAVE_AS_BITMASK(detection_bitmask, ipoque_struct
->packet.detected_protocol);

通过gdb可以查看 detection_bitmask的值是:bitmask = {1, 0}。

这样就把每一个包放入已有的协议模式去匹配。

主要流程图:

opendpi 源码分析(二)第11张

也许有错误,希望指教。




免责声明:文章转载自《opendpi 源码分析(二)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇限定登录失败次数,超过指定次数就限制登录一段时间CAM(内容可寻址存储器)的认知下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Vue.js 源码分析(二十七) 高级应用 异步组件 详解

当我们的项目足够大,使用的组件就会很多,此时如果一次性加载所有的组件是比较花费时间的。一开始就把所有的组件都加载是没必要的一笔开销,此时可以用异步组件来优化一下。 异步组件简单的说就是只有等到在页面里显示该组件的时候才会从服务器加载,不显式的话就不会加载,这样即可提高客户端的访问速度也可以降低对服务器的请求次数,可谓优化的一个利器。 异步组件常用有3种异步...

如何阅读mysql源码

  在微博上问mysql高手,如何阅读mysql 源码大致给了下面的一些建议: step 1,知道代码的组织结构(官方文档http://t.cn/z8LoLgh; Step2: 尝试大致了解一条sql涉及的上层接口 Step3:使用gdb单步调试 Step4 理解每个新版本mysql changelog的具体实现 以后深入关注mysql源码,今天以此为证。...

hwclock和date源码分析

一. hwclock 1.1 hwclock源码在哪里? util-linux 或者busybox 1.2 获取源码 git clone https://github.com/karelzak/util-linux.git 或 git clonegit://git.busybox.net/busybox 1.3 hwclock的源码路径 sys-utils...

[nginx] nginx源码分析--健康检查模块锁分析

健康检查模块 见前文:[nginx] nginx源码分析--健康检查模块 其中有一张框架图, 接下来的内容,将会利用到这个图中的内容。 [classic_tong @ https:////www.cnblogs.com/hugetong/p/12274125.html ]  描述 我们知道nginx是多进程的,每个进程都保存了相同的配置。但是实际上, 并不...

详解S7源码(1)----Types

1,Bit.cs 第一个布尔表达是,v前面加int强制原因是由于,&与操作符号是int,int类型 /// <summary> /// Contains the conversion methods to convert Bit from S7 plc to C#. /// </summary> p...

手写Redux-Saga源码

上一篇文章我们分析了Redux-Thunk的源码,可以看到他的代码非常简单,只是让dispatch可以处理函数类型的action,其作者也承认对于复杂场景,Redux-Thunk并不适用,还推荐了Redux-Saga来处理复杂副作用。本文要讲的就是Redux-Saga,这个也是我在实际工作中使用最多的Redux异步解决方案。Redux-Saga比Redux...