一、前言
最近因项目需要用到nDPI采集流量进行报文深度检测,主要在nDPI基础上进行协议扩展,根据官网用户手册描述有两种方式支持协议扩展,在此通过nDPI示例程序ndpiReader进行展示。
在ndpiReader中增加自定义协议的方式如下:
1、是通过编辑example/protos.txt文件来使ndpiReader匹配相应的协议,但是这种的匹配条件有限,只能通过端口、host和IP地址来定义新协议。
2、通过在源码中注册自定义协议以及自己编写自定义协议的匹配逻辑,来自定义协议。这种方法需要编码,但是协议自定义匹配方式更为灵活。
二、开发自定义协议
1、修改protos.txt
此种方法网上介绍的资料很多,在此省略。
2、修改源码
以下说明基于nDPI 最新版本3.4版本中的源码添加自定义协议。为了方便说明,假设我们需要自定义的协议名字叫做ONEONEPROTOCOL。顾名思义,当应用层协议中的数据全为1,那么就认为这是ONEONEPROTOCOL协议。
详细步骤如下:
1)添加新的协议ID
首先,每一个协议都必须在头文件ndpi_protocol_ids.h中有一个对应的协议ID的定义,ID号数字不能随便写,需要在现有的ID编号后新增。
// Reddragon
NDPI_PROTOCOL_ONEONEPROTOCOL = 254, /* all of the tcp payload is 1*/
2)编写协议源文件
在定义完协议ID后,我们必须在src/lib/protocols/文件夹中创建自定义协议的源文件:oneoneprotocol.c。该文件用来识别协议格式。
#include "ndpi_protocol_ids.h"
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_ONEONEPROTOCOL
#include "ndpi_api.h"
void ndpi_search_oneoneprotocol(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &flow->packet;
u_int nIndex = 0;
u_int count = 0;
u_int16_t dport = 0;
NDPI_LOG_DBG(ndpi_struct, "search oneoneprotocol\n");
printf("\n packet_len = %d\n", packet->payload_packet_len);
while(nIndex < packet->payload_packet_len) {
printf("\n nIndex = %d, payloadValue = %d \n", nIndex, packet->payload[nIndex]);
if (packet->payload[nIndex] == 0x31){
count++;
}
nIndex++;
}
if(count == packet->payload_packet_len){
printf("\n count = %d, found oneoneprotocol \n", count);
NDPI_LOG_INFO(ndpi_struct, "found oneoneprotocol\n");
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_ONEONEPROTOCOL, NDPI_PROTOCOL_UNKNOWN);
return;
}
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
}
void init_oneoneprotocol_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id,
NDPI_PROTOCOL_BITMASK *detection_bitmask)
{
ndpi_set_bitmask_protocol_detection(
"oneoneprotocol", ndpi_struct, detection_bitmask, *id,
NDPI_PROTOCOL_ONEONEPROTOCOL,
ndpi_search_oneoneprotocol,
NDPI_SELECTION_BITMASK_PROTOCOL_TCP_WITH_PAYLOAD,
SAVE_DETECTION_BITMASK_AS_UNKNOWN,
ADD_TO_DETECTION_BITMASK);
*id += 1;
}
3)添加你的协议到nDPI
在ndpi_main.c中注册,依葫芦画瓢在1508行后面添加ndpi_set_proto_defaults函数。
// oneoneprotocol
ndpi_set_proto_defaults(ndpi_str, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_ONEONEPROTOCOL, 1 /* no subprotocol */,
no_master,
no_master, "ONEONEPROTOCOL", NDPI_PROTOCOL_CATEGORY_CHAT,
ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */,
ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */);
通过适当的宏并将他们设置到检测模块中来启用协议。在ndpi_set_protocol_detection_bitmask2函数3362行后面添加我们的函数:init_oneoneprotocol_dissector(ndpi_str, &a, detection_bitmask)。
// ONEONEPROTOCOL
init_oneoneprotocol_dissector(ndpi_str, &a, detection_bitmask);
4)完成
三、自测
在虚拟机linux上通过nc工具监听11011端口,windows通过NetAssist工具选择TCP Client连接到linux主机端口,发生数字111,ndpiReader抓包测试。测试结果如下图所示。
本文主要步骤参考如下链接,原文测试很多细节有误,特重新测试发布。详细介绍可参考原链接。
参考连接:
https://blog.csdn.net/ACMer_L/article/details/107594060