该翻译文档转载自:https://blog.csdn.net/A_lber_t/article/details/89552332,我自己做了一些修改
官方文档(英文版)链接:https://github.com/ntop/nDPI/tree/3.0-stable/doc
目录
1. nDPI介绍
nDPI是一个基于OpenDPI的DPI库(Deep Packet Inspection,深度包检测),目前由ntop维护。
为了给您提供一个跨平台的DPI体验,我们除了支持Unix/Linux外,同时也支持Windows。不仅如此,我们已经通过修改nDPI,使得它更加适合于流量监控应用,我们通过禁用那些对网络流量监控不必要的特性,已经实现了这一功能,因此也加快了DPI引擎的速度。
nDPI允许应用层协议的检测,而不管该协议使用的端口是什么。这意味着不仅可以检测使用非标准端口的知名协议(例如不使用80端口的HTTP协议),而且可以检测使用标准端口传输的其他协议(例如在80端口检测skype流量)。这是由于在目前“端口=应用”的概念不再适用。
在过去的几个月里,我们也新增加了几个功能特性,包括:
- 示例ndpiReader应用在速度/功能方面和封装支持上都得到了加强。(例如你现在可以对GTP隧道流量进行分析)
- 能够将nDPI编译到Linux内核中,以便于你能使用它开发高效的基于内核的模块。
- 多方面速度加强,nDPI现在比他的前身(之前的版本)更快。
- 添加了许多协议(到目前为止我们支持大约200个协议),其中包括如SAP与Citrix等的“业务”协议,也有像Dropbox与Spotify的“桌面”协议。
- 能够去定义基于端口(和端口范围)的协议检测,以便于你能使用经典的基于端口的检测来去补充协议检测。
- 为了能让nDPI支持加密的链接,我们已经为SSL(包括服务器与客户端)证书添加了解码器。因此,我们能够使用加密证书来理解弄清楚协议。同时这也能让我们去识别如Citrix Online与Apple ICloud等一般无法检测到的协议。
- 能通过使用基于字符串的匹配来支持子协议。
1.1 下载源
当你在构建ntop与nProbe时nDPI会自动被下载。当然也没有什么能阻止你将其用作一个独立的DPI库。你可以从https://github.com/ntop/nDPI 下载源码。
2. nDPI库
2.1 编译nDPI源码
开始使用nDPI库非常地简单。为了编译这个库,你必须满足一些先决条件比如:
- GNU autotools/libtool
- gawk
- gcc
为了实现这些,你需要使用以下命令来安装他们:
Fedora yum groupinstall Development tools
yum install automake libpcap-devel gcc-c++ libtool
Debian apt-get install build-essential libpcap-dev
Mac OSX port install XXX (Please install macports)
一旦你完成了上面的安装,你就能使用以下命令编译nDPI源码:
cd <nDPI source code directory>
./autogen.sh
./configure
make
2.2 编译示例ndpiReader源码
开始使用ndpiReader也很简单。为了编译它你必须使用以下命令:
cd <nDPI source code directory>/example
make
2.3 ndpiReader命令行选项
这个示例ndpiReader应用在速度/功能分析方面和封装支持上均能被使用。特别的是,ndpiReader能够指定很多命令行选项。
下面列举了可使用的命令选项和每一个选项的简要简要介绍:
ndpiReader -i <file|device> [-f <filter>][-s <duration>]
[-p <protos>][-l <loops> [-q][-d][-h][-t][-v <level>]
[-n <threads>] [-w <file>] [-j <file>]
Usage:
-i <file.pcap|device> Specify a pcap file/playlist to read packets from or a
device for live capture (comma-separated list)
指定一个pcap文件/播放列表来读取数据包,或者指定一个用于实时捕获的
设备(逗号分隔的列表)
-f <BPF filter> Specify a BPF filter for filtering selected traffic
指定一个BPF过滤器来过滤选定的流量
-s <duration> Maximum capture duration in seconds (live traffic capture
only)
最大捕获持续时间(以秒计)(仅实时捕获流量)
-p <file>.protos Specify a protocol file (eg. protos.txt)
指定一个协议文件(例如protos.txt)
-l <num loops> Number of detection loops (test only)
检测循环次数(仅限测试)
-n <num threads> Number of threads. Default: number of interfaces in -i.
Ignored with pcap files.
线程的数量,默认是在i命令中接口的数量,不算pcap文件
-j <file.json> | Specify a file to write the content of packets in .json
format
指定一个文件以.json格式写入包的内容
-d Disable protocol guess and use only DPI
禁用协议猜测并仅使用DPI
-q Quiet mode
静音模式
-t Dissect GTP tunnels
解剖GTP隧道
-r Print nDPI version and git revision
打印nDPI版本和git版本
-w <path> Write test output on the specified file. This is useful
for testing purposes in order to compare results across runs
在指定的文件上写测试输出
-h This help
-v <1|2> Verbose 'unknown protocol' packet print. 1=verbose,2=very verbose
详细的“未知协议”包打印。1 =冗长,2 =非常冗长
-i<file.pcap |device>
这项命令用于指定一个pcap文件来读取数据包,或者指定一个用于实时捕获的设备。而且只能指定两者当中的一个。
-f<BPF filter>
指定一个BPF过滤器用来过滤选定的流量。它只允许nDPI接受那些和过滤器匹配的数据包(如果被指定的话)。
-s<duration>
定义了捕获持续时间,以秒为单位,仅用于实时流量捕获。
-p<file.protos>
指定了一个协议文件(例如protos.txt)来扩展对子协议和基于端口协议检测的支持。尤其需要小心的是,协议一旦被定义到protos文件中就会覆盖之前的已经存在的协议。
-l<num loops>
检测循环数(仅用与测试)
-d
这个标志会禁用nDPI协议猜测,仅使用DPI。
-h
打印ndpiReader帮助
-v<1|2>
使用这个标志时,ndpiReader会生成详细的输出,这个输出能被用于调试其性能。数字1是显示带有“未知协议”数据包的最低等级,而2级会显示地更加详细,两者只能指定其一。
UDP 62.101.93.101:53 > 192.168.1.132:56130 [proto: 5/DNS][2 pkts/260 bytes][chat.stackoverflow.com]
TCP 192.168.1.132:59323 > 62.161.94.220:80 [proto: 7/HTTP][8 pkts/1925 bytes][]
UDP 62.101.93.101:53 > 192.168.1.132:56682 [proto: 5/DNS][2 pkts/258 bytes][diy.stackexchange.com]
UDP 62.101.93.101:53 > 192.168.1.132:56916 [proto: 5/DNS][2 pkts/524 bytes][conjugator.reverso.net]
.....................................................................................
.....................................................................................
TCP 192.168.1.132:59323 > 62.161.94.220:80 [proto: 7/HTTP][8 pkts/1925 bytes][]
Undetected flows:
TCP 192.168.1.132:57995 > 157.55.133.142:12350 [proto: 0/Unknown][3 pkts/208 bytes][]
TCP 65.55.223.47:33033 > 192.168.1.132:57997 [proto: 0/Unknown][8 pkts/547 bytes][]
TCP 127.23.238.168:16384 > 240.199.103.219:0 [proto: 0/Unknown][11 pkts/1611 bytes][]
TCP 127.23.238.168:0 > 240.199.103.219:16384 [proto: 0/Unknown][11 pkts/2734 bytes][]
2.4 协议文件
nDPI能够通过基于字符串的匹配支持子协议。这是由于许多新的子协议比如Apple iCloud/iMessage、WhatsApp和许多其他使用HTTP(s)的协议能够通过解码SSL证书主机或者HTTP“Host:”被检测到。因此我们决定将一个基于流行的Aho-Corasick 算法的高效字符匹配库嵌入到nDPI中,用于数十万子字符的高效匹配(即在普通硬件上能足够快地支持10Gb的流量)。
你可以在运行时通过使用一个用以下格式的协议文件来指定子协议:
# Subprotocols
# Format:
# host:"<value>",host:"<value>",.....@<subproto>
host:"googlesyndacation.com"@Google
host:"venere.com"@Veneer
除此之外,你也能使用以下格式来指定一个基于端口的检测:
# Format:
# <tcp|udp>:,<tcp|udp>:,.....@
tcp:81,tcp:8181@HTTP
udp:5061-5062@SIP
tcp:860,udp:860,tcp:3260,udp:3260@iSCSI
tcp:3000@ntop
你可以使用ndpiReader这个应用(使用 –p 选项)来测试你的自定义配置。或者你可以使用ndpi_load_protocls_file() nDPI API调用来增强你自己的应用。
3. 示例
在这一节我们会展示一些ndpiReader的使用范例。
3.1 实时捕获模式
下面这个例子将会展示ndpiReader的实时捕获模式。使用参数-i指定接口设备,参数-s 指定实时捕获持续时间。
$ ./ndpiReader -i eth0 -s 20
-----------------------------------------------------------
* NOTE: This is demo app to show *some* nDPI features.
* In this demo we have implemented only some basic features
* just to show you what you can do with the library. Feel
* free to extend it and send us the patches for inclusion
------------------------------------------------------------
Using nDPI nDPI ($Revision: #### $)
Capturing live traffic from device eth0...
Capturing traffic up to 20 seconds
pcap file contains
IP packets: 2390 of 2391 packets total
IP bytes: 1775743
Unique flows: 78
nDPI throughout: 122.30 pps / 709.92 Kb/sec
Guessed flow protocols: 0
Detected protocols:
DNS packets: 57 bytes: 7904 flows: 28
SSL_No_Cert packets: 483 bytes: 229203 flows: 6
FaceBook packets: 136 bytes: 74702 flows: 4
DropBox packets: 9 bytes: 668 flows: 3
Skype packets: 5 bytes: 339 flows: 3
Google packets: 1700 bytes: 619135 flows: 34
3.2 pcap 捕获模式
创建一个pcap文件最简单的方法就是通过使用tcpdump命令,就像下面这个例子:
ntop$ tcpdump -ni eth0 -s0 -w /var/tmp/capture.pcap -v
tcpdump: listening on en1, link-type EN10MB (Ethernet), capture size 65535 bytes
Got 0
Got 64
Got 75
Got 76
^C122 packets captured
122 packets received by filter
0 packets dropped by kernel
一旦pcap文件被创建,你就能启动ndpiReader,使用参数-i:
$ ./ndpiReader -i /var/tmp/capture.pcap
-----------------------------------------------------------
* NOTE: This is demo app to show *some* nDPI features.
* In this demo we have implemented only some basic features
* just to show you what you can do with the library. Feel
* free to extend it and send us the patches for inclusion
------------------------------------------------------------
Using nDPI nDPI ($Revision: #### $)
Reading packets from pcap file /var/tmp/capture.pcap...
pcap file contains
IP packets: 4911 of 4911 packets total
IP bytes: 3321544
Unique flows: 145
nDPI throughout: 612.80 K pps / 3.09 Gb/sec
Guessed flow protocols: 11
Detected protocols:
Unknown packets: 6 bytes: 764 flows: 1
DNS packets: 50 bytes: 6158 flows: 25
HTTP packets: 2537 bytes: 841638 flows: 73
SSL_No_Cert packets: 1522 bytes: 303380 flows: 10
SSL packets: 24 bytes: 1648 flows: 8
FaceBook packets: 644 bytes: 201216 flows: 17
Skype packets: 11 bytes: 872 flows: 6
3.3 协议文件
为了阐明协议文件的特性,我们现在将解释怎样让你识别来自ntop.org的流。
例如我们可以通过编辑protos.txt文件来实现它:
ntop$ echo 'host:"ntop.org"@nTop'> protos.txt
一旦这个协议文件已经被修改,你可以启动ndpiReader,使用参数 –p:
$ ./ndpiReader -i en1 -s 30 -p protos.txt
-----------------------------------------------------------
* NOTE: This is demo app to show *some* nDPI features.
* In this demo we have implemented only some basic features
* just to show you what you can do with the library. Feel
* free to extend it and send us the patches for inclusion
------------------------------------------------------------
Using nDPI nDPI ($Revision: #### $)
Capturing live traffic from device en1...
Capturing traffic up to 30 seconds
WARNING: only IPv4/IPv6 packets are supported in this demo (nDPI supports both IPv4
and IPv6), all other packets will be discarded
pcap file contains
IP packets: 4755 of 4757 packets total
IP bytes: 1766370
Unique flows: 245
Guessed flow protocols: 16
Detected protocols:
Unknown packets: 1 bytes: 94 flows: 1
DNS packets: 38 bytes: 5160 flows: 19
HTTP packets: 265 bytes: 59831 flows: 20
SSDP packets: 20 bytes: 9564 flows: 14
SSL packets: 33 bytes: 2572 flows: 13
DropBox packets: 17 bytes: 2481 flows: 6
Skype packets: 12 bytes: 944 flows: 2
Google packets: 2544 bytes: 612765 flows: 94
nTop packets: 407 bytes: 66765 flows: 32
4. API nDPI
在这一节中nDPI API是重点。
示例ndpiReader现在有一个基础的例子用来展示如何初始化这个库。需要一个已经编译好的库和一个合适配置的Makefile(即示例Makefile)。
想要在你的应用中开始使用nDPI的API,除了你自己的包含外,必须也添加下面这个包含文件:
#include"dpi_main.h"
这个库可以像下面这样初始化:
1、声明协议位掩码,初始化检测模块:
NDPI_PROTOCOL_BITMASK all;
ndpi_struct = ndpi_init_detection_module(
detection_ticks_resolution,
malloc_wrapper,
free_wrapper,
debug_printf);
这个函数允许你初始化检测模块。字段有如下含义:
- U_int32_t ticks_per_second
每秒时间戳分辨率(比如1000每毫秒分辨率)。
- void*(*_ndpi_malloc)(unsigned long size);
指向一个内存分配器的函数指针。
- void*(*_ndpi_free)(void*prt);
指向一个调试输出函数的函数指针,在生产环境下置空(NULL)
2、通过适当的宏启用所有协议(注意,如果需要,可以启用协议的一个子集),并在检测模块中设置它们
// enable all protocols
NDPI_BITMASK_SET_ALL(all);
ndpi_set_protocol_detection_bitmask2(ndpi_struct, &all);
这个函数能让你设置已经定义到检测模块中的协议位掩码。
3、为了加载一个存在的协议文件,你必须使用如下函数:
dpi_load_protocols_file(ndpi_struct, _protoFilePath);
4、每当从你的pcap文件或者入口设备中捕获到流时,它们可以通过使用以下函数分析:
protocol = (const u_int32_t)ndpi_detection_process_packet(
ndpi_struct,
ndpi_flow,iph ? (uint8_t *)iph : (uint8_t *)if,
ipsize,
time,
src,
dst);
这些字段有以下的含义:
- struct ndpi_detection_module_struct*ndpi_struct;
检测模块。
- struct ndpi_flow_struct*flow;
指向连接状态机的流空指针。
- const unsigned char*packet;
这个packet作为一个无符号的字符指针,长度为packetlen。这个指针必须指向第三层(IP报头)。
- const unsigned short packetlen;
packetlen包的长度。
- const U_int32_t current_tickt;
数据包的当前时间戳。
- struct ndpi_id_struct*src;
指向源订阅状态机的空指针。
- struct ndpi_id_struct*dst;
指向目的订阅状态机的空指针。
5、一旦流被分析后,有必要通过下面的函数来摧毁检测模块。
ndpi_exit_detection_module(ndpi_struct, free_wrapper);
这些字段有以下含义:
- struct ndpi_detection_module_struct*ndpi_struct;
需要被消除的检测模块。
- void*(*_ndpi_free)(void*prt);
指向一个内存释放函数的函数指针。
如需进一步的信息,我们建议可以阅读以下文件:
nDPI/example/ndpiReader.c,
nDPI/src/include/ndpi_structs.h,
nDPI/src/include/ndpi_public_functions.h
nDPI/src/ndpi_main.c.
协议解析器文件被包含在nDPI/src/protocols 目录下。
5. 开发nDPI自定义协议
在这一节中,我们将展示将你的协议包含在nDPI中的方法。
5.1 介绍
每个nDPI协议都会作为一个入口函数被实现,在运行时通过nDPI被使用。nDPI有几个协议可以被用来当作这个方面的例子。下面,我们列出了一些主要的概念,如果你打算开发一个nDPI协议,这些是你必须知道的。
5.2 创建新的协议
每一个协议都必须在下面的头文件中有一个对应的#define:
<nDPI source code directory>/src/include/ndpi_protocols_osdpi.h
例如:
#define NDPI_PROTOCOL_MY_PROTOCOL 171
NDPI_PROTOCOL_MY_PROTOCOL是这个协议的名字,171是这个协议的ID,且必须是独一无二的。
协议被定义好了之后,你必须创建一个协议源文件,就像:
<nDPI source code directory>/src/lib/protocols/my_protocol.c
包括以下内容:
#include "ndpi_utils.h"
#ifdef NDPI_PROTOCOL_MY_PROTOCOLS
.....
#endif
在里面,需要定义一个入口函数,如:
void ndpi_search_my_protocol(
struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow)
{
struct ndpi_packet_struct *packet = &flow->packet;
NDPI_LOG(NDPI_PROTOCOL_MY_PROTOCOL, ndpi_struct, NDPI_LOG_DEBUG, "my protocol detection...\n");
/* skip marked packets by checking if the detection protocol stack */
if (packet->detected_protocol_stack[0] != NDPI_PROTOCOL_MY_PROTOCOL) {
ndpi_check_my_protocol(ndpi_struct, flow);
}
}
以及一个检测核心函数,用来处理一个流的数据包,包括以下内容:
static void ndpi_check_my_protocol(
struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow)
{
struct ndpi_packet_struct *packet = &flow->packet;
u_int32_t payload_len = packet->payload_packet_len;
.....
.....
if(“Found Protocol”) {
NDPI_LOG(NDPI_PROTOCOL_MY_PROTOCOL, ndpi_struct,
NDPI_LOG_DEBUG, "Found my protocol.\n");
ndpi_int_my_protocol_add_connection(ndpi_struct, flow);
return;
}
/*Exclude Protocol*/
NDPI_LOG(NDPI_PROTOCOL_MY_PROTOCOL, ndpi_struct, NDPI_LOG_DEBUG,“exclude my protocol.\n");
NDPI_ADD_PROTOCOL_TO_BITMASK(
flow->excluded_protocol_bitmask,
NDPI_PROTOCOL_MY_PROTOCOL);
}
}
以及一个特定的函数用来报告关于协议正确的识别信息,如:
static void ndpi_int_my_protocol_add_connection(
struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
u_int8_t due_to_correlation)
{
ndpi_int_add_connection(ndpi_struct, flow,
NDPI_PROTOCOL_MY_PROTOCOL,
/*Choose the type of your protocol*/
NDPI_CORRELATED_PROTOCOL or NDPI_REAL_PROTOCOL);
}
5.3 添加你的协议到nDPI
协议被创建之后,你必须在下面的头文件中声明你的入口函数:
<nDPI source code directory>/src/include/ndpi_protocols.h
包括如下内容:
/* my protocol entry */
void ndpi_search_my_protocol(
struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow);
每个协议必须与一个NDPI_SELECTION_BITMASK相关联。NDPI_SELECTION_BITMASK的完整列表被包含在文件:
<nDPI source code directory>/src/include/ndpi_define.h
在为你的协议选择了一个确定的位掩码之后,你必须通知nDPI新协议的存在,通过编辑文件:
<nDPI source code directory>/src/lib/ndpi_main.c
你需要将你的协议添加到如下函数中:
void ndpi_set_protocol_detection_bitmask2(
struct ndpi_detection_module_struct *ndpi_struct,
const NDPI_PROTOCOL_BITMASK * dbm)
.....
.....
.....
#ifdef NDPI_PROTOCOL_MY_PROTOCOL
ndpi_set_bitmask_protocol_detection(ndpi_struct,detection_bitmask,a,
NDPI_PROTOCOL_MY_PROTOCOL,
ndpi_search_my_protocol,
NDPI_SELECTION_BITMASK_MY_PROTOCOL,
SAVE_DETECTION_BITMASK_AS_UNKNOW,
ADD_TO_DETECTION_BITMASK);
/* Update callback_buffer index */
a++;
#endif
.....
.....
.....
ndpi_struct->callback_buffer_size = a;
NDPI_LOG(NDPI_PROTOCOL_UNKNOWN, ndpi_struct, NDPI_LOG_DEBUG,
"callback_buffer_size is %u\n", ndpi_struct-
>callback_buffer_size);