【智能路由器】ndpi深度报文分析之协议分析器
【智能路由器】系列文章连接 本篇博客讲述ndpi已实现的QQ协议分析器的实现 和 编写1个微信协议分析器的框架要点。 ndpi协议分析器结构框架每一个协议分析器都必须定义1个独有的id,例如: /*ndpi_protocol_ids.h*/
#define NDPI_PROTOCOL_QQ 48 协议分析器格式 #include "ndpi_utils.h"
#ifdef NDPI_PROTOCOL_QQ
.....
#endif 协议分析器的初始化函数,初始化函数中调用 void init_qq_dissector(struct ndpi_detection_module_struct *ndpi_struct,u_int32_t *id,NDPI_PROTOCOL_BITMASK *detection_bitmask)
{
ndpi_set_bitmask_protocol_detection("QQ",ndpi_struct,detection_bitmask,*id,NDPI_PROTOCOL_QQ,ndpi_search_qq,NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_UDP_WITH_PAYLOAD,SAVE_DETECTION_BITMASK_AS_UNKNOWN,ADD_TO_DETECTION_BITMASK);
*id += 1;
}
1个回调函数,用来处理数据包,这个函数就是初始化中注册的函数,这个函数将细分情况,然后交给实际的分析函数,这里分别是 void ndpi_search_qq(struct ndpi_detection_module_struct *ndpi_struct,struct ndpi_flow_struct *flow)
{
struct ndpi_packet_struct *packet = &flow->packet;
if (packet->udp != NULL && flow->detected_protocol_stack[0] != NDPI_PROTOCOL_QQ)
ndpi_search_qq_udp(ndpi_struct,flow);
if (packet->tcp != NULL && flow->detected_protocol_stack[0] != NDPI_PROTOCOL_QQ)
ndpi_search_qq_tcp(ndpi_struct,flow);
} 协议分析器的框架就到此为止,然后将初始化函数添加到ndpi_main.c文件的 static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndpi_mod) {
int i;
ndpi_port_range ports_a[MAX_DEFAULT_PORTS],ports_b[MAX_DEFAULT_PORTS];
u_int16_t no_master[2] = { NDPI_PROTOCOL_NO_MASTER_PROTO,NDPI_PROTOCOL_NO_MASTER_PROTO },custom_master[2];
/* Reset all settings */
memset(ndpi_mod->proto_defaults,0,sizeof(ndpi_mod->proto_defaults));
//......
ndpi_set_proto_defaults(ndpi_mod,NDPI_PROTOCOL_FUN,no_master,"QQ",ndpi_build_default_ports(ports_a,0) /* TCP */,ndpi_build_default_ports(ports_b,0) /* UDP */);
//......
} 宏定义 ndpi协议分析中QQ协议分析器的代码概要根据packet是tcp还是udp将探测进程被分为两中情况: void ndpi_search_qq(struct ndpi_detection_module_struct *ndpi_struct,flow);
} 看1下qq的udp报文是怎样探测的,在下面这个函数中
static void ndpi_search_qq_udp(struct ndpi_detection_module_struct *ndpi_struct,struct ndpi_flow_struct *flow)
{
struct ndpi_packet_struct *packet = &flow->packet;
static const u_int16_t p8000_patt_02[13] = // maybe version numbers
{ 0x1549,0x1801,0x180d,0x0961,0x01501,0x0e35,0x113f,0x0b37,0x1131,0x163a,0x1e0d,0x3619,};
u_int16_t no_of_patterns = 12,index = 0;
NDPI_LOG(NDPI_PROTOCOL_QQ,NDPI_LOG_DEBUG,"search qq udp.n");
if (flow->qq_stage <= 3) {
if ((packet->payload_packet_len == 27 && ntohs(get_u_int16_t(packet->payload,0)) == 0x0300
&& packet->payload[2] == 0x01)
|| (packet->payload_packet_len == 84 && ((ntohs(get_u_int16_t(packet->payload,0)) == 0x000e
&& packet->payload[2] == 0x35)
|| (ntohs(get_u_int16_t(packet->payload,0)) == 0x0015
&& packet->payload[2] == 0x01)
|| (ntohs(get_u_int16_t(packet->payload,0)) == 0x000b
&& packet->payload[2] == 0x37)
|| (ntohs(get_u_int16_t(packet->payload,0)) == 0x0015
&& packet->payload[2] == 0x49)))
|| (packet->payload_packet_len > 10
&& ((get_u_int16_t(packet->payload,0) == htons(0x000b) && packet->payload[2] == 0x37)
|| (get_u_int32_t(packet->payload,0) == htonl(0x04163a00)
&& packet->payload[packet->payload_packet_len - 1] == 0x03
&& packet->payload[4] == packet->payload_packet_len)))) {
/*
if (flow->qq_stage == 3 && flow->detected_protocol == NDPI_PROTOCOL_QQ) {
if (flow->packet_direction_counter[0] > 0 && flow->packet_direction_counter[1] > 0) {
flow->protocol_subtype = NDPI_PROTOCOL_QQ_SUBTYPE_AUDIO;
return;
} else if (flow->packet_counter < 10) {
return;
}
} */
flow->qq_stage++;
if (flow->qq_stage == 3) {
NDPI_LOG(NDPI_PROTOCOL_QQ,"found qq udp pattern 030001 or 000e35 four times.n");
ndpi_int_qq_add_connection(ndpi_struct,flow);
return;
}
return;
}
if (packet->payload_packet_len > 2 && (packet->payload[0] == 0x02 || packet->payload[0] == 0x04)) {
u_int16_t pat = ntohs(get_u_int16_t(packet->payload,1));
for (index = 0; index < no_of_patterns; index++) {
if (pat == p8000_patt_02[index] && packet->payload[packet->payload_packet_len - 1] == 0x03) {
flow->qq_stage++;
// maybe we can test here packet->payload[4] == packet->payload_packet_len
if (flow->qq_stage == 3) {
NDPI_LOG(NDPI_PROTOCOL_QQ,"found qq udp pattern 02 ... 03 four times.n");
/*
if (packet->payload[0] == 0x04) {
ndpi_int_qq_add_connection(ndpi_struct,flow,NDPI_REAL_PROTOCOL);
return;
} */
ndpi_int_qq_add_connection(ndpi_struct,flow);
return;
}
return;
}
}
}
if (packet->payload_packet_len == 84 && (packet->payload[0] == 0 || packet->payload[0] == 0x03)) {
u_int16_t pat = ntohs(get_u_int16_t(packet->payload,1));
for (index = 0; index < no_of_patterns; index++) {
if (pat == p8000_patt_02[index]) {
flow->qq_stage++;
/*
if (flow->qq_stage == 3 && flow->packet_direction_counter[0] > 0 &&
flow->packet_direction_counter[1] > 0) {
NDPI_LOG(NDPI_PROTOCOL_QQ,"found qq udp pattern four times.n");
ndpi_int_qq_add_connection(ndpi_struct,NDPI_REAL_PROTOCOL);
return;
} else */ if (flow->qq_stage == 3) {
NDPI_LOG(NDPI_PROTOCOL_QQ,flow);
return;
}
return;
}
}
}
if (packet->payload_packet_len > 2 && packet->payload[0] == 0x04
&& ((ntohs(get_u_int16_t(packet->payload,1)) == 0x1549
|| ntohs(get_u_int16_t(packet->payload,1)) == 0x1801 || ntohs(get_u_int16_t(packet->payload,1)) == 0x0961)
||
(packet->payload_packet_len > 16
&& (ntohs(get_u_int16_t(packet->payload,1)) == 0x180d || ntohs(get_u_int16_t(packet->payload,1)) == 0x096d)
&& ntohl(get_u_int32_t(packet->payload,12)) == 0x28000000
&& ntohs(get_u_int16_t(packet->payload,3)) == packet->payload_packet_len))
&& packet->payload[packet->payload_packet_len - 1] == 0x03) {
flow->qq_stage++;
if (flow->qq_stage == 3) {
NDPI_LOG(NDPI_PROTOCOL_QQ,"found qq udp pattern 04 1159 ... 03 four times.n");
ndpi_int_qq_add_connection(ndpi_struct,flow);
return;
}
return;
}
if (packet->payload_packet_len > 2 && (packet->payload[0] == 0x06 || packet->payload[0] == 0x02)
&& ntohs(get_u_int16_t(packet->payload,1)) == 0x0100
&& (packet->payload[packet->payload_packet_len - 1] == 0x00
|| packet->payload[packet->payload_packet_len - 1] == 0x03)) {
flow->qq_stage++;
if (flow->qq_stage == 3) {
NDPI_LOG(NDPI_PROTOCOL_QQ,"found qq udp pattern 02/06 0100 ... 03/00 four times.n");
ndpi_int_qq_add_connection(ndpi_struct,flow);
return;
}
return;
}
if (packet->payload_packet_len > 2 && (packet->payload[0] == 0x02)
&& ntohs(get_u_int16_t(packet->payload,1)) == 0x1131 && packet->payload[packet->payload_packet_len - 1] == 0x03) {
flow->qq_stage++;
if (flow->qq_stage == 3) {
NDPI_LOG(NDPI_PROTOCOL_QQ,"found qq udp pattern 02 1131 ... 03 four times.n");
ndpi_int_qq_add_connection(ndpi_struct,flow);
return;
}
return;
}
if (packet->payload_packet_len > 5 && get_u_int16_t(packet->payload,0) == htons(0x0203) &&
ntohs(get_u_int16_t(packet->payload,2)) == packet->payload_packet_len &&
get_u_int16_t(packet->payload,4) == htons(0x0b0b)) {
flow->qq_stage++;
if (flow->qq_stage == 3) {
NDPI_LOG(NDPI_PROTOCOL_QQ,"found qq udp pattern 0203[packet_length_0b0b] three times.n");
ndpi_int_qq_add_connection(ndpi_struct,flow);
return;
}
return;
}
if (packet->udp->dest == htons(9000) || packet->udp->source == htons(9000)) {
if (packet->payload_packet_len > 3
&& ntohs(get_u_int16_t(packet->payload,0)) == 0x0202
&& ntohs(get_u_int16_t(packet->payload,2)) == packet->payload_packet_len) {
flow->qq_stage++;
if (flow->qq_stage == 3) {
NDPI_LOG(NDPI_PROTOCOL_QQ,"found qq udp pattern 02 02 <length> four times.n");
ndpi_int_qq_add_connection(ndpi_struct,flow);
return;
}
return;
}
}
}
if (ndpi_is_valid_qq_packet(packet)) {
flow->qq_stage++;
if (flow->qq_stage == 3) {
NDPI_LOG(NDPI_PROTOCOL_QQ,"found qq over udp.n");
ndpi_int_qq_add_connection(ndpi_struct,flow);
return;
}
NDPI_LOG(NDPI_PROTOCOL_QQ,"found qq packet stage %dn",flow->qq_stage);
return;
}
if (ndpi_is_valid_qq_ft_packet(packet)) {
flow->qq_stage++;
if (flow->qq_stage == 3) {
NDPI_LOG(NDPI_PROTOCOL_QQ,"found qq ft over udp.n");
ndpi_int_qq_add_connection(ndpi_struct,flow);
return;
}
return;
}
if (flow->qq_stage && flow->packet_counter <= 5) {
return;
}
NDPI_LOG(NDPI_PROTOCOL_QQ,"QQ excludedn");
NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask,NDPI_PROTOCOL_QQ);
} 该函数有点长,不过基本都是属于探测OICQ协议的报头,oicq协议是qq用于即时通讯的协议,数据流经8000端口,具体oicq协议头的解释可参看arvik的另外一篇博客http://blog.csdn.net/u012819339/article/details/50374252 得到payload头指针后起始可以直接强迫指针类型转换成 oicqhdr *,就比较方便啦 typedef struct _oicqhdr {
uint8_t flag;
uint16_t ver;
uint16_t command;
uint16_t sequence;
uint32_t qq;
} __attribute__((packed)) oicqhdr; tcp检测就不叙述了,总之都是先抓包分析QQ报文头的结构特点,然后拿到协议分析器中做匹配。 ndpi协议分析中编写1个微信协议分析器的方法指点协议分析器框架见上文所述,可以参照QQ协议分析器依葫芦画瓢, 好了,本文到此结束,作者arvik。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |