在本文中,我们将看到ndpi提供的的分析函数ndpi_detection_process_packet的主要实现。以及ndpi内部是如何对FTP协议实现深度包检测技术。对于前期的初始化和API的使用,请参考附录中的文章。欢迎大家一起讨论学习。然后我们这次会带着下面几个问题阅读源代码:
1、ndpi的分析函数进行了怎么样的工作?
2、ndpi内部是如何实现深度包检测技术的?
3、ndpi里面,对于多种协议的检测是基于怎样的准则进行选择?
注意:因为限于篇幅需要下面进行分析默认针对ipv4,如果有不正确的地方欢迎大家一起来讨论学习
unsigned int ndpi_detection_process_packet(
struct ndpi_detection_module_struct *ndpi_struct,
//ndpi_detection_module_struct在附录2中进行了详细的叙述,在ndpi_init_detection_module函数进行初始化
struct ndpi_flow_struct *flow,
//用来维护当前会话的检测协议栈,以及检测的参数等
const unsigned char *packet,
//ip层数据报文
const unsigned short packetlen,
//报文长度
const u_int32_t current_tick,
//包的tick值
struct ndpi_id_struct *src,struct ndpi_id_struct *dst)
//ndpi_id_struct里面包含各个协议的源目的端信息
if (tcph->syn != 0 && tcph->ack == 0 && flow->l4.tcp.seen_syn == 0 && flow->l4.tcp.seen_syn_ack == 0
&& flow->l4.tcp.seen_ack == 0) {
flow->l4.tcp.seen_syn = 1;}
if (tcph->syn != 0 && tcph->ack != 0 && flow->l4.tcp.seen_syn == 1 && flow->l4.tcp.seen_syn_ack == 0
&& flow->l4.tcp.seen_ack == 0) {
flow->l4.tcp.seen_syn_ack = 1;}
if (tcph->syn == 0 && tcph->ack == 1 && flow->l4.tcp.seen_syn == 1 && flow->l4.tcp.seen_syn_ack == 1
&& flow->l4.tcp.seen_ack == 0) {
flow->l4.tcp.seen_ack = 1;}
if (flow != NULL && flow->packet.tcp != NULL) {
//....tcp类别
} else if (flow != NULL && flow->packet.udp != NULL) {
//....udp类别
for (a = 0; a < ndpi_struct->callback_buffer_size_udp; a++) {
//对每个udp协议,ndpi内部根据先前的检测结果,判断是否应该继续进行检测。ndpi内部很多运用移位和与或运算,有兴趣的朋友可以先去看看这些
if ((ndpi_struct->callback_buffer_udp[a].ndpi_selection_bitmask & ndpi_selection_packet) ==
ndpi_struct->callback_buffer_udp[a].ndpi_selection_bitmask
&& NDPI_BITMASK_COMPARE(flow->excluded_protocol_bitmask,
ndpi_struct->callback_buffer_udp[a].excluded_protocol_bitmask) == 0
&& NDPI_BITMASK_COMPARE(ndpi_struct->callback_buffer_udp[a].detection_bitmask,
detection_bitmask) != 0) {
//这里调用在初始化阶段注册的检测函数,func字段是一个函数指针。我们接下来的FTP协议也是通过这种方式进行调用。不过FTP是tcp类别的
ndpi_struct->callback_buffer_udp[a].func(ndpi_struct, flow);
if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_UNKNOWN)
break; /* Stop after detecting the first protocol */
}
}
} else {
//....非tcp&&udp类别
}
typedef struct ndpi_flow_struct {
u_int16_t detected_protocol_stack[NDPI_PROTOCOL_HISTORY_SIZE]; //define in ndpi_struct.h中
#if NDPI_PROTOCOL_HISTORY_SIZE > 1
# if NDPI_PROTOCOL_HISTORY_SIZE > 5
# error protocol stack size not supported
# endif
struct {
u_int8_t entry_is_real_protocol:5;
u_int8_t current_stack_size_minus_one:3;
}//栈描述结构
#if !defined(WIN32)
__attribute__ ((__packed__))
#endif
protocol_stack_info;
#endif
.......
} ndpi_flow_struct_t;
/* now shift and insert */
for (a = stack_size - 1; a > 0; a--) {
flow->detected_protocol_stack[a] = flow->detected_protocol_stack[a - 1];
}
flow->protocol_stack_info.entry_is_real_protocol <<= 1;
/* now set the new protocol */
flow->detected_protocol_stack[0] = detected_protocol;
if (packet->payload_packet_len > 34 && ndpi_mem_cmp(packet->payload, "229 Entering Extended Passive Mode", 34) == 0) {
if (dst != NULL) {
ndpi_packet_src_ip_get(packet, &dst->ftp_ip);
dst->ftp_timer = packet->tick_timestamp;
dst->ftp_timer_set = 1;
NDPI_LOG(NDPI_PROTOCOL_FTP, ndpi_struct, NDPI_LOG_DEBUG, "saved ftp_ip, ftp_timer, ftp_timer_set to dst");
NDPI_LOG(NDPI_PROTOCOL_FTP, ndpi_struct, NDPI_LOG_DEBUG,
"FTP Extended PASSIVE MODE FOUND: use Server %s\n", ndpi_get_ip_string(ndpi_struct, &dst->ftp_ip));
}
if (src != NULL) {
ndpi_packet_dst_ip_get(packet, &src->ftp_ip);
src->ftp_timer = packet->tick_timestamp;
src->ftp_timer_set = 1;
NDPI_LOG(NDPI_PROTOCOL_FTP, ndpi_struct, NDPI_LOG_DEBUG, "saved ftp_ip, ftp_timer, ftp_timer_set to src");
NDPI_LOG(NDPI_PROTOCOL_FTP, ndpi_struct, NDPI_LOG_DEBUG,
"FTP Extended PASSIVE MODE FOUND: use Server %s\n", ndpi_get_ip_string(ndpi_struct, &src->ftp_ip));
}
return;
}