3 Commits

Author SHA1 Message Date
lns
9678d33d0c sync'd with ndpiSimpleIntegration from https://github.com/ntop/nDPI.git
Signed-off-by: lns <matzeton@googlemail.com>
2023-06-01 19:33:51 +02:00
Toni Uhlig
b94bf63067 sync'd with ndpiSimpleIntegration from https://github.com/ntop/nDPI.git
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
2021-07-04 20:02:48 +02:00
Toni Uhlig
0c24bb5d04 proposal ready for review
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
2020-06-24 22:04:13 +02:00

497
main.c
View File

@@ -1,20 +1,43 @@
/*
*
* Copyright (C) 2011-22 - ntop.org
*
* nDPI is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* nDPI is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with nDPI. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef WIN32
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h>
#include <linux/if_ether.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <ndpi/ndpi_api.h> #endif
#include <ndpi/ndpi_main.h> #include <errno.h>
#include <ndpi_api.h>
#include <ndpi_main.h>
#include <ndpi_typedefs.h>
#include <pcap/pcap.h> #include <pcap/pcap.h>
#include <pthread.h> #include <pthread.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
#if !(NDPI_MAJOR >= 3 && NDPI_MINOR >= 2) #ifdef WIN32
#error "nDPI >= 3.2.0 requiired" #include <windows.h>
#endif #endif
//#define VERBOSE 1
#define MAX_FLOW_ROOTS_PER_THREAD 2048 #define MAX_FLOW_ROOTS_PER_THREAD 2048
#define MAX_IDLE_FLOWS_PER_THREAD 64 #define MAX_IDLE_FLOWS_PER_THREAD 64
#define TICK_RESOLUTION 1000 #define TICK_RESOLUTION 1000
@@ -23,27 +46,46 @@
#define MAX_IDLE_TIME 300000 /* msec */ #define MAX_IDLE_TIME 300000 /* msec */
#define INITIAL_THREAD_HASH 0x03dd018b #define INITIAL_THREAD_HASH 0x03dd018b
enum nDPId_l3_type { #ifndef ETH_P_IP
#define ETH_P_IP 0x0800
#endif
#ifndef ETH_P_IPV6
#define ETH_P_IPV6 0x86DD
#endif
#ifndef ETH_P_ARP
#define ETH_P_ARP 0x0806
#endif
enum nDPI_l3_type {
L3_IP, L3_IP6 L3_IP, L3_IP6
}; };
struct nDPId_flow_info { struct nDPI_flow_info {
uint32_t flow_id; uint32_t flow_id;
unsigned long long int packets_processed; unsigned long long int packets_processed;
uint64_t first_seen; uint64_t first_seen;
uint64_t last_seen; uint64_t last_seen;
uint64_t hashval; uint64_t hashval;
enum nDPId_l3_type l3_type; enum nDPI_l3_type l3_type;
union { union {
struct { struct {
uint32_t src; uint32_t src;
uint32_t pad_00[3];
uint32_t dst; uint32_t dst;
uint32_t pad_01[3];
} v4; } v4;
struct { struct {
uint64_t src[2]; uint64_t src[2];
uint64_t dst[2]; uint64_t dst[2];
} v6; } v6;
struct {
uint32_t src[4];
uint32_t dst[4];
} u32;
} ip_tuple; } ip_tuple;
unsigned long long int total_l4_data_len; unsigned long long int total_l4_data_len;
@@ -56,23 +98,20 @@ struct nDPId_flow_info {
uint8_t detection_completed:1; uint8_t detection_completed:1;
uint8_t tls_client_hello_seen:1; uint8_t tls_client_hello_seen:1;
uint8_t tls_server_hello_seen:1; uint8_t tls_server_hello_seen:1;
uint8_t reserved_00:2; uint8_t flow_info_printed:1;
uint8_t reserved_00:1;
uint8_t l4_protocol; uint8_t l4_protocol;
struct ndpi_proto detected_l7_protocol; struct ndpi_proto detected_l7_protocol;
struct ndpi_proto guessed_protocol; struct ndpi_proto guessed_protocol;
struct ndpi_flow_struct * ndpi_flow; struct ndpi_flow_struct * ndpi_flow;
struct ndpi_id_struct * ndpi_src;
struct ndpi_id_struct * ndpi_dst;
}; };
struct nDPId_workflow { struct nDPI_workflow {
pcap_t * pcap_handle; pcap_t * pcap_handle;
uint8_t error_or_eof:1; volatile long int error_or_eof;
uint8_t reserved_00:7;
uint8_t reserved_01[3];
unsigned long long int packets_captured; unsigned long long int packets_captured;
unsigned long long int packets_processed; unsigned long long int packets_processed;
@@ -95,23 +134,26 @@ struct nDPId_workflow {
struct ndpi_detection_module_struct * ndpi_struct; struct ndpi_detection_module_struct * ndpi_struct;
}; };
struct nDPId_reader_thread { struct nDPI_reader_thread {
struct nDPId_workflow * workflow; struct nDPI_workflow * workflow;
pthread_t thread_id; pthread_t thread_id;
int array_index; uint32_t array_index;
}; };
static struct nDPId_reader_thread reader_threads[MAX_READER_THREADS] = {}; static struct nDPI_reader_thread reader_threads[MAX_READER_THREADS] = {};
static int reader_thread_count = MAX_READER_THREADS; static int reader_thread_count = MAX_READER_THREADS;
static int main_thread_shutdown = 0; static volatile long int main_thread_shutdown = 0;
static uint32_t flow_id = 0; static volatile long int flow_id = 0;
static void free_workflow(struct nDPId_workflow ** const workflow); static void free_workflow(struct nDPI_workflow ** const workflow);
static struct nDPId_workflow * init_workflow(char const * const file_or_device) static struct nDPI_workflow * init_workflow(char const * const file_or_device)
{ {
char pcap_error_buffer[PCAP_ERRBUF_SIZE]; char pcap_error_buffer[PCAP_ERRBUF_SIZE];
struct nDPId_workflow * workflow = (struct nDPId_workflow *)ndpi_calloc(1, sizeof(*workflow)); struct nDPI_workflow * workflow = (struct nDPI_workflow *)ndpi_calloc(1, sizeof(*workflow));
const char *bpfFilter = "ip or ip6";
static struct bpf_program bpf_code;
static struct bpf_program *bpf_cfilter = NULL;
if (workflow == NULL) { if (workflow == NULL) {
return NULL; return NULL;
@@ -120,16 +162,32 @@ static struct nDPId_workflow * init_workflow(char const * const file_or_device)
if (access(file_or_device, R_OK) != 0 && errno == ENOENT) { if (access(file_or_device, R_OK) != 0 && errno == ENOENT) {
workflow->pcap_handle = pcap_open_live(file_or_device, /* 1536 */ 65535, 1, 250, pcap_error_buffer); workflow->pcap_handle = pcap_open_live(file_or_device, /* 1536 */ 65535, 1, 250, pcap_error_buffer);
} else { } else {
#ifdef WIN32
workflow->pcap_handle = pcap_open_offline(file_or_device, pcap_error_buffer);
#else
workflow->pcap_handle = pcap_open_offline_with_tstamp_precision(file_or_device, PCAP_TSTAMP_PRECISION_MICRO, workflow->pcap_handle = pcap_open_offline_with_tstamp_precision(file_or_device, PCAP_TSTAMP_PRECISION_MICRO,
pcap_error_buffer); pcap_error_buffer);
#endif
} }
if (workflow->pcap_handle == NULL) { if (workflow->pcap_handle == NULL) {
fprintf(stderr, "pcap_open_live / pcap_open_offline_with_tstamp_precision: %s\n", pcap_error_buffer); fprintf(stderr, "pcap_open_live / pcap_open_offline: %.*s\n",
(int) PCAP_ERRBUF_SIZE, pcap_error_buffer);
free_workflow(&workflow); free_workflow(&workflow);
return NULL; return NULL;
} }
if(pcap_compile(workflow->pcap_handle, &bpf_code, bpfFilter, 1, 0xFFFFFF00) < 0) {
printf("pcap_compile error: '%s'\n", pcap_geterr(workflow->pcap_handle));
exit(-1);
}
bpf_cfilter = &bpf_code;
if(pcap_setfilter(workflow->pcap_handle, bpf_cfilter) < 0) {
printf("pcap_setfilter error: '%s'\n", pcap_geterr(workflow->pcap_handle));
}
ndpi_init_prefs init_prefs = ndpi_no_prefs; ndpi_init_prefs init_prefs = ndpi_no_prefs;
workflow->ndpi_struct = ndpi_init_detection_module(init_prefs); workflow->ndpi_struct = ndpi_init_detection_module(init_prefs);
if (workflow->ndpi_struct == NULL) { if (workflow->ndpi_struct == NULL) {
@@ -156,24 +214,22 @@ static struct nDPId_workflow * init_workflow(char const * const file_or_device)
NDPI_PROTOCOL_BITMASK protos; NDPI_PROTOCOL_BITMASK protos;
NDPI_BITMASK_SET_ALL(protos); NDPI_BITMASK_SET_ALL(protos);
ndpi_set_protocol_detection_bitmask2(workflow->ndpi_struct, &protos); ndpi_set_protocol_detection_bitmask2(workflow->ndpi_struct, &protos);
ndpi_finalize_initalization(workflow->ndpi_struct); ndpi_finalize_initialization(workflow->ndpi_struct);
return workflow; return workflow;
} }
static void ndpi_flow_info_freer(void * const node) static void ndpi_flow_info_freer(void * const node)
{ {
struct nDPId_flow_info * const flow = (struct nDPId_flow_info *)node; struct nDPI_flow_info * const flow = (struct nDPI_flow_info *)node;
ndpi_free(flow->ndpi_dst);
ndpi_free(flow->ndpi_src);
ndpi_flow_free(flow->ndpi_flow); ndpi_flow_free(flow->ndpi_flow);
ndpi_free(flow); ndpi_free(flow);
} }
static void free_workflow(struct nDPId_workflow ** const workflow) static void free_workflow(struct nDPI_workflow ** const workflow)
{ {
struct nDPId_workflow * const w = *workflow; struct nDPI_workflow * const w = *workflow;
if (w == NULL) { if (w == NULL) {
return; return;
@@ -196,9 +252,25 @@ static void free_workflow(struct nDPId_workflow ** const workflow)
*workflow = NULL; *workflow = NULL;
} }
static char * get_default_pcapdev(char *errbuf)
{
char * ifname;
pcap_if_t * all_devices = NULL;
if (pcap_findalldevs(&all_devices, errbuf) != 0)
{
return NULL;
}
ifname = strdup(all_devices[0].name);
pcap_freealldevs(all_devices);
return ifname;
}
static int setup_reader_threads(char const * const file_or_device) static int setup_reader_threads(char const * const file_or_device)
{ {
char const * file_or_default_device; char * file_or_default_device;
char pcap_error_buffer[PCAP_ERRBUF_SIZE]; char pcap_error_buffer[PCAP_ERRBUF_SIZE];
if (reader_thread_count > MAX_READER_THREADS) { if (reader_thread_count > MAX_READER_THREADS) {
@@ -206,27 +278,32 @@ static int setup_reader_threads(char const * const file_or_device)
} }
if (file_or_device == NULL) { if (file_or_device == NULL) {
file_or_default_device = pcap_lookupdev(pcap_error_buffer); file_or_default_device = get_default_pcapdev(pcap_error_buffer);
if (file_or_default_device == NULL) { if (file_or_default_device == NULL) {
fprintf(stderr, "pcap_lookupdev: %s\n", pcap_error_buffer); fprintf(stderr, "pcap_findalldevs: %.*s\n", (int) PCAP_ERRBUF_SIZE, pcap_error_buffer);
return 1; return 1;
} }
} else { } else {
file_or_default_device = file_or_device; file_or_default_device = strdup(file_or_device);
if (file_or_default_device == NULL) {
return 1;
}
} }
for (int i = 0; i < reader_thread_count; ++i) { for (int i = 0; i < reader_thread_count; ++i) {
reader_threads[i].workflow = init_workflow(file_or_default_device); reader_threads[i].workflow = init_workflow(file_or_default_device);
if (reader_threads[i].workflow == NULL) if (reader_threads[i].workflow == NULL)
{ {
free(file_or_default_device);
return 1; return 1;
} }
} }
free(file_or_default_device);
return 0; return 0;
} }
static int ip_tuple_to_string(struct nDPId_flow_info const * const flow, static int ip_tuple_to_string(struct nDPI_flow_info const * const flow,
char * const src_addr_str, size_t src_addr_len, char * const src_addr_str, size_t src_addr_len,
char * const dst_addr_str, size_t dst_addr_len) char * const dst_addr_str, size_t dst_addr_len)
{ {
@@ -247,18 +324,18 @@ static int ip_tuple_to_string(struct nDPId_flow_info const * const flow,
} }
#ifdef VERBOSE #ifdef VERBOSE
static void print_packet_info(struct nDPId_reader_thread const * const reader_thread, static void print_packet_info(struct nDPI_reader_thread const * const reader_thread,
struct pcap_pkthdr const * const header, struct pcap_pkthdr const * const header,
uint32_t l4_data_len, uint32_t l4_data_len,
struct nDPId_flow_info const * const flow) struct nDPI_flow_info const * const flow)
{ {
struct nDPId_workflow const * const workflow = reader_thread->workflow; struct nDPI_workflow const * const workflow = reader_thread->workflow;
char src_addr_str[INET6_ADDRSTRLEN+1] = {0}; char src_addr_str[INET6_ADDRSTRLEN+1] = {0};
char dst_addr_str[INET6_ADDRSTRLEN+1] = {0}; char dst_addr_str[INET6_ADDRSTRLEN+1] = {0};
char buf[256]; char buf[256];
int used = 0, ret; int used = 0, ret;
ret = snprintf(buf, sizeof(buf), "[%8llu, %d, %4u] %4u bytes: ", ret = ndpi_snprintf(buf, sizeof(buf), "[%8llu, %d, %4u] %4u bytes: ",
workflow->packets_captured, reader_thread->array_index, workflow->packets_captured, reader_thread->array_index,
flow->flow_id, header->caplen); flow->flow_id, header->caplen);
if (ret > 0) { if (ret > 0) {
@@ -266,9 +343,9 @@ static void print_packet_info(struct nDPId_reader_thread const * const reader_th
} }
if (ip_tuple_to_string(flow, src_addr_str, sizeof(src_addr_str), dst_addr_str, sizeof(dst_addr_str)) != 0) { if (ip_tuple_to_string(flow, src_addr_str, sizeof(src_addr_str), dst_addr_str, sizeof(dst_addr_str)) != 0) {
ret = snprintf(buf + used, sizeof(buf) - used, "IP[%s -> %s]", src_addr_str, dst_addr_str); ret = ndpi_snprintf(buf + used, sizeof(buf) - used, "IP[%s -> %s]", src_addr_str, dst_addr_str);
} else { } else {
ret = snprintf(buf + used, sizeof(buf) - used, "IP[ERROR]"); ret = ndpi_snprintf(buf + used, sizeof(buf) - used, "IP[ERROR]");
} }
if (ret > 0) { if (ret > 0) {
used += ret; used += ret;
@@ -276,24 +353,24 @@ static void print_packet_info(struct nDPId_reader_thread const * const reader_th
switch (flow->l4_protocol) { switch (flow->l4_protocol) {
case IPPROTO_UDP: case IPPROTO_UDP:
ret = snprintf(buf + used, sizeof(buf) - used, " -> UDP[%u -> %u, %u bytes]", ret = ndpi_snprintf(buf + used, sizeof(buf) - used, " -> UDP[%u -> %u, %u bytes]",
flow->src_port, flow->dst_port, l4_data_len); flow->src_port, flow->dst_port, l4_data_len);
break; break;
case IPPROTO_TCP: case IPPROTO_TCP:
ret = snprintf(buf + used, sizeof(buf) - used, " -> TCP[%u -> %u, %u bytes]", ret = ndpi_snprintf(buf + used, sizeof(buf) - used, " -> TCP[%u -> %u, %u bytes]",
flow->src_port, flow->dst_port, l4_data_len); flow->src_port, flow->dst_port, l4_data_len);
break; break;
case IPPROTO_ICMP: case IPPROTO_ICMP:
ret = snprintf(buf + used, sizeof(buf) - used, " -> ICMP"); ret = ndpi_snprintf(buf + used, sizeof(buf) - used, " -> ICMP");
break; break;
case IPPROTO_ICMPV6: case IPPROTO_ICMPV6:
ret = snprintf(buf + used, sizeof(buf) - used, " -> ICMP6"); ret = ndpi_snprintf(buf + used, sizeof(buf) - used, " -> ICMP6");
break; break;
case IPPROTO_HOPOPTS: case IPPROTO_HOPOPTS:
ret = snprintf(buf + used, sizeof(buf) - used, " -> ICMP6 Hop-By-Hop"); ret = ndpi_snprintf(buf + used, sizeof(buf) - used, " -> ICMP6 Hop-By-Hop");
break; break;
default: default:
ret = snprintf(buf + used, sizeof(buf) - used, " -> Unknown[0x%X]", flow->l4_protocol); ret = ndpi_snprintf(buf + used, sizeof(buf) - used, " -> Unknown[0x%X]", flow->l4_protocol);
break; break;
} }
if (ret > 0) { if (ret > 0) {
@@ -304,67 +381,79 @@ static void print_packet_info(struct nDPId_reader_thread const * const reader_th
} }
#endif #endif
static int ip_tuples_equal(struct nDPId_flow_info const * const A, static int ip_tuples_compare(struct nDPI_flow_info const * const A, struct nDPI_flow_info const * const B)
struct nDPId_flow_info const * const B)
{ {
if (A->l3_type == L3_IP && B->l3_type == L3_IP6) { // generate a warning if the enum changes
return A->ip_tuple.v4.src == B->ip_tuple.v4.src && switch (A->l3_type)
A->ip_tuple.v4.dst == B->ip_tuple.v4.dst; {
} else if (A->l3_type == L3_IP6 && B->l3_type == L3_IP6) { case L3_IP:
return A->ip_tuple.v6.src[0] == B->ip_tuple.v6.src[0] && case L3_IP6:
A->ip_tuple.v6.src[1] == B->ip_tuple.v6.src[1] && break;
A->ip_tuple.v6.dst[0] == B->ip_tuple.v6.dst[0] &&
A->ip_tuple.v6.dst[1] == B->ip_tuple.v6.dst[1];
} }
return 0;
}
static int ip_tuples_compare(struct nDPId_flow_info const * const A, if (A->l3_type == L3_IP && B->l3_type == L3_IP)
struct nDPId_flow_info const * const B) {
{ if (A->ip_tuple.v4.src < B->ip_tuple.v4.src)
if (A->l3_type == L3_IP && B->l3_type == L3_IP6) {
if (A->ip_tuple.v4.src < B->ip_tuple.v4.src ||
A->ip_tuple.v4.dst < B->ip_tuple.v4.dst)
{ {
return -1; return -1;
} }
if (A->ip_tuple.v4.src > B->ip_tuple.v4.src || if (A->ip_tuple.v4.src > B->ip_tuple.v4.src)
A->ip_tuple.v4.dst > B->ip_tuple.v4.dst)
{ {
return 1; return 1;
} }
} else if (A->l3_type == L3_IP6 && B->l3_type == L3_IP6) { if (A->ip_tuple.v4.dst < B->ip_tuple.v4.dst)
if ((A->ip_tuple.v6.src[0] < B->ip_tuple.v6.src[0] &&
A->ip_tuple.v6.src[1] < B->ip_tuple.v6.src[1]) ||
(A->ip_tuple.v6.dst[0] < B->ip_tuple.v6.dst[0] &&
A->ip_tuple.v6.dst[1] < B->ip_tuple.v6.dst[1]))
{ {
return -1; return -1;
} }
if ((A->ip_tuple.v6.src[0] > B->ip_tuple.v6.src[0] && if (A->ip_tuple.v4.dst > B->ip_tuple.v4.dst)
A->ip_tuple.v6.src[1] > B->ip_tuple.v6.src[1]) ||
(A->ip_tuple.v6.dst[0] > B->ip_tuple.v6.dst[0] &&
A->ip_tuple.v6.dst[1] > B->ip_tuple.v6.dst[1]))
{ {
return 1; return 1;
} }
} }
if (A->src_port < B->src_port || else if (A->l3_type == L3_IP6 && B->l3_type == L3_IP6)
A->dst_port < B->dst_port) {
if (A->ip_tuple.v6.src[0] < B->ip_tuple.v6.src[0] && A->ip_tuple.v6.src[1] < B->ip_tuple.v6.src[1])
{ {
return -1; return -1;
} else if (A->src_port > B->src_port || }
A->dst_port > B->dst_port) if (A->ip_tuple.v6.src[0] > B->ip_tuple.v6.src[0] && A->ip_tuple.v6.src[1] > B->ip_tuple.v6.src[1])
{ {
return 1; return 1;
} }
if (A->ip_tuple.v6.dst[0] < B->ip_tuple.v6.dst[0] && A->ip_tuple.v6.dst[1] < B->ip_tuple.v6.dst[1])
{
return -1;
}
if (A->ip_tuple.v6.dst[0] > B->ip_tuple.v6.dst[0] && A->ip_tuple.v6.dst[1] > B->ip_tuple.v6.dst[1])
{
return 1;
}
}
if (A->src_port < B->src_port)
{
return -1;
}
if (A->src_port > B->src_port)
{
return 1;
}
if (A->dst_port < B->dst_port)
{
return -1;
}
if (A->dst_port > B->dst_port)
{
return 1;
}
return 0; return 0;
} }
static void ndpi_idle_scan_walker(void const * const A, ndpi_VISIT which, int depth, void * const user_data) static void ndpi_idle_scan_walker(void const * const A, ndpi_VISIT which, int depth, void * const user_data)
{ {
struct nDPId_workflow * const workflow = (struct nDPId_workflow *)user_data; struct nDPI_workflow * const workflow = (struct nDPI_workflow *)user_data;
struct nDPId_flow_info * const flow = *(struct nDPId_flow_info **)A; struct nDPI_flow_info * const flow = *(struct nDPI_flow_info **)A;
(void)depth; (void)depth;
@@ -390,8 +479,8 @@ static void ndpi_idle_scan_walker(void const * const A, ndpi_VISIT which, int de
} }
static int ndpi_workflow_node_cmp(void const * const A, void const * const B) { static int ndpi_workflow_node_cmp(void const * const A, void const * const B) {
struct nDPId_flow_info const * const flow_info_a = (struct nDPId_flow_info *)A; struct nDPI_flow_info const * const flow_info_a = (struct nDPI_flow_info *)A;
struct nDPId_flow_info const * const flow_info_b = (struct nDPId_flow_info *)B; struct nDPI_flow_info const * const flow_info_b = (struct nDPI_flow_info *)B;
if (flow_info_a->hashval < flow_info_b->hashval) { if (flow_info_a->hashval < flow_info_b->hashval) {
return(-1); return(-1);
@@ -406,25 +495,18 @@ static int ndpi_workflow_node_cmp(void const * const A, void const * const B) {
return(1); return(1);
} }
if (ip_tuples_equal(flow_info_a, flow_info_b) != 0 &&
flow_info_a->src_port == flow_info_b->src_port &&
flow_info_a->dst_port == flow_info_b->dst_port)
{
return(0);
}
return ip_tuples_compare(flow_info_a, flow_info_b); return ip_tuples_compare(flow_info_a, flow_info_b);
} }
static void check_for_idle_flows(struct nDPId_workflow * const workflow) static void check_for_idle_flows(struct nDPI_workflow * const workflow)
{ {
if (workflow->last_idle_scan_time + IDLE_SCAN_PERIOD < workflow->last_time) { if (workflow->last_idle_scan_time + IDLE_SCAN_PERIOD < workflow->last_time) {
for (size_t idle_scan_index = 0; idle_scan_index < workflow->max_active_flows; ++idle_scan_index) { for (size_t idle_scan_index = 0; idle_scan_index < workflow->max_active_flows; ++idle_scan_index) {
ndpi_twalk(workflow->ndpi_flows_active[idle_scan_index], ndpi_idle_scan_walker, workflow); ndpi_twalk(workflow->ndpi_flows_active[idle_scan_index], ndpi_idle_scan_walker, workflow);
while (workflow->cur_idle_flows > 0) { while (workflow->cur_idle_flows > 0) {
struct nDPId_flow_info * const f = struct nDPI_flow_info * const f =
(struct nDPId_flow_info *)workflow->ndpi_flows_idle[--workflow->cur_idle_flows]; (struct nDPI_flow_info *)workflow->ndpi_flows_idle[--workflow->cur_idle_flows];
if (f->flow_fin_ack_seen == 1) { if (f->flow_fin_ack_seen == 1) {
printf("Free fin flow with id %u\n", f->flow_id); printf("Free fin flow with id %u\n", f->flow_id);
} else { } else {
@@ -445,18 +527,14 @@ static void ndpi_process_packet(uint8_t * const args,
struct pcap_pkthdr const * const header, struct pcap_pkthdr const * const header,
uint8_t const * const packet) uint8_t const * const packet)
{ {
struct nDPId_reader_thread * const reader_thread = struct nDPI_reader_thread * const reader_thread =
(struct nDPId_reader_thread *)args; (struct nDPI_reader_thread *)args;
struct nDPId_workflow * workflow; struct nDPI_workflow * workflow;
struct nDPId_flow_info flow = {}; struct nDPI_flow_info flow = {};
size_t hashed_index; size_t hashed_index;
void * tree_result; void * tree_result;
struct nDPId_flow_info * flow_to_process; struct nDPI_flow_info * flow_to_process;
int direction_changed = 0;
struct ndpi_id_struct * ndpi_src;
struct ndpi_id_struct * ndpi_dst;
const struct ndpi_ethhdr * ethernet; const struct ndpi_ethhdr * ethernet;
const struct ndpi_iphdr * ip; const struct ndpi_iphdr * ip;
@@ -471,7 +549,7 @@ static void ndpi_process_packet(uint8_t * const args,
uint16_t l4_len = 0; uint16_t l4_len = 0;
uint16_t type; uint16_t type;
int thread_index = INITIAL_THREAD_HASH; // generated with `dd if=/dev/random bs=1024 count=1 |& hd' uint32_t thread_index = INITIAL_THREAD_HASH; // generated with `dd if=/dev/random bs=1024 count=1 |& hd'
if (reader_thread == NULL) { if (reader_thread == NULL) {
return; return;
@@ -655,7 +733,7 @@ static void ndpi_process_packet(uint8_t * const args,
workflow->total_l4_data_len += l4_len; workflow->total_l4_data_len += l4_len;
#ifdef VERBOSE #ifdef VERBOSE
print_packet_info(reader_thread, header, l4_data_len, &flow); print_packet_info(reader_thread, header, l4_len, &flow);
#endif #endif
/* calculate flow hash for btree find, search(insert) */ /* calculate flow hash for btree find, search(insert) */
@@ -681,27 +759,38 @@ static void ndpi_process_packet(uint8_t * const args,
tree_result = ndpi_tfind(&flow, &workflow->ndpi_flows_active[hashed_index], ndpi_workflow_node_cmp); tree_result = ndpi_tfind(&flow, &workflow->ndpi_flows_active[hashed_index], ndpi_workflow_node_cmp);
if (tree_result == NULL) { if (tree_result == NULL) {
/* flow not found in btree: switch src <-> dst and try to find it again */ /* flow not found in btree: switch src <-> dst and try to find it again */
uint64_t orig_src_ip[2] = { flow.ip_tuple.v6.src[0], flow.ip_tuple.v6.src[1] }; uint32_t orig_src_ip[4] = { flow.ip_tuple.u32.src[0], flow.ip_tuple.u32.src[1],
uint64_t orig_dst_ip[2] = { flow.ip_tuple.v6.dst[0], flow.ip_tuple.v6.dst[1] }; flow.ip_tuple.u32.src[2], flow.ip_tuple.u32.src[3] };
uint32_t orig_dst_ip[4] = { flow.ip_tuple.u32.dst[0], flow.ip_tuple.u32.dst[1],
flow.ip_tuple.u32.dst[2], flow.ip_tuple.u32.dst[3] };
uint16_t orig_src_port = flow.src_port; uint16_t orig_src_port = flow.src_port;
uint16_t orig_dst_port = flow.dst_port; uint16_t orig_dst_port = flow.dst_port;
flow.ip_tuple.v6.src[0] = orig_dst_ip[0]; flow.ip_tuple.u32.src[0] = orig_dst_ip[0];
flow.ip_tuple.v6.src[1] = orig_dst_ip[1]; flow.ip_tuple.u32.src[1] = orig_dst_ip[1];
flow.ip_tuple.v6.dst[0] = orig_src_ip[0]; flow.ip_tuple.u32.src[2] = orig_dst_ip[2];
flow.ip_tuple.v6.dst[1] = orig_src_ip[1]; flow.ip_tuple.u32.src[3] = orig_dst_ip[3];
flow.ip_tuple.u32.dst[0] = orig_src_ip[0];
flow.ip_tuple.u32.dst[1] = orig_src_ip[1];
flow.ip_tuple.u32.dst[2] = orig_src_ip[2];
flow.ip_tuple.u32.dst[3] = orig_src_ip[3];
flow.src_port = orig_dst_port; flow.src_port = orig_dst_port;
flow.dst_port = orig_src_port; flow.dst_port = orig_src_port;
tree_result = ndpi_tfind(&flow, &workflow->ndpi_flows_active[hashed_index], ndpi_workflow_node_cmp); tree_result = ndpi_tfind(&flow, &workflow->ndpi_flows_active[hashed_index], ndpi_workflow_node_cmp);
if (tree_result != NULL) {
direction_changed = 1;
}
flow.ip_tuple.v6.src[0] = orig_src_ip[0]; flow.ip_tuple.u32.src[0] = orig_src_ip[0];
flow.ip_tuple.v6.src[1] = orig_src_ip[1]; flow.ip_tuple.u32.src[1] = orig_src_ip[1];
flow.ip_tuple.v6.dst[0] = orig_dst_ip[0]; flow.ip_tuple.u32.src[2] = orig_src_ip[2];
flow.ip_tuple.v6.dst[1] = orig_dst_ip[1]; flow.ip_tuple.u32.src[3] = orig_src_ip[3];
flow.ip_tuple.u32.dst[0] = orig_dst_ip[0];
flow.ip_tuple.u32.dst[1] = orig_dst_ip[1];
flow.ip_tuple.u32.dst[2] = orig_dst_ip[2];
flow.ip_tuple.u32.dst[3] = orig_dst_ip[3];
flow.src_port = orig_src_port; flow.src_port = orig_src_port;
flow.dst_port = orig_dst_port; flow.dst_port = orig_dst_port;
} }
@@ -715,17 +804,15 @@ static void ndpi_process_packet(uint8_t * const args,
return; return;
} }
flow_to_process = (struct nDPId_flow_info *)ndpi_malloc(sizeof(*flow_to_process)); flow_to_process = (struct nDPI_flow_info *)ndpi_malloc(sizeof(*flow_to_process));
if (flow_to_process == NULL) { if (flow_to_process == NULL) {
fprintf(stderr, "[%8llu, %d] Not enough memory for flow info\n", fprintf(stderr, "[%8llu, %d] Not enough memory for flow info\n",
workflow->packets_captured, reader_thread->array_index); workflow->packets_captured, reader_thread->array_index);
return; return;
} }
workflow->cur_active_flows++;
workflow->total_active_flows++;
memcpy(flow_to_process, &flow, sizeof(*flow_to_process)); memcpy(flow_to_process, &flow, sizeof(*flow_to_process));
flow_to_process->flow_id = flow_id++; flow_to_process->flow_id = __sync_fetch_and_add(&flow_id, 1);
flow_to_process->ndpi_flow = (struct ndpi_flow_struct *)ndpi_flow_malloc(SIZEOF_FLOW_STRUCT); flow_to_process->ndpi_flow = (struct ndpi_flow_struct *)ndpi_flow_malloc(SIZEOF_FLOW_STRUCT);
if (flow_to_process->ndpi_flow == NULL) { if (flow_to_process->ndpi_flow == NULL) {
@@ -735,20 +822,6 @@ static void ndpi_process_packet(uint8_t * const args,
} }
memset(flow_to_process->ndpi_flow, 0, SIZEOF_FLOW_STRUCT); memset(flow_to_process->ndpi_flow, 0, SIZEOF_FLOW_STRUCT);
flow_to_process->ndpi_src = (struct ndpi_id_struct *)ndpi_calloc(1, SIZEOF_ID_STRUCT);
if (flow_to_process->ndpi_src == NULL) {
fprintf(stderr, "[%8llu, %d, %4u] Not enough memory for src id struct\n",
workflow->packets_captured, reader_thread->array_index, flow_to_process->flow_id);
return;
}
flow_to_process->ndpi_dst = (struct ndpi_id_struct *)ndpi_calloc(1, SIZEOF_ID_STRUCT);
if (flow_to_process->ndpi_dst == NULL) {
fprintf(stderr, "[%8llu, %d, %4u] Not enough memory for dst id struct\n",
workflow->packets_captured, reader_thread->array_index, flow_to_process->flow_id);
return;
}
printf("[%8llu, %d, %4u] new %sflow\n", workflow->packets_captured, thread_index, printf("[%8llu, %d, %4u] new %sflow\n", workflow->packets_captured, thread_index,
flow_to_process->flow_id, flow_to_process->flow_id,
(flow_to_process->is_midstream_flow != 0 ? "midstream-" : "")); (flow_to_process->is_midstream_flow != 0 ? "midstream-" : ""));
@@ -757,18 +830,10 @@ static void ndpi_process_packet(uint8_t * const args,
return; return;
} }
ndpi_src = flow_to_process->ndpi_src; workflow->cur_active_flows++;
ndpi_dst = flow_to_process->ndpi_dst; workflow->total_active_flows++;
} else { } else {
flow_to_process = *(struct nDPId_flow_info **)tree_result; flow_to_process = *(struct nDPI_flow_info **)tree_result;
if (direction_changed != 0) {
ndpi_src = flow_to_process->ndpi_dst;
ndpi_dst = flow_to_process->ndpi_src;
} else {
ndpi_src = flow_to_process->ndpi_src;
ndpi_dst = flow_to_process->ndpi_dst;
}
} }
flow_to_process->packets_processed++; flow_to_process->packets_processed++;
@@ -789,6 +854,10 @@ static void ndpi_process_packet(uint8_t * const args,
return; return;
} }
/*
* This example tries to use maximum supported packets for detection:
* for uint8: 0xFF
*/
if (flow_to_process->ndpi_flow->num_processed_pkts == 0xFF) { if (flow_to_process->ndpi_flow->num_processed_pkts == 0xFF) {
return; return;
} else if (flow_to_process->ndpi_flow->num_processed_pkts == 0xFE) { } else if (flow_to_process->ndpi_flow->num_processed_pkts == 0xFE) {
@@ -815,16 +884,18 @@ static void ndpi_process_packet(uint8_t * const args,
flow_to_process->detected_l7_protocol = flow_to_process->detected_l7_protocol =
ndpi_detection_process_packet(workflow->ndpi_struct, flow_to_process->ndpi_flow, ndpi_detection_process_packet(workflow->ndpi_struct, flow_to_process->ndpi_flow,
ip != NULL ? (uint8_t *)ip : (uint8_t *)ip6, ip != NULL ? (uint8_t *)ip : (uint8_t *)ip6,
ip_size, time_ms, ndpi_src, ndpi_dst); ip_size, time_ms, NULL);
if (ndpi_is_protocol_detected(workflow->ndpi_struct, if (ndpi_is_protocol_detected(workflow->ndpi_struct,
flow_to_process->detected_l7_protocol) != 0 && flow_to_process->detected_l7_protocol) != 0 &&
flow_to_process->detection_completed == 0) flow_to_process->detection_completed == 0)
{ {
if (flow_to_process->detected_l7_protocol.master_protocol != NDPI_PROTOCOL_UNKNOWN || if (flow_to_process->detected_l7_protocol.master_protocol != NDPI_PROTOCOL_UNKNOWN ||
flow_to_process->detected_l7_protocol.app_protocol != NDPI_PROTOCOL_UNKNOWN) { flow_to_process->detected_l7_protocol.app_protocol != NDPI_PROTOCOL_UNKNOWN)
{
flow_to_process->detection_completed = 1; flow_to_process->detection_completed = 1;
workflow->detected_flow_protocols++; workflow->detected_flow_protocols++;
printf("[%8llu, %d, %4d][DETECTED] protocol: %s | app protocol: %s | category: %s\n", printf("[%8llu, %d, %4d][DETECTED] protocol: %s | app protocol: %s | category: %s\n",
workflow->packets_captured, workflow->packets_captured,
reader_thread->array_index, reader_thread->array_index,
@@ -835,53 +906,83 @@ static void ndpi_process_packet(uint8_t * const args,
} }
} }
if (flow_to_process->ndpi_flow->num_extra_packets_checked < if (flow_to_process->ndpi_flow->num_extra_packets_checked <=
flow_to_process->ndpi_flow->max_extra_packets_to_check) flow_to_process->ndpi_flow->max_extra_packets_to_check)
{ {
/*
* Your business logic starts here.
*
* This example does print some information about
* TLS client and server hellos if available.
*
* You could also use nDPI's built-in json serialization
* and send it to a high-level application for further processing.
*
* EoE - End of Example
*/
if (flow_to_process->flow_info_printed == 0)
{
char const * const flow_info = ndpi_get_flow_info(flow_to_process->ndpi_flow, &flow_to_process->detected_l7_protocol);
if (flow_info != NULL)
{
printf("[%8llu, %d, %4d] info: %s\n",
workflow->packets_captured,
reader_thread->array_index,
flow_to_process->flow_id,
flow_info);
flow_to_process->flow_info_printed = 1;
}
}
if (flow_to_process->detected_l7_protocol.master_protocol == NDPI_PROTOCOL_TLS || if (flow_to_process->detected_l7_protocol.master_protocol == NDPI_PROTOCOL_TLS ||
flow_to_process->detected_l7_protocol.app_protocol == NDPI_PROTOCOL_TLS) flow_to_process->detected_l7_protocol.app_protocol == NDPI_PROTOCOL_TLS)
{ {
if (flow_to_process->tls_client_hello_seen == 0 && if (flow_to_process->tls_client_hello_seen == 0 &&
flow_to_process->ndpi_flow->l4.tcp.tls.hello_processed != 0) flow_to_process->ndpi_flow->protos.tls_quic.hello_processed != 0)
{ {
uint8_t unknown_tls_version = 0; uint8_t unknown_tls_version = 0;
printf("[%8llu, %d, %4d][TLS-CLIENT-HELLO] version: %s | sni: %s | alpn: %s\n", char buf_ver[16];
printf("[%8llu, %d, %4d][TLS-CLIENT-HELLO] version: %s | sni: %s | (advertised) ALPNs: %s\n",
workflow->packets_captured, workflow->packets_captured,
reader_thread->array_index, reader_thread->array_index,
flow_to_process->flow_id, flow_to_process->flow_id,
ndpi_ssl_version2str(flow_to_process->ndpi_flow->protos.stun_ssl.ssl.ssl_version, ndpi_ssl_version2str(buf_ver, sizeof(buf_ver),
flow_to_process->ndpi_flow->protos.tls_quic.ssl_version,
&unknown_tls_version), &unknown_tls_version),
flow_to_process->ndpi_flow->protos.stun_ssl.ssl.client_requested_server_name, flow_to_process->ndpi_flow->host_server_name,
(flow_to_process->ndpi_flow->protos.stun_ssl.ssl.alpn != NULL ? (flow_to_process->ndpi_flow->protos.tls_quic.advertised_alpns != NULL ?
flow_to_process->ndpi_flow->protos.stun_ssl.ssl.alpn : "-")); flow_to_process->ndpi_flow->protos.tls_quic.advertised_alpns : "-"));
flow_to_process->tls_client_hello_seen = 1; flow_to_process->tls_client_hello_seen = 1;
} }
#if (NDPI_MAJOR >= 3 && NDPI_MINOR > 2)
if (flow_to_process->tls_server_hello_seen == 0 && if (flow_to_process->tls_server_hello_seen == 0 &&
flow_to_process->ndpi_flow->l4.tcp.tls.certificate_processed != 0) flow_to_process->ndpi_flow->tls_quic.certificate_processed != 0)
{ {
uint8_t unknown_tls_version = 0; uint8_t unknown_tls_version = 0;
char buf_ver[16];
printf("[%8llu, %d, %4d][TLS-SERVER-HELLO] version: %s | common-name(s): %.*s | " printf("[%8llu, %d, %4d][TLS-SERVER-HELLO] version: %s | common-name(s): %.*s | "
"issuer: %s | subject: %s\n", "issuer: %s | subject: %s\n",
workflow->packets_captured, workflow->packets_captured,
reader_thread->array_index, reader_thread->array_index,
flow_to_process->flow_id, flow_to_process->flow_id,
ndpi_ssl_version2str(flow_to_process->ndpi_flow->protos.stun_ssl.ssl.ssl_version, ndpi_ssl_version2str(buf_ver, sizeof(buf_ver),
flow_to_process->ndpi_flow->protos.tls_quic.ssl_version,
&unknown_tls_version), &unknown_tls_version),
flow_to_process->ndpi_flow->protos.stun_ssl.ssl.server_names_len, (flow_to_process->ndpi_flow->protos.tls_quic.server_names_len == 0 ?
flow_to_process->ndpi_flow->protos.stun_ssl.ssl.server_names, 1 : flow_to_process->ndpi_flow->protos.tls_quic.server_names_len),
(flow_to_process->ndpi_flow->protos.stun_ssl.ssl.issuerDN != NULL ? (flow_to_process->ndpi_flow->protos.tls_quic.server_names == NULL ?
flow_to_process->ndpi_flow->protos.stun_ssl.ssl.issuerDN : "-"), "-" : flow_to_process->ndpi_flow->protos.tls_quic.server_names),
(flow_to_process->ndpi_flow->protos.stun_ssl.ssl.subjectDN != NULL ? (flow_to_process->ndpi_flow->protos.tls_quic.issuerDN != NULL ?
flow_to_process->ndpi_flow->protos.stun_ssl.ssl.subjectDN : "-")); flow_to_process->ndpi_flow->protos.tls_quic.issuerDN : "-"),
(flow_to_process->ndpi_flow->protos.tls_quic.subjectDN != NULL ?
flow_to_process->ndpi_flow->protos.tls_quic.subjectDN : "-"));
flow_to_process->tls_server_hello_seen = 1; flow_to_process->tls_server_hello_seen = 1;
} }
#endif
} }
} }
} }
static void run_pcap_loop(struct nDPId_reader_thread const * const reader_thread) static void run_pcap_loop(struct nDPI_reader_thread const * const reader_thread)
{ {
if (reader_thread->workflow != NULL && if (reader_thread->workflow != NULL &&
reader_thread->workflow->pcap_handle != NULL) { reader_thread->workflow->pcap_handle != NULL) {
@@ -891,12 +992,12 @@ static void run_pcap_loop(struct nDPId_reader_thread const * const reader_thread
fprintf(stderr, "Error while reading pcap file: '%s'\n", fprintf(stderr, "Error while reading pcap file: '%s'\n",
pcap_geterr(reader_thread->workflow->pcap_handle)); pcap_geterr(reader_thread->workflow->pcap_handle));
reader_thread->workflow->error_or_eof = 1; __sync_fetch_and_add(&reader_thread->workflow->error_or_eof, 1);
} }
} }
} }
static void break_pcap_loop(struct nDPId_reader_thread * const reader_thread) static void break_pcap_loop(struct nDPI_reader_thread * const reader_thread)
{ {
if (reader_thread->workflow != NULL && if (reader_thread->workflow != NULL &&
reader_thread->workflow->pcap_handle != NULL) reader_thread->workflow->pcap_handle != NULL)
@@ -907,19 +1008,19 @@ static void break_pcap_loop(struct nDPId_reader_thread * const reader_thread)
static void * processing_thread(void * const ndpi_thread_arg) static void * processing_thread(void * const ndpi_thread_arg)
{ {
struct nDPId_reader_thread const * const reader_thread = struct nDPI_reader_thread const * const reader_thread =
(struct nDPId_reader_thread *)ndpi_thread_arg; (struct nDPI_reader_thread *)ndpi_thread_arg;
printf("Starting ThreadID %d\n", reader_thread->array_index); printf("Starting Thread %d\n", reader_thread->array_index);
run_pcap_loop(reader_thread); run_pcap_loop(reader_thread);
reader_thread->workflow->error_or_eof = 1; __sync_fetch_and_add(&reader_thread->workflow->error_or_eof, 1);
return NULL; return NULL;
} }
static int processing_threads_error_or_eof(void) static int processing_threads_error_or_eof(void)
{ {
for (int i = 0; i < reader_thread_count; ++i) { for (int i = 0; i < reader_thread_count; ++i) {
if (reader_threads[i].workflow->error_or_eof == 0) { if (__sync_fetch_and_add(&reader_threads[i].workflow->error_or_eof, 0) == 0) {
return 0; return 0;
} }
} }
@@ -928,6 +1029,7 @@ static int processing_threads_error_or_eof(void)
static int start_reader_threads(void) static int start_reader_threads(void)
{ {
#ifndef WIN32
sigset_t thread_signal_set, old_signal_set; sigset_t thread_signal_set, old_signal_set;
sigfillset(&thread_signal_set); sigfillset(&thread_signal_set);
@@ -937,6 +1039,7 @@ static int start_reader_threads(void)
fprintf(stderr, "pthread_sigmask: %s\n", strerror(errno)); fprintf(stderr, "pthread_sigmask: %s\n", strerror(errno));
return 1; return 1;
} }
#endif
for (int i = 0; i < reader_thread_count; ++i) { for (int i = 0; i < reader_thread_count; ++i) {
reader_threads[i].array_index = i; reader_threads[i].array_index = i;
@@ -964,6 +1067,7 @@ static int start_reader_threads(void)
static int stop_reader_threads(void) static int stop_reader_threads(void)
{ {
unsigned long long int total_packets_captured = 0;
unsigned long long int total_packets_processed = 0; unsigned long long int total_packets_processed = 0;
unsigned long long int total_l4_data_len = 0; unsigned long long int total_l4_data_len = 0;
unsigned long long int total_flows_captured = 0; unsigned long long int total_flows_captured = 0;
@@ -981,6 +1085,10 @@ static int stop_reader_threads(void)
continue; continue;
} }
if (pthread_join(reader_threads[i].thread_id, NULL) != 0) {
fprintf(stderr, "pthread_join: %s\n", strerror(errno));
}
total_packets_processed += reader_threads[i].workflow->packets_processed; total_packets_processed += reader_threads[i].workflow->packets_processed;
total_l4_data_len += reader_threads[i].workflow->total_l4_data_len; total_l4_data_len += reader_threads[i].workflow->total_l4_data_len;
total_flows_captured += reader_threads[i].workflow->total_active_flows; total_flows_captured += reader_threads[i].workflow->total_active_flows;
@@ -993,27 +1101,25 @@ static int stop_reader_threads(void)
reader_threads[i].workflow->total_l4_data_len, reader_threads[i].workflow->total_active_flows, reader_threads[i].workflow->total_l4_data_len, reader_threads[i].workflow->total_active_flows,
reader_threads[i].workflow->total_idle_flows, reader_threads[i].workflow->detected_flow_protocols); reader_threads[i].workflow->total_idle_flows, reader_threads[i].workflow->detected_flow_protocols);
} }
/* total packets captured: same value for all threads as packet2thread distribution happens later */ /* total packets captured: same value for all threads as packet2thread distribution happens later */
printf("Total packets captured.: %llu\n", total_packets_captured = reader_threads[0].workflow->packets_captured;
reader_threads[0].workflow->packets_captured);
printf("Total packets processed: %llu\n", total_packets_processed);
printf("Total layer4 data size.: %llu\n", total_l4_data_len);
printf("Total flows captured...: %llu\n", total_flows_captured);
printf("Total flows timed out..: %llu\n", total_flows_idle);
printf("Total flows detected...: %llu\n", total_flows_detected);
for (int i = 0; i < reader_thread_count; ++i) { for (int i = 0; i < reader_thread_count; ++i) {
if (reader_threads[i].workflow == NULL) { if (reader_threads[i].workflow == NULL) {
continue; continue;
} }
if (pthread_join(reader_threads[i].thread_id, NULL) != 0) {
fprintf(stderr, "pthread_join: %s\n", strerror(errno));
}
free_workflow(&reader_threads[i].workflow); free_workflow(&reader_threads[i].workflow);
} }
printf("Total packets captured.: %llu\n", total_packets_captured);
printf("Total packets processed: %llu\n", total_packets_processed);
printf("Total layer4 data size.: %llu\n", total_l4_data_len);
printf("Total flows captured...: %llu\n", total_flows_captured);
printf("Total flows timed out..: %llu\n", total_flows_idle);
printf("Total flows detected...: %llu\n", total_flows_detected);
return 0; return 0;
} }
@@ -1021,12 +1127,8 @@ static void sighandler(int signum)
{ {
fprintf(stderr, "Received SIGNAL %d\n", signum); fprintf(stderr, "Received SIGNAL %d\n", signum);
if (main_thread_shutdown == 0) { if (__sync_fetch_and_add(&main_thread_shutdown, 0) == 0) {
main_thread_shutdown = 1; __sync_fetch_and_add(&main_thread_shutdown, 1);
if (stop_reader_threads() != 0) {
fprintf(stderr, "Failed to stop reader threads!\n");
exit(EXIT_FAILURE);
}
} else { } else {
fprintf(stderr, "Reader threads are already shutting down, please be patient.\n"); fprintf(stderr, "Reader threads are already shutting down, please be patient.\n");
} }
@@ -1035,6 +1137,7 @@ static void sighandler(int signum)
int main(int argc, char ** argv) int main(int argc, char ** argv)
{ {
if (argc == 0) { if (argc == 0) {
printf("usage: ndpiSimpleIntegration Mdevice name>\n");
return 1; return 1;
} }
@@ -1042,9 +1145,11 @@ int main(int argc, char ** argv)
"----------------------------------\n" "----------------------------------\n"
"nDPI version: %s\n" "nDPI version: %s\n"
" API version: %u\n" " API version: %u\n"
"libgcrypt...: %s\n"
"----------------------------------\n", "----------------------------------\n",
argv[0], argv[0],
ndpi_revision(), ndpi_get_api_version()); ndpi_revision(), ndpi_get_api_version(),
(ndpi_get_gcrypt_version() == NULL ? "-" : ndpi_get_gcrypt_version()));
if (setup_reader_threads((argc >= 2 ? argv[1] : NULL)) != 0) { if (setup_reader_threads((argc >= 2 ? argv[1] : NULL)) != 0) {
fprintf(stderr, "%s: setup_reader_threads failed\n", argv[0]); fprintf(stderr, "%s: setup_reader_threads failed\n", argv[0]);
@@ -1058,11 +1163,11 @@ int main(int argc, char ** argv)
signal(SIGINT, sighandler); signal(SIGINT, sighandler);
signal(SIGTERM, sighandler); signal(SIGTERM, sighandler);
while (main_thread_shutdown == 0 && processing_threads_error_or_eof() == 0) { while (__sync_fetch_and_add(&main_thread_shutdown, 0) == 0 && processing_threads_error_or_eof() == 0) {
sleep(1); sleep(1);
} }
if (main_thread_shutdown == 0 && stop_reader_threads() != 0) { if (stop_reader_threads() != 0) {
fprintf(stderr, "%s: stop_reader_threads\n", argv[0]); fprintf(stderr, "%s: stop_reader_threads\n", argv[0]);
return 1; return 1;
} }