aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToni <matzeton@googlemail.com>2024-10-16 14:13:55 +0200
committerGitHub <noreply@github.com>2024-10-16 14:13:55 +0200
commitefed6f196ecab333b76b83a5d256c9e4e6b75867 (patch)
treed8e5963a07a1ea87f3547a0e9ae8d370e6cb06f5
parent3e2ce661f01545daeb311d671bf222d378729bca (diff)
Read and parse configuration files. Fixes #41. (#42)1.7rc1
Read and parse configuration files. Fixes #41. * supports nDPId / nDPIsrvd via command line parameter `-f` * nDPId: read general/tuning and libnDPI settings * support for settings risk domains libnDPI option via config file or via `-R` (Fixes #45, thanks to @UnveilTech) * added some documentation in the config file * adjusted Systemd and Debian packaging to make use of config files Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rw-r--r--CMakeLists.txt9
-rw-r--r--dependencies/nDPIsrvd.h4
-rw-r--r--examples/c-analysed/c-analysed.c2
-rw-r--r--examples/c-captured/c-captured.c14
-rw-r--r--examples/c-influxd/c-influxd.c2
-rw-r--r--nDPId-test.c31
-rw-r--r--nDPId.c1087
-rw-r--r--nDPIsrvd.c374
-rw-r--r--ndpid.conf.example86
-rw-r--r--ndpisrvd.conf.example31
-rwxr-xr-xpackages/debian/postrm6
-rwxr-xr-xpackages/debian/preinst16
-rwxr-xr-xpackages/debian/prerm3
-rw-r--r--packages/systemd/default.cfg2
-rw-r--r--packages/systemd/ndpid@.service.in5
-rw-r--r--packages/systemd/ndpisrvd.service.in7
-rw-r--r--utils.c361
-rw-r--r--utils.h87
18 files changed, 1494 insertions, 633 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 90ab44042..b10262580 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,6 +22,11 @@ find_package(PkgConfig REQUIRED)
set(CPACK_PACKAGE_CONTACT "toni@impl.cc")
set(CPACK_DEBIAN_PACKAGE_NAME "nDPId")
+set(CPACK_DEBIAN_PACKAGE_SECTION "network")
+set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "nDPId is a set of daemons and tools to capture, process and classify network traffic.")
+set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Toni Uhlig")
+set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/packages/debian/preinst;${CMAKE_SOURCE_DIR}/packages/debian/prerm;${CMAKE_SOURCE_DIR}/packages/debian/postrm")
+set(CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION TRUE)
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
set(CPACK_DEBIAN_DEBUGINFO_PACKAGE ON)
set(CPACK_STRIP_FILES ON)
@@ -516,7 +521,9 @@ if(ENABLE_SYSTEMD)
configure_file(packages/systemd/ndpisrvd.service.in ndpisrvd.service @ONLY)
configure_file(packages/systemd/ndpid@.service.in ndpid@.service @ONLY)
- install(FILES packages/systemd/default.cfg DESTINATION etc/default RENAME ndpid)
+ install(DIRECTORY DESTINATION etc/nDPId)
+ install(FILES "ndpid.conf.example" DESTINATION share/nDPId)
+ install(FILES "ndpisrvd.conf.example" DESTINATION share/nDPId)
install(FILES "${CMAKE_BINARY_DIR}/ndpisrvd.service" DESTINATION lib/systemd/system)
install(FILES "${CMAKE_BINARY_DIR}/ndpid@.service" DESTINATION lib/systemd/system)
endif()
diff --git a/dependencies/nDPIsrvd.h b/dependencies/nDPIsrvd.h
index 133beff5e..3b12304da 100644
--- a/dependencies/nDPIsrvd.h
+++ b/dependencies/nDPIsrvd.h
@@ -33,8 +33,8 @@
#define nDPIsrvd_JSON_KEY_STRLEN (32)
#define nDPIsrvd_HASHKEY_SEED (0x995fd871u)
-#define nDPIsrvd_ARRAY_LENGTH(s) (sizeof(s) / sizeof(s[0]))
-#define nDPIsrvd_STRLEN_SZ(s) (sizeof(s) / sizeof(s[0]) - sizeof(s[0]))
+#define nDPIsrvd_ARRAY_LENGTH(s) ((size_t)(sizeof(s) / sizeof(s[0])))
+#define nDPIsrvd_STRLEN_SZ(s) ((size_t)((sizeof(s) / sizeof(s[0])) - sizeof(s[0])))
#define TOKEN_GET_SZ(sock, ...) nDPIsrvd_get_token(sock, __VA_ARGS__, NULL)
#define TOKEN_VALUE_EQUALS(sock, token, string_to_check, string_to_check_length) \
nDPIsrvd_token_value_equals(sock, token, string_to_check, string_to_check_length)
diff --git a/examples/c-analysed/c-analysed.c b/examples/c-analysed/c-analysed.c
index 71ab7fa4a..2811f70f8 100644
--- a/examples/c-analysed/c-analysed.c
+++ b/examples/c-analysed/c-analysed.c
@@ -2059,7 +2059,7 @@ int main(int argc, char ** argv)
}
errno = 0;
- if (user != NULL && change_user_group(user, group, pidfile, NULL, NULL) != 0)
+ if (user != NULL && change_user_group(user, group, pidfile) != 0)
{
if (errno != 0)
{
diff --git a/examples/c-captured/c-captured.c b/examples/c-captured/c-captured.c
index ce0c46c2e..98df7c4b8 100644
--- a/examples/c-captured/c-captured.c
+++ b/examples/c-captured/c-captured.c
@@ -24,7 +24,7 @@
#include "utarray.h"
#include "utils.h"
-//#define VERBOSE
+// #define VERBOSE
#define DEFAULT_DATADIR "/tmp/nDPId-captured"
struct packet_data
@@ -1355,8 +1355,14 @@ int main(int argc, char ** argv)
return 1;
}
+ if (capture_mode != 0 && chmod_chown(datadir, S_IRWXU | S_IRGRP | S_IXGRP, user, group) != 0)
+ {
+ logger(1, "Could not chmod/chown `%s': %s", datadir, strerror(errno));
+ return 1;
+ }
+
errno = 0;
- if (user != NULL && change_user_group(user, group, pidfile, datadir /* :D */, NULL) != 0)
+ if (user != NULL && change_user_group(user, group, pidfile) != 0)
{
if (errno != 0)
{
@@ -1368,10 +1374,6 @@ int main(int argc, char ** argv)
}
return 1;
}
- if (datadir != NULL)
- {
- chmod(datadir, S_IRWXU);
- }
if (nDPIsrvd_set_read_timeout(ndpisrvd_socket, 180, 0) != 0)
{
diff --git a/examples/c-influxd/c-influxd.c b/examples/c-influxd/c-influxd.c
index fd4ab8cb0..9eabbe461 100644
--- a/examples/c-influxd/c-influxd.c
+++ b/examples/c-influxd/c-influxd.c
@@ -1671,7 +1671,7 @@ int main(int argc, char ** argv)
}
errno = 0;
- if (user != NULL && change_user_group(user, group, pidfile, NULL, NULL) != 0)
+ if (user != NULL && change_user_group(user, group, pidfile) != 0)
{
if (errno != 0)
{
diff --git a/nDPId-test.c b/nDPId-test.c
index 38f327a38..d48784f38 100644
--- a/nDPId-test.c
+++ b/nDPId-test.c
@@ -7,7 +7,7 @@ extern void nDPIsrvd_memprof_log(char const * const format, ...);
extern void nDPIsrvd_memprof_log_alloc(size_t alloc_size);
extern void nDPIsrvd_memprof_log_free(size_t free_size);
-//#define VERBOSE_MEMORY_PROFILING 1
+// #define VERBOSE_MEMORY_PROFILING 1
#define NO_MAIN 1
#include "utils.c"
#include "nio.c"
@@ -1315,7 +1315,7 @@ static void * nDPId_mainloop_thread(void * const arg)
}
run_capture_loop(&reader_threads[0]);
process_remaining_flows();
- for (size_t i = 0; i < nDPId_options.reader_thread_count; ++i)
+ for (size_t i = 0; i < GET_CMDARG_ULL(nDPId_options.reader_thread_count); ++i)
{
nrv->packets_captured += reader_threads[i].workflow->packets_captured;
nrv->packets_processed += reader_threads[i].workflow->packets_processed;
@@ -1667,27 +1667,30 @@ int main(int argc, char ** argv)
return retval;
}
- nDPIsrvd_options.max_write_buffers = 32;
- nDPId_options.enable_data_analysis = 1;
- nDPId_options.max_packets_per_flow_to_send = 5;
+ set_cmdarg_ull(&nDPIsrvd_options.max_write_buffers, 32);
+ set_cmdarg_boolean(&nDPId_options.enable_data_analysis, 1);
+ set_cmdarg_ull(&nDPId_options.max_packets_per_flow_to_send, 5);
#ifdef ENABLE_ZLIB
/*
* zLib compression is forced enabled for testing.
* Remember to compile nDPId with zlib enabled.
* There will be diff's while running `test/run_tests.sh' otherwise.
*/
- nDPId_options.enable_zlib_compression = 1;
+ set_cmdarg_boolean(&nDPId_options.enable_zlib_compression, 1);
#endif
- nDPId_options.memory_profiling_log_interval = (unsigned long long int)-1;
- nDPId_options.reader_thread_count = 1; /* Please do not change this! Generating meaningful pcap diff's relies on a
- single reader thread! */
- set_cmdarg(&nDPId_options.instance_alias, "nDPId-test");
+ set_cmdarg_ull(&nDPId_options.memory_profiling_log_interval, (unsigned long long int)-1);
+ set_cmdarg_ull(&nDPId_options.reader_thread_count, 1); /* Please do not change this! Generating meaningful pcap
+ diff's relies on a single reader thread! */
+ set_cmdarg_string(&nDPId_options.instance_alias, "nDPId-test");
if (access(argv[1], R_OK) != 0)
{
logger(1, "%s: pcap file `%s' does not exist or is not readable", argv[0], argv[1]);
return 1;
}
- set_cmdarg(&nDPId_options.pcap_file_or_interface, argv[1]);
+ set_cmdarg_string(&nDPId_options.pcap_file_or_interface, argv[1]);
+ set_config_defaults(&config_map[0], nDPIsrvd_ARRAY_LENGTH(config_map));
+ set_config_defaults(&general_config_map[0], nDPIsrvd_ARRAY_LENGTH(general_config_map));
+ set_config_defaults(&tuning_config_map[0], nDPIsrvd_ARRAY_LENGTH(tuning_config_map));
if (validate_options() != 0)
{
return 1;
@@ -1845,10 +1848,12 @@ int main(int argc, char ** argv)
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n",
total_alloc_bytes -
sizeof(struct nDPId_workflow) *
- nDPId_options.reader_thread_count /* We do not want to take the workflow into account. */,
+ GET_CMDARG_ULL(
+ nDPId_options.reader_thread_count) /* We do not want to take the workflow into account. */,
total_free_bytes -
sizeof(struct nDPId_workflow) *
- nDPId_options.reader_thread_count /* We do not want to take the workflow into account. */,
+ GET_CMDARG_ULL(
+ nDPId_options.reader_thread_count) /* We do not want to take the workflow into account. */,
total_alloc_count,
total_free_count);
diff --git a/nDPId.c b/nDPId.c
index ba997c25e..61b17cd0f 100644
--- a/nDPId.c
+++ b/nDPId.c
@@ -40,10 +40,6 @@
#endif
#include "utils.h"
-#ifndef UNIX_PATH_MAX
-#define UNIX_PATH_MAX 108
-#endif
-
#ifndef ETHERTYPE_DCE
#define ETHERTYPE_DCE 0x8903
#endif
@@ -462,7 +458,6 @@ static char const * const daemon_event_name_table[DAEMON_EVENT_COUNT] = {
};
static struct nDPId_reader_thread reader_threads[nDPId_MAX_READER_THREADS] = {};
-static struct nDPIsrvd_address collector_address;
static MT_VALUE(nDPId_main_thread_shutdown, int) = MT_INIT(0);
static MT_VALUE(global_flow_id, uint64_t) = MT_INIT(1);
@@ -481,69 +476,87 @@ static MT_VALUE(zlib_compression_bytes, uint64_t) = MT_INIT(0);
static struct
{
+ /* options which are resolved automatically */
+ struct nDPIsrvd_address parsed_collector_address;
+ union nDPId_ip pcap_dev_ip4, pcap_dev_ip6;
+ union nDPId_ip pcap_dev_netmask4, pcap_dev_netmask6;
+ union nDPId_ip pcap_dev_subnet4, pcap_dev_subnet6;
/* opts */
+ struct cmdarg config_file;
struct cmdarg pcap_file_or_interface;
struct cmdarg bpf_str;
struct cmdarg pidfile;
struct cmdarg user;
struct cmdarg group;
+ struct cmdarg custom_risk_domain_file;
struct cmdarg custom_protocols_file;
struct cmdarg custom_categories_file;
struct cmdarg custom_ja3_file;
struct cmdarg custom_sha1_file;
struct cmdarg collector_address;
struct cmdarg instance_alias;
- union nDPId_ip pcap_dev_ip4, pcap_dev_ip6;
- union nDPId_ip pcap_dev_netmask4, pcap_dev_netmask6;
- union nDPId_ip pcap_dev_subnet4, pcap_dev_subnet6;
- uint8_t process_internal_initial_direction;
- uint8_t process_external_initial_direction;
+ struct cmdarg process_internal_initial_direction;
+ struct cmdarg process_external_initial_direction;
#ifdef ENABLE_ZLIB
- uint8_t enable_zlib_compression;
+ struct cmdarg enable_zlib_compression;
#endif
- uint8_t enable_data_analysis;
+ struct cmdarg enable_data_analysis;
#ifdef ENABLE_EPOLL
- uint8_t use_poll;
+ struct cmdarg use_poll;
#endif
#ifdef ENABLE_PFRING
- uint8_t use_pfring;
+ struct cmdarg use_pfring;
#endif
/* subopts */
- unsigned long long int max_flows_per_thread;
- unsigned long long int max_idle_flows_per_thread;
- unsigned long long int reader_thread_count;
- unsigned long long int daemon_status_interval;
+ struct cmdarg max_flows_per_thread;
+ struct cmdarg max_idle_flows_per_thread;
+ struct cmdarg reader_thread_count;
+ struct cmdarg daemon_status_interval;
#ifdef ENABLE_MEMORY_PROFILING
- unsigned long long int memory_profiling_log_interval;
+ struct cmdarg memory_profiling_log_interval;
+#endif
+#ifdef ENABLE_ZLIB
+ struct cmdarg compression_scan_interval;
+ struct cmdarg compression_flow_inactivity;
#endif
+ struct cmdarg flow_scan_interval;
+ struct cmdarg generic_max_idle_time;
+ struct cmdarg icmp_max_idle_time;
+ struct cmdarg udp_max_idle_time;
+ struct cmdarg tcp_max_idle_time;
+ struct cmdarg tcp_max_post_end_flow_time;
+ struct cmdarg max_packets_per_flow_to_send;
+ struct cmdarg max_packets_per_flow_to_process;
+ struct cmdarg max_packets_per_flow_to_analyse;
+ struct cmdarg error_event_threshold_n;
+ struct cmdarg error_event_threshold_time;
+} nDPId_options = {.config_file = CMDARG_STR(NULL),
+ .pcap_file_or_interface = CMDARG_STR(NULL),
+ .bpf_str = CMDARG_STR(NULL),
+ .pidfile = CMDARG_STR(nDPId_PIDFILE),
+ .user = CMDARG_STR(DEFAULT_CHUSER),
+ .group = CMDARG_STR(NULL),
+ .custom_risk_domain_file = CMDARG_STR(NULL),
+ .custom_protocols_file = CMDARG_STR(NULL),
+ .custom_categories_file = CMDARG_STR(NULL),
+ .custom_ja3_file = CMDARG_STR(NULL),
+ .custom_sha1_file = CMDARG_STR(NULL),
+ .collector_address = CMDARG_STR(COLLECTOR_UNIX_SOCKET),
+ .instance_alias = CMDARG_STR(NULL),
+ .process_internal_initial_direction = CMDARG_BOOL(0),
+ .process_external_initial_direction = CMDARG_BOOL(0),
#ifdef ENABLE_ZLIB
- unsigned long long int compression_scan_interval;
- unsigned long long int compression_flow_inactivity;
+ .enable_zlib_compression = CMDARG_BOOL(0),
+#endif
+ .enable_data_analysis = CMDARG_BOOL(0),
+#ifdef ENABLE_EPOLL
+ .use_poll = CMDARG_BOOL(0),
+#endif
+#ifdef ENABLE_PFRING
+ .use_pfring = CMDARG_BOOL(0),
#endif
- unsigned long long int flow_scan_interval;
- unsigned long long int generic_max_idle_time;
- unsigned long long int icmp_max_idle_time;
- unsigned long long int udp_max_idle_time;
- unsigned long long int tcp_max_idle_time;
- unsigned long long int tcp_max_post_end_flow_time;
- unsigned long long int max_packets_per_flow_to_send;
- unsigned long long int max_packets_per_flow_to_process;
- unsigned long long int max_packets_per_flow_to_analyse;
- unsigned long long int error_event_threshold_n;
- unsigned long long int error_event_threshold_time;
-} nDPId_options = {.pcap_file_or_interface = CMDARG(NULL),
- .bpf_str = CMDARG(NULL),
- .pidfile = CMDARG(nDPId_PIDFILE),
- .user = CMDARG(DEFAULT_CHUSER),
- .group = CMDARG(NULL),
- .custom_protocols_file = CMDARG(NULL),
- .custom_categories_file = CMDARG(NULL),
- .custom_ja3_file = CMDARG(NULL),
- .custom_sha1_file = CMDARG(NULL),
- .collector_address = CMDARG(COLLECTOR_UNIX_SOCKET),
- .instance_alias = CMDARG(NULL),
- .max_flows_per_thread = nDPId_MAX_FLOWS_PER_THREAD / 2,
- .max_idle_flows_per_thread = nDPId_MAX_IDLE_FLOWS_PER_THREAD / 2,
+ .max_flows_per_thread = CMDARG_ULL(nDPId_MAX_FLOWS_PER_THREAD / 2),
+ .max_idle_flows_per_thread = CMDARG_ULL(nDPId_MAX_IDLE_FLOWS_PER_THREAD / 2),
#ifdef CROSS_COMPILATION
/*
* We are assuming that in the cross compilation case
@@ -551,78 +564,78 @@ static struct
* To further reduce memory consumption caused by allocating nDPId / nDPI workflows per thread,
* we set the default reader thread count to two.
*/
- .reader_thread_count = 2,
+ .reader_thread_count = CMDARG_ULL(2),
#else
- .reader_thread_count = nDPId_MAX_READER_THREADS / 3,
+ .reader_thread_count = CMDARG_ULL(nDPId_MAX_READER_THREADS / 3),
#endif
- .daemon_status_interval = nDPId_DAEMON_STATUS_INTERVAL,
+ .daemon_status_interval = CMDARG_ULL(nDPId_DAEMON_STATUS_INTERVAL),
#ifdef ENABLE_MEMORY_PROFILING
- .memory_profiling_log_interval = nDPId_MEMORY_PROFILING_LOG_INTERVAL,
+ .memory_profiling_log_interval = CMDARG_ULL(nDPId_MEMORY_PROFILING_LOG_INTERVAL),
#endif
#ifdef ENABLE_ZLIB
- .compression_scan_interval = nDPId_COMPRESSION_SCAN_INTERVAL,
- .compression_flow_inactivity = nDPId_COMPRESSION_FLOW_INACTIVITY,
-#endif
- .flow_scan_interval = nDPId_FLOW_SCAN_INTERVAL,
- .generic_max_idle_time = nDPId_GENERIC_IDLE_TIME,
- .icmp_max_idle_time = nDPId_ICMP_IDLE_TIME,
- .udp_max_idle_time = nDPId_UDP_IDLE_TIME,
- .tcp_max_idle_time = nDPId_TCP_IDLE_TIME,
- .tcp_max_post_end_flow_time = nDPId_TCP_POST_END_FLOW_TIME,
- .max_packets_per_flow_to_send = nDPId_PACKETS_PER_FLOW_TO_SEND,
- .max_packets_per_flow_to_process = nDPId_PACKETS_PER_FLOW_TO_PROCESS,
- .max_packets_per_flow_to_analyse = nDPId_PACKETS_PER_FLOW_TO_ANALYZE,
- .error_event_threshold_n = nDPId_ERROR_EVENT_THRESHOLD_N,
- .error_event_threshold_time = nDPId_ERROR_EVENT_THRESHOLD_TIME};
-
-enum nDPId_subopts
-{
- MAX_FLOWS_PER_THREAD = 0,
- MAX_IDLE_FLOWS_PER_THREAD,
- MAX_READER_THREADS,
- DAEMON_STATUS_INTERVAL,
-#ifdef ENABLE_MEMORY_PROFILING
- MEMORY_PROFILING_LOG_INTERVAL,
+ .compression_scan_interval = CMDARG_ULL(nDPId_COMPRESSION_SCAN_INTERVAL),
+ .compression_flow_inactivity = CMDARG_ULL(nDPId_COMPRESSION_FLOW_INACTIVITY),
#endif
+ .flow_scan_interval = CMDARG_ULL(nDPId_FLOW_SCAN_INTERVAL),
+ .generic_max_idle_time = CMDARG_ULL(nDPId_GENERIC_IDLE_TIME),
+ .icmp_max_idle_time = CMDARG_ULL(nDPId_ICMP_IDLE_TIME),
+ .udp_max_idle_time = CMDARG_ULL(nDPId_UDP_IDLE_TIME),
+ .tcp_max_idle_time = CMDARG_ULL(nDPId_TCP_IDLE_TIME),
+ .tcp_max_post_end_flow_time = CMDARG_ULL(nDPId_TCP_POST_END_FLOW_TIME),
+ .max_packets_per_flow_to_send = CMDARG_ULL(nDPId_PACKETS_PER_FLOW_TO_SEND),
+ .max_packets_per_flow_to_process = CMDARG_ULL(nDPId_PACKETS_PER_FLOW_TO_PROCESS),
+ .max_packets_per_flow_to_analyse = CMDARG_ULL(nDPId_PACKETS_PER_FLOW_TO_ANALYZE),
+ .error_event_threshold_n = CMDARG_ULL(nDPId_ERROR_EVENT_THRESHOLD_N),
+ .error_event_threshold_time = CMDARG_ULL(nDPId_ERROR_EVENT_THRESHOLD_TIME)};
+struct confopt general_config_map[] = {CONFOPT("netif", &nDPId_options.pcap_file_or_interface),
+ CONFOPT("bpf", &nDPId_options.bpf_str),
+ CONFOPT("pidfile", &nDPId_options.pidfile),
+ CONFOPT("user", &nDPId_options.user),
+ CONFOPT("group", &nDPId_options.group),
+ CONFOPT("riskdomains", &nDPId_options.custom_risk_domain_file),
+ CONFOPT("protocols", &nDPId_options.custom_protocols_file),
+ CONFOPT("categories", &nDPId_options.custom_categories_file),
+ CONFOPT("ja3", &nDPId_options.custom_ja3_file),
+ CONFOPT("sha1", &nDPId_options.custom_sha1_file),
+ CONFOPT("collector", &nDPId_options.collector_address),
+ CONFOPT("alias", &nDPId_options.instance_alias),
+ CONFOPT("internal", &nDPId_options.process_internal_initial_direction),
+ CONFOPT("external", &nDPId_options.process_external_initial_direction),
#ifdef ENABLE_ZLIB
- COMPRESSION_SCAN_INTERVAL,
- COMPRESSION_FLOW_INACTIVITY,
+ CONFOPT("compression", &nDPId_options.enable_zlib_compression),
+#endif
+ CONFOPT("analysis", &nDPId_options.enable_data_analysis),
+#ifdef ENABLE_EPOLL
+ CONFOPT("poll", &nDPId_options.use_poll),
+#endif
+#ifdef ENABLE_PFRING
+ CONFOPT("pfring", &nDPId_options.use_pfring)
#endif
- FLOW_SCAN_INTVERAL,
- GENERIC_MAX_IDLE_TIME,
- ICMP_MAX_IDLE_TIME,
- UDP_MAX_IDLE_TIME,
- TCP_MAX_IDLE_TIME,
- TCP_MAX_POST_END_FLOW_TIME,
- MAX_PACKETS_PER_FLOW_TO_SEND,
- MAX_PACKETS_PER_FLOW_TO_PROCESS,
- MAX_PACKETS_PER_FLOW_TO_ANALYZE,
- ERROR_EVENT_THRESHOLD_N,
- ERROR_EVENT_THRESHOLD_TIME,
};
-static char * const subopt_token[] = {[MAX_FLOWS_PER_THREAD] = "max-flows-per-thread",
- [MAX_IDLE_FLOWS_PER_THREAD] = "max-idle-flows-per-thread",
- [MAX_READER_THREADS] = "max-reader-threads",
- [DAEMON_STATUS_INTERVAL] = "daemon-status-interval",
+struct confopt tuning_config_map[] = {
+ CONFOPT("max-flows-per-thread", &nDPId_options.max_flows_per_thread),
+ CONFOPT("max-idle-flows-per-thread", &nDPId_options.max_idle_flows_per_thread),
+ CONFOPT("max-reader-threads", &nDPId_options.reader_thread_count),
+ CONFOPT("daemon-status-interval", &nDPId_options.daemon_status_interval),
#ifdef ENABLE_MEMORY_PROFILING
- [MEMORY_PROFILING_LOG_INTERVAL] = "memory-profiling-log-interval",
+ CONFOPT("memory-profiling-log-interval", &nDPId_options.memory_profiling_log_interval),
#endif
#ifdef ENABLE_ZLIB
- [COMPRESSION_SCAN_INTERVAL] = "compression-scan-interval",
- [COMPRESSION_FLOW_INACTIVITY] = "compression-flow-inactivity",
+ CONFOPT("compression-scan-interval", &nDPId_options.compression_scan_interval),
+ CONFOPT("compression-flow-inactivity", &nDPId_options.compression_flow_inactivity),
#endif
- [FLOW_SCAN_INTVERAL] = "flow-scan-interval",
- [GENERIC_MAX_IDLE_TIME] = "generic-max-idle-time",
- [ICMP_MAX_IDLE_TIME] = "icmp-max-idle-time",
- [UDP_MAX_IDLE_TIME] = "udp-max-idle-time",
- [TCP_MAX_IDLE_TIME] = "tcp-max-idle-time",
- [TCP_MAX_POST_END_FLOW_TIME] = "tcp-max-post-end-flow-time",
- [MAX_PACKETS_PER_FLOW_TO_SEND] = "max-packets-per-flow-to-send",
- [MAX_PACKETS_PER_FLOW_TO_PROCESS] = "max-packets-per-flow-to-process",
- [MAX_PACKETS_PER_FLOW_TO_ANALYZE] = "max-packets-per-flow-to-analyse",
- [ERROR_EVENT_THRESHOLD_N] = "error-event-threshold-n",
- [ERROR_EVENT_THRESHOLD_TIME] = "error-event-threshold-time",
- NULL};
+ CONFOPT("flow-scan-interval", &nDPId_options.flow_scan_interval),
+ CONFOPT("generic-max-idle-time", &nDPId_options.generic_max_idle_time),
+ CONFOPT("icmp-max-idle-time", &nDPId_options.icmp_max_idle_time),
+ CONFOPT("udp-max-idle-time", &nDPId_options.udp_max_idle_time),
+ CONFOPT("tcp-max-idle-time", &nDPId_options.tcp_max_idle_time),
+ CONFOPT("tcp-max-post-end-flow-time", &nDPId_options.tcp_max_post_end_flow_time),
+ CONFOPT("max-packets-per-flow-to-send", &nDPId_options.max_packets_per_flow_to_send),
+ CONFOPT("max-packets-per-flow-to-process", &nDPId_options.max_packets_per_flow_to_process),
+ CONFOPT("max-packets-per-flow-to-analyse", &nDPId_options.max_packets_per_flow_to_analyse),
+ CONFOPT("error-event-threshold-n", &nDPId_options.error_event_threshold_n),
+ CONFOPT("error-event-threshold-time", &nDPId_options.error_event_threshold_time),
+};
static void sighandler(int signum);
static WARN_UNUSED int processing_threads_error_or_eof(void);
@@ -883,7 +896,7 @@ static void ndpi_comp_scan_walker(void const * const A, ndpi_VISIT which, int de
case FS_INFO:
{
- if (get_last_pkt_time(flow_basic) + nDPId_options.compression_flow_inactivity <
+ if (get_last_pkt_time(flow_basic) + GET_CMDARG_ULL(nDPId_options.compression_flow_inactivity) <
workflow->last_thread_time)
{
struct nDPId_flow * const flow = (struct nDPId_flow *)flow_basic;
@@ -919,7 +932,8 @@ static void check_for_compressable_flows(struct nDPId_reader_thread * const read
{
struct nDPId_workflow * const workflow = reader_thread->workflow;
- if (workflow->last_compression_scan_time + nDPId_options.compression_scan_interval < workflow->last_thread_time)
+ if (workflow->last_compression_scan_time + GET_CMDARG_ULL(nDPId_options.compression_scan_interval) <
+ workflow->last_thread_time)
{
for (size_t comp_scan_index = 0; comp_scan_index < workflow->max_active_flows; ++comp_scan_index)
{
@@ -1016,7 +1030,7 @@ static void get_ip6_address_and_netmask(struct ifaddrs const * const ifaddr)
void * ssubn = &nDPId_options.pcap_dev_subnet6.v6.ip;
logger(0,
"%s IPv6 address netmask subnet: %s %s %s",
- get_cmdarg(&nDPId_options.pcap_file_or_interface),
+ GET_CMDARG_STR(nDPId_options.pcap_file_or_interface),
inet_ntop(AF_INET6, saddr, addr, sizeof(addr)),
inet_ntop(AF_INET6, snetm, netm, sizeof(netm)),
inet_ntop(AF_INET6, ssubn, subn, sizeof(subn)));
@@ -1040,7 +1054,7 @@ static void get_ip4_address_and_netmask(struct ifaddrs const * const ifaddr)
void * ssubn = &nDPId_options.pcap_dev_subnet4.v4.ip;
logger(0,
"%s IPv4 address netmask subnet: %s %s %s",
- get_cmdarg(&nDPId_options.pcap_file_or_interface),
+ GET_CMDARG_STR(nDPId_options.pcap_file_or_interface),
inet_ntop(AF_INET, saddr, addr, sizeof(addr)),
inet_ntop(AF_INET, snetm, netm, sizeof(netm)),
inet_ntop(AF_INET, ssubn, subn, sizeof(subn)));
@@ -1091,8 +1105,8 @@ static int get_ip_netmask_from_pcap_dev(char const * const pcap_dev)
}
if (retval == 0 && found_dev != 0 &&
- (nDPId_options.process_internal_initial_direction != 0 ||
- nDPId_options.process_external_initial_direction != 0) &&
+ (GET_CMDARG_BOOL(nDPId_options.process_internal_initial_direction) != 0 ||
+ GET_CMDARG_BOOL(nDPId_options.process_external_initial_direction) != 0) &&
ip4_interface_avail == 0 && ip6_interface_avail == 0)
{
logger_early(1, "Interface %s does not have any IPv4 / IPv6 address set, -I / -E won't work.", pcap_dev);
@@ -1257,6 +1271,94 @@ static int cfg_set_u64(struct nDPId_workflow * const workflow,
return 0;
}
+static int cfg_set(struct nDPId_workflow * const workflow, const char * proto, const char * param, const char * value)
+{
+ ndpi_cfg_error cfg_err;
+
+ cfg_err = ndpi_set_config(workflow->ndpi_struct, proto, param, value);
+ if (cfg_err != NDPI_CFG_OK)
+ {
+ if (proto != NULL)
+ {
+ logger_early(1,
+ "Could not set nDPI configuration for protocol `%s' with key `%s' and value `%s': %s",
+ proto,
+ param,
+ value,
+ cfg_err2str(cfg_err));
+ }
+ else
+ {
+ logger_early(1,
+ "Could not set nDPI configuration for key `%s' with value `%s': %s",
+ param,
+ value,
+ cfg_err2str(cfg_err));
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+static int libnDPI_parsed_config_line(
+ int lineno, char const * const section, char const * const name, char const * const value, void * const user_data)
+{
+ struct nDPId_workflow * const workflow = (struct nDPId_workflow *)user_data;
+
+ if ((strnlen(section, INI_MAX_SECTION) == nDPIsrvd_STRLEN_SZ("general") &&
+ strncmp(section, "general", INI_MAX_SECTION) == 0) ||
+ (strnlen(section, INI_MAX_SECTION) == nDPIsrvd_STRLEN_SZ("tuning") &&
+ strncmp(section, "tuning", INI_MAX_SECTION) == 0))
+ {
+ // Nothing to do here right now (already initialized)
+ return 1;
+ }
+ else if (strnlen(section, INI_MAX_SECTION) == nDPIsrvd_STRLEN_SZ("ndpi") &&
+ strncmp(section, "ndpi", INI_MAX_SECTION) == 0)
+ {
+ return (cfg_set(workflow, NULL, name, value) == 0);
+ }
+ else if (strnlen(section, INI_MAX_SECTION) == nDPIsrvd_STRLEN_SZ("protos") &&
+ strncmp(section, "protos", INI_MAX_SECTION) == 0)
+ {
+ char const * const first_sep = strchr(name, '.');
+ char proto[INI_MAX_NAME];
+
+ if (first_sep == NULL)
+ {
+ logger_early(1,
+ "Missing first `.' for section `protos' at line %d with key `%s' and value `%s'",
+ lineno,
+ name,
+ value);
+ return 0;
+ }
+ int s_ret = snprintf(proto, sizeof(proto), "%.*s", (int)(first_sep - name), name);
+ if (s_ret < 0)
+ {
+ logger_early(1,
+ "Could not format protocol at line %d with key `%s' and value `%s': snprintf returnded %d, "
+ "buffer size %zu",
+ lineno,
+ name,
+ value,
+ s_ret,
+ sizeof(proto));
+ return 0;
+ }
+
+ return (cfg_set(workflow, proto, first_sep + 1, value) == 0);
+ }
+ else
+ {
+ logger_early(
+ 1, "Invalid config section `%s' at line %d with key `%s' and value `%s'", section, lineno, name, value);
+ }
+
+ return 1;
+}
+
static struct nDPId_workflow * init_workflow(char const * const file_or_device)
{
char pcap_error_buffer[PCAP_ERRBUF_SIZE];
@@ -1278,7 +1380,7 @@ static struct nDPId_workflow * init_workflow(char const * const file_or_device)
MT_INIT2(workflow->error_or_eof, 0);
#ifdef ENABLE_PFRING
- if (nDPId_options.use_pfring != 0)
+ if (GET_CMDARG_BOOL(nDPId_options.use_pfring) != 0)
{
errno = 0;
@@ -1289,9 +1391,9 @@ static struct nDPId_workflow * init_workflow(char const * const file_or_device)
return NULL;
}
- if (is_cmdarg_set(&nDPId_options.bpf_str) != 0)
+ if (IS_CMDARG_SET(nDPId_options.bpf_str) != 0)
{
- if (npfring_set_bpf(&workflow->npf, get_cmdarg(&nDPId_options.bpf_str)) != 0)
+ if (npfring_set_bpf(&workflow->npf, GET_CMDARG_STR(nDPId_options.bpf_str)) != 0)
{
logger_early(1, "%s", "PF_RING set bpf filter failed");
free_workflow(&workflow);
@@ -1333,11 +1435,11 @@ static struct nDPId_workflow * init_workflow(char const * const file_or_device)
return NULL;
}
- if (is_cmdarg_set(&nDPId_options.bpf_str) != 0)
+ if (IS_CMDARG_SET(nDPId_options.bpf_str) != 0)
{
struct bpf_program fp;
- if (pcap_compile(workflow->pcap_handle, &fp, get_cmdarg(&nDPId_options.bpf_str), 1, PCAP_NETMASK_UNKNOWN) !=
- 0)
+ if (pcap_compile(
+ workflow->pcap_handle, &fp, GET_CMDARG_STR(nDPId_options.bpf_str), 1, PCAP_NETMASK_UNKNOWN) != 0)
{
logger_early(1, "pcap_compile: %s", pcap_geterr(workflow->pcap_handle));
free_workflow(&workflow);
@@ -1355,7 +1457,7 @@ static struct nDPId_workflow * init_workflow(char const * const file_or_device)
}
#ifdef ENABLE_PFRING
- if (nDPId_options.use_pfring != 0)
+ if (GET_CMDARG_BOOL(nDPId_options.use_pfring) != 0)
{
if (npfring_enable(&workflow->npf) != 0)
{
@@ -1377,14 +1479,45 @@ static struct nDPId_workflow * init_workflow(char const * const file_or_device)
ndpi_set_user_data(workflow->ndpi_struct, workflow);
set_ndpi_debug_function(workflow->ndpi_struct, ndpi_debug_printf);
+ {
+ int ret;
+
+ if (IS_CMDARG_SET(nDPId_options.config_file) != 0 &&
+ (ret =
+ parse_config_file(GET_CMDARG_STR(nDPId_options.config_file), libnDPI_parsed_config_line, workflow)) !=
+ 0)
+ {
+ if (ret > 0)
+ {
+ logger_early(1, "Config file `%s' is malformed", GET_CMDARG_STR(nDPId_options.config_file));
+ }
+ else if (ret == -ENOENT)
+ {
+ logger_early(1, "Path `%s' is not a regular file", GET_CMDARG_STR(nDPId_options.config_file));
+ }
+ else
+ {
+ logger_early(1,
+ "Could not open file `%s' for reading: %s",
+ GET_CMDARG_STR(nDPId_options.config_file),
+ strerror(errno));
+ }
+ free_workflow(&workflow);
+ return NULL;
+ }
+ }
+
cfg_set_u64(workflow, NULL, "log.level", 3);
- cfg_set_u64(workflow, NULL, "packets_limit_per_flow", nDPId_options.max_packets_per_flow_to_process);
+ cfg_set_u64(workflow,
+ NULL,
+ "packets_limit_per_flow",
+ GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_process));
cfg_set_u64(workflow, "tls", "application_blocks_tracking", 1);
cfg_set_u64(workflow, "tls", "certificate_expiration_threshold", 5);
workflow->total_skipped_flows = 0;
workflow->total_active_flows = 0;
- workflow->max_active_flows = nDPId_options.max_flows_per_thread;
+ workflow->max_active_flows = GET_CMDARG_ULL(nDPId_options.max_flows_per_thread);
workflow->ndpi_flows_active = (void **)ndpi_calloc(workflow->max_active_flows, sizeof(void *));
if (workflow->ndpi_flows_active == NULL)
{
@@ -1396,7 +1529,7 @@ static struct nDPId_workflow * init_workflow(char const * const file_or_device)
}
workflow->total_idle_flows = 0;
- workflow->max_idle_flows = nDPId_options.max_idle_flows_per_thread;
+ workflow->max_idle_flows = GET_CMDARG_ULL(nDPId_options.max_idle_flows_per_thread);
workflow->ndpi_flows_idle = (void **)ndpi_calloc(workflow->max_idle_flows, sizeof(void *));
if (workflow->ndpi_flows_idle == NULL)
{
@@ -1410,21 +1543,25 @@ static struct nDPId_workflow * init_workflow(char const * const file_or_device)
NDPI_PROTOCOL_BITMASK protos;
NDPI_BITMASK_SET_ALL(protos);
ndpi_set_protocol_detection_bitmask2(workflow->ndpi_struct, &protos);
- if (is_cmdarg_set(&nDPId_options.custom_protocols_file) != 0)
+ if (IS_CMDARG_SET(nDPId_options.custom_risk_domain_file) != 0)
{
- ndpi_load_protocols_file(workflow->ndpi_struct, get_cmdarg(&nDPId_options.custom_protocols_file));
+ ndpi_load_risk_domain_file(workflow->ndpi_struct, GET_CMDARG_STR(nDPId_options.custom_risk_domain_file));
}
- if (is_cmdarg_set(&nDPId_options.custom_categories_file) != 0)
+ if (IS_CMDARG_SET(nDPId_options.custom_protocols_file) != 0)
{
- ndpi_load_categories_file(workflow->ndpi_struct, get_cmdarg(&nDPId_options.custom_categories_file), NULL);
+ ndpi_load_protocols_file(workflow->ndpi_struct, GET_CMDARG_STR(nDPId_options.custom_protocols_file));
}
- if (is_cmdarg_set(&nDPId_options.custom_ja3_file) != 0)
+ if (IS_CMDARG_SET(nDPId_options.custom_categories_file) != 0)
{
- ndpi_load_malicious_ja3_file(workflow->ndpi_struct, get_cmdarg(&nDPId_options.custom_ja3_file));
+ ndpi_load_categories_file(workflow->ndpi_struct, GET_CMDARG_STR(nDPId_options.custom_categories_file), NULL);
}
- if (is_cmdarg_set(&nDPId_options.custom_sha1_file) != 0)
+ if (IS_CMDARG_SET(nDPId_options.custom_ja3_file) != 0)
{
- ndpi_load_malicious_sha1_file(workflow->ndpi_struct, get_cmdarg(&nDPId_options.custom_sha1_file));
+ ndpi_load_malicious_ja3_file(workflow->ndpi_struct, GET_CMDARG_STR(nDPId_options.custom_ja3_file));
+ }
+ if (IS_CMDARG_SET(nDPId_options.custom_sha1_file) != 0)
+ {
+ ndpi_load_malicious_sha1_file(workflow->ndpi_struct, GET_CMDARG_STR(nDPId_options.custom_sha1_file));
}
ndpi_finalize_initialization(workflow->ndpi_struct);
@@ -1441,7 +1578,7 @@ static struct nDPId_workflow * init_workflow(char const * const file_or_device)
static void free_analysis_data(struct nDPId_flow_extended * const flow_ext)
{
- if (nDPId_options.enable_data_analysis != 0 && flow_ext->flow_analysis != NULL)
+ if (GET_CMDARG_BOOL(nDPId_options.enable_data_analysis) != 0 && flow_ext->flow_analysis != NULL)
{
ndpi_free_data_analysis(&flow_ext->flow_analysis->iat, 0);
ndpi_free_data_analysis(&flow_ext->flow_analysis->pktlen, 0);
@@ -1475,7 +1612,7 @@ static int alloc_detection_data(struct nDPId_flow * const flow)
memset(flow->info.detection_data, 0, sizeof(*flow->info.detection_data));
- if (nDPId_options.enable_data_analysis != 0)
+ if (GET_CMDARG_BOOL(nDPId_options.enable_data_analysis) != 0)
{
flow->flow_extended.flow_analysis =
(struct nDPId_flow_analysis *)ndpi_malloc(sizeof(*flow->flow_extended.flow_analysis));
@@ -1485,13 +1622,16 @@ static int alloc_detection_data(struct nDPId_flow * const flow)
}
ndpi_init_data_analysis(&flow->flow_extended.flow_analysis->iat,
- nDPId_options.max_packets_per_flow_to_analyse - 1 /* first packet IAT is always 0 */);
+ GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_analyse) -
+ 1 /* first packet IAT is always 0 */);
ndpi_init_data_analysis(&flow->flow_extended.flow_analysis->pktlen,
- nDPId_options.max_packets_per_flow_to_analyse);
- flow->flow_extended.flow_analysis->directions = (uint8_t *)ndpi_malloc(
- sizeof(*flow->flow_extended.flow_analysis->directions) * nDPId_options.max_packets_per_flow_to_analyse);
- flow->flow_extended.flow_analysis->entropies = (float *)ndpi_malloc(
- sizeof(*flow->flow_extended.flow_analysis->entropies) * nDPId_options.max_packets_per_flow_to_analyse);
+ GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_analyse));
+ flow->flow_extended.flow_analysis->directions =
+ (uint8_t *)ndpi_malloc(sizeof(*flow->flow_extended.flow_analysis->directions) *
+ GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_analyse));
+ flow->flow_extended.flow_analysis->entropies =
+ (float *)ndpi_malloc(sizeof(*flow->flow_extended.flow_analysis->entropies) *
+ GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_analyse));
if (ndpi_init_bin(&flow->flow_extended.flow_analysis->payload_len_bin[FD_SRC2DST],
ndpi_bin_family8,
@@ -1556,7 +1696,7 @@ static void free_workflow(struct nDPId_workflow ** const workflow)
}
#ifdef ENABLE_PFRING
- if (nDPId_options.use_pfring != 0)
+ if (GET_CMDARG_BOOL(nDPId_options.use_pfring) != 0)
{
npfring_close(&w->npf);
}
@@ -1606,63 +1746,52 @@ static int setup_reader_threads(void)
{
char pcap_error_buffer[PCAP_ERRBUF_SIZE];
- if (nDPId_options.reader_thread_count > nDPId_MAX_READER_THREADS)
+ if (GET_CMDARG_ULL(nDPId_options.reader_thread_count) > nDPId_MAX_READER_THREADS)
{
return 1;
}
- if (is_cmdarg_set(&nDPId_options.pcap_file_or_interface) == 0)
+ if (IS_CMDARG_SET(nDPId_options.pcap_file_or_interface) == 0)
{
char * const pcapdev = get_default_pcapdev(pcap_error_buffer);
- set_cmdarg(&nDPId_options.pcap_file_or_interface, pcapdev);
+ set_cmdarg_string(&nDPId_options.pcap_file_or_interface, pcapdev);
free(pcapdev);
- if (is_cmdarg_set(&nDPId_options.pcap_file_or_interface) == 0)
+ if (IS_CMDARG_SET(nDPId_options.pcap_file_or_interface) == 0)
{
logger_early(1, "pcap_lookupdev: %.*s", (int)PCAP_ERRBUF_SIZE, pcap_error_buffer);
return 1;
}
- logger_early(0, "Capturing packets from default device: %s", get_cmdarg(&nDPId_options.pcap_file_or_interface));
+ logger_early(0,
+ "Capturing packets from default device: %s",
+ GET_CMDARG_STR(nDPId_options.pcap_file_or_interface));
}
errno = 0;
- if (access(get_cmdarg(&nDPId_options.pcap_file_or_interface), R_OK) != 0 && errno == ENOENT)
+ if (access(GET_CMDARG_STR(nDPId_options.pcap_file_or_interface), R_OK) != 0 && errno == ENOENT)
{
errno = 0;
- if (get_ip_netmask_from_pcap_dev(get_cmdarg(&nDPId_options.pcap_file_or_interface)) != 0)
+ if (get_ip_netmask_from_pcap_dev(GET_CMDARG_STR(nDPId_options.pcap_file_or_interface)) != 0)
{
if (errno != 0)
{
logger_early(1,
"Could not get netmask for pcap device %s: %s",
- get_cmdarg(&nDPId_options.pcap_file_or_interface),
+ GET_CMDARG_STR(nDPId_options.pcap_file_or_interface),
strerror(errno));
}
else
{
logger_early(1,
"Unexpected error while retrieving netmask for pcap device %s",
- get_cmdarg(&nDPId_options.pcap_file_or_interface));
+ GET_CMDARG_STR(nDPId_options.pcap_file_or_interface));
}
return 1;
}
}
- else
- {
- if (nDPId_options.process_internal_initial_direction != 0)
- {
- logger_early(1, "%s", "You are processing a PCAP file, `-I' ignored");
- nDPId_options.process_internal_initial_direction = 0;
- }
- if (nDPId_options.process_external_initial_direction != 0)
- {
- logger_early(1, "%s", "You are processing a PCAP file, `-E' ignored");
- nDPId_options.process_external_initial_direction = 0;
- }
- }
- for (unsigned long long int i = 0; i < nDPId_options.reader_thread_count; ++i)
+ for (unsigned long long int i = 0; i < GET_CMDARG_ULL(nDPId_options.reader_thread_count); ++i)
{
- reader_threads[i].workflow = init_workflow(get_cmdarg(&nDPId_options.pcap_file_or_interface));
+ reader_threads[i].workflow = init_workflow(GET_CMDARG_STR(nDPId_options.pcap_file_or_interface));
if (reader_threads[i].workflow == NULL)
{
return 1;
@@ -1747,13 +1876,13 @@ static uint64_t get_l4_protocol_idle_time(uint8_t l4_protocol)
{
case IPPROTO_ICMP:
case IPPROTO_ICMPV6:
- return nDPId_options.icmp_max_idle_time;
+ return GET_CMDARG_ULL(nDPId_options.icmp_max_idle_time);
case IPPROTO_TCP:
- return nDPId_options.tcp_max_idle_time;
+ return GET_CMDARG_ULL(nDPId_options.tcp_max_idle_time);
case IPPROTO_UDP:
- return nDPId_options.udp_max_idle_time;
+ return GET_CMDARG_ULL(nDPId_options.udp_max_idle_time);
default:
- return nDPId_options.generic_max_idle_time;
+ return GET_CMDARG_ULL(nDPId_options.generic_max_idle_time);
}
}
@@ -1761,10 +1890,10 @@ static uint64_t get_l4_protocol_idle_time_external(uint8_t l4_protocol)
{
uint64_t idle_time = get_l4_protocol_idle_time(l4_protocol);
- idle_time += nDPId_options.flow_scan_interval * 2;
+ idle_time += GET_CMDARG_ULL(nDPId_options.flow_scan_interval) * 2;
if (l4_protocol == IPPROTO_TCP)
{
- idle_time += nDPId_options.tcp_max_post_end_flow_time;
+ idle_time += GET_CMDARG_ULL(nDPId_options.tcp_max_post_end_flow_time);
}
return idle_time;
@@ -1783,7 +1912,8 @@ static int is_tcp_post_end(struct nDPId_workflow const * const workflow,
{
return flow_basic->l4_protocol != IPPROTO_TCP || flow_basic->tcp_fin_rst_seen == 0 ||
(flow_basic->tcp_fin_rst_seen == 1 &&
- get_last_pkt_time(flow_basic) + nDPId_options.tcp_max_post_end_flow_time <= workflow->last_thread_time);
+ get_last_pkt_time(flow_basic) + GET_CMDARG_ULL(nDPId_options.tcp_max_post_end_flow_time) <=
+ workflow->last_thread_time);
}
static int is_flow_update_required(struct nDPId_workflow const * const workflow,
@@ -1800,13 +1930,14 @@ static int is_flow_update_required(struct nDPId_workflow const * const workflow,
static int is_error_event_threshold(struct nDPId_workflow * const workflow)
{
- if (workflow->last_global_time - workflow->last_error_time > nDPId_options.error_event_threshold_time)
+ if (workflow->last_global_time - workflow->last_error_time >
+ GET_CMDARG_ULL(nDPId_options.error_event_threshold_time))
{
workflow->error_count = 0;
}
workflow->last_error_time = workflow->last_global_time;
- if (workflow->error_count >= nDPId_options.error_event_threshold_n)
+ if (workflow->error_count >= GET_CMDARG_ULL(nDPId_options.error_event_threshold_n))
{
return 1;
}
@@ -1827,7 +1958,7 @@ static void ndpi_idle_scan_walker(void const * const A, ndpi_VISIT which, int de
return;
}
- if (workflow->cur_idle_flows == nDPId_options.max_idle_flows_per_thread)
+ if (workflow->cur_idle_flows == GET_CMDARG_ULL(nDPId_options.max_idle_flows_per_thread))
{
return;
}
@@ -1921,7 +2052,8 @@ static void process_idle_flow(struct nDPId_reader_thread * const reader_thread,
struct nDPId_flow * const flow = (struct nDPId_flow *)flow_basic;
#ifdef ENABLE_ZLIB
- if (nDPId_options.enable_zlib_compression != 0 && flow->info.detection_data_compressed_size > 0)
+ if (GET_CMDARG_BOOL(nDPId_options.enable_zlib_compression) != 0 &&
+ flow->info.detection_data_compressed_size > 0)
{
workflow->current_compression_diff -= flow->info.detection_data_compressed_size;
int ret = detection_data_inflate(flow);
@@ -2119,8 +2251,8 @@ static void jsonize_basic(struct nDPId_reader_thread * const reader_thread, int
ndpi_serialize_string_uint32(&workflow->ndpi_serializer, "packet_id", workflow->packets_captured);
ndpi_serialize_string_string(&workflow->ndpi_serializer,
"source",
- get_cmdarg(&nDPId_options.pcap_file_or_interface));
- ndpi_serialize_string_string(&workflow->ndpi_serializer, "alias", get_cmdarg(&nDPId_options.instance_alias));
+ GET_CMDARG_STR(nDPId_options.pcap_file_or_interface));
+ ndpi_serialize_string_string(&workflow->ndpi_serializer, "alias", GET_CMDARG_STR(nDPId_options.instance_alias));
}
static void jsonize_daemon(struct nDPId_reader_thread * const reader_thread, enum daemon_event event)
@@ -2161,37 +2293,38 @@ static void jsonize_daemon(struct nDPId_reader_thread * const reader_thread, enu
case DAEMON_EVENT_RECONNECT:
ndpi_serialize_string_uint64(&workflow->ndpi_serializer,
"max-flows-per-thread",
- nDPId_options.max_flows_per_thread);
+ GET_CMDARG_ULL(nDPId_options.max_flows_per_thread));
ndpi_serialize_string_uint64(&workflow->ndpi_serializer,
"max-idle-flows-per-thread",
- nDPId_options.max_idle_flows_per_thread);
+ GET_CMDARG_ULL(nDPId_options.max_idle_flows_per_thread));
ndpi_serialize_string_uint64(&workflow->ndpi_serializer,
"reader-thread-count",
- nDPId_options.reader_thread_count);
+ GET_CMDARG_ULL(nDPId_options.reader_thread_count));
ndpi_serialize_string_uint64(&workflow->ndpi_serializer,
"flow-scan-interval",
- nDPId_options.flow_scan_interval);
+ GET_CMDARG_ULL(nDPId_options.flow_scan_interval));
ndpi_serialize_string_uint64(&workflow->ndpi_serializer,
"generic-max-idle-time",
- nDPId_options.generic_max_idle_time);
+ GET_CMDARG_ULL(nDPId_options.generic_max_idle_time));
ndpi_serialize_string_uint64(&workflow->ndpi_serializer,
"icmp-max-idle-time",
- nDPId_options.icmp_max_idle_time);
+ GET_CMDARG_ULL(nDPId_options.icmp_max_idle_time));
ndpi_serialize_string_uint64(&workflow->ndpi_serializer,
"udp-max-idle-time",
- nDPId_options.udp_max_idle_time);
+ GET_CMDARG_ULL(nDPId_options.udp_max_idle_time));
ndpi_serialize_string_uint64(&workflow->ndpi_serializer,
"tcp-max-idle-time",
- nDPId_options.tcp_max_idle_time + nDPId_options.tcp_max_post_end_flow_time);
+ GET_CMDARG_ULL(nDPId_options.tcp_max_idle_time) +
+ GET_CMDARG_ULL(nDPId_options.tcp_max_post_end_flow_time));
ndpi_serialize_string_uint64(&workflow->ndpi_serializer,
"max-packets-per-flow-to-send",
- nDPId_options.max_packets_per_flow_to_send);
+ GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_send));
ndpi_serialize_string_uint64(&workflow->ndpi_serializer,
"max-packets-per-flow-to-process",
- nDPId_options.max_packets_per_flow_to_process);
+ GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_process));
ndpi_serialize_string_uint64(&workflow->ndpi_serializer,
"max-packets-per-flow-to-analyse",
- nDPId_options.max_packets_per_flow_to_analyse);
+ GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_analyse));
break;
case DAEMON_EVENT_STATUS:
@@ -2203,7 +2336,7 @@ static void jsonize_daemon(struct nDPId_reader_thread * const reader_thread, enu
int rc;
struct npfring_stats stats = {};
- if (nDPId_options.use_pfring != 0)
+ if (GET_CMDARG_BOOL(nDPId_options.use_pfring) != 0)
{
if ((rc = npfring_stats(&workflow->npf, &stats)) != 0)
{
@@ -2218,7 +2351,7 @@ static void jsonize_daemon(struct nDPId_reader_thread * const reader_thread, enu
{
ndpi_serialize_string_boolean(&workflow->ndpi_serializer,
"pfring_active",
- nDPId_options.use_pfring);
+ GET_CMDARG_BOOL(nDPId_options.use_pfring));
ndpi_serialize_string_uint64(&workflow->ndpi_serializer, "pfring_recv", stats.recv);
ndpi_serialize_string_uint64(&workflow->ndpi_serializer, "pfring_drop", stats.drop);
ndpi_serialize_string_uint64(&workflow->ndpi_serializer, "pfring_shunt", stats.shunt);
@@ -2356,8 +2489,8 @@ static int connect_to_collector(struct nDPId_reader_thread * const reader_thread
close(reader_thread->collector_sockfd);
}
- int sock_type = (collector_address.raw.sa_family == AF_UNIX ? SOCK_STREAM : SOCK_DGRAM);
- reader_thread->collector_sockfd = socket(collector_address.raw.sa_family, sock_type, 0);
+ int sock_type = (nDPId_options.parsed_collector_address.raw.sa_family == AF_UNIX ? SOCK_STREAM : SOCK_DGRAM);
+ reader_thread->collector_sockfd = socket(nDPId_options.parsed_collector_address.raw.sa_family, sock_type, 0);
if (reader_thread->collector_sockfd < 0 || set_fd_cloexec(reader_thread->collector_sockfd) < 0)
{
reader_thread->collector_sock_last_errno = errno;
@@ -2375,7 +2508,9 @@ static int connect_to_collector(struct nDPId_reader_thread * const reader_thread
return 1;
}
- if (connect(reader_thread->collector_sockfd, &collector_address.raw, collector_address.size) < 0)
+ if (connect(reader_thread->collector_sockfd,
+ &nDPId_options.parsed_collector_address.raw,
+ nDPId_options.parsed_collector_address.size) < 0)
{
reader_thread->collector_sock_last_errno = errno;
return 1;
@@ -2434,13 +2569,13 @@ static void send_to_collector(struct nDPId_reader_thread * const reader_thread,
if (connect_to_collector(reader_thread) == 0)
{
- if (collector_address.raw.sa_family == AF_UNIX)
+ if (nDPId_options.parsed_collector_address.raw.sa_family == AF_UNIX)
{
logger(1,
"[%8llu, %zu] Reconnected to nDPIsrvd Collector at %s",
workflow->packets_captured,
reader_thread->array_index,
- get_cmdarg(&nDPId_options.collector_address));
+ GET_CMDARG_STR(nDPId_options.collector_address));
jsonize_daemon(reader_thread, DAEMON_EVENT_RECONNECT);
}
}
@@ -2452,7 +2587,7 @@ static void send_to_collector(struct nDPId_reader_thread * const reader_thread,
"[%8llu, %zu] Could not connect to nDPIsrvd Collector at %s, will try again later. Error: %s",
workflow->packets_captured,
reader_thread->array_index,
- get_cmdarg(&nDPId_options.collector_address),
+ GET_CMDARG_STR(nDPId_options.collector_address),
(reader_thread->collector_sock_last_errno != 0
? strerror(reader_thread->collector_sock_last_errno)
: "Internal Error."));
@@ -2482,12 +2617,12 @@ static void send_to_collector(struct nDPId_reader_thread * const reader_thread,
"[%8llu, %zu] %s to %s refused by endpoint",
workflow->packets_captured,
reader_thread->array_index,
- (collector_address.raw.sa_family == AF_UNIX ? "Connection" : "Datagram"),
- get_cmdarg(&nDPId_options.collector_address));
+ (nDPId_options.parsed_collector_address.raw.sa_family == AF_UNIX ? "Connection" : "Datagram"),
+ GET_CMDARG_STR(nDPId_options.collector_address));
}
reader_thread->collector_sock_last_errno = saved_errno;
}
- else if (collector_address.raw.sa_family == AF_UNIX)
+ else if (nDPId_options.parsed_collector_address.raw.sa_family == AF_UNIX)
{
size_t pos = (written < 0 ? 0 : written);
set_collector_block(reader_thread);
@@ -2510,7 +2645,7 @@ static void send_to_collector(struct nDPId_reader_thread * const reader_thread,
"[%8llu, %zu] Send data (blocking I/O) to nDPIsrvd Collector at %s failed: %s",
workflow->packets_captured,
reader_thread->array_index,
- get_cmdarg(&nDPId_options.collector_address),
+ GET_CMDARG_STR(nDPId_options.collector_address),
strerror(saved_errno));
reader_thread->collector_sock_last_errno = saved_errno;
break;
@@ -2641,7 +2776,7 @@ static void jsonize_data_analysis(struct nDPId_reader_thread * const reader_thre
struct nDPId_workflow * const workflow = reader_thread->workflow;
struct nDPId_flow_analysis * const analysis = (struct nDPId_flow_analysis *)flow_ext->flow_analysis;
- if (nDPId_options.enable_data_analysis != 0 && flow_ext->flow_analysis != NULL)
+ if (GET_CMDARG_BOOL(nDPId_options.enable_data_analysis) != 0 && flow_ext->flow_analysis != NULL)
{
ndpi_serialize_start_of_block(&workflow->ndpi_serializer, "data_analysis");
ndpi_serialize_start_of_block(&workflow->ndpi_serializer, "iat");
@@ -2698,14 +2833,14 @@ static void jsonize_data_analysis(struct nDPId_reader_thread * const reader_thre
ndpi_serialize_end_of_block(&workflow->ndpi_serializer);
ndpi_serialize_start_of_list(&workflow->ndpi_serializer, "directions");
- for (unsigned long long int i = 0; i < nDPId_options.max_packets_per_flow_to_analyse; ++i)
+ for (unsigned long long int i = 0; i < GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_analyse); ++i)
{
ndpi_serialize_string_uint32(&workflow->ndpi_serializer, "", analysis->directions[i]);
}
ndpi_serialize_end_of_list(&workflow->ndpi_serializer);
ndpi_serialize_start_of_list(&workflow->ndpi_serializer, "entropies");
- for (unsigned long long int i = 0; i < nDPId_options.max_packets_per_flow_to_analyse; ++i)
+ for (unsigned long long int i = 0; i < GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_analyse); ++i)
{
ndpi_serialize_string_float(&workflow->ndpi_serializer, "", analysis->entropies[i], "%.9f");
}
@@ -2739,7 +2874,7 @@ static void jsonize_packet_event(struct nDPId_reader_thread * const reader_threa
return;
}
if (flow_ext->packets_processed[FD_SRC2DST] + flow_ext->packets_processed[FD_DST2SRC] >
- nDPId_options.max_packets_per_flow_to_send)
+ GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_send))
{
return;
}
@@ -2775,7 +2910,7 @@ static void jsonize_packet_event(struct nDPId_reader_thread * const reader_threa
}
#ifdef ENABLE_PFRING
- if (nDPId_options.use_pfring != 0)
+ if (GET_CMDARG_BOOL(nDPId_options.use_pfring) != 0)
{
ndpi_serialize_string_int32(&workflow->ndpi_serializer,
"pkt_datalink",
@@ -2853,7 +2988,7 @@ static void jsonize_flow_event(struct nDPId_reader_thread * const reader_thread,
case FLOW_EVENT_UPDATE:
case FLOW_EVENT_ANALYSE:
#ifdef ENABLE_PFRING
- if (nDPId_options.use_pfring != 0)
+ if (GET_CMDARG_BOOL(nDPId_options.use_pfring) != 0)
{
ndpi_serialize_string_int32(&workflow->ndpi_serializer,
"flow_datalink",
@@ -2868,7 +3003,7 @@ static void jsonize_flow_event(struct nDPId_reader_thread * const reader_thread,
}
ndpi_serialize_string_uint32(&workflow->ndpi_serializer,
"flow_max_packets",
- nDPId_options.max_packets_per_flow_to_send);
+ GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_send));
if (event == FLOW_EVENT_ANALYSE)
{
@@ -2895,7 +3030,8 @@ static void jsonize_flow_event(struct nDPId_reader_thread * const reader_thread,
struct nDPId_flow * const flow = (struct nDPId_flow *)flow_ext;
#ifdef ENABLE_ZLIB
- if (nDPId_options.enable_zlib_compression != 0 && flow->info.detection_data_compressed_size > 0)
+ if (GET_CMDARG_BOOL(nDPId_options.enable_zlib_compression) != 0 &&
+ flow->info.detection_data_compressed_size > 0)
{
workflow->current_compression_diff -= flow->info.detection_data_compressed_size;
int ret = detection_data_inflate(flow);
@@ -3032,7 +3168,16 @@ static void vjsonize_error_eventf(struct nDPId_reader_thread * const reader_thre
char * value = va_arg(ap, char *);
if (got_jsonkey == 0)
{
- snprintf(json_key, sizeof(json_key), "%s", value);
+ int s_ret = snprintf(json_key, sizeof(json_key), "%s", value);
+ if (s_ret < 0)
+ {
+ logger(1,
+ "[%8llu, %zu] Error event format failed: snprintf returned %d, buffer size %zu",
+ reader_thread->workflow->packets_captured,
+ reader_thread->array_index,
+ s_ret,
+ sizeof(json_key));
+ }
got_jsonkey = 1;
}
else
@@ -3171,10 +3316,10 @@ __attribute__((format(printf, 3, 4))) static void jsonize_error_eventf(struct nD
ndpi_serialize_string_uint32(&reader_thread->workflow->ndpi_serializer, "threshold_n", workflow->error_count);
ndpi_serialize_string_uint32(&reader_thread->workflow->ndpi_serializer,
"threshold_n_max",
- nDPId_options.error_event_threshold_n);
+ GET_CMDARG_ULL(nDPId_options.error_event_threshold_n));
ndpi_serialize_string_uint64(&reader_thread->workflow->ndpi_serializer,
"threshold_time",
- nDPId_options.error_event_threshold_time);
+ GET_CMDARG_ULL(nDPId_options.error_event_threshold_time));
ndpi_serialize_string_uint64(&reader_thread->workflow->ndpi_serializer,
"threshold_ts_usec",
workflow->last_error_time);
@@ -3284,8 +3429,8 @@ static uint32_t calculate_ndpi_flow_struct_hash(struct ndpi_flow_struct const *
/* mask for FCF */
#define WIFI_DATA 0x2
#define FCF_TYPE(fc) (((fc) >> 2) & 0x3) /* 0000 0011 = 0x3 */
-#define FCF_TO_DS(fc) ((fc)&0x0100)
-#define FCF_FROM_DS(fc) ((fc)&0x0200)
+#define FCF_TO_DS(fc) ((fc) & 0x0100)
+#define FCF_FROM_DS(fc) ((fc) & 0x0200)
/* mask for Bad FCF presence */
#define BAD_FCS 0x50 /* 0101 0000 */
static int process_datalink_layer(struct nDPId_reader_thread * const reader_thread,
@@ -3299,7 +3444,7 @@ static int process_datalink_layer(struct nDPId_reader_thread * const reader_thre
const struct ndpi_ethhdr * ethernet;
#ifdef ENABLE_PFRING
- if (nDPId_options.use_pfring != 0)
+ if (GET_CMDARG_BOOL(nDPId_options.use_pfring) != 0)
{
datalink_type = npfring_datalink(&reader_thread->workflow->npf);
}
@@ -3722,14 +3867,14 @@ static struct nDPId_flow_basic * add_new_flow(struct nDPId_workflow * const work
static void do_periodically_work(struct nDPId_reader_thread * const reader_thread)
{
- if (reader_thread->workflow->last_scan_time + nDPId_options.flow_scan_interval <=
+ if (reader_thread->workflow->last_scan_time + GET_CMDARG_ULL(nDPId_options.flow_scan_interval) <=
reader_thread->workflow->last_global_time)
{
check_for_idle_flows(reader_thread);
check_for_flow_updates(reader_thread);
reader_thread->workflow->last_scan_time = reader_thread->workflow->last_global_time;
}
- if (reader_thread->workflow->last_status_time + nDPId_options.daemon_status_interval +
+ if (reader_thread->workflow->last_status_time + GET_CMDARG_ULL(nDPId_options.daemon_status_interval) +
reader_thread->array_index * 1000 <=
reader_thread->workflow->last_global_time)
{
@@ -3738,7 +3883,8 @@ static void do_periodically_work(struct nDPId_reader_thread * const reader_threa
reader_thread->workflow->last_global_time + reader_thread->array_index * 1000;
}
#ifdef ENABLE_MEMORY_PROFILING
- if (reader_thread->workflow->last_memory_usage_log_time + nDPId_options.memory_profiling_log_interval <=
+ if (reader_thread->workflow->last_memory_usage_log_time +
+ GET_CMDARG_ULL(nDPId_options.memory_profiling_log_interval) <=
reader_thread->workflow->last_global_time)
{
log_memory_usage(reader_thread);
@@ -3749,7 +3895,7 @@ static void do_periodically_work(struct nDPId_reader_thread * const reader_threa
static int distribute_single_packet(struct nDPId_reader_thread * const reader_thread)
{
- return (reader_thread->workflow->packets_captured % nDPId_options.reader_thread_count ==
+ return (reader_thread->workflow->packets_captured % GET_CMDARG_ULL(nDPId_options.reader_thread_count) ==
reader_thread->array_index);
}
@@ -4024,7 +4170,7 @@ static void ndpi_process_packet(uint8_t * const args,
/* distribute flows to threads while keeping stability (same flow goes always to same thread) */
thread_index += (flow_basic.src_port < flow_basic.dst_port ? flow_basic.dst_port : flow_basic.src_port);
- thread_index %= nDPId_options.reader_thread_count;
+ thread_index %= GET_CMDARG_ULL(nDPId_options.reader_thread_count);
if (thread_index != reader_thread->array_index)
{
return;
@@ -4118,7 +4264,8 @@ static void ndpi_process_packet(uint8_t * const args,
subnet = &nDPId_options.pcap_dev_subnet6;
break;
}
- if (nDPId_options.process_internal_initial_direction != 0 && flow_basic.tcp_is_midstream_flow == 0)
+ if (GET_CMDARG_BOOL(nDPId_options.process_internal_initial_direction) != 0 &&
+ flow_basic.tcp_is_midstream_flow == 0)
{
if (is_ip_in_subnet(&flow_basic.src, netmask, subnet, flow_basic.l3_type) == 0)
{
@@ -4143,7 +4290,8 @@ static void ndpi_process_packet(uint8_t * const args,
return;
}
}
- else if (nDPId_options.process_external_initial_direction != 0 && flow_basic.tcp_is_midstream_flow == 0)
+ else if (GET_CMDARG_BOOL(nDPId_options.process_external_initial_direction) != 0 &&
+ flow_basic.tcp_is_midstream_flow == 0)
{
if (is_ip_in_subnet(&flow_basic.src, netmask, subnet, flow_basic.l3_type) != 0)
{
@@ -4272,7 +4420,8 @@ static void ndpi_process_packet(uint8_t * const args,
if (flow_to_process->flow_extended.flow_basic.state == FS_INFO)
{
#ifdef ENABLE_ZLIB
- if (nDPId_options.enable_zlib_compression != 0 && flow_to_process->info.detection_data_compressed_size > 0)
+ if (GET_CMDARG_BOOL(nDPId_options.enable_zlib_compression) != 0 &&
+ flow_to_process->info.detection_data_compressed_size > 0)
{
workflow->current_compression_diff -= flow_to_process->info.detection_data_compressed_size;
int ret = detection_data_inflate(flow_to_process);
@@ -4315,10 +4464,11 @@ static void ndpi_process_packet(uint8_t * const args,
jsonize_flow_event(reader_thread, &flow_to_process->flow_extended, FLOW_EVENT_NEW);
}
- if (nDPId_options.enable_data_analysis != 0 && flow_to_process->flow_extended.flow_analysis != NULL &&
+ if (GET_CMDARG_BOOL(nDPId_options.enable_data_analysis) != 0 &&
+ flow_to_process->flow_extended.flow_analysis != NULL &&
flow_to_process->flow_extended.packets_processed[FD_SRC2DST] +
flow_to_process->flow_extended.packets_processed[FD_DST2SRC] <=
- nDPId_options.max_packets_per_flow_to_analyse)
+ GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_analyse))
{
unsigned long long int total_flow_packets = flow_to_process->flow_extended.packets_processed[FD_SRC2DST] +
flow_to_process->flow_extended.packets_processed[FD_DST2SRC];
@@ -4330,15 +4480,16 @@ static void ndpi_process_packet(uint8_t * const args,
}
ndpi_data_add_value(&flow_to_process->flow_extended.flow_analysis->pktlen, ip_size);
flow_to_process->flow_extended.flow_analysis
- ->directions[(total_flow_packets - 1) % nDPId_options.max_packets_per_flow_to_analyse] = direction;
+ ->directions[(total_flow_packets - 1) % GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_analyse)] =
+ direction;
ndpi_inc_bin(&flow_to_process->flow_extended.flow_analysis->payload_len_bin[direction],
plen2slot(l4_payload_len),
1);
flow_to_process->flow_extended.flow_analysis
- ->entropies[(total_flow_packets - 1) % nDPId_options.max_packets_per_flow_to_analyse] =
+ ->entropies[(total_flow_packets - 1) % GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_analyse)] =
ndpi_entropy((ip != NULL ? (uint8_t *)ip : (uint8_t *)ip6), ip_size);
- if (total_flow_packets == nDPId_options.max_packets_per_flow_to_analyse)
+ if (total_flow_packets == GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_analyse))
{
jsonize_flow_event(reader_thread, &flow_to_process->flow_extended, FLOW_EVENT_ANALYSE);
free_analysis_data(&flow_to_process->flow_extended);
@@ -4400,7 +4551,7 @@ static void ndpi_process_packet(uint8_t * const args,
}
if (flow_to_process->info.detection_data->flow.num_processed_pkts ==
- nDPId_options.max_packets_per_flow_to_process &&
+ GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_process) &&
flow_to_process->info.detection_completed == 0)
{
/* last chance to guess something, better then nothing */
@@ -4422,7 +4573,7 @@ static void ndpi_process_packet(uint8_t * const args,
}
if (flow_to_process->info.detection_data->flow.num_processed_pkts ==
- nDPId_options.max_packets_per_flow_to_process ||
+ GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_process) ||
(ndpi_is_protocol_detected(flow_to_process->flow_extended.detected_l7_protocol) != 0 &&
ndpi_extra_dissection_possible(workflow->ndpi_struct, &flow_to_process->info.detection_data->flow) == 0))
{
@@ -4456,7 +4607,7 @@ static void ndpi_process_packet(uint8_t * const args,
}
#ifdef ENABLE_ZLIB
- if (nDPId_options.enable_zlib_compression != 0)
+ if (GET_CMDARG_BOOL(nDPId_options.enable_zlib_compression) != 0)
{
check_for_compressable_flows(reader_thread);
}
@@ -4607,7 +4758,7 @@ static void run_capture_loop(struct nDPId_reader_thread * const reader_thread)
int capture_fd = -1;
#ifdef ENABLE_PFRING
- if (nDPId_options.use_pfring != 0)
+ if (GET_CMDARG_BOOL(nDPId_options.use_pfring) != 0)
{
capture_fd = npfring_get_selectable_fd(&reader_thread->workflow->npf);
}
@@ -4622,9 +4773,9 @@ static void run_capture_loop(struct nDPId_reader_thread * const reader_thread)
"Got an invalid %s fd",
(
#ifdef ENABLE_PFRING
- nDPId_options.use_pfring != 0 ? "PF_RING" :
+ GET_CMDARG_BOOL(nDPId_options.use_pfring) != 0 ? "PF_RING" :
#endif
- "PCAP"));
+ "PCAP"));
MT_GET_AND_ADD(reader_thread->workflow->error_or_eof, 1);
return;
}
@@ -4632,8 +4783,9 @@ static void run_capture_loop(struct nDPId_reader_thread * const reader_thread)
struct nio io;
nio_init(&io);
#ifdef ENABLE_EPOLL
- if ((nDPId_options.use_poll == 0 && nio_use_epoll(&io, 32) != NIO_SUCCESS) ||
- (nDPId_options.use_poll != 0 && nio_use_poll(&io, nDPIsrvd_MAX_REMOTE_DESCRIPTORS) != NIO_SUCCESS))
+ if ((GET_CMDARG_BOOL(nDPId_options.use_poll) == 0 && nio_use_epoll(&io, 32) != NIO_SUCCESS) ||
+ (GET_CMDARG_BOOL(nDPId_options.use_poll) != 0 &&
+ nio_use_poll(&io, nDPIsrvd_MAX_REMOTE_DESCRIPTORS) != NIO_SUCCESS))
#else
if (nio_use_poll(&io, nDPIsrvd_MAX_REMOTE_DESCRIPTORS) != NIO_SUCCESS)
#endif
@@ -4714,23 +4866,34 @@ static void run_capture_loop(struct nDPId_reader_thread * const reader_thread)
}
else
{
+ int is_valid_signal = 0;
char const * signame = "unknown";
switch (fdsi.ssi_signo)
{
case SIGINT:
+ is_valid_signal = 1;
signame = "SIGINT";
sighandler(SIGINT);
break;
case SIGTERM:
+ is_valid_signal = 1;
signame = "SIGTERM";
sighandler(SIGTERM);
break;
case SIGUSR1:
+ is_valid_signal = 1;
signame = "SIGUSR1";
log_all_flows(reader_thread);
break;
}
- logger(1, "Received signal %d (%s)", fdsi.ssi_signo, signame);
+ if (is_valid_signal != 0)
+ {
+ logger(1, "Received signal %d (%s)", fdsi.ssi_signo, signame);
+ }
+ else
+ {
+ logger(1, "Received signal %d (%s), ignored", fdsi.ssi_signo, signame);
+ }
}
}
else
@@ -4738,7 +4901,7 @@ static void run_capture_loop(struct nDPId_reader_thread * const reader_thread)
if (fd == capture_fd)
{
#ifdef ENABLE_PFRING
- if (nDPId_options.use_pfring != 0)
+ if (GET_CMDARG_BOOL(nDPId_options.use_pfring) != 0)
{
struct pcap_pkthdr hdr;
@@ -4806,7 +4969,7 @@ static void * processing_thread(void * const ndpi_thread_arg)
logger(1,
"Thread %zu: Could not connect to nDPIsrvd Collector at %s, will try again later. Error: %s",
reader_thread->array_index,
- get_cmdarg(&nDPId_options.collector_address),
+ GET_CMDARG_STR(nDPId_options.collector_address),
(reader_thread->collector_sock_last_errno != 0 ? strerror(reader_thread->collector_sock_last_errno)
: "Internal Error."));
}
@@ -4823,7 +4986,7 @@ static void * processing_thread(void * const ndpi_thread_arg)
static WARN_UNUSED int processing_threads_error_or_eof(void)
{
- for (unsigned long long int i = 0; i < nDPId_options.reader_thread_count; ++i)
+ for (unsigned long long int i = 0; i < GET_CMDARG_ULL(nDPId_options.reader_thread_count); ++i)
{
if (MT_GET_AND_ADD(reader_threads[i].workflow->error_or_eof, 0) == 0)
{
@@ -4846,38 +5009,32 @@ static int start_reader_threads(void)
return 1;
}
- if (daemonize_with_pidfile(get_cmdarg(&nDPId_options.pidfile)) != 0)
+ if (daemonize_with_pidfile(GET_CMDARG_STR(nDPId_options.pidfile)) != 0)
{
return 1;
}
- errno = 0;
- if (change_user_group(get_cmdarg(&nDPId_options.user),
- get_cmdarg(&nDPId_options.group),
- get_cmdarg(&nDPId_options.pidfile),
- NULL,
- NULL) != 0 &&
- errno != EPERM)
- {
- if (errno != 0)
+ int ret = change_user_group(GET_CMDARG_STR(nDPId_options.user),
+ GET_CMDARG_STR(nDPId_options.group),
+ GET_CMDARG_STR(nDPId_options.pidfile));
+ if (ret != 0 && ret != -EPERM)
+ {
+ if (GET_CMDARG_STR(nDPId_options.group) != NULL)
{
logger(1,
"Change user/group to %s/%s failed: %s",
- get_cmdarg(&nDPId_options.user),
- get_cmdarg(&nDPId_options.group),
- strerror(errno));
+ GET_CMDARG_STR(nDPId_options.user),
+ GET_CMDARG_STR(nDPId_options.group),
+ strerror(-ret));
}
else
{
- logger(1,
- "Change user/group to %s/%s failed.",
- get_cmdarg(&nDPId_options.user),
- get_cmdarg(&nDPId_options.group));
+ logger(1, "Change user to %s failed: %s", GET_CMDARG_STR(nDPId_options.user), strerror(-ret));
}
return 1;
}
- for (unsigned long long int i = 0; i < nDPId_options.reader_thread_count; ++i)
+ for (unsigned long long int i = 0; i < GET_CMDARG_ULL(nDPId_options.reader_thread_count); ++i)
{
reader_threads[i].array_index = i;
@@ -4915,7 +5072,7 @@ static void ndpi_shutdown_walker(void const * const A, ndpi_VISIT which, int dep
return;
}
- if (workflow->cur_idle_flows == nDPId_options.max_idle_flows_per_thread)
+ if (workflow->cur_idle_flows == GET_CMDARG_ULL(nDPId_options.max_idle_flows_per_thread))
{
return;
}
@@ -4940,7 +5097,7 @@ static void ndpi_shutdown_walker(void const * const A, ndpi_VISIT which, int dep
static void process_remaining_flows(void)
{
- for (unsigned long long int i = 0; i < nDPId_options.reader_thread_count; ++i)
+ for (unsigned long long int i = 0; i < GET_CMDARG_ULL(nDPId_options.reader_thread_count); ++i)
{
set_collector_block(&reader_threads[i]);
@@ -4970,13 +5127,13 @@ static int stop_reader_threads(void)
unsigned long long int total_flow_detection_updates = 0;
unsigned long long int total_flow_updates = 0;
- for (unsigned long long int i = 0; i < nDPId_options.reader_thread_count; ++i)
+ for (unsigned long long int i = 0; i < GET_CMDARG_ULL(nDPId_options.reader_thread_count); ++i)
{
break_pcap_loop(&reader_threads[i]);
}
printf("------------------------------------ Stopping reader threads\n");
- for (unsigned long long int i = 0; i < nDPId_options.reader_thread_count; ++i)
+ for (unsigned long long int i = 0; i < GET_CMDARG_ULL(nDPId_options.reader_thread_count); ++i)
{
if (reader_threads[i].workflow == NULL)
{
@@ -4993,7 +5150,7 @@ static int stop_reader_threads(void)
process_remaining_flows();
printf("------------------------------------ Results\n");
- for (unsigned long long int i = 0; i < nDPId_options.reader_thread_count; ++i)
+ for (unsigned long long int i = 0; i < GET_CMDARG_ULL(nDPId_options.reader_thread_count); ++i)
{
if (reader_threads[i].workflow == NULL)
{
@@ -5047,7 +5204,7 @@ static int stop_reader_threads(void)
static void free_reader_threads(void)
{
- for (unsigned long long int i = 0; i < nDPId_options.reader_thread_count; ++i)
+ for (unsigned long long int i = 0; i < GET_CMDARG_ULL(nDPId_options.reader_thread_count); ++i)
{
if (reader_threads[i].workflow == NULL)
{
@@ -5070,90 +5227,18 @@ static void sighandler(int signum)
static void print_subopt_usage(void)
{
- int index = MAX_FLOWS_PER_THREAD;
- char * const * token = &subopt_token[0];
-
fprintf(stderr, "\tsubopts:\n");
- do
+ for (size_t i = 0; i < nDPIsrvd_ARRAY_LENGTH(tuning_config_map); ++i)
{
- if (*token != NULL)
- {
- fprintf(stderr, "\t\t%s = ", *token);
- enum nDPId_subopts subopts = index++;
- switch (subopts)
- {
- case MAX_FLOWS_PER_THREAD:
- fprintf(stderr, "%llu\n", nDPId_options.max_flows_per_thread);
- break;
- case MAX_IDLE_FLOWS_PER_THREAD:
- fprintf(stderr, "%llu\n", nDPId_options.max_idle_flows_per_thread);
- break;
- case MAX_READER_THREADS:
- fprintf(stderr, "%llu\n", nDPId_options.reader_thread_count);
- break;
- case DAEMON_STATUS_INTERVAL:
- fprintf(stderr, "%llu\n", nDPId_options.daemon_status_interval);
- break;
-#ifdef ENABLE_MEMORY_PROFILING
- case MEMORY_PROFILING_LOG_INTERVAL:
- fprintf(stderr, "%llu\n", nDPId_options.memory_profiling_log_interval);
- break;
-#endif
-#ifdef ENABLE_ZLIB
- case COMPRESSION_SCAN_INTERVAL:
- fprintf(stderr, "%llu\n", nDPId_options.compression_scan_interval);
- break;
- case COMPRESSION_FLOW_INACTIVITY:
- fprintf(stderr, "%llu\n", nDPId_options.compression_flow_inactivity);
- break;
-#endif
- case FLOW_SCAN_INTVERAL:
- fprintf(stderr, "%llu\n", nDPId_options.flow_scan_interval);
- break;
- case GENERIC_MAX_IDLE_TIME:
- fprintf(stderr, "%llu\n", nDPId_options.generic_max_idle_time);
- break;
- case ICMP_MAX_IDLE_TIME:
- fprintf(stderr, "%llu\n", nDPId_options.icmp_max_idle_time);
- break;
- case UDP_MAX_IDLE_TIME:
- fprintf(stderr, "%llu\n", nDPId_options.udp_max_idle_time);
- break;
- case TCP_MAX_IDLE_TIME:
- fprintf(stderr, "%llu\n", nDPId_options.tcp_max_idle_time);
- break;
- case TCP_MAX_POST_END_FLOW_TIME:
- fprintf(stderr, "%llu\n", nDPId_options.tcp_max_post_end_flow_time);
- break;
- case MAX_PACKETS_PER_FLOW_TO_SEND:
- fprintf(stderr, "%llu\n", nDPId_options.max_packets_per_flow_to_send);
- break;
- case MAX_PACKETS_PER_FLOW_TO_PROCESS:
- fprintf(stderr, "%llu\n", nDPId_options.max_packets_per_flow_to_process);
- break;
- case MAX_PACKETS_PER_FLOW_TO_ANALYZE:
- fprintf(stderr, "%llu\n", nDPId_options.max_packets_per_flow_to_analyse);
- break;
- case ERROR_EVENT_THRESHOLD_N:
- fprintf(stderr, "%llu\n", nDPId_options.error_event_threshold_n);
- break;
- case ERROR_EVENT_THRESHOLD_TIME:
- fprintf(stderr, "%llu\n", nDPId_options.error_event_threshold_time);
- break;
- }
- }
- else
- {
- break;
- }
- token++;
- } while (1);
+ fprintf(stderr, "\t\t%s = %llu\n", tuning_config_map[i].key, tuning_config_map[i].opt->ull.default_value);
+ }
}
static void print_usage(char const * const arg0)
{
static char const usage[] =
"Usage: %s "
+ "[-f config-file]\n"
"[-i pcap-file/interface] [-I] [-E] [-B bpf-filter]\n"
"\t \t"
"[-l] [-L logfile] [-c address] [-e]"
@@ -5167,6 +5252,7 @@ static void print_usage(char const * const arg0)
"[-o subopt=value]\n"
"\t \t"
"[-v] [-h]\n\n"
+ "\t-f\tLoad nDPId/libnDPI options from a configuration file.\n"
"\t-i\tInterface or file from where to read packets from.\n"
#ifdef ENABLE_PFRING
"\t-r\tUse PFRING to capture packets instead of libpcap.\n"
@@ -5188,6 +5274,7 @@ static void print_usage(char const * const arg0)
"\t-u\tChange UID to the numeric value of user.\n"
"\t \tDefault: %s\n"
"\t-g\tChange GID to the numeric value of group.\n"
+ "\t-R\tLoad a nDPI custom risk domain file.\n"
"\t-P\tLoad a nDPI custom protocols file.\n"
"\t-C\tLoad a nDPI custom categories file.\n"
"\t-J\tLoad a nDPI JA3 hash blacklist file.\n"
@@ -5210,9 +5297,9 @@ static void print_usage(char const * const arg0)
fprintf(stderr,
usage,
arg0,
- get_cmdarg(&nDPId_options.collector_address),
- get_cmdarg(&nDPId_options.pidfile),
- get_cmdarg(&nDPId_options.user));
+ nDPId_options.collector_address.string.default_value,
+ nDPId_options.pidfile.string.default_value,
+ nDPId_options.user.string.default_value);
}
static void nDPId_print_deps_version(FILE * const out)
@@ -5243,29 +5330,32 @@ static int nDPId_parse_options(int argc, char ** argv)
{
int opt;
- while ((opt = getopt(argc, argv, "i:rIEB:lL:c:edp:u:g:P:C:J:S:a:Azo:vh")) != -1)
+ while ((opt = getopt(argc, argv, "f:i:rIEB:lL:c:edp:u:g:R:P:C:J:S:a:Azo:vh")) != -1)
{
switch (opt)
{
+ case 'f':
+ set_cmdarg_string(&nDPId_options.config_file, optarg);
+ break;
case 'i':
- set_cmdarg(&nDPId_options.pcap_file_or_interface, optarg);
+ set_cmdarg_string(&nDPId_options.pcap_file_or_interface, optarg);
break;
case 'r':
#ifdef ENABLE_PFRING
- nDPId_options.use_pfring = 1;
+ set_cmdarg_boolean(&nDPId_options.use_pfring, 1);
break;
#else
logger_early(1, "%s", "nDPId was built w/o PFRING support");
return 1;
#endif
case 'I':
- nDPId_options.process_internal_initial_direction = 1;
+ set_cmdarg_boolean(&nDPId_options.process_internal_initial_direction, 1);
break;
case 'E':
- nDPId_options.process_external_initial_direction = 1;
+ set_cmdarg_boolean(&nDPId_options.process_external_initial_direction, 1);
break;
case 'B':
- set_cmdarg(&nDPId_options.bpf_str, optarg);
+ set_cmdarg_string(&nDPId_options.bpf_str, optarg);
break;
case 'l':
enable_console_logger();
@@ -5277,11 +5367,11 @@ static int nDPId_parse_options(int argc, char ** argv)
}
break;
case 'c':
- set_cmdarg(&nDPId_options.collector_address, optarg);
+ set_cmdarg_string(&nDPId_options.collector_address, optarg);
break;
case 'e':
#ifdef ENABLE_EPOLL
- nDPId_options.use_poll = 1;
+ set_cmdarg_boolean(&nDPId_options.use_poll, 1);
#else
logger_early(1, "%s", "nDPId was built w/o epoll() support, poll() is already the default");
#endif
@@ -5290,35 +5380,38 @@ static int nDPId_parse_options(int argc, char ** argv)
daemonize_enable();
break;
case 'p':
- set_cmdarg(&nDPId_options.pidfile, optarg);
+ set_cmdarg_string(&nDPId_options.pidfile, optarg);
break;
case 'u':
- set_cmdarg(&nDPId_options.user, optarg);
+ set_cmdarg_string(&nDPId_options.user, optarg);
break;
case 'g':
- set_cmdarg(&nDPId_options.group, optarg);
+ set_cmdarg_string(&nDPId_options.group, optarg);
+ break;
+ case 'R':
+ set_cmdarg_string(&nDPId_options.custom_risk_domain_file, optarg);
break;
case 'P':
- set_cmdarg(&nDPId_options.custom_protocols_file, optarg);
+ set_cmdarg_string(&nDPId_options.custom_protocols_file, optarg);
break;
case 'C':
- set_cmdarg(&nDPId_options.custom_categories_file, optarg);
+ set_cmdarg_string(&nDPId_options.custom_categories_file, optarg);
break;
case 'J':
- set_cmdarg(&nDPId_options.custom_ja3_file, optarg);
+ set_cmdarg_string(&nDPId_options.custom_ja3_file, optarg);
break;
case 'S':
- set_cmdarg(&nDPId_options.custom_sha1_file, optarg);
+ set_cmdarg_string(&nDPId_options.custom_sha1_file, optarg);
break;
case 'a':
- set_cmdarg(&nDPId_options.instance_alias, optarg);
+ set_cmdarg_string(&nDPId_options.instance_alias, optarg);
break;
case 'A':
- nDPId_options.enable_data_analysis = 1;
+ set_cmdarg_boolean(&nDPId_options.enable_data_analysis, 1);
break;
case 'z':
#ifdef ENABLE_ZLIB
- nDPId_options.enable_zlib_compression = 1;
+ set_cmdarg_boolean(&nDPId_options.enable_zlib_compression, 1);
break;
#else
logger_early(1, "%s", "nDPId was built w/o zLib compression");
@@ -5329,18 +5422,23 @@ static int nDPId_parse_options(int argc, char ** argv)
int errfnd = 0;
char * subopts = optarg;
char * value;
+ char * subopt_tokens[nDPIsrvd_ARRAY_LENGTH(tuning_config_map) + 1] = {};
- while (*subopts != '\0' && !errfnd)
+ for (size_t i = 0; i < nDPIsrvd_ARRAY_LENGTH(tuning_config_map); ++i)
+ {
+ subopt_tokens[i] = strdup(tuning_config_map[i].key);
+ }
+ while (*subopts != '\0' && errfnd == 0)
{
- char * endptr;
- int subopt = getsubopt(&subopts, subopt_token, &value);
+ int subopt = getsubopt(&subopts, subopt_tokens, &value);
if (value == NULL && subopt != -1)
{
- logger_early(1, "Missing value for `%s'", subopt_token[subopt]);
+ logger_early(1, "Missing value for `%s'", subopt_tokens[subopt]);
fprintf(stderr, "%s", "\n");
print_usage(argv[0]);
print_subopt_usage();
- return 1;
+ errfnd = 1;
+ break;
}
if (subopt == -1)
{
@@ -5348,83 +5446,25 @@ static int nDPId_parse_options(int argc, char ** argv)
fprintf(stderr, "%s", "\n");
print_usage(argv[0]);
print_subopt_usage();
- return 1;
- }
-
- long int value_llu = strtoull(value, &endptr, 10);
- if (value == endptr)
- {
- logger_early(1, "Subopt `%s': Value `%s' is not a valid number.", subopt_token[subopt], value);
- return 1;
- }
- if (errno == ERANGE)
- {
- logger_early(1, "Subopt `%s': Number too large.", subopt_token[subopt]);
- return 1;
+ errfnd = 1;
+ break;
}
- switch ((enum nDPId_subopts)subopt)
+ if (set_config_from(&tuning_config_map[subopt], value) != 0)
{
- case MAX_FLOWS_PER_THREAD:
- nDPId_options.max_flows_per_thread = value_llu;
- break;
- case MAX_IDLE_FLOWS_PER_THREAD:
- nDPId_options.max_idle_flows_per_thread = value_llu;
- break;
- case MAX_READER_THREADS:
- nDPId_options.reader_thread_count = value_llu;
- break;
- case DAEMON_STATUS_INTERVAL:
- nDPId_options.daemon_status_interval = value_llu;
- break;
-#ifdef ENABLE_MEMORY_PROFILING
- case MEMORY_PROFILING_LOG_INTERVAL:
- nDPId_options.memory_profiling_log_interval = value_llu;
- break;
-#endif
-#ifdef ENABLE_ZLIB
- case COMPRESSION_SCAN_INTERVAL:
- nDPId_options.compression_scan_interval = value_llu;
- break;
- case COMPRESSION_FLOW_INACTIVITY:
- nDPId_options.compression_flow_inactivity = value_llu;
- break;
-#endif
- case FLOW_SCAN_INTVERAL:
- nDPId_options.flow_scan_interval = value_llu;
- break;
- case GENERIC_MAX_IDLE_TIME:
- nDPId_options.generic_max_idle_time = value_llu;
- break;
- case ICMP_MAX_IDLE_TIME:
- nDPId_options.icmp_max_idle_time = value_llu;
- break;
- case UDP_MAX_IDLE_TIME:
- nDPId_options.udp_max_idle_time = value_llu;
- break;
- case TCP_MAX_IDLE_TIME:
- nDPId_options.tcp_max_idle_time = value_llu;
- break;
- case TCP_MAX_POST_END_FLOW_TIME:
- nDPId_options.tcp_max_post_end_flow_time = value_llu;
- break;
- case MAX_PACKETS_PER_FLOW_TO_SEND:
- nDPId_options.max_packets_per_flow_to_send = value_llu;
- break;
- case MAX_PACKETS_PER_FLOW_TO_PROCESS:
- nDPId_options.max_packets_per_flow_to_process = value_llu;
- break;
- case MAX_PACKETS_PER_FLOW_TO_ANALYZE:
- nDPId_options.max_packets_per_flow_to_analyse = value_llu;
- break;
- case ERROR_EVENT_THRESHOLD_N:
- nDPId_options.error_event_threshold_n = value_llu;
- break;
- case ERROR_EVENT_THRESHOLD_TIME:
- nDPId_options.error_event_threshold_time = value_llu;
- break;
+ logger_early(1, "Could not set subopt: %s", tuning_config_map[subopt].key);
+ errfnd = 1;
+ break;
}
}
+ for (size_t i = 0; i < nDPIsrvd_ARRAY_LENGTH(tuning_config_map); ++i)
+ {
+ free(subopt_tokens[i]);
+ }
+ if (errfnd != 0)
+ {
+ return 1;
+ }
break;
}
case 'v':
@@ -5465,10 +5505,10 @@ static int validate_options(void)
retval = 1;
}
#ifdef ENABLE_ZLIB
- if (nDPId_options.enable_zlib_compression != 0)
+ if (GET_CMDARG_BOOL(nDPId_options.enable_zlib_compression) != 0)
{
- if (nDPId_options.compression_flow_inactivity < TIME_S_TO_US(6u) ||
- nDPId_options.compression_scan_interval < TIME_S_TO_US(4u))
+ if (GET_CMDARG_ULL(nDPId_options.compression_flow_inactivity) < TIME_S_TO_US(6u) ||
+ GET_CMDARG_ULL(nDPId_options.compression_scan_interval) < TIME_S_TO_US(4u))
{
logger_early(1,
"Setting compression-scan-interval / compression-flow-inactivity "
@@ -5479,12 +5519,13 @@ static int validate_options(void)
}
}
#endif
- if (nDPIsrvd_setup_address(&collector_address, get_cmdarg(&nDPId_options.collector_address)) != 0)
+ if (nDPIsrvd_setup_address(&nDPId_options.parsed_collector_address,
+ GET_CMDARG_STR(nDPId_options.collector_address)) != 0)
{
retval = 1;
- logger_early(1, "Collector socket invalid address: %s.", get_cmdarg(&nDPId_options.collector_address));
+ logger_early(1, "Collector socket invalid address: %s.", GET_CMDARG_STR(nDPId_options.collector_address));
}
- if (is_cmdarg_set(&nDPId_options.instance_alias) == 0)
+ if (IS_CMDARG_SET(nDPId_options.instance_alias) == 0)
{
char hname[256];
@@ -5496,101 +5537,106 @@ static int validate_options(void)
}
else
{
- set_cmdarg(&nDPId_options.instance_alias, hname);
+ set_cmdarg_string(&nDPId_options.instance_alias, hname);
logger_early(1,
"No instance alias given, using your hostname '%s'",
- get_cmdarg(&nDPId_options.instance_alias));
- if (is_cmdarg_set(&nDPId_options.instance_alias) == 0)
+ GET_CMDARG_STR(nDPId_options.instance_alias));
+ if (IS_CMDARG_SET(nDPId_options.instance_alias) == 0)
{
retval = 1;
}
}
}
- if (nDPId_options.max_flows_per_thread < 128 || nDPId_options.max_flows_per_thread > nDPId_MAX_FLOWS_PER_THREAD)
+ if (GET_CMDARG_ULL(nDPId_options.max_flows_per_thread) < 128 ||
+ GET_CMDARG_ULL(nDPId_options.max_flows_per_thread) > nDPId_MAX_FLOWS_PER_THREAD)
{
logger_early(1,
"Value not in range: 128 < max-flows-per-thread[%llu] < %d",
- nDPId_options.max_flows_per_thread,
+ GET_CMDARG_ULL(nDPId_options.max_flows_per_thread),
nDPId_MAX_FLOWS_PER_THREAD);
retval = 1;
}
- if (nDPId_options.max_idle_flows_per_thread < 64 ||
- nDPId_options.max_idle_flows_per_thread > nDPId_MAX_IDLE_FLOWS_PER_THREAD)
+ if (GET_CMDARG_ULL(nDPId_options.max_idle_flows_per_thread) < 64 ||
+ GET_CMDARG_ULL(nDPId_options.max_idle_flows_per_thread) > nDPId_MAX_IDLE_FLOWS_PER_THREAD)
{
logger_early(1,
"Value not in range: 64 < max-idle-flows-per-thread[%llu] < %d",
- nDPId_options.max_idle_flows_per_thread,
+ GET_CMDARG_ULL(nDPId_options.max_idle_flows_per_thread),
nDPId_MAX_IDLE_FLOWS_PER_THREAD);
retval = 1;
}
- if (nDPId_options.reader_thread_count < 1 || nDPId_options.reader_thread_count > nDPId_MAX_READER_THREADS)
+ if (GET_CMDARG_ULL(nDPId_options.reader_thread_count) < 1 ||
+ GET_CMDARG_ULL(nDPId_options.reader_thread_count) > nDPId_MAX_READER_THREADS)
{
logger_early(1,
"Value not in range: 1 < reader-thread-count[%llu] < %d",
- nDPId_options.reader_thread_count,
+ GET_CMDARG_ULL(nDPId_options.reader_thread_count),
nDPId_MAX_READER_THREADS);
retval = 1;
}
- if (nDPId_options.flow_scan_interval < TIME_S_TO_US(5u))
+ if (GET_CMDARG_ULL(nDPId_options.flow_scan_interval) < TIME_S_TO_US(5u))
{
logger_early(1,
"Value not in range: idle-scan-interval[%llu] > %llu",
- nDPId_options.flow_scan_interval,
+ GET_CMDARG_ULL(nDPId_options.flow_scan_interval),
TIME_S_TO_US(5u));
retval = 1;
}
- if (nDPId_options.flow_scan_interval >= nDPId_options.generic_max_idle_time)
+ if (GET_CMDARG_ULL(nDPId_options.flow_scan_interval) >= GET_CMDARG_ULL(nDPId_options.generic_max_idle_time))
{
logger_early(1,
"Value not in range: flow-scan-interval[%llu] < generic-max-idle-time[%llu]",
- nDPId_options.flow_scan_interval,
- nDPId_options.generic_max_idle_time);
+ GET_CMDARG_ULL(nDPId_options.flow_scan_interval),
+ GET_CMDARG_ULL(nDPId_options.generic_max_idle_time));
retval = 1;
}
- if (nDPId_options.flow_scan_interval >= nDPId_options.icmp_max_idle_time)
+ if (GET_CMDARG_ULL(nDPId_options.flow_scan_interval) >= GET_CMDARG_ULL(nDPId_options.icmp_max_idle_time))
{
logger_early(1,
"Value not in range: flow-scan-interval[%llu] < icmp-max-idle-time[%llu]",
- nDPId_options.flow_scan_interval,
- nDPId_options.icmp_max_idle_time);
+ GET_CMDARG_ULL(nDPId_options.flow_scan_interval),
+ GET_CMDARG_ULL(nDPId_options.icmp_max_idle_time));
retval = 1;
}
- if (nDPId_options.flow_scan_interval >= nDPId_options.tcp_max_idle_time)
+ if (GET_CMDARG_ULL(nDPId_options.flow_scan_interval) >= GET_CMDARG_ULL(nDPId_options.tcp_max_idle_time))
{
logger_early(1,
"Value not in range: flow-scan-interval[%llu] < generic-max-idle-time[%llu]",
- nDPId_options.flow_scan_interval,
- nDPId_options.tcp_max_idle_time);
+ GET_CMDARG_ULL(nDPId_options.flow_scan_interval),
+ GET_CMDARG_ULL(nDPId_options.tcp_max_idle_time));
retval = 1;
}
- if (nDPId_options.flow_scan_interval >= nDPId_options.udp_max_idle_time)
+ if (GET_CMDARG_ULL(nDPId_options.flow_scan_interval) >= GET_CMDARG_ULL(nDPId_options.udp_max_idle_time))
{
logger_early(1,
"Value not in range:flow-scan-interval[%llu] < udp-max-idle-time[%llu]",
- nDPId_options.flow_scan_interval,
- nDPId_options.udp_max_idle_time);
+ GET_CMDARG_ULL(nDPId_options.flow_scan_interval),
+ GET_CMDARG_ULL(nDPId_options.udp_max_idle_time));
retval = 1;
}
- if (nDPId_options.process_internal_initial_direction != 0 && nDPId_options.process_external_initial_direction != 0)
+ if (GET_CMDARG_BOOL(nDPId_options.process_internal_initial_direction) != 0 &&
+ GET_CMDARG_BOOL(nDPId_options.process_external_initial_direction) != 0)
{
logger_early(1, "%s", "Internal and External packet processing does not make sense as this is the default.");
retval = 1;
}
- if (nDPId_options.process_internal_initial_direction != 0 || nDPId_options.process_external_initial_direction != 0)
+ if (GET_CMDARG_BOOL(nDPId_options.process_internal_initial_direction) != 0 ||
+ GET_CMDARG_BOOL(nDPId_options.process_external_initial_direction) != 0)
{
logger_early(1,
"%s",
"Internal and External packet processing may lead to incorrect results for flows that were active "
"before the daemon started.");
}
- if (nDPId_options.max_packets_per_flow_to_process < 1 || nDPId_options.max_packets_per_flow_to_process > 65535)
+ if (GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_process) < 1 ||
+ GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_process) > 65535)
{
logger_early(1,
"Value not in range: 1 =< max-packets-per-flow-to-process[%llu] =< 65535",
- nDPId_options.max_packets_per_flow_to_process);
+ GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_process));
retval = 1;
}
- if (nDPId_options.max_packets_per_flow_to_send > 30)
+ if (GET_CMDARG_ULL(nDPId_options.max_packets_per_flow_to_send) > 30)
{
logger_early(1, "%s", "Higher values of max-packets-per-flow-to-send may cause superfluous network usage.");
}
@@ -5598,6 +5644,81 @@ static int validate_options(void)
return retval;
}
+static int nDPId_parsed_config_line(
+ int lineno, char const * const section, char const * const name, char const * const value, void * const user_data)
+{
+ (void)user_data;
+
+ if (strnlen(section, INI_MAX_SECTION) == nDPIsrvd_STRLEN_SZ("general") &&
+ strncmp(section, "general", INI_MAX_SECTION) == 0)
+ {
+ size_t i;
+
+ for (i = 0; i < nDPIsrvd_ARRAY_LENGTH(general_config_map); ++i)
+ {
+ if (strnlen(name, INI_MAX_NAME) == strnlen(general_config_map[i].key, INI_MAX_NAME) &&
+ strncmp(name, general_config_map[i].key, INI_MAX_NAME) == 0)
+ {
+ if (IS_CMDARG_SET(*general_config_map[i].opt) != 0)
+ {
+ logger_early(1, "General config key `%s' already set, ignoring value `%s'", name, value);
+ }
+ else
+ {
+ if (set_config_from(&general_config_map[i], value) != 0)
+ {
+ return 0;
+ }
+ }
+ break;
+ }
+ }
+ if (i == nDPIsrvd_ARRAY_LENGTH(general_config_map))
+ {
+ logger_early(1, "Invalid general config key `%s' at line %d", name, lineno);
+ }
+ }
+ else if (strnlen(section, INI_MAX_SECTION) == nDPIsrvd_STRLEN_SZ("tuning") &&
+ strncmp(section, "tuning", INI_MAX_SECTION) == 0)
+ {
+ size_t i;
+
+ for (i = 0; i < nDPIsrvd_ARRAY_LENGTH(tuning_config_map); ++i)
+ {
+ if (strnlen(name, INI_MAX_NAME) == strnlen(tuning_config_map[i].key, INI_MAX_NAME) &&
+ strncmp(name, tuning_config_map[i].key, INI_MAX_NAME) == 0)
+ {
+ if (set_config_from(&tuning_config_map[i], value) != 0)
+ {
+ logger_early(
+ 1, "Non numeric tuning config value `%s' for key `%s' at line %d", value, name, lineno);
+ return 0;
+ }
+ break;
+ }
+ }
+ if (i == nDPIsrvd_ARRAY_LENGTH(tuning_config_map))
+ {
+ logger_early(1, "Invalid tuning config key `%s' at line %d", name, lineno);
+ }
+ }
+ else if ((strnlen(section, INI_MAX_SECTION) == nDPIsrvd_STRLEN_SZ("ndpi") &&
+ strncmp(section, "ndpi", INI_MAX_SECTION) == 0) ||
+ (strnlen(section, INI_MAX_SECTION) == nDPIsrvd_STRLEN_SZ("protos") &&
+ strncmp(section, "protos", INI_MAX_SECTION) == 0))
+ {
+ // Nothing to do here right now (workflow not initialized yet)
+ return 1;
+ }
+ else
+ {
+ logger_early(
+ 1, "Invalid config section `%s' at line %d with key `%s' and value `%s'", section, lineno, name, value);
+ }
+
+ return 1;
+}
+
#ifndef NO_MAIN
int main(int argc, char ** argv)
{
@@ -5612,6 +5733,32 @@ int main(int argc, char ** argv)
{
return 1;
}
+ set_config_defaults(&general_config_map[0], nDPIsrvd_ARRAY_LENGTH(general_config_map));
+ set_config_defaults(&tuning_config_map[0], nDPIsrvd_ARRAY_LENGTH(tuning_config_map));
+ {
+ int ret;
+
+ if (IS_CMDARG_SET(nDPId_options.config_file) != 0 &&
+ (ret = parse_config_file(GET_CMDARG_STR(nDPId_options.config_file), nDPId_parsed_config_line, NULL)) != 0)
+ {
+ if (ret > 0)
+ {
+ logger_early(1, "Config file `%s' is malformed", GET_CMDARG_STR(nDPId_options.config_file));
+ }
+ else if (ret == -ENOENT)
+ {
+ logger_early(1, "Path `%s' is not a regular file", GET_CMDARG_STR(nDPId_options.config_file));
+ }
+ else
+ {
+ logger_early(1,
+ "Could not open file `%s' for reading: %s",
+ GET_CMDARG_STR(nDPId_options.config_file),
+ strerror(errno));
+ }
+ return 1;
+ }
+ }
if (validate_options() != 0)
{
logger_early(1, "%s", "Option validation failed.");
@@ -5670,7 +5817,7 @@ int main(int argc, char ** argv)
}
free_reader_threads();
- daemonize_shutdown(get_cmdarg(&nDPId_options.pidfile));
+ daemonize_shutdown(GET_CMDARG_STR(nDPId_options.pidfile));
logger(0, "%s", "Bye.");
shutdown_logging();
diff --git a/nDPIsrvd.c b/nDPIsrvd.c
index 3c3fddf94..1e675ba5b 100644
--- a/nDPIsrvd.c
+++ b/nDPIsrvd.c
@@ -90,27 +90,54 @@ static struct nDPIsrvd_address distributor_in_address = {
static struct
{
+ struct cmdarg config_file;
struct cmdarg pidfile;
struct cmdarg collector_un_sockpath;
struct cmdarg distributor_un_sockpath;
struct cmdarg distributor_in_address;
struct cmdarg user;
struct cmdarg group;
- nDPIsrvd_ull max_remote_descriptors;
- nDPIsrvd_ull max_write_buffers;
- uint8_t bufferbloat_fallback_to_blocking;
+ struct cmdarg collector_group;
+ struct cmdarg distributor_group;
+ struct cmdarg max_remote_descriptors;
+ struct cmdarg max_write_buffers;
+ struct cmdarg bufferbloat_fallback_to_blocking;
#ifdef ENABLE_EPOLL
- uint8_t use_poll;
+ struct cmdarg use_poll;
#endif
-} nDPIsrvd_options = {.pidfile = CMDARG(nDPIsrvd_PIDFILE),
- .collector_un_sockpath = CMDARG(COLLECTOR_UNIX_SOCKET),
- .distributor_un_sockpath = CMDARG(DISTRIBUTOR_UNIX_SOCKET),
- .distributor_in_address = CMDARG(NULL),
- .user = CMDARG(DEFAULT_CHUSER),
- .group = CMDARG(NULL),
- .max_remote_descriptors = nDPIsrvd_MAX_REMOTE_DESCRIPTORS,
- .max_write_buffers = nDPIsrvd_MAX_WRITE_BUFFERS,
- .bufferbloat_fallback_to_blocking = 1};
+} nDPIsrvd_options = {.config_file = CMDARG_STR(NULL),
+ .pidfile = CMDARG_STR(nDPIsrvd_PIDFILE),
+ .collector_un_sockpath = CMDARG_STR(COLLECTOR_UNIX_SOCKET),
+ .distributor_un_sockpath = CMDARG_STR(DISTRIBUTOR_UNIX_SOCKET),
+ .distributor_in_address = CMDARG_STR(NULL),
+ .user = CMDARG_STR(DEFAULT_CHUSER),
+ .group = CMDARG_STR(NULL),
+ .collector_group = CMDARG_STR(NULL),
+ .distributor_group = CMDARG_STR(NULL),
+ .max_remote_descriptors = CMDARG_ULL(nDPIsrvd_MAX_REMOTE_DESCRIPTORS),
+ .max_write_buffers = CMDARG_ULL(nDPIsrvd_MAX_WRITE_BUFFERS),
+ .bufferbloat_fallback_to_blocking = CMDARG_BOOL(1)
+#ifdef ENABLE_EPOLL
+ ,
+ .use_poll = CMDARG_BOOL(0)
+#endif
+};
+struct confopt config_map[] = {CONFOPT("pidfile", &nDPIsrvd_options.pidfile),
+ CONFOPT("collector", &nDPIsrvd_options.collector_un_sockpath),
+ CONFOPT("distributor-unix", &nDPIsrvd_options.distributor_un_sockpath),
+ CONFOPT("distributor-in", &nDPIsrvd_options.distributor_in_address),
+ CONFOPT("user", &nDPIsrvd_options.user),
+ CONFOPT("group", &nDPIsrvd_options.group),
+ CONFOPT("collector-group", &nDPIsrvd_options.collector_group),
+ CONFOPT("distributor-group", &nDPIsrvd_options.distributor_group),
+ CONFOPT("max-remote-descriptors", &nDPIsrvd_options.max_remote_descriptors),
+ CONFOPT("max-write-buffers", &nDPIsrvd_options.max_write_buffers),
+ CONFOPT("blocking-io-fallback", &nDPIsrvd_options.bufferbloat_fallback_to_blocking)
+#ifdef ENABLE_EPOLL
+ ,
+ CONFOPT("poll", &nDPIsrvd_options.use_poll)
+#endif
+};
static void logger_nDPIsrvd(struct remote_desc const * const remote,
char const * const prefix,
@@ -239,9 +266,9 @@ static int add_to_additional_write_buffers(struct remote_desc * const remote,
return -1;
}
- if (utarray_len(additional_write_buffers) >= nDPIsrvd_options.max_write_buffers)
+ if (utarray_len(additional_write_buffers) >= GET_CMDARG_ULL(nDPIsrvd_options.max_write_buffers))
{
- if (nDPIsrvd_options.bufferbloat_fallback_to_blocking == 0)
+ if (GET_CMDARG_BOOL(nDPIsrvd_options.bufferbloat_fallback_to_blocking) == 0)
{
logger_nDPIsrvd(remote,
"Buffer limit for",
@@ -498,7 +525,7 @@ static int create_listen_sockets(void)
return 1;
}
- if (is_cmdarg_set(&nDPIsrvd_options.distributor_in_address) != 0)
+ if (IS_CMDARG_SET(nDPIsrvd_options.distributor_in_address) != 0)
{
distributor_in_sockfd = socket(distributor_in_address.raw.sa_family, SOCK_STREAM, 0);
if (distributor_in_sockfd < 0 || set_fd_cloexec(distributor_in_sockfd) < 0)
@@ -528,7 +555,7 @@ static int create_listen_sockets(void)
int written = snprintf(collector_addr.sun_path,
sizeof(collector_addr.sun_path),
"%s",
- get_cmdarg(&nDPIsrvd_options.collector_un_sockpath));
+ GET_CMDARG_STR(nDPIsrvd_options.collector_un_sockpath));
if (written < 0)
{
logger(1, "snprintf failed: %s", strerror(errno));
@@ -536,10 +563,7 @@ static int create_listen_sockets(void)
}
else if (written == sizeof(collector_addr.sun_path))
{
- logger(1,
- "Collector UNIX socket path too long, current/max: %zu/%zu",
- strlen(get_cmdarg(&nDPIsrvd_options.collector_un_sockpath)),
- sizeof(collector_addr.sun_path) - 1);
+ logger(1, "Collector UNIX socket path too long, max: %zu characters", sizeof(collector_addr.sun_path) - 1);
return 1;
}
@@ -547,7 +571,7 @@ static int create_listen_sockets(void)
{
logger(1,
"Error binding Collector UNIX socket to `%s': %s",
- get_cmdarg(&nDPIsrvd_options.collector_un_sockpath),
+ GET_CMDARG_STR(nDPIsrvd_options.collector_un_sockpath),
strerror(errno));
return 1;
}
@@ -559,7 +583,7 @@ static int create_listen_sockets(void)
int written = snprintf(distributor_addr.sun_path,
sizeof(distributor_addr.sun_path),
"%s",
- get_cmdarg(&nDPIsrvd_options.distributor_un_sockpath));
+ GET_CMDARG_STR(nDPIsrvd_options.distributor_un_sockpath));
if (written < 0)
{
logger(1, "snprintf failed: %s", strerror(errno));
@@ -568,8 +592,7 @@ static int create_listen_sockets(void)
else if (written == sizeof(distributor_addr.sun_path))
{
logger(1,
- "Distributor UNIX socket path too long, current/max: %zu/%zu",
- strlen(get_cmdarg(&nDPIsrvd_options.distributor_un_sockpath)),
+ "Distributor UNIX socket path too long, max: %zu characters",
sizeof(distributor_addr.sun_path) - 1);
return 2;
}
@@ -578,19 +601,19 @@ static int create_listen_sockets(void)
{
logger(1,
"Error binding Distributor socket to `%s': %s",
- get_cmdarg(&nDPIsrvd_options.distributor_un_sockpath),
+ GET_CMDARG_STR(nDPIsrvd_options.distributor_un_sockpath),
strerror(errno));
return 2;
}
}
- if (is_cmdarg_set(&nDPIsrvd_options.distributor_in_address) != 0)
+ if (IS_CMDARG_SET(nDPIsrvd_options.distributor_in_address) != 0)
{
if (bind(distributor_in_sockfd, &distributor_in_address.raw, distributor_in_address.size) < 0)
{
logger(1,
"Error binding Distributor TCP/IP socket to %s: %s",
- get_cmdarg(&nDPIsrvd_options.distributor_in_address),
+ GET_CMDARG_STR(nDPIsrvd_options.distributor_in_address),
strerror(errno));
return 3;
}
@@ -598,7 +621,7 @@ static int create_listen_sockets(void)
{
logger(1,
"Error listening Distributor TCP/IP socket to %s: %s",
- get_cmdarg(&nDPIsrvd_options.distributor_in_address),
+ GET_CMDARG_STR(nDPIsrvd_options.distributor_in_address),
strerror(errno));
return 3;
}
@@ -606,7 +629,7 @@ static int create_listen_sockets(void)
{
logger(1,
"Error setting Distributor TCP/IP socket %s to non-blocking mode: %s",
- get_cmdarg(&nDPIsrvd_options.distributor_in_address),
+ GET_CMDARG_STR(nDPIsrvd_options.distributor_in_address),
strerror(errno));
return 3;
}
@@ -622,7 +645,7 @@ static int create_listen_sockets(void)
{
logger(1,
"Error setting Collector UNIX socket `%s' to non-blocking mode: %s",
- get_cmdarg(&nDPIsrvd_options.collector_un_sockpath),
+ GET_CMDARG_STR(nDPIsrvd_options.collector_un_sockpath),
strerror(errno));
return 3;
}
@@ -631,7 +654,7 @@ static int create_listen_sockets(void)
{
logger(1,
"Error setting Distributor UNIX socket `%s' to non-blocking mode: %s",
- get_cmdarg(&nDPIsrvd_options.distributor_un_sockpath),
+ GET_CMDARG_STR(nDPIsrvd_options.distributor_un_sockpath),
strerror(errno));
return 3;
}
@@ -804,10 +827,13 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
{
int opt;
- while ((opt = getopt(argc, argv, "lL:c:dp:s:S:m:u:g:C:Dvh")) != -1)
+ while ((opt = getopt(argc, argv, "f:lL:c:dp:s:S:G:m:u:g:C:Dvh")) != -1)
{
switch (opt)
{
+ case 'f':
+ set_cmdarg_string(&nDPIsrvd_options.config_file, optarg);
+ break;
case 'l':
enable_console_logger();
break;
@@ -818,11 +844,11 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
}
break;
case 'c':
- set_cmdarg(&nDPIsrvd_options.collector_un_sockpath, optarg);
+ set_cmdarg_string(&nDPIsrvd_options.collector_un_sockpath, optarg);
break;
case 'e':
#ifdef ENABLE_EPOLL
- nDPIsrvd_options.use_poll = 1;
+ set_cmdarg_boolean(&nDPIsrvd_options.use_poll, 1);
#else
logger_early(1, "%s", "nDPIsrvd was built w/o epoll() support, poll() is already the default");
#endif
@@ -831,36 +857,67 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
daemonize_enable();
break;
case 'p':
- set_cmdarg(&nDPIsrvd_options.pidfile, optarg);
+ set_cmdarg_string(&nDPIsrvd_options.pidfile, optarg);
break;
case 's':
- set_cmdarg(&nDPIsrvd_options.distributor_un_sockpath, optarg);
+ set_cmdarg_string(&nDPIsrvd_options.distributor_un_sockpath, optarg);
break;
case 'S':
- set_cmdarg(&nDPIsrvd_options.distributor_in_address, optarg);
+ set_cmdarg_string(&nDPIsrvd_options.distributor_in_address, optarg);
break;
+ case 'G':
+ {
+ char const * const sep = strchr(optarg, ':');
+ char group[256];
+
+ if (sep == NULL)
+ {
+ fprintf(stderr, "%s: Argument for `-G' is not in the format group:group\n", argv[0]);
+ return 1;
+ }
+
+ if (snprintf(group, sizeof(group), "%.*s", (int)(sep - optarg), optarg) > 0)
+ {
+ set_cmdarg_string(&nDPIsrvd_options.collector_group, group);
+ }
+ if (snprintf(group, sizeof(group), "%s", sep + 1) > 0)
+ {
+ set_cmdarg_string(&nDPIsrvd_options.distributor_group, group);
+ }
+ break;
+ }
case 'm':
- if (str_value_to_ull(optarg, &nDPIsrvd_options.max_remote_descriptors) != CONVERSION_OK)
+ {
+ nDPIsrvd_ull tmp;
+
+ if (str_value_to_ull(optarg, &tmp) != CONVERSION_OK)
{
fprintf(stderr, "%s: Argument for `-C' is not a number: %s\n", argv[0], optarg);
return 1;
}
+ set_cmdarg_ull(&nDPIsrvd_options.max_remote_descriptors, tmp);
break;
+ }
case 'u':
- set_cmdarg(&nDPIsrvd_options.user, optarg);
+ set_cmdarg_string(&nDPIsrvd_options.user, optarg);
break;
case 'g':
- set_cmdarg(&nDPIsrvd_options.group, optarg);
+ set_cmdarg_string(&nDPIsrvd_options.group, optarg);
break;
case 'C':
- if (str_value_to_ull(optarg, &nDPIsrvd_options.max_write_buffers) != CONVERSION_OK)
+ {
+ nDPIsrvd_ull tmp;
+
+ if (str_value_to_ull(optarg, &tmp) != CONVERSION_OK)
{
fprintf(stderr, "%s: Argument for `-C' is not a number: %s\n", argv[0], optarg);
return 1;
}
+ set_cmdarg_ull(&nDPIsrvd_options.max_write_buffers, tmp);
break;
+ }
case 'D':
- nDPIsrvd_options.bufferbloat_fallback_to_blocking = 0;
+ set_cmdarg_boolean(&nDPIsrvd_options.bufferbloat_fallback_to_blocking, 0);
break;
case 'v':
fprintf(stderr, "%s", get_nDPId_version());
@@ -869,11 +926,14 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
default:
fprintf(stderr, "%s\n", get_nDPId_version());
fprintf(stderr,
- "Usage: %s [-l] [-L logfile] [-c path-to-unix-sock] [-e] [-d] [-p pidfile]\n"
+ "Usage: %s [-f config-file] [-l] [-L logfile]\n"
+ "\t[-c path-to-unix-sock] [-e] [-d] [-p pidfile]\n"
"\t[-s path-to-distributor-unix-socket] [-S distributor-host:port]\n"
+ "\t[-G collector-unix-socket-group:distributor-unix-socket-group]\n"
"\t[-m max-remote-descriptors] [-u user] [-g group]\n"
"\t[-C max-buffered-json-lines] [-D]\n"
"\t[-v] [-h]\n\n"
+ "\t-f\tLoad nDPIsrvd options from a configuration file.\n"
"\t-l\tLog all messages to stderr.\n"
"\t-L\tLog all messages to a log file.\n"
"\t-c\tPath to a listening UNIX socket (nDPIsrvd Collector).\n"
@@ -892,40 +952,45 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
"\t-s\tPath to a listening UNIX socket (nDPIsrvd Distributor).\n"
"\t \tDefault: %s\n"
"\t-S\tAddress:Port of the listening TCP/IP socket (nDPIsrvd Distributor).\n"
+ "\t-G\tGroup owner of the UNIX collector/distributor socket.\n"
+ "\t \tDefault: Either the group set via `-g', otherwise the primary group of `-u'\n"
"\t-v\tversion\n"
"\t-h\tthis\n\n",
argv[0],
- get_cmdarg(&nDPIsrvd_options.collector_un_sockpath),
- get_cmdarg(&nDPIsrvd_options.pidfile),
- get_cmdarg(&nDPIsrvd_options.user),
- get_cmdarg(&nDPIsrvd_options.distributor_un_sockpath));
+ nDPIsrvd_options.collector_un_sockpath.string.default_value,
+ nDPIsrvd_options.pidfile.string.default_value,
+ nDPIsrvd_options.user.string.default_value,
+ nDPIsrvd_options.distributor_un_sockpath.string.default_value);
return 1;
}
}
- if (is_path_absolute("Pidfile", get_cmdarg(&nDPIsrvd_options.pidfile)) != 0)
+ set_config_defaults(&config_map[0], nDPIsrvd_ARRAY_LENGTH(config_map));
+
+ if (is_path_absolute("Pidfile", GET_CMDARG_STR(nDPIsrvd_options.pidfile)) != 0)
{
return 1;
}
- if (is_path_absolute("Collector UNIX socket", get_cmdarg(&nDPIsrvd_options.collector_un_sockpath)) != 0)
+ if (is_path_absolute("Collector UNIX socket", GET_CMDARG_STR(nDPIsrvd_options.collector_un_sockpath)) != 0)
{
return 1;
}
- if (is_path_absolute("Distributor UNIX socket", get_cmdarg(&nDPIsrvd_options.distributor_un_sockpath)) != 0)
+ if (is_path_absolute("Distributor UNIX socket", GET_CMDARG_STR(nDPIsrvd_options.distributor_un_sockpath)) != 0)
{
return 1;
}
- if (is_cmdarg_set(&nDPIsrvd_options.distributor_in_address) != 0)
+ if (IS_CMDARG_SET(nDPIsrvd_options.distributor_in_address) != 0)
{
- if (nDPIsrvd_setup_address(&distributor_in_address, get_cmdarg(&nDPIsrvd_options.distributor_in_address)) != 0)
+ if (nDPIsrvd_setup_address(&distributor_in_address, GET_CMDARG_STR(nDPIsrvd_options.distributor_in_address)) !=
+ 0)
{
logger_early(1,
"%s: Could not parse address %s",
argv[0],
- get_cmdarg(&nDPIsrvd_options.distributor_in_address));
+ GET_CMDARG_STR(nDPIsrvd_options.distributor_in_address));
return 1;
}
if (distributor_in_address.raw.sa_family == AF_UNIX)
@@ -933,8 +998,8 @@ static int nDPIsrvd_parse_options(int argc, char ** argv)
logger_early(1,
"%s: You've requested to setup another UNIX socket `%s', but there is already one at `%s'",
argv[0],
- get_cmdarg(&nDPIsrvd_options.distributor_in_address),
- get_cmdarg(&nDPIsrvd_options.distributor_un_sockpath));
+ GET_CMDARG_STR(nDPIsrvd_options.distributor_in_address),
+ GET_CMDARG_STR(nDPIsrvd_options.distributor_un_sockpath));
return 1;
}
}
@@ -1516,8 +1581,9 @@ static int mainloop(struct nio * const io)
static int setup_event_queue(struct nio * const io)
{
#ifdef ENABLE_EPOLL
- if ((nDPIsrvd_options.use_poll == 0 && nio_use_epoll(io, 32) != NIO_SUCCESS) ||
- (nDPIsrvd_options.use_poll != 0 && nio_use_poll(io, nDPIsrvd_MAX_REMOTE_DESCRIPTORS) != NIO_SUCCESS))
+ if ((GET_CMDARG_BOOL(nDPIsrvd_options.use_poll) == 0 && nio_use_epoll(io, 32) != NIO_SUCCESS) ||
+ (GET_CMDARG_BOOL(nDPIsrvd_options.use_poll) != 0 &&
+ nio_use_poll(io, nDPIsrvd_MAX_REMOTE_DESCRIPTORS) != NIO_SUCCESS))
#else
if (nio_use_poll(io, nDPIsrvd_MAX_REMOTE_DESCRIPTORS) != NIO_SUCCESS)
#endif
@@ -1576,6 +1642,49 @@ static int setup_remote_descriptors(nDPIsrvd_ull max_remote_descriptors)
return 0;
}
+static int nDPIsrvd_parsed_config_line(
+ int lineno, char const * const section, char const * const name, char const * const value, void * const user_data)
+{
+ (void)user_data;
+
+ if (strnlen(section, INI_MAX_SECTION) == nDPIsrvd_STRLEN_SZ("general") &&
+ strncmp(section, "general", INI_MAX_SECTION) == 0)
+ {
+ size_t i;
+
+ for (i = 0; i < nDPIsrvd_ARRAY_LENGTH(config_map); ++i)
+ {
+ if (strnlen(name, INI_MAX_NAME) == strnlen(config_map[i].key, INI_MAX_NAME) &&
+ strncmp(name, config_map[i].key, INI_MAX_NAME) == 0)
+ {
+ if (IS_CMDARG_SET(*config_map[i].opt) != 0)
+ {
+ logger_early(1, "General config key `%s' already set, ignoring value `%s'", name, value);
+ }
+ else
+ {
+ if (set_config_from(&config_map[i], value) != 0)
+ {
+ return 0;
+ }
+ }
+ break;
+ }
+ }
+ if (i == nDPIsrvd_ARRAY_LENGTH(config_map))
+ {
+ logger_early(1, "Invalid general config key `%s' at line %d", name, lineno);
+ }
+ }
+ else
+ {
+ logger_early(
+ 1, "Invalid config section `%s' at line %d with key `%s' and value `%s'", section, lineno, name, value);
+ }
+
+ return 1;
+}
+
#ifndef NO_MAIN
int main(int argc, char ** argv)
{
@@ -1594,6 +1703,32 @@ int main(int argc, char ** argv)
{
return 1;
}
+ {
+ int ret;
+
+ if (IS_CMDARG_SET(nDPIsrvd_options.config_file) != 0 &&
+ (ret =
+ parse_config_file(GET_CMDARG_STR(nDPIsrvd_options.config_file), nDPIsrvd_parsed_config_line, NULL)) !=
+ 0)
+ {
+ if (ret > 0)
+ {
+ logger_early(1, "Config file `%s' is malformed", GET_CMDARG_STR(nDPIsrvd_options.config_file));
+ }
+ else if (ret == -ENOENT)
+ {
+ logger_early(1, "Path `%s' is not a regular file", GET_CMDARG_STR(nDPIsrvd_options.config_file));
+ }
+ else
+ {
+ logger_early(1,
+ "Could not open file `%s' for reading: %s",
+ GET_CMDARG_STR(nDPIsrvd_options.config_file),
+ strerror(errno));
+ }
+ return 1;
+ }
+ }
if (is_daemonize_enabled() != 0 && is_console_logger_enabled() != 0)
{
@@ -1604,32 +1739,32 @@ int main(int argc, char ** argv)
return 1;
}
- if (access(get_cmdarg(&nDPIsrvd_options.collector_un_sockpath), F_OK) == 0)
+ if (access(GET_CMDARG_STR(nDPIsrvd_options.collector_un_sockpath), F_OK) == 0)
{
logger_early(1,
"UNIX socket `%s' exists; nDPIsrvd already running? "
"Please remove the socket manually or change socket path.",
- get_cmdarg(&nDPIsrvd_options.collector_un_sockpath));
+ GET_CMDARG_STR(nDPIsrvd_options.collector_un_sockpath));
return 1;
}
- if (access(get_cmdarg(&nDPIsrvd_options.distributor_un_sockpath), F_OK) == 0)
+ if (access(GET_CMDARG_STR(nDPIsrvd_options.distributor_un_sockpath), F_OK) == 0)
{
logger_early(1,
"UNIX socket `%s' exists; nDPIsrvd already running? "
"Please remove the socket manually or change socket path.",
- get_cmdarg(&nDPIsrvd_options.distributor_un_sockpath));
+ GET_CMDARG_STR(nDPIsrvd_options.distributor_un_sockpath));
return 1;
}
log_app_info();
- if (daemonize_with_pidfile(get_cmdarg(&nDPIsrvd_options.pidfile)) != 0)
+ if (daemonize_with_pidfile(GET_CMDARG_STR(nDPIsrvd_options.pidfile)) != 0)
{
goto error;
}
- if (setup_remote_descriptors(nDPIsrvd_options.max_remote_descriptors) != 0)
+ if (setup_remote_descriptors(GET_CMDARG_ULL(nDPIsrvd_options.max_remote_descriptors)) != 0)
{
goto error;
}
@@ -1641,11 +1776,11 @@ int main(int argc, char ** argv)
case 1:
goto error;
case 2:
- if (unlink(get_cmdarg(&nDPIsrvd_options.collector_un_sockpath)) != 0)
+ if (unlink(GET_CMDARG_STR(nDPIsrvd_options.collector_un_sockpath)) != 0)
{
logger(1,
"Could not unlink `%s': %s",
- get_cmdarg(&nDPIsrvd_options.collector_un_sockpath),
+ GET_CMDARG_STR(nDPIsrvd_options.collector_un_sockpath),
strerror(errno));
}
goto error;
@@ -1655,8 +1790,8 @@ int main(int argc, char ** argv)
goto error;
}
- logger(0, "collector UNIX socket listen on `%s'", get_cmdarg(&nDPIsrvd_options.collector_un_sockpath));
- logger(0, "distributor UNIX listen on `%s'", get_cmdarg(&nDPIsrvd_options.distributor_un_sockpath));
+ logger(0, "collector UNIX socket listen on `%s'", GET_CMDARG_STR(nDPIsrvd_options.collector_un_sockpath));
+ logger(0, "distributor UNIX listen on `%s'", GET_CMDARG_STR(nDPIsrvd_options.distributor_un_sockpath));
switch (distributor_in_address.raw.sa_family)
{
default:
@@ -1672,28 +1807,88 @@ int main(int argc, char ** argv)
break;
}
- errno = 0;
- if (change_user_group(get_cmdarg(&nDPIsrvd_options.user),
- get_cmdarg(&nDPIsrvd_options.group),
- get_cmdarg(&nDPIsrvd_options.pidfile),
- get_cmdarg(&nDPIsrvd_options.collector_un_sockpath),
- get_cmdarg(&nDPIsrvd_options.distributor_un_sockpath)) != 0 &&
- errno != EPERM)
- {
- if (errno != 0)
+ int ret = chmod_chown(GET_CMDARG_STR(nDPIsrvd_options.collector_un_sockpath),
+ S_IRUSR | S_IWUSR | S_IWGRP,
+ GET_CMDARG_STR(nDPIsrvd_options.user),
+ IS_CMDARG_SET(nDPIsrvd_options.collector_group) != 0
+ ? GET_CMDARG_STR(nDPIsrvd_options.collector_group)
+ : GET_CMDARG_STR(nDPIsrvd_options.group));
+ if (ret != 0)
+ {
+ if (IS_CMDARG_SET(nDPIsrvd_options.collector_group) != 0 || IS_CMDARG_SET(nDPIsrvd_options.group) != 0)
{
logger(1,
- "Change user/group to %s/%s failed: %s",
- get_cmdarg(&nDPIsrvd_options.user),
- (is_cmdarg_set(&nDPIsrvd_options.group) != 0 ? get_cmdarg(&nDPIsrvd_options.group) : "-"),
+ "Could not chmod/chown `%s' to user `%s' and group `%s': %s",
+ GET_CMDARG_STR(nDPIsrvd_options.collector_un_sockpath),
+ GET_CMDARG_STR(nDPIsrvd_options.user),
+ IS_CMDARG_SET(nDPIsrvd_options.collector_group) != 0
+ ? GET_CMDARG_STR(nDPIsrvd_options.collector_group)
+ : GET_CMDARG_STR(nDPIsrvd_options.group),
strerror(errno));
}
else
{
logger(1,
- "Change user/group to %s/%s failed.",
- get_cmdarg(&nDPIsrvd_options.user),
- (is_cmdarg_set(&nDPIsrvd_options.group) != 0 ? get_cmdarg(&nDPIsrvd_options.group) : "-"));
+ "Could not chmod/chown `%s' to user `%s': %s",
+ GET_CMDARG_STR(nDPIsrvd_options.collector_un_sockpath),
+ GET_CMDARG_STR(nDPIsrvd_options.user),
+ strerror(errno));
+ }
+ if (ret != -EPERM)
+ {
+ goto error_unlink_sockets;
+ }
+ }
+
+ ret = chmod_chown(GET_CMDARG_STR(nDPIsrvd_options.distributor_un_sockpath),
+ S_IRUSR | S_IWUSR | S_IWGRP,
+ GET_CMDARG_STR(nDPIsrvd_options.user),
+ IS_CMDARG_SET(nDPIsrvd_options.distributor_group) != 0
+ ? GET_CMDARG_STR(nDPIsrvd_options.distributor_group)
+ : GET_CMDARG_STR(nDPIsrvd_options.group));
+ if (ret != 0)
+ {
+ if (IS_CMDARG_SET(nDPIsrvd_options.distributor_group) != 0 || IS_CMDARG_SET(nDPIsrvd_options.group) != 0)
+ {
+ logger(1,
+ "Could not chmod/chown `%s' to user `%s' and group `%s': %s",
+ GET_CMDARG_STR(nDPIsrvd_options.distributor_un_sockpath),
+ GET_CMDARG_STR(nDPIsrvd_options.user),
+ IS_CMDARG_SET(nDPIsrvd_options.distributor_group) != 0
+ ? GET_CMDARG_STR(nDPIsrvd_options.distributor_group)
+ : GET_CMDARG_STR(nDPIsrvd_options.group),
+ strerror(errno));
+ }
+ else
+ {
+ logger(1,
+ "Could not chmod/chown `%s' to user `%s': %s",
+ GET_CMDARG_STR(nDPIsrvd_options.distributor_un_sockpath),
+ GET_CMDARG_STR(nDPIsrvd_options.user),
+ strerror(errno));
+ }
+ if (ret != -EPERM)
+ {
+ goto error_unlink_sockets;
+ }
+ }
+
+ ret = change_user_group(GET_CMDARG_STR(nDPIsrvd_options.user),
+ GET_CMDARG_STR(nDPIsrvd_options.group),
+ GET_CMDARG_STR(nDPIsrvd_options.pidfile));
+ if (ret != 0 && ret != -EPERM)
+ {
+ if (GET_CMDARG_STR(nDPIsrvd_options.group) != NULL)
+ {
+ logger(1,
+ "Change user/group to %s/%s failed: %s",
+ GET_CMDARG_STR(nDPIsrvd_options.user),
+ GET_CMDARG_STR(nDPIsrvd_options.group),
+ strerror(-ret));
+ }
+ else
+ {
+ logger(1, "Change user to %s failed: %s", GET_CMDARG_STR(nDPIsrvd_options.user), strerror(-ret));
}
goto error_unlink_sockets;
}
@@ -1713,20 +1908,23 @@ int main(int argc, char ** argv)
retval = mainloop(&io);
error_unlink_sockets:
- if (unlink(get_cmdarg(&nDPIsrvd_options.collector_un_sockpath)) != 0)
+ if (unlink(GET_CMDARG_STR(nDPIsrvd_options.collector_un_sockpath)) != 0)
{
- logger(1, "Could not unlink `%s': %s", get_cmdarg(&nDPIsrvd_options.collector_un_sockpath), strerror(errno));
+ logger(1, "Could not unlink `%s': %s", GET_CMDARG_STR(nDPIsrvd_options.collector_un_sockpath), strerror(errno));
}
- if (unlink(get_cmdarg(&nDPIsrvd_options.distributor_un_sockpath)) != 0)
+ if (unlink(GET_CMDARG_STR(nDPIsrvd_options.distributor_un_sockpath)) != 0)
{
- logger(1, "Could not unlink `%s': %s", get_cmdarg(&nDPIsrvd_options.distributor_un_sockpath), strerror(errno));
+ logger(1,
+ "Could not unlink `%s': %s",
+ GET_CMDARG_STR(nDPIsrvd_options.distributor_un_sockpath),
+ strerror(errno));
}
error:
close(collector_un_sockfd);
close(distributor_un_sockfd);
close(distributor_in_sockfd);
- daemonize_shutdown(get_cmdarg(&nDPIsrvd_options.pidfile));
+ daemonize_shutdown(GET_CMDARG_STR(nDPIsrvd_options.pidfile));
logger(0, "Bye.");
shutdown_logging();
diff --git a/ndpid.conf.example b/ndpid.conf.example
new file mode 100644
index 000000000..61255a04e
--- /dev/null
+++ b/ndpid.conf.example
@@ -0,0 +1,86 @@
+[general]
+# Set the network interface from which packets are captured and processed.
+# Leave it empty to let nDPId choose the default network interface.
+#netif = eth0
+
+# Set a Berkeley Packet Filter.
+# This will work for libpcap as well as with PF_RING.
+#bpf = udp or tcp
+
+#pidfile = /tmp/ndpid.pid
+#user = nobody
+#group = daemon
+#riskdomains = /path/to/libnDPI/example/risky_domains.txt
+#protocols = /path/to/libnDPI/example/protos.txt
+#categories = /path/to/libnDPI/example/categories.txt
+#ja3 = /path/to/libnDPI/example/ja3_fingerprints.csv
+#sha1 = /path/to/libnDPI/example/sha1_fingerprints.csv
+
+# Collector endpoint as UNIX socket (usually nDPIsrvd)
+#collector = /run/nDPIsrvd/collector
+# Collector endpoint as UDP socket (usually a custom application)
+#collector = 127.0.0.1:7777
+
+# Set a name for this nDPId instance
+#alias = myhostname
+
+# Process only internal initial connections
+#internal = true
+
+# Process only external initial connections
+#external = true
+
+# Enable zLib compression of flow memory for long lasting flows
+compression = true
+
+# Enable "analyse" events, which can be used for machine learning
+analysis = true
+
+# Force poll() on systems that support epoll() as well
+#poll = false
+
+# Enable PF_RING packet capture instead of libpcap
+#pfring = false
+
+[tuning]
+max-flows-per-thread = 2048
+max-idle-flows-per-thread = 64
+max-reader-threads = 10
+daemon-status-interval = 600000000
+#memory-profiling-log-interval = 5
+compression-scan-interval = 20000000
+compression-flow-inactivity = 30000000
+flow-scan-interval = 10000000
+generic-max-idle-time = 600000000
+icmp-max-idle-time = 120000000
+tcp-max-idle-time = 180000000
+udp-max-idle-time = 7440000000
+tcp-max-post-end-flow-time = 120000000
+max-packets-per-flow-to-send = 15
+max-packets-per-flow-to-process = 32
+max-packets-per-flow-to-analyse = 32
+error-event-threshold-n = 16
+error-event-threshold-time = 10000000
+
+# Please note that the following options are libnDPI related and can only be set via config file,
+# not as commnand line parameter.
+# See libnDPI/doc/configuration_parameters.md for detailed information.
+
+[ndpi]
+packets_limit_per_flow = 32
+flow.direction_detection = enable
+flow.track_payload = disable
+tcp_ack_payload_heuristic = disable
+fully_encrypted_heuristic = enable
+libgcrypt.init = 1
+dpi.compute_entropy = 1
+fpc = disable
+dpi.guess_on_giveup = 0x03
+flow_risk_lists.load = 1
+flow_risk.crawler_bot.list.load = 1
+log.level = 0
+
+[protos]
+tls.certificate_expiration_threshold = 7
+tls.application_blocks_tracking = enable
+stun.max_packets_extra_dissection = 8
diff --git a/ndpisrvd.conf.example b/ndpisrvd.conf.example
new file mode 100644
index 000000000..67ea60f4f
--- /dev/null
+++ b/ndpisrvd.conf.example
@@ -0,0 +1,31 @@
+[general]
+#pidfile = /tmp/ndpisrvd.pid
+#user = nobody
+#group = nogroup
+
+# Collector listener as UNIX socket
+#collector = /run/nDPIsrvd/collector
+
+# Distributor listener as UNIX socket
+#distributor-unix = /run/nDPIsrvd/distributor
+
+# Distributor listener as IP socket
+#distributor-in = 127.0.0.1:7000
+
+# Change group of the collector socket
+#collector-group = daemon
+
+# Change group of the distirbutor socket
+#distirbutor-group = staff
+
+# Max (distributor) clients allowed to connect to nDPIsrvd
+max-remote-descriptors = 128
+
+# Additional output buffers useful if a distributor sink speed unstable
+max-write-buffers = 1024
+
+# Fallback to blocking I/O if output buffers full
+blocking-io-fallback = true
+
+# Force poll() on systems that support epoll() as well
+#poll = false
diff --git a/packages/debian/postrm b/packages/debian/postrm
new file mode 100755
index 000000000..0699f2a47
--- /dev/null
+++ b/packages/debian/postrm
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rm -rf /run/nDPId /run/nDPIsrvd
+deluser ndpid || true
+deluser ndpisrvd || true
+delgroup ndpisrvd-distributor || true
diff --git a/packages/debian/preinst b/packages/debian/preinst
new file mode 100755
index 000000000..e60ef3af3
--- /dev/null
+++ b/packages/debian/preinst
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+addgroup --system ndpisrvd-distributor
+adduser --system --no-create-home --shell=/bin/false --group ndpisrvd
+adduser --system --no-create-home --shell=/bin/false --group ndpid
+
+cat <<EOF
+**********************************************************************************
+* The that may want to access DPI data needs access to /run/nDPIsrvd/distributor *
+* *
+* To make it accessible to a user, type: *
+* sudo usermod --append --groups ndpisrvd-distributor [USER] *
+* *
+* Please not that you might need to re-login to make changes take effect. *
+**********************************************************************************
+EOF
diff --git a/packages/debian/prerm b/packages/debian/prerm
new file mode 100755
index 000000000..6942225bd
--- /dev/null
+++ b/packages/debian/prerm
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+systemctl stop ndpisrvd.service
diff --git a/packages/systemd/default.cfg b/packages/systemd/default.cfg
deleted file mode 100644
index 8598da168..000000000
--- a/packages/systemd/default.cfg
+++ /dev/null
@@ -1,2 +0,0 @@
-COLLECTOR_PATH=/var/run/ndpisrvd-collector
-NDPID_ARGS="-A -z"
diff --git a/packages/systemd/ndpid@.service.in b/packages/systemd/ndpid@.service.in
index cfbb4110f..b59a6612c 100644
--- a/packages/systemd/ndpid@.service.in
+++ b/packages/systemd/ndpid@.service.in
@@ -5,10 +5,9 @@ Requires=ndpisrvd.service
[Service]
Type=simple
-ExecStart=@CMAKE_INSTALL_PREFIX@/sbin/nDPId $NDPID_ARGS -i %i -c ${COLLECTOR_PATH}
+ExecStartPre=/bin/sh -c 'test -r "@CMAKE_INSTALL_PREFIX@/etc/nDPId/%i.conf" || cp -v "@CMAKE_INSTALL_PREFIX@/share/nDPId/ndpid.conf.example" "@CMAKE_INSTALL_PREFIX@/etc/nDPId/%i.conf"'
+ExecStart=@CMAKE_INSTALL_PREFIX@/sbin/nDPId -f @CMAKE_INSTALL_PREFIX@/etc/nDPId/%i.conf -i %i -u ndpid -c /run/nDPIsrvd/collector
Restart=on-failure
-Environment=COLLECTOR_PATH=/var/run/ndpisrvd-collector NDPID_ARGS="-A -z"
-EnvironmentFile=@CMAKE_INSTALL_PREFIX@/etc/default/ndpid
[Install]
WantedBy=multi-user.target
diff --git a/packages/systemd/ndpisrvd.service.in b/packages/systemd/ndpisrvd.service.in
index 0fd3ba8e7..89f87a682 100644
--- a/packages/systemd/ndpisrvd.service.in
+++ b/packages/systemd/ndpisrvd.service.in
@@ -4,11 +4,10 @@ After=network.target
[Service]
Type=simple
-ExecStart=@CMAKE_INSTALL_PREFIX@/bin/nDPIsrvd -c ${COLLECTOR_PATH}
-ExecStopPost=/bin/rm -f /var/run/ndpisrvd-collector
+ExecStartPre=/bin/sh -c 'test -r "@CMAKE_INSTALL_PREFIX@/etc/nDPId/nDPIsrvd.conf" || cp -v "@CMAKE_INSTALL_PREFIX@/share/nDPId/ndpisrvd.conf.example" "@CMAKE_INSTALL_PREFIX@/etc/nDPId/nDPIsrvd.conf"'
+ExecStartPre=/bin/sh -c 'mkdir -p /run/nDPIsrvd && chown root:root /run/nDPIsrvd && chmod 0775 /run/nDPIsrvd'
+ExecStart=@CMAKE_INSTALL_PREFIX@/bin/nDPIsrvd -f @CMAKE_INSTALL_PREFIX@/etc/nDPId/nDPIsrvd.conf -u ndpisrvd -c /run/nDPIsrvd/collector -s /run/nDPIsrvd/distributor -G ndpid:ndpisrvd-distributor
Restart=on-failure
-Environment=COLLECTOR_PATH=/var/run/ndpisrvd-collector
-EnvironmentFile=@CMAKE_INSTALL_PREFIX@/etc/default/ndpid
[Install]
WantedBy=multi-user.target
diff --git a/utils.c b/utils.c
index f2a152850..dd080d59f 100644
--- a/utils.c
+++ b/utils.c
@@ -1,3 +1,4 @@
+#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
@@ -10,11 +11,19 @@
#include <syslog.h>
#endif
#include <sys/stat.h>
-#include <sys/types.h>
#include <unistd.h>
#include "utils.h"
+#define UTILS_STRLEN_SZ(s) ((size_t)((sizeof(s) / sizeof(s[0])) - sizeof(s[0])))
+
+#ifndef INI_MAX_LINE
+#define INI_MAX_LINE BUFSIZ
+#endif
+
+#define INI_INLINE_COMMENT_PREFIXES ";"
+#define INI_START_COMMENT_PREFIXES ";#"
+
typedef char pid_str[16];
static char const * app_name = NULL;
@@ -22,40 +31,151 @@ static int daemonize = 0;
static int log_to_console = 0;
static int log_to_file_fd = -1;
-void set_cmdarg(struct cmdarg * const ca, char const * const val)
+void set_config_defaults(struct confopt * const co_array, size_t array_length)
+{
+ for (size_t i = 0; i < array_length; ++i)
+ {
+ if (co_array[i].opt == NULL)
+ {
+ logger_early(1, "%s", "BUG: Config option is NULL");
+ continue;
+ }
+ if (IS_CMDARG_SET(*co_array[i].opt) == 0)
+ {
+ switch (co_array[i].opt->type)
+ {
+ case CMDTYPE_INVALID:
+ logger_early(1, "BUG: Config option `%s' has CMDTYPE_INVALID!", co_array[i].key);
+ break;
+ case CMDTYPE_STRING:
+ if (co_array[i].opt->string.default_value == NULL)
+ {
+ break;
+ }
+ co_array[i].opt->string.value = strdup(co_array[i].opt->string.default_value);
+ break;
+ case CMDTYPE_BOOLEAN:
+ co_array[i].opt->boolean.value = co_array[i].opt->boolean.default_value;
+ break;
+ case CMDTYPE_ULL:
+ co_array[i].opt->ull.value = co_array[i].opt->ull.default_value;
+ break;
+ }
+ }
+ }
+}
+
+int set_config_from(struct confopt * const co, char const * const from)
+{
+ if (co == NULL || co->opt == NULL || from == NULL)
+ {
+ return -1;
+ }
+
+ switch (co->opt->type)
+ {
+ case CMDTYPE_INVALID:
+ break;
+ case CMDTYPE_STRING:
+ set_cmdarg_string(co->opt, from);
+ break;
+ case CMDTYPE_BOOLEAN:
+ {
+ uint8_t enabled;
+
+ if ((strnlen(from, INI_MAX_LINE) == UTILS_STRLEN_SZ("true") &&
+ strncasecmp(from, "true", INI_MAX_LINE) == 0) ||
+ (strnlen(from, INI_MAX_LINE) == UTILS_STRLEN_SZ("1") && strncasecmp(from, "1", INI_MAX_LINE) == 0))
+ {
+ enabled = 1;
+ }
+ else if ((strnlen(from, INI_MAX_LINE) == UTILS_STRLEN_SZ("false") &&
+ strncasecmp(from, "false", INI_MAX_LINE) == 0) ||
+ (strnlen(from, INI_MAX_LINE) == UTILS_STRLEN_SZ("0") && strncasecmp(from, "0", INI_MAX_LINE) == 0))
+ {
+ enabled = 0;
+ }
+ else
+ {
+ logger_early(1, "Config key `%s' has a value not of type bool: `%s'", co->key, from);
+ return 1;
+ }
+ set_cmdarg_boolean(co->opt, enabled);
+ }
+ break;
+ case CMDTYPE_ULL:
+ {
+ char * endptr;
+ long int value_llu = strtoull(from, &endptr, 10);
+
+ if (from == endptr)
+ {
+ logger_early(1, "Subopt `%s': Value `%s' is not a valid number.", co->key, from);
+ return 1;
+ }
+ if (errno == ERANGE)
+ {
+ logger_early(1, "Subopt `%s': Number too large.", co->key);
+ return 1;
+ }
+ set_cmdarg_ull(co->opt, value_llu);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+void set_cmdarg_string(struct cmdarg * const ca, char const * const val)
{
if (ca == NULL || val == NULL)
{
return;
}
- free(ca->value);
- ca->value = strdup(val);
+ if (ca->type != CMDTYPE_STRING)
+ {
+ logger_early(1, "%s", "BUG: Type is not CMDTYPE_STRING!");
+ return;
+ }
+
+ ca->is_set = 1;
+ free(ca->string.value);
+ ca->string.value = strdup(val);
}
-char const * get_cmdarg(struct cmdarg const * const ca)
+void set_cmdarg_boolean(struct cmdarg * const ca, uint8_t val)
{
if (ca == NULL)
{
- return NULL;
+ return;
}
- if (ca->value != NULL)
+ if (ca->type != CMDTYPE_BOOLEAN)
{
- return ca->value;
+ logger_early(1, "%s", "BUG: Type is not CMDTYPE_BOOLEAN!");
+ return;
}
- return ca->default_value;
+ ca->is_set = 1;
+ ca->boolean.value = (val != 0);
}
-int is_cmdarg_set(struct cmdarg const * const ca)
+void set_cmdarg_ull(struct cmdarg * const ca, unsigned long long int val)
{
if (ca == NULL)
{
- return 0;
+ return;
}
- return ca->value != NULL;
+ if (ca->type != CMDTYPE_ULL)
+ {
+ logger_early(1, "%s", "BUG: Type is not CMDTYPE_ULL!");
+ return;
+ }
+
+ ca->is_set = 1;
+ ca->ull.value = val;
}
void daemonize_enable(void)
@@ -218,11 +338,7 @@ int daemonize_shutdown(char const * const pidfile)
return 0;
}
-int change_user_group(char const * const user,
- char const * const group,
- char const * const pidfile,
- char const * const uds_collector_path,
- char const * const uds_distributor_path)
+int change_user_group(char const * const user, char const * const group, char const * const pidfile)
{
struct passwd * pwd;
struct group * grp;
@@ -237,7 +353,7 @@ int change_user_group(char const * const user,
pwd = getpwnam(user);
if (pwd == NULL)
{
- return -errno;
+ return (errno != 0 ? -errno : -ENOENT);
}
if (group != NULL)
@@ -246,7 +362,7 @@ int change_user_group(char const * const user,
grp = getgrnam(group);
if (grp == NULL)
{
- return -errno;
+ return (errno != 0 ? -errno : -ENOENT);
}
gid = grp->gr_gid;
}
@@ -255,32 +371,65 @@ int change_user_group(char const * const user,
gid = pwd->pw_gid;
}
- if (uds_collector_path != NULL)
+ if (daemonize != 0 && pidfile != NULL)
{
errno = 0;
- if (chmod(uds_collector_path, S_IRUSR | S_IWUSR) != 0 || chown(uds_collector_path, pwd->pw_uid, gid) != 0)
+ if (chown(pidfile, pwd->pw_uid, gid) != 0)
{
return -errno;
}
}
- if (uds_distributor_path != NULL)
+ return setregid(gid, gid) != 0 || setreuid(pwd->pw_uid, pwd->pw_uid);
+}
+
+WARN_UNUSED
+int chmod_chown(char const * const path, mode_t mode, char const * const user, char const * const group)
+{
+ uid_t path_uid = (uid_t)-1;
+ gid_t path_gid = (gid_t)-1;
+
+ if (mode != 0)
{
- errno = 0;
- if (chmod(uds_distributor_path, S_IRUSR | S_IWUSR | S_IRGRP) != 0 ||
- chown(uds_distributor_path, pwd->pw_uid, gid) != 0)
+ if (chmod(path, mode) != 0)
{
return -errno;
}
}
- if (daemonize != 0 && pidfile != NULL)
+
+ if (user != NULL)
{
errno = 0;
- if (chown(pidfile, pwd->pw_uid, gid) != 0)
+
+ struct passwd * const pwd = getpwnam(user);
+ if (pwd == NULL)
+ {
+ return (errno != 0 ? -errno : -ENOENT);
+ }
+ path_uid = pwd->pw_uid;
+ path_gid = pwd->pw_gid;
+ }
+
+ if (group != NULL)
+ {
+ errno = 0;
+
+ struct group * const grp = getgrnam(group);
+ if (grp == NULL)
+ {
+ return (errno != 0 ? -errno : -ENOENT);
+ }
+ path_gid = grp->gr_gid;
+ }
+
+ if (path_uid != (uid_t)-1 || path_gid != (gid_t)-1)
+ {
+ if (chown(path, path_uid, path_gid) != 0)
{
return -errno;
}
}
- return setregid(gid, gid) != 0 || setreuid(pwd->pw_uid, pwd->pw_uid);
+
+ return 0;
}
void init_logging(char const * const name)
@@ -454,6 +603,160 @@ char const * get_nDPId_version(void)
"unknown"
#endif
"\n"
- "(C) 2020-2023 Toni Uhlig\n"
+ "(C) 2020-2024 Toni Uhlig\n"
"Please report any BUG to toni@impl.cc\n";
}
+
+/* Strip whitespace chars off end of given string, in place. Return s. */
+static char * ini_rstrip(char * s)
+{
+ char * p = s + strlen(s);
+ while (p > s && isspace((unsigned char)(*--p)))
+ *p = '\0';
+ return s;
+}
+
+/* Return pointer to first non-whitespace char in given string. */
+static char * ini_lskip(const char * s)
+{
+ while (*s && isspace((unsigned char)(*s)))
+ s++;
+ return (char *)s;
+}
+
+/* Return pointer to first char (of chars) or inline comment in given string,
+ or pointer to NUL at end of string if neither found. Inline comment must
+ be prefixed by a whitespace character to register as a comment. */
+static char * ini_find_chars_or_comment(const char * s, const char * chars)
+{
+ int was_space = 0;
+ while (*s && (!chars || !strchr(chars, *s)) && !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s)))
+ {
+ was_space = isspace((unsigned char)(*s));
+ s++;
+ }
+ return (char *)s;
+}
+
+/* See: https://github.com/benhoyt/inih/blob/master/ini.c#L97C67-L97C74 */
+static int parse_config_lines(FILE * const file, config_line_callback cb, void * const user_data)
+{
+ char line[INI_MAX_LINE];
+ int max_line = INI_MAX_LINE;
+ char section[INI_MAX_SECTION] = "";
+ char prev_name[INI_MAX_NAME] = "";
+ char * start;
+ char * end;
+ char * name;
+ char * value;
+ int lineno = 0;
+ int error = 0;
+
+ while (fgets(line, max_line, file) != NULL)
+ {
+ lineno++;
+ start = line;
+ start = ini_lskip(ini_rstrip(start));
+
+ if (strchr(INI_START_COMMENT_PREFIXES, *start))
+ {
+ /* Start-of-line comment */
+ }
+ else if (*prev_name && *start && start > line)
+ {
+ end = ini_find_chars_or_comment(start, NULL);
+ if (*end)
+ {
+ *end = '\0';
+ }
+ ini_rstrip(start);
+
+ /* Non-blank line with leading whitespace, treat as continuation
+ of previous name's value (as per Python configparser). */
+ if (!cb(lineno, section, prev_name, start, user_data) && !error)
+ {
+ error = lineno;
+ }
+ }
+ else if (*start == '[')
+ {
+ /* A "[section]" line */
+ end = ini_find_chars_or_comment(start + 1, "]");
+ if (*end == ']')
+ {
+ *end = '\0';
+ snprintf(section, sizeof(section), "%s", start + 1);
+ *prev_name = '\0';
+ }
+ else if (!error)
+ {
+ /* No ']' found on section line */
+ error = lineno;
+ }
+ }
+ else if (*start)
+ {
+ /* Not a comment, must be a name[=:]value pair */
+ end = ini_find_chars_or_comment(start, "=:");
+ if (*end == '=' || *end == ':')
+ {
+ *end = '\0';
+ name = ini_rstrip(start);
+ value = end + 1;
+ end = ini_find_chars_or_comment(value, NULL);
+ if (*end)
+ {
+ *end = '\0';
+ }
+ value = ini_lskip(value);
+ ini_rstrip(value);
+
+ /* Valid name[=:]value pair found, call handler */
+ snprintf(prev_name, sizeof(prev_name), "%s", name);
+ if (!cb(lineno, section, prev_name, value, user_data) && !error)
+ {
+ error = lineno;
+ }
+ }
+ else if (!error)
+ {
+ /* No '=' or ':' found on name[=:]value line */
+ error = lineno;
+ }
+ }
+ }
+
+ return error;
+}
+
+int parse_config_file(char const * const config_file, config_line_callback cb, void * const user_data)
+{
+ int file_fd;
+ FILE * file;
+ int error;
+ struct stat sbuf;
+
+ file_fd = open(config_file, O_RDONLY);
+ if (file_fd < 0)
+ {
+ return -1;
+ }
+ if (fstat(file_fd, &sbuf) != 0)
+ {
+ return -1;
+ }
+ if ((sbuf.st_mode & S_IFMT) != S_IFREG)
+ {
+ return -ENOENT;
+ }
+
+ file = fdopen(file_fd, "r");
+ if (file == NULL)
+ {
+ return -1;
+ }
+
+ error = parse_config_lines(file, cb, user_data);
+ fclose(file);
+ return error;
+}
diff --git a/utils.h b/utils.h
index 8dca5e469..0a78264c3 100644
--- a/utils.h
+++ b/utils.h
@@ -2,27 +2,86 @@
#define UTILS_H 1
#include <stdarg.h>
+#include <stdint.h>
+#include <sys/types.h>
#define WARN_UNUSED __attribute__((__warn_unused_result__))
-#define CMDARG(_default_value) \
+#define INI_MAX_SECTION 50
+#define INI_MAX_NAME 50
+
+#define CMDARG_STR(_default_value) \
+ { \
+ .is_set = 0, .type = CMDTYPE_STRING, .string.value = NULL, .string.default_value = (_default_value) \
+ }
+#define CMDARG_BOOL(_default_value) \
{ \
- .value = NULL, .default_value = (_default_value) \
+ .is_set = 0, .type = CMDTYPE_BOOLEAN, .boolean.value = 0, .boolean.default_value = (_default_value) \
}
+#define CMDARG_ULL(_default_value) \
+ { \
+ .is_set = 0, .type = CMDTYPE_ULL, .ull.value = 0ull, .ull.default_value = (_default_value) \
+ }
+#define CONFOPT(_key, _opt) \
+ { \
+ .key = _key, .opt = _opt \
+ }
+#define GET_CMDARG_STR(cmdarg) ((cmdarg).string.value)
+#define GET_CMDARG_BOOL(cmdarg) ((cmdarg).boolean.value)
+#define GET_CMDARG_ULL(cmdarg) ((cmdarg).ull.value)
+#define IS_CMDARG_SET(cmdarg) ((cmdarg).is_set)
+
+enum cmdtype
+{
+ CMDTYPE_INVALID = 0,
+ CMDTYPE_STRING,
+ CMDTYPE_BOOLEAN,
+ CMDTYPE_ULL
+};
struct cmdarg
{
- char * value;
- char const * const default_value;
+ enum cmdtype type;
+ int is_set;
+ union
+ {
+ struct
+ {
+ char * value;
+ char const * const default_value;
+ } string;
+ struct
+ {
+ uint8_t value;
+ uint8_t const default_value;
+ } boolean;
+ struct
+ {
+ unsigned long long int value;
+ unsigned long long int const default_value;
+ } ull;
+ };
};
-void set_cmdarg(struct cmdarg * const ca, char const * const val);
+struct confopt
+{
+ char const * const key;
+ struct cmdarg * const opt;
+};
-WARN_UNUSED
-char const * get_cmdarg(struct cmdarg const * const ca);
+typedef int (*config_line_callback)(
+ int lineno, char const * const section, char const * const key, char const * const value, void * const user_data);
+
+void set_config_defaults(struct confopt * const co_array, size_t array_length);
WARN_UNUSED
-int is_cmdarg_set(struct cmdarg const * const ca);
+int set_config_from(struct confopt * const co, char const * const from);
+
+void set_cmdarg_string(struct cmdarg * const ca, char const * const val);
+
+void set_cmdarg_boolean(struct cmdarg * const ca, uint8_t val);
+
+void set_cmdarg_ull(struct cmdarg * const ca, unsigned long long int val);
WARN_UNUSED
int is_path_absolute(char const * const prefix, char const * const path);
@@ -38,11 +97,10 @@ int daemonize_with_pidfile(char const * const pidfile);
int daemonize_shutdown(char const * const pidfile);
WARN_UNUSED
-int change_user_group(char const * const user,
- char const * const group,
- char const * const pidfile,
- char const * const uds_collector_path,
- char const * const uds_distributor_path);
+int change_user_group(char const * const user, char const * const group, char const * const pidfile);
+
+WARN_UNUSED
+int chmod_chown(char const * const path, mode_t mode, char const * const user, char const * const group);
void init_logging(char const * const daemon_name);
@@ -73,4 +131,7 @@ int set_fd_cloexec(int fd);
WARN_UNUSED
char const * get_nDPId_version(void);
+WARN_UNUSED
+int parse_config_file(char const * const config_file, config_line_callback cb, void * const user_data);
+
#endif