Abstract
nDPId is a set of daemons and tools to capture, process and classify network traffic. It's minimal dependencies (besides a half-way modern c library and POSIX threads) are libnDPI (>= 4.4.0 or current github dev branch) and libpcap.
The daemon nDPId
is capable of multithreading for packet processing, but w/o mutexes for performance reasons.
Instead synchronization is achieved by a packet distribution mechanism.
To balance all workload to all threads (more or less) equally a unique identifier represented as hash value is calculated using a 3-tuple consisting of IPv4/IPv6 src/dst address, IP header value of the layer4 protocol and (for TCP/UDP) src/dst port. Other protocols e.g. ICMP/ICMPv6 are lacking relevance for DPI, thus nDPId does not distinguish between different ICMP/ICMPv6 flows coming from the same host. Saves memory and performance, but might change in the future.
nDPId
uses libnDPI's JSON serialization interface to generate a JSON strings for each event it receive from the library and which it then sends out to a UNIX-socket (default: /tmp/ndpid-collector.sock ). From such a socket, nDPIsrvd
(or other custom applications) can retrieve incoming JSON-messages and further proceed working/distributing messages to higher-level applications.
Unfortunately nDPIsrvd
does currently not support any encryption/authentication for TCP connections (TODO!).
Architecture
This project uses some kind of microservice architecture.
connect to UNIX socket [1] connect to UNIX/TCP socket [2]
_______________________ | | __________________________
| "producer" |___| |___| "consumer" |
|---------------------| _____________________________ |------------------------|
| | | nDPIsrvd | | |
| nDPId --- Thread 1 >| ---> |> | <| ---> |< example/c-json-stdout |
| (eth0) `- Thread 2 >| ---> |> collector | distributor <| ---> |________________________|
| `- Thread N >| ---> |> >>> forward >>> <| ---> | |
|_____________________| ^ |____________|______________| ^ |< example/py-flow-info |
| | | | |________________________|
| nDPId --- Thread 1 >| `- send serialized data [1] | | |
| (eth1) `- Thread 2 >| | |< example/... |
| `- Thread N >| receive serialized data [2] -' |________________________|
|_____________________|
where:
* nDPId
capture traffic, extract traffic data (with libnDPI) and send a JSON-serialized output stream to an already existing UNIX-socket;
* nDPIsrvd
:
* create and manage an "incoming" UNIX-socket (ref [1] above), to fetch data from a local nDPId
;
* apply a filtering logic to received data to select "flow_event_id" related JSONs;
* create and manage an "outgoing" UNIX or TCP socket (ref [2] above) to relay matched events
to connected clients
* consumers
are common/custom applications being able to receive selected flows/events, via both UNIX-socket or TCP-socket.
JSON stream format
JSON messages streamed by both nDPId
and nDPIsrvd
are presented with:
- a 5-digit-number describing (as decimal number) of the entire JSON string including the newline
\n
at the end; - the JSON messages
[5-digit-number][JSON string]
as with the following example:
01223{"flow_event_id":7,"flow_event_name":"detection-update","thread_id":12,"packet_id":307,"source":"wlan0",[...]}
00458{"packet_event_id":2,"packet_event_name":"packet-flow","thread_id":11,"packet_id":324,"source":"wlan0",[...]]}
00572{"flow_event_id":1,"flow_event_name":"new","thread_id":11,"packet_id":324,"source":"wlan0",[...]}
The full stream of nDPId
generated JSON-events can be retrieved directly from nDPId
, without relying on nDPIsrvd
, by providing a properly managed UNIX-socket.
Technical details about JSON-messages format can be obtained from related .schema
file included in the schema
directory
Build (CMake)
nDPId
build system is based on CMake
git clone https://github.com/utoni/nDPId.git
[...]
cd ndpid
mkdir build
cd build
cmake ..
[...]
make
see below for a full/test live-session
Based on your building environment and/or desiderata, you could need:
mkdir build
cd build
ccmake ..
or to build with a staticially linked libnDPI:
mkdir build
cd build
cmake .. -DSTATIC_LIBNDPI_INSTALLDIR=[path/to/your/libnDPI/installdir]
If you're using the latter one, make sure that you've configured libnDPI with ./configure --prefix=[path/to/your/libnDPI/installdir]
and do not forget to set the all necessary CMake variables to link against shared libraries used by your nDPI build.
e.g.:
mkdir build
cd build
cmake .. -DSTATIC_LIBNDPI_INSTALLDIR=[path/to/your/libnDPI/installdir] -DNDPI_WITH_GCRYPT=ON -DNDPI_WITH_PCRE=OFF -DNDPI_WITH_MAXMINDDB=OFF
Or let a shell script do the work for you:
mkdir build
cd build
cmake .. -DBUILD_NDPI=ON
The CMake cache variable -DBUILD_NDPI=ON
builds a version of libnDPI
residing as git submodule in this repository.
run
As mentioned above, in order to run nDPId
a UNIX-socket need to be provided in order to stream our related JSON-data.
Such a UNIX-socket can be provided by both the included nDPIsrvd
daemon, or, if you simply need a quick check, with the ncat utility, with a simple ncat -U /tmp/listen.sock -l -k
Once the socket is ready, you can run nDPId
capturing and analyzing your own traffic, with something similar to:
Of course, both ncat
and nDPId
need to point to the same UNIX-socket (nDPId
provides the -c
option, exactly for this. As a default, nDPId
refer to /tmp/ndpid-collector.sock
, and the same default-path is also used by nDPIsrvd
as for the incoming socket)
You also need to provide nDPId
some real-traffic. You can capture your own traffic, with something similar to:
./nDPId -c /tmp/listen.sock -i wlan0 -l
or you can generate a nDPId-compatible JSON dump with:
./nDPId-test [path-to-a-PCAP-file]
You can also automatically fire both nDPId
and nDPIsrvd
automatically, with:
Daemons:
make -C [path-to-a-build-dir] daemon
Or you can proceed with a manual approach with:
./nDPIsrvd -d
sudo ./nDPId -d
or for a usage printout:
./nDPIsrvd -h
./nDPId -h
And why not a flow-info example?
./examples/py-flow-info/flow-info.py
or
./nDPIsrvd-json-dump
or anything below ./examples
.
test
The recommended way to run integration / diff tests:
mkdir build
cd build
cmake .. -DBUILD_NDPI=ON
make nDPId-test test
Alternatively you can run some integration tests manually:
./test/run_tests.sh [/path/to/libnDPI/root/directory] [/path/to/nDPId-test]
e.g.:
./test/run_tests.sh [${HOME}/git/nDPI] [${HOME}/git/nDPId/build/nDPId-test]
Remember that all test results are tied to a specific libnDPI commit hash
as part of the git submodule
. Using test/run_tests.sh
for other commit hashes
will most likely result in PCAP diff's.
Why not use examples/py-flow-dashboard/flow-dash.py
to visualize nDPId's output.