aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNardi Ivan <nardi.ivan@gmail.com>2024-01-09 08:41:44 +0100
committerIvan Nardi <12729895+IvanNardi@users.noreply.github.com>2024-01-18 10:21:24 +0100
commitd72a760ac3895dd8a0bd3e55d4b51f9e22e04e6c (patch)
treec00c477a043b58c5c05f4afe6b5ecde5864011df
parentca7df1db82e97954724f547c5966a5f99ad86e6b (diff)
New API for library configuration
This is the first step into providing (more) configuration options in nDPI. The idea is to have a simple way to configure (most of) nDPI: only one function (`ndpi_set_config()`) to set any configuration parameters (in the present or on in the future) and we try to keep this function prototype as agnostic as possible. You can configure the library: * via API, using `ndpi_set_config()` * via a configuration file, in a text format This way, anytime we need to add a new configuration parameter: * we don't need to add two public functions (a getter and a setter) * we don't break API/ABI compatibility of the library; even changing the parameter type (from integer to a list of integer, for example) doesn't break the compatibility. The complete list of configuration options is provided in `doc/configuration_parameters.md`. As a first example, two configuration knobs are provided: * the ability to enable/disable the extraction of the sha1 fingerprint of the TLS certificates. * the upper limit on the number of packets per flow that will be subject to inspection
-rw-r--r--.gitignore1
-rw-r--r--Makefile.am2
-rw-r--r--doc/configuration_parameters.md10
-rw-r--r--example/config.txt10
-rw-r--r--example/ndpiReader.c133
-rw-r--r--fuzz/Makefile.am7
-rw-r--r--fuzz/corpus/fuzz_config/0dfcfaf91c524f3982a883227fd2de87906e6bb0bin619 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/3036bf1df14f0ad0c2b5614e51789f575af97dfbbin690 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/3243ac924573c7a3687f8aac1ca5bfa11fb89b7abin617 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/3bf49bd80bf3c787f49222fc50c41f48f85fa013bin614 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/3f22430a14710ba1d01f3547b60aded67efb9833bin612 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/4714c051ed397aa1778184fc9ba513f77f17a511bin706 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/4e873d14a5b6764f075247f14e69a615a9c702d0bin625 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/4fb64ad53f9797dcaf8b9e28ec77adceb22340aabin799 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/5d9677c7a2ad657e021b83e2a231e4a61ff7375bbin635 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/685a648c4186681d6e5a663fa7797d424dd8181ebin612 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/77281fce6fb40a568b750e97b356153447f92021bin643 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/7b261995a0ed0a8b6ca544edfd56765963d113bebin615 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/828f8f1454722c92c14f9b25ad776eb5e676459cbin611 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/8bb38a19254c0d699e4d551a9ff65bc7a99e9a63bin627 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/907d8cd14928d4035594a91347a407857b868bafbin615 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/a79e2ad75b81e48a7e7153d9f1d2a60740e04360bin616 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/b160a30be750571b70090c2811c25d0c6ba460d4bin769 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/b46ee834ea6b1b6b860bbcc0bfad3de77ec72d32bin611 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/b791553ea6d3ad8415c7bd462ca18482dd9eaadfbin616 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/c3cd2ec494821a138c82f087290f8cf105bf41e7bin622 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/cbf4471e64914dc5eb45a1de426f42723c703cecbin613 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/ccc5d3518a38a1c9c89139202aac46507a7b9f08bin616 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/ccd00f1345fccd5b8435039f30fc6f27639029dbbin741 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/d874a185c26c951bf84d9a7d69e00ffb56b0e563bin710 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/d8c164d651c3d986e00694838757e33d54cf38eebin615 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/e063dec4ae4ac11531c42b97ff54614517327eb1bin616 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/e2f04c963eacfd329b213aae9910639b3e8f9ca5bin606 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/ecf80e7622e869e8783e6bf9be48bc1dd4a61c13bin611 -> 0 bytes
-rw-r--r--fuzz/corpus/fuzz_config/fea0c8b59dc63399afd8a0e6eab1753c444e4833bin613 -> 0 bytes
-rw-r--r--fuzz/fuzz_common_code.c2
-rw-r--r--fuzz/fuzz_config.cpp31
-rw-r--r--src/include/ndpi_api.h9
-rw-r--r--src/include/ndpi_define.h.in1
-rw-r--r--src/include/ndpi_private.h17
-rw-r--r--src/include/ndpi_typedefs.h9
-rw-r--r--src/include/ndpi_win32.h4
-rw-r--r--src/lib/ndpi_main.c454
-rw-r--r--src/lib/protocols/tls.c60
-rw-r--r--tests/cfgs/disable_metadata/config.txt1
l---------tests/cfgs/disable_metadata/pcap/tls_verylong_certificate.pcap1
-rw-r--r--tests/cfgs/disable_metadata/result/tls_verylong_certificate.pcap.out33
-rw-r--r--tests/cfgs/packets_limit_per_flow/config.txt1
l---------tests/cfgs/packets_limit_per_flow/pcap/tls_verylong_certificate.pcap1
-rw-r--r--tests/cfgs/packets_limit_per_flow/result/tls_verylong_certificate.pcap.out33
-rwxr-xr-xtests/do.sh.in2
-rw-r--r--tests/ossfuzz.sh1
52 files changed, 743 insertions, 80 deletions
diff --git a/.gitignore b/.gitignore
index 83eb5a759..1323ab273 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,7 +94,6 @@
/fuzz/fuzz_ndpi_reader_alloc_fail_seed_corpus.zip
/fuzz/fuzz_ndpi_reader_seed_corpus.zip
/fuzz/fuzz_quic_get_crypto_data_seed_corpus.zip
-/fuzz/fuzz_config_seed_corpus.zip
/fuzz/fuzz_community_id_seed_corpus.zip
/fuzz/fuzz_is_stun_udp_seed_corpus.zip
/fuzz/fuzz_is_stun_tcp_seed_corpus.zip
diff --git a/Makefile.am b/Makefile.am
index 857ec608b..eea950d78 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,7 +14,7 @@ EXTRA_DIST = README.md README.fuzzer.md CHANGELOG.md CONTRIBUTING.md \
rrdtool/Makefile.in rrdtool/README.txt rrdtool/rrd_anomaly.c rrdtool/rrd_similarity.c \
doc/requirements.txt doc/conf.py doc/flow_risks.rst doc/protocols.rst doc/guide/nDPI_QuickStartGuide.pages \
doc/guide/nDPI_QuickStartGuide.pdf doc/img/logo.png doc/index.rst \
- doc/Makefile doc/what_is_ndpi.rst doc/FAQ.md \
+ doc/Makefile doc/what_is_ndpi.rst doc/FAQ.md doc/configuration_parameters.md \
python/DEV_GUIDE.md python/dev_requirements.txt python/ndpi_example.py python/ndpi/__init__.py \
python/ndpi/ndpi_build.py python/ndpi/ndpi.py python/README.md \
python/requirements.txt python/setup.py python/tests.py \
diff --git a/doc/configuration_parameters.md b/doc/configuration_parameters.md
new file mode 100644
index 000000000..77ce00236
--- /dev/null
+++ b/doc/configuration_parameters.md
@@ -0,0 +1,10 @@
+
+# Configuration knobs
+
+TODO
+
+| Protocol | Parameter | Default value | Min value | Max value | Description | Notes |
+| ------ | ------ | ------ | ------ | ------ | ------ | ------ |
+| NULL | "packets_limit_per_flow" | 32 | 0 | 255 | The upper limit on the number of packets per flow that will be subject to DPI, after which classification will be considered complete (0 = no limit) |
+| NULL | "filename.config" | NULL | NULL | NULL | Name of the file containing a list of configuration knobs itself (one per line)!. Useful to configure nDPI via text file instead of via API |
+| "tls" | "metadata.sha1_fingerprint.enable" | 1 | NULL | NULL | Enable/disable computation and export of SHA1 fingerprint for TLS flows. Note that if it is disable, the flow risk `NDPI_MALICIOUS_SHA1_CERTIFICATE` is not checked |
diff --git a/example/config.txt b/example/config.txt
new file mode 100644
index 000000000..dc8aac250
--- /dev/null
+++ b/example/config.txt
@@ -0,0 +1,10 @@
+#Format: <proto, param, value>
+#proto might be empty
+#Basic example of how to set nDPI configuration parameters via file
+#We set only some default values
+#See doc/configuration_parameters.md for a complete list and description of all the accepted knobs
+
+packets_limit_per_flow,32
+tls,metadata.sha1_fingerprint.enable,1
+
+
diff --git a/example/ndpiReader.c b/example/ndpiReader.c
index c7f641650..e597de3d4 100644
--- a/example/ndpiReader.c
+++ b/example/ndpiReader.c
@@ -94,6 +94,16 @@ static u_int8_t ignore_vlanid = 0;
/** User preferences **/
u_int8_t enable_realtime_output = 0, enable_protocol_guess = 1, enable_payload_analyzer = 0, num_bin_clusters = 0, extcap_exit = 0;
u_int8_t verbose = 0, enable_flow_stats = 0;
+
+struct cfg {
+ char *proto;
+ char *param;
+ char *value;
+};
+#define MAX_NUM_CFGS 32
+static struct cfg cfgs[MAX_NUM_CFGS];
+static int num_cfgs = 0;
+
int nDPI_LogLevel = 0;
char *_debug_protocols = NULL;
char *_disabled_protocols = NULL;
@@ -363,6 +373,8 @@ static void ndpiCheckIPMatch(char *testChar) {
struct in_addr addr;
char appBufStr[64];
ndpi_protocol detected_protocol;
+ int i;
+ ndpi_cfg_error rc;
NDPI_PROTOCOL_BITMASK all;
if(!testChar)
@@ -375,6 +387,14 @@ static void ndpiCheckIPMatch(char *testChar) {
if(_protoFilePath != NULL)
ndpi_load_protocols_file(ndpi_str, _protoFilePath);
+ for(i = 0; i < num_cfgs; i++) {
+ rc = ndpi_set_config(ndpi_str,
+ cfgs[i].proto, cfgs[i].param, cfgs[i].value);
+ if (rc < NDPI_CFG_OK)
+ fprintf(stderr, "Error setting config [%s][%s][%s]: %d\n",
+ cfgs[i].proto, cfgs[i].param, cfgs[i].value, rc);
+ }
+
ndpi_finalize_initialization(ndpi_str);
ip_str = strtok_r(testChar, ":", &saveptr);
@@ -571,7 +591,7 @@ static void help(u_int long_help) {
" | 1 = verbose\n"
" | 2 = very verbose\n"
" | 3 = port stats\n"
- " | 4 = hash stats\n"
+ " | 4 = hash stats\n"
" -V <1-4> | nDPI logging level\n"
" | 1 - trace, 2 - debug, 3 - full debug\n"
" | >3 - full debug + log enabled for all protocols (i.e. '-u all')\n"
@@ -589,6 +609,7 @@ static void help(u_int long_help) {
" -Z proto:value | Set this value of aggressiveness for this protocol (0 to disable it). This flag can be used multiple times\n"
" --lru-cache-size=NAME:size | Specify the size for this LRU cache (0 to disable it). This flag can be used multiple times\n"
" --lru-cache-ttl=NAME:size | Specify the TTL [in seconds] for this LRU cache (0 to disable it). This flag can be used multiple times\n"
+ " --cfg=proto,param,value | Configure the specific attribute of this protocol\n"
,
human_readeable_string_len,
min_pattern_len, max_pattern_len, max_num_packets_per_flow, max_packet_payload_dissection,
@@ -596,6 +617,15 @@ static void help(u_int long_help) {
printf("\nLRU Cache names: ookla, bittorrent, zoom, stun, tls_cert, mining, msteams, stun_zoom\n");
+ NDPI_PROTOCOL_BITMASK all;
+ struct ndpi_detection_module_struct *ndpi_info_mod = ndpi_init_detection_module(init_prefs);
+ NDPI_BITMASK_SET_ALL(all);
+ ndpi_set_protocol_detection_bitmask2(ndpi_info_mod, &all);
+ ndpi_finalize_initialization(ndpi_info_mod);
+
+ printf("\nProtocols configuration parameters:\n");
+ ndpi_dump_config(ndpi_info_mod, stdout);
+
#ifndef WIN32
printf("\nExcap (wireshark) options:\n"
" --extcap-interfaces\n"
@@ -616,24 +646,19 @@ static void help(u_int long_help) {
ndpi_detection_get_sizeof_ndpi_flow_struct(),
sizeof(((struct ndpi_flow_struct *)0)->protos));
- NDPI_PROTOCOL_BITMASK all;
- struct ndpi_detection_module_struct *ndpi_info_mod = ndpi_init_detection_module(init_prefs);
printf("\n\nnDPI supported protocols:\n");
printf("%3s %-22s %-10s %-8s %-12s %s\n",
"Id", "Protocol", "Layer_4", "Nw_Proto", "Breed", "Category");
num_threads = 1;
- NDPI_BITMASK_SET_ALL(all);
- ndpi_set_protocol_detection_bitmask2(ndpi_info_mod, &all);
-
ndpi_dump_protocols(ndpi_info_mod, stdout);
printf("\n\nnDPI supported risks:\n");
ndpi_dump_risks_score(stdout);
-
- ndpi_exit_detection_module(ndpi_info_mod);
}
+ ndpi_exit_detection_module(ndpi_info_mod);
+
exit(!long_help);
}
@@ -641,6 +666,8 @@ static void help(u_int long_help) {
#define OPTLONG_VALUE_LRU_CACHE_SIZE 1000
#define OPTLONG_VALUE_LRU_CACHE_TTL 1001
+#define OPTLONG_VALUE_CFG 3000
+
static struct option longopts[] = {
/* mandatory extcap options */
{ "extcap-interfaces", no_argument, NULL, '0'},
@@ -685,6 +712,8 @@ static struct option longopts[] = {
{ "lru-cache-size", required_argument, NULL, OPTLONG_VALUE_LRU_CACHE_SIZE},
{ "lru-cache-ttl", required_argument, NULL, OPTLONG_VALUE_LRU_CACHE_TTL},
+ { "cfg", required_argument, NULL, OPTLONG_VALUE_CFG},
+
{0, 0, 0, 0}
};
@@ -941,6 +970,69 @@ static int parse_two_unsigned_integer(char *param, u_int32_t *num1, u_int32_t *n
return -1;
}
+static int parse_three_strings(char *param, char **s1, char **s2, char **s3)
+{
+ char *saveptr, *tmp_str, *s1_str, *s2_str = NULL, *s3_str;
+ int num_commas;
+ unsigned int i;
+
+ tmp_str = ndpi_strdup(param);
+ if(tmp_str) {
+
+ /* First parameter might be missing */
+ num_commas = 0;
+ for(i = 0; i < strlen(tmp_str); i++) {
+ if(tmp_str[i] == ',')
+ num_commas++;
+ }
+
+ if(num_commas == 1) {
+ s1_str = NULL;
+ s2_str = strtok_r(tmp_str, ",", &saveptr);
+ } else if(num_commas == 2) {
+ s1_str = strtok_r(tmp_str, ",", &saveptr);
+ if(s1_str) {
+ s2_str = strtok_r(NULL, ",", &saveptr);
+ }
+ } else {
+ ndpi_free(tmp_str);
+ return -1;
+ }
+
+ if(s2_str) {
+ s3_str = strtok_r(NULL, ",", &saveptr);
+ if(s3_str) {
+ *s1 = ndpi_strdup(s1_str);
+ *s2 = ndpi_strdup(s2_str);
+ *s3 = ndpi_strdup(s3_str);
+ ndpi_free(tmp_str);
+ if(!s1 || !s2 || !s3) {
+ ndpi_free(s1);
+ ndpi_free(s2);
+ ndpi_free(s3);
+ return -1;
+ }
+ return 0;
+ }
+ }
+ }
+ ndpi_free(tmp_str);
+ return -1;
+}
+
+int reader_add_cfg(char *proto, char *param, char *value, int dup)
+{
+ if(num_cfgs >= MAX_NUM_CFGS) {
+ printf("Too many parameter! [num:%d/%d]\n", num_cfgs, MAX_NUM_CFGS);
+ return -1;
+ }
+ cfgs[num_cfgs].proto = dup ? ndpi_strdup(proto) : proto;
+ cfgs[num_cfgs].param = dup ? ndpi_strdup(param) : param;
+ cfgs[num_cfgs].value = dup ? ndpi_strdup(value) : value;
+ num_cfgs++;
+ return 0;
+}
+
/* ********************************** */
/**
@@ -958,6 +1050,7 @@ static void parseOptions(int argc, char **argv) {
#endif
#endif
int cache_idx, cache_size, cache_ttl;
+ char *s1, *s2, *s3;
#ifdef USE_DPDK
{
@@ -1301,6 +1394,14 @@ static void parseOptions(int argc, char **argv) {
lru_cache_ttls[cache_idx] = cache_ttl;
break;
+ case OPTLONG_VALUE_CFG:
+ if(parse_three_strings(optarg, &s1, &s2, &s3) == -1 ||
+ reader_add_cfg(s1, s2, s3, 0) == -1) {
+ printf("Invalid parameter [%s] [num:%d/%d]\n", optarg, num_cfgs, MAX_NUM_CFGS);
+ exit(1);
+ }
+ break;
+
default:
#ifdef DEBUG_TRACE
if(trace) fprintf(trace, " #### Unknown option -%c: skipping it #### \n", opt);
@@ -2731,6 +2832,7 @@ static void setupDetection(u_int16_t thread_id, pcap_t * pcap_handle) {
NDPI_PROTOCOL_BITMASK enabled_bitmask;
struct ndpi_workflow_prefs prefs;
int i;
+ ndpi_cfg_error rc;
memset(&prefs, 0, sizeof(prefs));
prefs.decode_tunnels = decode_tunnels;
@@ -2821,6 +2923,15 @@ static void setupDetection(u_int16_t thread_id, pcap_t * pcap_handle) {
ndpi_set_protocol_aggressiveness(ndpi_thread_info[thread_id].workflow->ndpi_struct, i, aggressiveness[i]);
}
+ for(i = 0; i < num_cfgs; i++) {
+ rc = ndpi_set_config(ndpi_thread_info[thread_id].workflow->ndpi_struct,
+ cfgs[i].proto, cfgs[i].param, cfgs[i].value);
+ if (rc != NDPI_CFG_OK)
+ fprintf(stderr, "Error setting config [%s][%s][%s]: %d\n",
+ cfgs[i].proto, cfgs[i].param, cfgs[i].value, rc);
+ }
+
+
ndpi_finalize_initialization(ndpi_thread_info[thread_id].workflow->ndpi_struct);
if(enable_doh_dot_detection)
@@ -5833,6 +5944,12 @@ int main(int argc, char **argv) {
ndpi_free(_debug_protocols);
ndpi_free(_disabled_protocols);
+ for(i = 0; i < num_cfgs; i++) {
+ ndpi_free(cfgs[i].proto);
+ ndpi_free(cfgs[i].param);
+ ndpi_free(cfgs[i].value);
+ }
+
#ifdef DEBUG_TRACE
if(trace) fclose(trace);
#endif
diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am
index 3252b1fba..0e14eb69e 100644
--- a/fuzz/Makefile.am
+++ b/fuzz/Makefile.am
@@ -611,10 +611,6 @@ files_corpus_fuzz_quic_get_crypto_data := $(wildcard corpus/fuzz_quic_get_crypt
fuzz_quic_get_crypto_data_seed_corpus.zip: $(files_corpus_fuzz_quic_get_crypto_data)
zip -j fuzz_quic_get_crypto_data_seed_corpus.zip $(files_corpus_fuzz_quic_get_crypto_data)
-files_corpus_fuzz_config := $(wildcard corpus/fuzz_config/*)
-fuzz_config_seed_corpus.zip: $(files_corpus_fuzz_config)
- zip -j fuzz_config_seed_corpus.zip $(files_corpus_fuzz_config)
-
files_corpus_fuzz_serialization := $(wildcard corpus/fuzz_serialization/*)
fuzz_serialization_seed_corpus.zip: $(files_corpus_fuzz_serialization)
zip -j fuzz_serialization_seed_corpus.zip $(files_corpus_fuzz_serialization)
@@ -715,7 +711,7 @@ files_corpus_fuzz_ds_domain_classify := $(wildcard corpus/fuzz_ds_domain_classi
fuzz_ds_domain_classify_seed_corpus.zip: $(files_corpus_fuzz_ds_domain_classify)
zip -j fuzz_ds_domain_classify_seed_corpus.zip $(files_corpus_fuzz_ds_domain_classify)
-corpus: fuzz_ndpi_reader_seed_corpus.zip fuzz_ndpi_reader_alloc_fail_seed_corpus.zip fuzz_ndpi_reader_payload_analyzer_seed_corpus.zip fuzz_quic_get_crypto_data_seed_corpus.zip fuzz_config_seed_corpus.zip fuzz_ds_patricia_seed_corpus.zip fuzz_alg_ses_des_seed_corpus.zip fuzz_alg_bins_seed_corpus.zip fuzz_alg_hll_seed_corpus.zip fuzz_alg_jitter_seed_corpus.zip fuzz_ds_libcache_seed_corpus.zip fuzz_community_id_seed_corpus.zip fuzz_ds_tree_seed_corpus.zip fuzz_serialization_seed_corpus.zip fuzz_ds_ptree_seed_corpus.zip fuzz_alg_crc32_md5_seed_corpus.zip fuzz_alg_bytestream_seed_corpus.zip fuzz_libinjection_seed_corpus.zip fuzz_tls_certificate_seed_corpus.zip fuzz_filecfg_protocols_seed_corpus.zip fuzz_readerutils_workflow_seed_corpus.zip fuzz_readerutils_parseprotolist_seed_corpus.zip fuzz_ds_bitmap64_seed_corpus.zip fuzz_ds_domain_classify_seed_corpus.zip fuzz_filecfg_protocols_seed_corpus.zip fuzz_is_stun_udp_seed_corpus.zip fuzz_is_stun_tcp_seed_corpus.zip fuzz_filecfg_malicious_sha1_seed_corpus.zip fuzz_filecfg_malicious_ja3_seed_corpus.zip fuzz_filecfg_risk_domains_seed_corpus.zip
+corpus: fuzz_ndpi_reader_seed_corpus.zip fuzz_ndpi_reader_alloc_fail_seed_corpus.zip fuzz_ndpi_reader_payload_analyzer_seed_corpus.zip fuzz_quic_get_crypto_data_seed_corpus.zip fuzz_ds_patricia_seed_corpus.zip fuzz_alg_ses_des_seed_corpus.zip fuzz_alg_bins_seed_corpus.zip fuzz_alg_hll_seed_corpus.zip fuzz_alg_jitter_seed_corpus.zip fuzz_ds_libcache_seed_corpus.zip fuzz_community_id_seed_corpus.zip fuzz_ds_tree_seed_corpus.zip fuzz_serialization_seed_corpus.zip fuzz_ds_ptree_seed_corpus.zip fuzz_alg_crc32_md5_seed_corpus.zip fuzz_alg_bytestream_seed_corpus.zip fuzz_libinjection_seed_corpus.zip fuzz_tls_certificate_seed_corpus.zip fuzz_filecfg_protocols_seed_corpus.zip fuzz_readerutils_workflow_seed_corpus.zip fuzz_readerutils_parseprotolist_seed_corpus.zip fuzz_ds_bitmap64_seed_corpus.zip fuzz_ds_domain_classify_seed_corpus.zip fuzz_filecfg_protocols_seed_corpus.zip fuzz_is_stun_udp_seed_corpus.zip fuzz_is_stun_tcp_seed_corpus.zip fuzz_filecfg_malicious_sha1_seed_corpus.zip fuzz_filecfg_malicious_ja3_seed_corpus.zip fuzz_filecfg_risk_domains_seed_corpus.zip
cp corpus/fuzz_*seed_corpus.zip .
#Create dictionaries exactly as expected by oss-fuzz.
@@ -750,7 +746,6 @@ distdir:
-o -path './corpus/fuzz_filecfg_risk_domains/*' \
-o -path './corpus/fuzz_readerutils_workflow/*' \
-o -path './corpus/fuzz_readerutils_parseprotolist/*' \
- -o -path './corpus/fuzz_config/*' \
-o -path './corpus/fuzz_is_stun_udp/*' \
-o -path './corpus/fuzz_is_stun_tcp/*' \
-o -path './corpus/fuzz_serialization/*' \
diff --git a/fuzz/corpus/fuzz_config/0dfcfaf91c524f3982a883227fd2de87906e6bb0 b/fuzz/corpus/fuzz_config/0dfcfaf91c524f3982a883227fd2de87906e6bb0
deleted file mode 100644
index d425c3cce..000000000
--- a/fuzz/corpus/fuzz_config/0dfcfaf91c524f3982a883227fd2de87906e6bb0
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/3036bf1df14f0ad0c2b5614e51789f575af97dfb b/fuzz/corpus/fuzz_config/3036bf1df14f0ad0c2b5614e51789f575af97dfb
deleted file mode 100644
index 0053008b5..000000000
--- a/fuzz/corpus/fuzz_config/3036bf1df14f0ad0c2b5614e51789f575af97dfb
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/3243ac924573c7a3687f8aac1ca5bfa11fb89b7a b/fuzz/corpus/fuzz_config/3243ac924573c7a3687f8aac1ca5bfa11fb89b7a
deleted file mode 100644
index 1eabadc56..000000000
--- a/fuzz/corpus/fuzz_config/3243ac924573c7a3687f8aac1ca5bfa11fb89b7a
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/3bf49bd80bf3c787f49222fc50c41f48f85fa013 b/fuzz/corpus/fuzz_config/3bf49bd80bf3c787f49222fc50c41f48f85fa013
deleted file mode 100644
index 05a402637..000000000
--- a/fuzz/corpus/fuzz_config/3bf49bd80bf3c787f49222fc50c41f48f85fa013
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/3f22430a14710ba1d01f3547b60aded67efb9833 b/fuzz/corpus/fuzz_config/3f22430a14710ba1d01f3547b60aded67efb9833
deleted file mode 100644
index 9c2b1e5c6..000000000
--- a/fuzz/corpus/fuzz_config/3f22430a14710ba1d01f3547b60aded67efb9833
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/4714c051ed397aa1778184fc9ba513f77f17a511 b/fuzz/corpus/fuzz_config/4714c051ed397aa1778184fc9ba513f77f17a511
deleted file mode 100644
index dffcb7aa1..000000000
--- a/fuzz/corpus/fuzz_config/4714c051ed397aa1778184fc9ba513f77f17a511
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/4e873d14a5b6764f075247f14e69a615a9c702d0 b/fuzz/corpus/fuzz_config/4e873d14a5b6764f075247f14e69a615a9c702d0
deleted file mode 100644
index da1238a44..000000000
--- a/fuzz/corpus/fuzz_config/4e873d14a5b6764f075247f14e69a615a9c702d0
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/4fb64ad53f9797dcaf8b9e28ec77adceb22340aa b/fuzz/corpus/fuzz_config/4fb64ad53f9797dcaf8b9e28ec77adceb22340aa
deleted file mode 100644
index d2c73ae0f..000000000
--- a/fuzz/corpus/fuzz_config/4fb64ad53f9797dcaf8b9e28ec77adceb22340aa
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/5d9677c7a2ad657e021b83e2a231e4a61ff7375b b/fuzz/corpus/fuzz_config/5d9677c7a2ad657e021b83e2a231e4a61ff7375b
deleted file mode 100644
index 6e933a4d9..000000000
--- a/fuzz/corpus/fuzz_config/5d9677c7a2ad657e021b83e2a231e4a61ff7375b
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/685a648c4186681d6e5a663fa7797d424dd8181e b/fuzz/corpus/fuzz_config/685a648c4186681d6e5a663fa7797d424dd8181e
deleted file mode 100644
index 267619009..000000000
--- a/fuzz/corpus/fuzz_config/685a648c4186681d6e5a663fa7797d424dd8181e
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/77281fce6fb40a568b750e97b356153447f92021 b/fuzz/corpus/fuzz_config/77281fce6fb40a568b750e97b356153447f92021
deleted file mode 100644
index 23259edba..000000000
--- a/fuzz/corpus/fuzz_config/77281fce6fb40a568b750e97b356153447f92021
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/7b261995a0ed0a8b6ca544edfd56765963d113be b/fuzz/corpus/fuzz_config/7b261995a0ed0a8b6ca544edfd56765963d113be
deleted file mode 100644
index ff311b19c..000000000
--- a/fuzz/corpus/fuzz_config/7b261995a0ed0a8b6ca544edfd56765963d113be
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/828f8f1454722c92c14f9b25ad776eb5e676459c b/fuzz/corpus/fuzz_config/828f8f1454722c92c14f9b25ad776eb5e676459c
deleted file mode 100644
index f7835fe77..000000000
--- a/fuzz/corpus/fuzz_config/828f8f1454722c92c14f9b25ad776eb5e676459c
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/8bb38a19254c0d699e4d551a9ff65bc7a99e9a63 b/fuzz/corpus/fuzz_config/8bb38a19254c0d699e4d551a9ff65bc7a99e9a63
deleted file mode 100644
index a9f5bc14c..000000000
--- a/fuzz/corpus/fuzz_config/8bb38a19254c0d699e4d551a9ff65bc7a99e9a63
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/907d8cd14928d4035594a91347a407857b868baf b/fuzz/corpus/fuzz_config/907d8cd14928d4035594a91347a407857b868baf
deleted file mode 100644
index 394b628e0..000000000
--- a/fuzz/corpus/fuzz_config/907d8cd14928d4035594a91347a407857b868baf
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/a79e2ad75b81e48a7e7153d9f1d2a60740e04360 b/fuzz/corpus/fuzz_config/a79e2ad75b81e48a7e7153d9f1d2a60740e04360
deleted file mode 100644
index 29e3c6d15..000000000
--- a/fuzz/corpus/fuzz_config/a79e2ad75b81e48a7e7153d9f1d2a60740e04360
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/b160a30be750571b70090c2811c25d0c6ba460d4 b/fuzz/corpus/fuzz_config/b160a30be750571b70090c2811c25d0c6ba460d4
deleted file mode 100644
index 22c00b7af..000000000
--- a/fuzz/corpus/fuzz_config/b160a30be750571b70090c2811c25d0c6ba460d4
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/b46ee834ea6b1b6b860bbcc0bfad3de77ec72d32 b/fuzz/corpus/fuzz_config/b46ee834ea6b1b6b860bbcc0bfad3de77ec72d32
deleted file mode 100644
index 2b7ced466..000000000
--- a/fuzz/corpus/fuzz_config/b46ee834ea6b1b6b860bbcc0bfad3de77ec72d32
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/b791553ea6d3ad8415c7bd462ca18482dd9eaadf b/fuzz/corpus/fuzz_config/b791553ea6d3ad8415c7bd462ca18482dd9eaadf
deleted file mode 100644
index c885c76cf..000000000
--- a/fuzz/corpus/fuzz_config/b791553ea6d3ad8415c7bd462ca18482dd9eaadf
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/c3cd2ec494821a138c82f087290f8cf105bf41e7 b/fuzz/corpus/fuzz_config/c3cd2ec494821a138c82f087290f8cf105bf41e7
deleted file mode 100644
index b24588d19..000000000
--- a/fuzz/corpus/fuzz_config/c3cd2ec494821a138c82f087290f8cf105bf41e7
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/cbf4471e64914dc5eb45a1de426f42723c703cec b/fuzz/corpus/fuzz_config/cbf4471e64914dc5eb45a1de426f42723c703cec
deleted file mode 100644
index 64aa513d2..000000000
--- a/fuzz/corpus/fuzz_config/cbf4471e64914dc5eb45a1de426f42723c703cec
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/ccc5d3518a38a1c9c89139202aac46507a7b9f08 b/fuzz/corpus/fuzz_config/ccc5d3518a38a1c9c89139202aac46507a7b9f08
deleted file mode 100644
index cd8e2ffec..000000000
--- a/fuzz/corpus/fuzz_config/ccc5d3518a38a1c9c89139202aac46507a7b9f08
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/ccd00f1345fccd5b8435039f30fc6f27639029db b/fuzz/corpus/fuzz_config/ccd00f1345fccd5b8435039f30fc6f27639029db
deleted file mode 100644
index 81d59ad0c..000000000
--- a/fuzz/corpus/fuzz_config/ccd00f1345fccd5b8435039f30fc6f27639029db
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/d874a185c26c951bf84d9a7d69e00ffb56b0e563 b/fuzz/corpus/fuzz_config/d874a185c26c951bf84d9a7d69e00ffb56b0e563
deleted file mode 100644
index 7b92ee675..000000000
--- a/fuzz/corpus/fuzz_config/d874a185c26c951bf84d9a7d69e00ffb56b0e563
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/d8c164d651c3d986e00694838757e33d54cf38ee b/fuzz/corpus/fuzz_config/d8c164d651c3d986e00694838757e33d54cf38ee
deleted file mode 100644
index 6673a8e51..000000000
--- a/fuzz/corpus/fuzz_config/d8c164d651c3d986e00694838757e33d54cf38ee
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/e063dec4ae4ac11531c42b97ff54614517327eb1 b/fuzz/corpus/fuzz_config/e063dec4ae4ac11531c42b97ff54614517327eb1
deleted file mode 100644
index fdcee70a9..000000000
--- a/fuzz/corpus/fuzz_config/e063dec4ae4ac11531c42b97ff54614517327eb1
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/e2f04c963eacfd329b213aae9910639b3e8f9ca5 b/fuzz/corpus/fuzz_config/e2f04c963eacfd329b213aae9910639b3e8f9ca5
deleted file mode 100644
index 74fca6df9..000000000
--- a/fuzz/corpus/fuzz_config/e2f04c963eacfd329b213aae9910639b3e8f9ca5
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/ecf80e7622e869e8783e6bf9be48bc1dd4a61c13 b/fuzz/corpus/fuzz_config/ecf80e7622e869e8783e6bf9be48bc1dd4a61c13
deleted file mode 100644
index 8caa90571..000000000
--- a/fuzz/corpus/fuzz_config/ecf80e7622e869e8783e6bf9be48bc1dd4a61c13
+++ /dev/null
Binary files differ
diff --git a/fuzz/corpus/fuzz_config/fea0c8b59dc63399afd8a0e6eab1753c444e4833 b/fuzz/corpus/fuzz_config/fea0c8b59dc63399afd8a0e6eab1753c444e4833
deleted file mode 100644
index 402b241c1..000000000
--- a/fuzz/corpus/fuzz_config/fea0c8b59dc63399afd8a0e6eab1753c444e4833
+++ /dev/null
Binary files differ
diff --git a/fuzz/fuzz_common_code.c b/fuzz/fuzz_common_code.c
index b48fa9133..1344e8516 100644
--- a/fuzz/fuzz_common_code.c
+++ b/fuzz/fuzz_common_code.c
@@ -57,6 +57,8 @@ void fuzz_init_detection_module(struct ndpi_detection_module_struct **ndpi_info_
NDPI_BITMASK_SET_ALL(all);
ndpi_set_protocol_detection_bitmask2(*ndpi_info_mod, &all);
+ ndpi_set_config(*ndpi_info_mod, NULL, "filename.config", "config.txt");
+
ndpi_finalize_initialization(*ndpi_info_mod);
}
}
diff --git a/fuzz/fuzz_config.cpp b/fuzz/fuzz_config.cpp
index afd9367fb..573f6ecbe 100644
--- a/fuzz/fuzz_config.cpp
+++ b/fuzz/fuzz_config.cpp
@@ -28,21 +28,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
ndpi_proto p, p2;
char out[128];
char log_ts[32];
+ int value;
+ char cfg_value[32];
- if(fuzzed_data.remaining_bytes() < 4 + /* ndpi_init_detection_module() */
- NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS +
- 1 + /* TLS cert expire */
- 6 + /* files */
- ((NDPI_LRUCACHE_MAX + 1) * 5) + /* LRU caches */
- 2 + 1 + 4 + /* ndpi_set_detection_preferences() */
- 7 + /* Opportunistic tls */
- 2 + /* Pid */
- 2 + /* Category */
- 1 + /* Tunnel */
- 1 + /* Bool value */
- 2 + /* input_info */
- 21 /* Min real data: ip length + 1 byte of L4 header */)
+ /* Just to be sure to have some data */
+ if(fuzzed_data.remaining_bytes() < NDPI_MAX_SUPPORTED_PROTOCOLS * 2 + 200)
return -1;
/* To allow memory allocation failures */
@@ -101,9 +92,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if(fuzzed_data.ConsumeBool())
ndpi_set_detection_preferences(ndpi_info_mod, ndpi_pref_enable_tls_block_dissection,
0 /* unused */);
- if(fuzzed_data.ConsumeBool())
- ndpi_set_detection_preferences(ndpi_info_mod, ndpi_pref_max_packets_to_process,
- fuzzed_data.ConsumeIntegralInRange(0, (1 << 16)));
ndpi_set_detection_preferences(ndpi_info_mod, static_cast<ndpi_detection_preference>(0xFF), 0xFF); /* Invalid preference */
@@ -126,6 +114,17 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
ndpi_get_protocol_aggressiveness(ndpi_info_mod, i);
}
+ if(fuzzed_data.ConsumeBool()) {
+ value = fuzzed_data.ConsumeIntegralInRange(0, 1 + 1);
+ sprintf(cfg_value, "%d", value);
+ ndpi_set_config(ndpi_info_mod, "tls", "metadata.sha1_fingerprint.enable", cfg_value);
+ }
+ if(fuzzed_data.ConsumeBool()) {
+ value = fuzzed_data.ConsumeIntegralInRange(0, 255 + 1);
+ sprintf(cfg_value, "%d", value);
+ ndpi_set_config(ndpi_info_mod, NULL, "packets_limit_per_flow", cfg_value);
+ }
+
ndpi_finalize_initialization(ndpi_info_mod);
/* Random protocol configuration */
diff --git a/src/include/ndpi_api.h b/src/include/ndpi_api.h
index 8bec8e3eb..3a5c7eccc 100644
--- a/src/include/ndpi_api.h
+++ b/src/include/ndpi_api.h
@@ -2246,6 +2246,15 @@ extern "C" {
/* ******************************* */
+ ndpi_cfg_error ndpi_set_config(struct ndpi_detection_module_struct *ndpi_str,
+ const char *proto, const char *param, const char *value);
+ char *ndpi_get_config(struct ndpi_detection_module_struct *ndpi_str,
+ const char *proto, const char *param, char *buf, int buf_len);
+ char *ndpi_dump_config(struct ndpi_detection_module_struct *ndpi_str,
+ FILE *fd);
+
+ /* ******************************* */
+
/* Can't call libc functions from kernel space, define some stub instead */
#define ndpi_isalpha(ch) (((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
diff --git a/src/include/ndpi_define.h.in b/src/include/ndpi_define.h.in
index 3a5585f12..3ec09ebdd 100644
--- a/src/include/ndpi_define.h.in
+++ b/src/include/ndpi_define.h.in
@@ -153,7 +153,6 @@
/* misc definitions */
#define NDPI_DEFAULT_MAX_TCP_RETRANSMISSION_WINDOW_SIZE 0x10000
-#define NDPI_DEFAULT_MAX_NUM_PKTS_PER_FLOW_TO_DISSECT 32
/* TODO: rebuild all memory areas to have a more aligned memory block here */
diff --git a/src/include/ndpi_private.h b/src/include/ndpi_private.h
index df3bfaf2c..d4ff2461f 100644
--- a/src/include/ndpi_private.h
+++ b/src/include/ndpi_private.h
@@ -144,13 +144,24 @@ typedef struct {
} nbpf_filter;
#endif
+#define CFG_MAX_LEN 256
+
+struct ndpi_detection_module_config_struct {
+ int max_packets_to_process;
+
+ char filename_config[CFG_MAX_LEN];
+
+ /* Protocols */
+
+ int tls_sha1_fingerprint_enabled;
+};
+
struct ndpi_detection_module_struct {
NDPI_PROTOCOL_BITMASK detection_bitmask;
u_int64_t current_ts;
- u_int16_t max_packets_to_process;
u_int16_t num_tls_blocks_to_follow;
- u_int8_t skip_tls_blocks_until_change_cipher:1, _notused:7;
+ u_int8_t skip_tls_blocks_until_change_cipher:1, finalized:1, _notused:6;
u_int8_t tls_certificate_expire_in_x_days;
void *user_data;
@@ -226,6 +237,8 @@ struct ndpi_detection_module_struct {
u_int8_t ip_version_limit;
+ struct ndpi_detection_module_config_struct cfg;
+
/* NDPI_PROTOCOL_TINC */
struct cache *tinc_cache;
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index 792aea9ee..3ed4ee50c 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -234,6 +234,14 @@ typedef enum {
ndpi_leaf
} ndpi_VISIT;
+typedef enum {
+ NDPI_CFG_INVALID_CONTEXT = -1,
+ NDPI_CFG_NOT_FOUND = -2,
+ NDPI_CFG_INVALID_PARAM = -3,
+ NDPI_CFG_CONTEXT_ALREADY_INITIALIZED = -4,
+
+ NDPI_CFG_OK = 0,
+} ndpi_cfg_error;
/* NDPI_MASK_SIZE */
typedef u_int32_t ndpi_ndpi_mask;
@@ -1065,7 +1073,6 @@ typedef enum {
typedef enum {
ndpi_pref_direction_detect_disable = 0,
- ndpi_pref_max_packets_to_process,
ndpi_pref_enable_tls_block_dissection, /* nDPI considers only those blocks past the certificate exchange */
} ndpi_detection_preference;
diff --git a/src/include/ndpi_win32.h b/src/include/ndpi_win32.h
index 2ad8602aa..c6b3290f6 100644
--- a/src/include/ndpi_win32.h
+++ b/src/include/ndpi_win32.h
@@ -59,6 +59,10 @@
#define strdup _strdup
#endif
+#ifndef F_OK
+#define F_OK 0
+#endif
+
extern char* strsep(char **sp, char *sep);
typedef unsigned char u_char;
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c
index 28c53714f..bc850df64 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -224,6 +224,8 @@ static int ndpi_callback_init(struct ndpi_detection_module_struct *ndpi_str);
static void ndpi_enabled_callbacks_init(struct ndpi_detection_module_struct *ndpi_str,
const NDPI_PROTOCOL_BITMASK *dbm, int count_only);
+static void set_default_config(struct ndpi_detection_module_config_struct *cfg);
+
/* ****************************************** */
ndpi_custom_dga_predict_fctn ndpi_dga_function = NULL;
@@ -977,13 +979,6 @@ int ndpi_set_detection_preferences(struct ndpi_detection_module_struct *ndpi_str
ndpi_str->skip_tls_blocks_until_change_cipher = 1;
break;
- case ndpi_pref_max_packets_to_process:
- if(value > 0xFFFF) {
- return(-1);
- }
- ndpi_str->max_packets_to_process = value;
- break;
-
default:
return(-1);
}
@@ -3154,9 +3149,7 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs
if((ndpi_str->protocols_ptree = ndpi_patricia_new(32 /* IPv4 */)) == NULL ||
(ndpi_str->protocols_ptree6 = ndpi_patricia_new(128 /* IPv6 */)) == NULL) {
NDPI_LOG_ERR(ndpi_str, "[NDPI] Error allocating tree\n");
- if(ndpi_str->protocols_ptree != NULL)
- ndpi_patricia_destroy(ndpi_str->protocols_ptree, free_ptree_data);
- ndpi_free(ndpi_str);
+ ndpi_exit_detection_module(ndpi_str);
return NULL;
}
ndpi_init_ptree_ipv4(ndpi_str, ndpi_str->protocols_ptree, host_protocol_list);
@@ -3297,7 +3290,7 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs
if((ndpi_str->ip_risk_ptree = ndpi_patricia_new(32 /* IPv4 */)) == NULL ||
(ndpi_str->ip_risk_ptree6 = ndpi_patricia_new(128 /* IPv6 */)) == NULL) {
- NDPI_LOG_ERR(ndpi_str, "[NDPI] Error allocating tree\n");
+ NDPI_LOG_ERR(ndpi_str, "[NDPI] Error allocating risk tree\n");
ndpi_exit_detection_module(ndpi_str);
return NULL;
}
@@ -3315,7 +3308,8 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs
}
}
- ndpi_str->max_packets_to_process = NDPI_DEFAULT_MAX_NUM_PKTS_PER_FLOW_TO_DISSECT;
+
+ set_default_config(&ndpi_str->cfg);
NDPI_BITMASK_SET_ALL(ndpi_str->detection_bitmask);
ndpi_str->user_data = NULL;
@@ -3525,6 +3519,8 @@ void ndpi_finalize_initialization(struct ndpi_detection_module_struct *ndpi_str)
if(!ndpi_str)
return;
+ if(ndpi_str->finalized) /* Already finalized */
+ return;
ndpi_add_domain_risk_exceptions(ndpi_str);
@@ -3608,6 +3604,10 @@ void ndpi_finalize_initialization(struct ndpi_detection_module_struct *ndpi_str)
}
ndpi_str->ac_automa_finalized = 1;
+
+ ndpi_str->finalized = 1;
+
+ return;
}
/* *********************************************** */
@@ -4514,6 +4514,76 @@ static int ndpi_handle_rule(struct ndpi_detection_module_struct *ndpi_str,
/*
* Format:
*
+ * <proto,param,value>
+ *
+ * Notes:
+ * - proto might be empty
+ * - empty lines or lines starting with # are ignored
+ */
+int load_config_file_fd(struct ndpi_detection_module_struct *ndpi_str, FILE *fd) {
+ char buffer[512], *line, *proto, *param = NULL, *value, *saveptr;
+ int len, i, num_commas;
+ ndpi_cfg_error rc;
+
+ if(!ndpi_str || !fd)
+ return -1;
+
+ while(1) {
+ line = fgets(buffer, sizeof(buffer), fd);
+
+ if(line == NULL)
+ break;
+
+ len = strlen(line);
+
+ if((len <= 1) || (line[0] == '#'))
+ continue;
+
+ line[len - 1] = '\0';
+
+ /* First parameter might be missing */
+ num_commas = 0;
+ for(i = 0; i < len; i++) {
+ if(line[i] == ',')
+ num_commas++;
+ }
+
+ if(num_commas == 1) {
+ proto = NULL;
+ param = strtok_r(line, ",", &saveptr);
+ } else if(num_commas == 2) {
+ proto = strtok_r(line, ",", &saveptr);
+ if(proto) {
+ param = strtok_r(NULL, ",", &saveptr);
+ }
+ } else {
+ NDPI_LOG_ERR(ndpi_str, "Error parsing [%s]\n", line);
+ continue;
+ }
+
+ if(param) {
+ value = strtok_r(NULL, ",", &saveptr);
+ if(value) {
+ rc = ndpi_set_config(ndpi_str, proto, param, value);
+ if(rc < NDPI_CFG_OK) {
+ NDPI_LOG_ERR(ndpi_str, "Error ndpi_set_config [%s/%s/%s]: %d\n",
+ proto, param, value, rc);
+ return rc;
+ }
+ continue;
+ }
+ }
+ NDPI_LOG_ERR(ndpi_str, "Error parsing [%s]\n", line);
+ return -2;
+ }
+ return 0;
+}
+
+/* ******************************************************************** */
+
+/*
+ * Format:
+ *
* <host|ip> <category_id>
*
* Notes:
@@ -7879,7 +7949,7 @@ static ndpi_protocol ndpi_internal_detection_process_packet(struct ndpi_detectio
memset(&ret, 0, sizeof(ret));
- if((!flow) || (!ndpi_str))
+ if((!flow) || (!ndpi_str) || (ndpi_str->finalized != 1))
return(ret);
packet = &ndpi_str->packet;
@@ -7898,7 +7968,7 @@ static ndpi_protocol ndpi_internal_detection_process_packet(struct ndpi_detectio
return(ret);
}
- if(ndpi_str->max_packets_to_process > 0 && flow->num_processed_pkts >= ndpi_str->max_packets_to_process) {
+ if(ndpi_str->cfg.max_packets_to_process > 0 && flow->num_processed_pkts >= ndpi_str->cfg.max_packets_to_process) {
flow->extra_packets_func = NULL; /* To allow ndpi_extra_dissection_possible() to fail */
flow->fail_with_unknown = 1;
return(ret); /* Avoid spending too much time with this flow */
@@ -10685,3 +10755,359 @@ void *ndpi_get_user_data(struct ndpi_detection_module_struct *ndpi_str)
return ndpi_str->user_data;
return NULL;
}
+
+/* ******************************************************************** */
+
+static u_int16_t __get_proto_id(const char *proto_name_or_id)
+{
+ struct ndpi_detection_module_struct *module;
+ NDPI_PROTOCOL_BITMASK all;
+ u_int16_t proto_id;
+ char *endptr;
+ long val;
+
+ /* Let try to decode the string as numerical protocol id */
+ /* We can't easily use ndpi_strtonum because we want to be sure that there are no
+ others characters after the number */
+ errno = 0; /* To distinguish success/failure after call */
+ val = strtol(proto_name_or_id, &endptr, 10);
+ if(errno == 0 && *endptr == '\0' &&
+ (val >= 0 && val < NDPI_MAX_SUPPORTED_PROTOCOLS + NDPI_MAX_NUM_CUSTOM_PROTOCOLS)) {
+ return val;
+
+ }
+
+ /* Try to decode the string as protocol name */
+ /* Use a temporary module with all protocols enabled */
+ module = ndpi_init_detection_module(ndpi_no_prefs);
+ if(!module)
+ return -1;
+ NDPI_BITMASK_SET_ALL(all);
+ ndpi_set_protocol_detection_bitmask2(module, &all);
+ /* Try to be fast: we need only the protocol name -> protocol id mapping! */
+ /* TODO */
+ ndpi_set_config(module, "any", "ip_list.load", "0");
+ ndpi_set_config(module, NULL, "flow_risk_lists.load", "0");
+ ndpi_finalize_initialization(module);
+ proto_id = ndpi_get_proto_by_name(module, proto_name_or_id);
+ ndpi_exit_detection_module(module);
+
+ return proto_id;
+}
+
+static ndpi_cfg_error _set_param_enable_disable(struct ndpi_detection_module_struct *ndpi_str,
+ void *_variable, const char *value,
+ const char *min_value, const char *max_value,
+ const char *proto)
+{
+ int *variable = (int *)_variable;
+
+ if(strcmp(value, "1") == 0 ||
+ strcmp(value, "enable") == 0) {
+ *variable = 1;
+ return NDPI_CFG_OK;
+ }
+ if(strcmp(value, "0") == 0 ||
+ strcmp(value, "disable") == 0) {
+ *variable = 0;
+ return NDPI_CFG_OK;
+ }
+ return NDPI_CFG_INVALID_PARAM;
+}
+
+static ndpi_cfg_error _set_param_int(struct ndpi_detection_module_struct *ndpi_str,
+ void *_variable, const char *value,
+ const char *min_value, const char *max_value,
+ const char *proto)
+{
+ int *variable = (int *)_variable;
+ const char *errstrp;
+ long val;
+
+ val = ndpi_strtonum(value, LONG_MIN, LONG_MAX, &errstrp, 0);
+ if(errstrp) {
+ return NDPI_CFG_INVALID_PARAM;
+ }
+
+ *variable = val;
+
+ /* Min and max values are set in the code, so we can convert them
+ to integers without too many checks...*/
+ if(min_value && max_value &&
+ (val < strtol(min_value, NULL, 0) || val > strtol(max_value, NULL, 0)))
+ return NDPI_CFG_INVALID_PARAM;
+
+ return NDPI_CFG_OK;
+}
+
+static char *_get_param_int(void *_variable, const char *proto, char *buf, int buf_len)
+{
+ int *variable = (int *)_variable;
+
+ snprintf(buf, buf_len, "%d", *variable);
+ buf[buf_len - 1] = '\0';
+ return buf;
+}
+
+static char *_get_param_string(void *_variable, const char *proto, char *buf, int buf_len)
+{
+ char *variable = (char *)_variable;
+
+ snprintf(buf, buf_len, "%s", variable);
+ buf[buf_len - 1] = '\0';
+ return buf;
+}
+
+static ndpi_cfg_error _set_param_filename(struct ndpi_detection_module_struct *ndpi_str,
+ void *_variable, const char *value,
+ const char *min_value, const char *max_value,
+ const char *proto)
+{
+ char *variable = (char *)_variable;
+
+ if(value == NULL) { /* Valid value */
+ variable[0] = '\0';
+ return NDPI_CFG_OK;
+ }
+
+ if(access(value, F_OK) != 0)
+ return NDPI_CFG_INVALID_PARAM;
+ strncpy(variable, value, CFG_MAX_LEN);
+ return NDPI_CFG_OK;
+}
+
+static ndpi_cfg_error _set_param_filename_config(struct ndpi_detection_module_struct *ndpi_str,
+ void *_variable, const char *value,
+ const char *min_value, const char *max_value,
+ const char *proto)
+{
+ int rc;
+ FILE *fd;
+
+ rc = _set_param_filename(ndpi_str, _variable, value, min_value, max_value, proto);
+ if(rc != 0 || value == NULL || ndpi_str == NULL)
+ return rc;
+
+ fd = fopen(value, "r");
+ if(fd == NULL)
+ return NDPI_CFG_INVALID_PARAM; /* It shoudn't happen because we already checked it */
+ rc = load_config_file_fd(ndpi_str, fd);
+ fclose(fd);
+ if(rc < 0)
+ return rc;
+
+ return NDPI_CFG_OK;
+}
+
+
+static char *_get_param_protocol_enable_disable(void *_variable, const char *proto, char *buf, int buf_len)
+{
+ NDPI_PROTOCOL_BITMASK *bitmask = (NDPI_PROTOCOL_BITMASK *)_variable;
+ u_int16_t proto_id;
+
+ proto_id = __get_proto_id(proto);
+ if(proto_id == NDPI_PROTOCOL_UNKNOWN)
+ return NULL;
+
+ snprintf(buf, buf_len, "%d", !!NDPI_ISSET(bitmask, proto_id));
+ buf[buf_len - 1] = '\0';
+ return buf;
+}
+
+static ndpi_cfg_error _set_param_protocol_enable_disable(struct ndpi_detection_module_struct *ndpi_str,
+ void *_variable, const char *value,
+ const char *min_value, const char *max_value,
+ const char *proto)
+{
+ NDPI_PROTOCOL_BITMASK *bitmask = (NDPI_PROTOCOL_BITMASK *)_variable;
+ u_int16_t proto_id;
+
+ if(strcmp(proto, "any") == 0 ||
+ strcmp(proto, "all") == 0 ||
+ strcmp(proto, "$PROTO_NAME_OR_ID") == 0) {
+ if(strcmp(value, "1") == 0 ||
+ strcmp(value, "enable") == 0) {
+ NDPI_BITMASK_SET_ALL(*bitmask);
+ return NDPI_CFG_OK;
+ }
+ if(strcmp(value, "0") == 0 ||
+ strcmp(value, "disable") == 0) {
+ NDPI_BITMASK_RESET(*bitmask);
+ return NDPI_CFG_OK;
+ }
+ }
+
+ proto_id = __get_proto_id(proto);
+ if(proto_id == NDPI_PROTOCOL_UNKNOWN)
+ return NDPI_CFG_INVALID_PARAM;
+
+ if(strcmp(value, "1") == 0 ||
+ strcmp(value, "enable") == 0) {
+ NDPI_BITMASK_ADD(*bitmask, proto_id);
+ return NDPI_CFG_OK;
+ }
+ if(strcmp(value, "0") == 0 ||
+ strcmp(value, "disable") == 0) {
+ NDPI_BITMASK_DEL(*bitmask, proto_id);
+ return NDPI_CFG_OK;
+ }
+ return NDPI_CFG_INVALID_PARAM;
+}
+
+
+enum cfg_param_type {
+ CFG_PARAM_ENABLE_DISABLE = 0,
+ CFG_PARAM_INT,
+ CFG_PARAM_PROTOCOL_ENABLE_DISABLE,
+ CFG_PARAM_FILENAME_CONFIG, /* We call ndpi_set_config() immediately for each row in it */
+};
+
+typedef ndpi_cfg_error (*cfg_set)(struct ndpi_detection_module_struct *ndpi_str,
+ void *_variable, const char *value,
+ const char *min_value, const char *max_value,
+ const char *proto);
+typedef char *(*cfg_get)(void *_variable, const char *proto, char *buf, int buf_len);
+
+static const struct cfg_op {
+ enum cfg_param_type type;
+ cfg_set fn_set;
+ cfg_get fn_get;
+} cfg_ops[] = {
+ { CFG_PARAM_ENABLE_DISABLE, _set_param_enable_disable, _get_param_int },
+ { CFG_PARAM_INT, _set_param_int, _get_param_int },
+ { CFG_PARAM_PROTOCOL_ENABLE_DISABLE, _set_param_protocol_enable_disable, _get_param_protocol_enable_disable },
+ { CFG_PARAM_FILENAME_CONFIG, _set_param_filename_config, _get_param_string },
+};
+
+#define __OFF(a) offsetof(struct ndpi_detection_module_config_struct, a)
+
+static const struct cfg_param {
+ char *proto;
+ char *param;
+ char *default_value;
+ char *min_value;
+ char *max_value;
+ enum cfg_param_type type;
+ int offset;
+} cfg_params[] = {
+ /* Per-protocol parameters */
+
+ { "tls", "metadata.sha1_fingerprint.enable", "1", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(tls_sha1_fingerprint_enabled) },
+
+ /* Global parameters */
+
+ { NULL, "packets_limit_per_flow", "32", "0", "255", CFG_PARAM_INT, __OFF(max_packets_to_process) },
+
+ { NULL, "filename.config", NULL, NULL, NULL, CFG_PARAM_FILENAME_CONFIG, __OFF(filename_config) },
+
+ { NULL, NULL, NULL, NULL, NULL, 0, -1 },
+};
+
+#undef __OFF
+
+static void set_default_config(struct ndpi_detection_module_config_struct *cfg)
+{
+ const struct cfg_param *c;
+
+ for(c = &cfg_params[0]; c && c->param; c++) {
+ cfg_ops[c->type].fn_set(NULL, (void *)((char *)cfg + c->offset),
+ c->default_value, c->min_value, c->max_value, c->proto);
+ }
+}
+
+ndpi_cfg_error ndpi_set_config(struct ndpi_detection_module_struct *ndpi_str,
+ const char *proto, const char *param, const char *value)
+{
+ const struct cfg_param *c;
+ ndpi_cfg_error rc;
+
+ if(!ndpi_str || !param || !value)
+ return NDPI_CFG_INVALID_CONTEXT;
+ if(ndpi_str->finalized)
+ return NDPI_CFG_CONTEXT_ALREADY_INITIALIZED;
+
+ NDPI_LOG_DBG(ndpi_str, "Set [%s][%s][%s]\n", proto, param, value);
+
+ for(c = &cfg_params[0]; c && c->param; c++) {
+ if((((proto == NULL && c->proto == NULL) ||
+ (proto && c->proto && strcmp(proto, c->proto) == 0)) &&
+ strcmp(param, c->param) == 0) ||
+ (proto && c->proto &&
+ strcmp(c->proto, "$PROTO_NAME_OR_ID") == 0 &&
+ strcmp(param, c->param) == 0)) {
+
+ rc = cfg_ops[c->type].fn_set(ndpi_str, (void *)((char *)&ndpi_str->cfg + c->offset),
+ value, c->min_value, c->max_value, proto);
+ return rc;
+ }
+ }
+ return NDPI_CFG_NOT_FOUND;
+}
+
+char *ndpi_get_config(struct ndpi_detection_module_struct *ndpi_str,
+ const char *proto, const char *param, char *buf, int buf_len)
+{
+ const struct cfg_param *c;
+
+ if(!ndpi_str || !param || !buf || buf_len <= 0)
+ return NULL;
+
+ NDPI_LOG_ERR(ndpi_str, "Get [%s][%s]\n", proto, param);
+
+ for(c = &cfg_params[0]; c && c->param; c++) {
+ if(((proto == NULL && c->proto == NULL) ||
+ (proto && c->proto && strcmp(proto, c->proto) == 0)) &&
+ strcmp(param, c->param) == 0) {
+
+ return cfg_ops[c->type].fn_get((void *)((char *)&ndpi_str->cfg + c->offset), proto, buf, buf_len);
+ }
+ }
+ return NULL;
+}
+
+char *ndpi_dump_config(struct ndpi_detection_module_struct *ndpi_str,
+ FILE *fd)
+{
+ const struct cfg_param *c;
+ char buf[64];
+
+ if(!ndpi_str || !fd)
+ return NULL;
+
+ fprintf(fd, " Protocol (empty/NULL for global knobs), parameter, value, [default value], [min value, max_value]\n");
+
+ /* TODO */
+ for(c = &cfg_params[0]; c && c->param; c++) {
+ switch(c->type) {
+ case CFG_PARAM_ENABLE_DISABLE:
+ case CFG_PARAM_INT:
+ fprintf(fd, " *) %s %s: %s [%s]",
+ c->proto ? c->proto : "NULL",
+ c->param,
+ _get_param_int((void *)((char *)&ndpi_str->cfg + c->offset), c->proto, buf, sizeof(buf)),
+ c->default_value);
+ if(c->min_value && c->max_value)
+ fprintf(fd, " [%s-%s]", c->min_value, c->max_value);
+ fprintf(fd, "\n");
+ break;
+ case CFG_PARAM_FILENAME_CONFIG:
+ fprintf(fd, " *) %s %s: %s [%s]",
+ c->proto ? c->proto : "NULL",
+ c->param,
+ _get_param_string((void *)((char *)&ndpi_str->cfg + c->offset), c->proto, buf, sizeof(buf)),
+ c->default_value);
+ fprintf(fd, "\n");
+ break;
+ /* TODO */
+ case CFG_PARAM_PROTOCOL_ENABLE_DISABLE:
+ fprintf(fd, " *) %s %s: %s [all %s]",
+ c->proto ? c->proto : "NULL",
+ c->param,
+ /* TODO */ _get_param_protocol_enable_disable((void *)((char *)&ndpi_str->cfg + c->offset), "any", buf, sizeof(buf)),
+ c->default_value);
+ fprintf(fd, "\n");
+ break;
+ }
+ }
+ return NULL;
+}
diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c
index 485357e06..943b817a4 100644
--- a/src/lib/protocols/tls.c
+++ b/src/lib/protocols/tls.c
@@ -772,7 +772,6 @@ int processCertificate(struct ndpi_detection_module_struct *ndpi_struct,
u_int32_t certificates_length, length = (packet->payload[1] << 16) + (packet->payload[2] << 8) + packet->payload[3];
u_int32_t certificates_offset = 7 + (is_dtls ? 8 : 0);
u_int8_t num_certificates_found = 0;
- SHA1_CTX srv_cert_fingerprint_ctx ;
#ifdef DEBUG_TLS
printf("[TLS] %s() [payload_packet_len=%u][direction: %u][%02X %02X %02X %02X %02X %02X...]\n",
@@ -824,9 +823,6 @@ int processCertificate(struct ndpi_detection_module_struct *ndpi_struct,
#endif
if(num_certificates_found++ == 0) /* Dissect only the first certificate that is the one we care */ {
- /* For SHA-1 we take into account only the first certificate and not all of them */
-
- SHA1Init(&srv_cert_fingerprint_ctx);
#ifdef DEBUG_CERTIFICATE_HASH
{
@@ -839,36 +835,42 @@ int processCertificate(struct ndpi_detection_module_struct *ndpi_struct,
}
#endif
- SHA1Update(&srv_cert_fingerprint_ctx,
- &packet->payload[certificates_offset],
- certificate_len);
-
- SHA1Final(flow->protos.tls_quic.sha1_certificate_fingerprint, &srv_cert_fingerprint_ctx);
-
- flow->protos.tls_quic.fingerprint_set = 1;
-
- uint8_t * sha1 = flow->protos.tls_quic.sha1_certificate_fingerprint;
- const size_t sha1_siz = sizeof(flow->protos.tls_quic.sha1_certificate_fingerprint);
- char sha1_str[20 /* sha1_siz */ * 2 + 1];
- static const char hexalnum[] = "0123456789ABCDEF";
- size_t i;
- for (i = 0; i < sha1_siz; ++i) {
- u_int8_t lower = (sha1[i] & 0x0F);
- u_int8_t upper = (sha1[i] & 0xF0) >> 4;
- sha1_str[i*2] = hexalnum[upper];
- sha1_str[i*2 + 1] = hexalnum[lower];
- }
- sha1_str[sha1_siz * 2] = '\0';
+ /* For SHA-1 we take into account only the first certificate and not all of them */
+ if(ndpi_struct->cfg.tls_sha1_fingerprint_enabled) {
+ SHA1_CTX srv_cert_fingerprint_ctx ;
+
+ SHA1Init(&srv_cert_fingerprint_ctx);
+ SHA1Update(&srv_cert_fingerprint_ctx,
+ &packet->payload[certificates_offset],
+ certificate_len);
+
+ SHA1Final(flow->protos.tls_quic.sha1_certificate_fingerprint, &srv_cert_fingerprint_ctx);
+
+ flow->protos.tls_quic.fingerprint_set = 1;
+
+ uint8_t * sha1 = flow->protos.tls_quic.sha1_certificate_fingerprint;
+ const size_t sha1_siz = sizeof(flow->protos.tls_quic.sha1_certificate_fingerprint);
+ char sha1_str[20 /* sha1_siz */ * 2 + 1];
+ static const char hexalnum[] = "0123456789ABCDEF";
+ size_t i;
+ for (i = 0; i < sha1_siz; ++i) {
+ u_int8_t lower = (sha1[i] & 0x0F);
+ u_int8_t upper = (sha1[i] & 0xF0) >> 4;
+ sha1_str[i*2] = hexalnum[upper];
+ sha1_str[i*2 + 1] = hexalnum[lower];
+ }
+ sha1_str[sha1_siz * 2] = '\0';
#ifdef DEBUG_TLS
- printf("[TLS] SHA-1: %s\n", sha1_str);
+ printf("[TLS] SHA-1: %s\n", sha1_str);
#endif
- if(ndpi_struct->malicious_sha1_hashmap != NULL) {
- u_int16_t rc1 = ndpi_hash_find_entry(ndpi_struct->malicious_sha1_hashmap, sha1_str, sha1_siz * 2, NULL);
+ if(ndpi_struct->malicious_sha1_hashmap != NULL) {
+ u_int16_t rc1 = ndpi_hash_find_entry(ndpi_struct->malicious_sha1_hashmap, sha1_str, sha1_siz * 2, NULL);
- if(rc1 == 0)
- ndpi_set_risk(ndpi_struct, flow, NDPI_MALICIOUS_SHA1_CERTIFICATE, sha1_str);
+ if(rc1 == 0)
+ ndpi_set_risk(ndpi_struct, flow, NDPI_MALICIOUS_SHA1_CERTIFICATE, sha1_str);
+ }
}
processCertificateElements(ndpi_struct, flow, certificates_offset, certificate_len);
diff --git a/tests/cfgs/disable_metadata/config.txt b/tests/cfgs/disable_metadata/config.txt
new file mode 100644
index 000000000..1e5e30bf8
--- /dev/null
+++ b/tests/cfgs/disable_metadata/config.txt
@@ -0,0 +1 @@
+--cfg=tls,metadata.sha1_fingerprint.enable,0
diff --git a/tests/cfgs/disable_metadata/pcap/tls_verylong_certificate.pcap b/tests/cfgs/disable_metadata/pcap/tls_verylong_certificate.pcap
new file mode 120000
index 000000000..2f722f28e
--- /dev/null
+++ b/tests/cfgs/disable_metadata/pcap/tls_verylong_certificate.pcap
@@ -0,0 +1 @@
+../../default/pcap/tls_verylong_certificate.pcap \ No newline at end of file
diff --git a/tests/cfgs/disable_metadata/result/tls_verylong_certificate.pcap.out b/tests/cfgs/disable_metadata/result/tls_verylong_certificate.pcap.out
new file mode 100644
index 000000000..049a4cec0
--- /dev/null
+++ b/tests/cfgs/disable_metadata/result/tls_verylong_certificate.pcap.out
@@ -0,0 +1,33 @@
+DPI Packets (TCP): 11 (11.00 pkts/flow)
+Confidence DPI : 1 (flows)
+Num dissector calls: 1 (1.00 diss/flow)
+LRU cache ookla: 0/0/0 (insert/search/found)
+LRU cache bittorrent: 0/0/0 (insert/search/found)
+LRU cache zoom: 0/0/0 (insert/search/found)
+LRU cache stun: 0/0/0 (insert/search/found)
+LRU cache tls_cert: 0/0/0 (insert/search/found)
+LRU cache mining: 0/0/0 (insert/search/found)
+LRU cache msteams: 0/0/0 (insert/search/found)
+LRU cache stun_zoom: 0/0/0 (insert/search/found)
+Automa host: 1/1 (search/found)
+Automa domain: 1/0 (search/found)
+Automa tls cert: 0/0 (search/found)
+Automa risk mask: 0/0 (search/found)
+Automa common alpns: 1/1 (search/found)
+Patricia risk mask: 0/0 (search/found)
+Patricia risk mask IPv6: 0/0 (search/found)
+Patricia risk: 0/0 (search/found)
+Patricia risk IPv6: 0/0 (search/found)
+Patricia protocols: 2/0 (search/found)
+Patricia protocols IPv6: 0/0 (search/found)
+
+Cybersec 48 22229 1
+
+Safe 48 22229 1
+
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.1.160 1
+
+
+ 1 TCP 192.168.1.160:54804 <-> 151.101.66.49:443 [proto: 91.283/TLS.Cybersec][IP: 0/Unknown][Encrypted][Confidence: DPI][DPI packets: 11][cat: Cybersecurity/33][24 pkts/2404 bytes <-> 24 pkts/19825 bytes][Goodput ratio: 35/92][0.09 sec][Hostname/SNI: feodotracker.abuse.ch][(Advertised) ALPNs: http/1.1][(Negotiated) ALPN: http/1.1][bytes ratio: -0.784 (Download)][IAT c2s/s2c min/avg/max/stddev: 0/0 4/4 15/21 5/7][Pkt Len c2s/s2c min/avg/max/stddev: 54/66 100/826 583/1434 109/662][TLSv1.2][JA3C: 2a26b1a62e40d25d4de3babc9d532f30][JA4: t12d6707ht_2955a3196ffa_b1760ac0ffd7][ServerNames: p2.shared.global.fastly.net,*.12wbt.com,*.2bleacherreport.com,*.3bleacherreport.com,*.4bleacherreport.com,*.8bleacherreport.com,*.abuse.ch,*.acdn-it.ps-pantheon.com,*.cdn.livingmap.com,*.content.plastiq.com,*.dimensions.ai,*.dollarshaveclub.co.uk,*.dollarshaveclub.com,*.dontpayfull.com,*.ebisubook.com,*.foreignaffairs.com,*.fs.jibjab.com,*.fs.unitprints.com,*.ggleap.com,*.goodeggs.com,*.huevosbuenos.com,*.indy.myomnigon.com,*.jwatch.org,*.kingsfordcharcoal.com.au,*.lancenters.com,*.madebywe.com,*.minirodini.com,*.modcloth.net,*.orionlabs.io,*.ps-pantheon.com,*.scodle.com,*.steelseries.com,*.theforeman.org,*.uploads.eversign.com,*.uploads.schoox.com,*.vts.com,*.x.stg1.ebisubook.com,*.yang2020.com,12wbt.com,2bleacherreport.com,3bleacherreport.com,4bleacherreport.com,8bleacherreport.com,abuse.ch,brita.com,cdn.fwupd.org,cdn.livingmap.com,cdn.seated.com,cdn.skillacademy.com,clinicaloptions.com,clorox.com,content-preprod.beaverbrooksweb2.co.uk,content.beaverbrooks.co.uk,content.plastiq.com,coolmathgames.com,copterroyale.coolmathgames.com,d8-dev.coolmathgames.com,deflyio.coolmathgames.com,delivery-api.evadacms.com,dimensions.ai,dollarshaveclub.co.uk,dollarshaveclub.com,dontpayfull.com,eluniverso.com,email.amg-group.co,email.tekoforlife.co.uk,feedmarket.fr,freshstep.com,ggleap.com,goodeggs.com,heap.io,huevosbuenos.com,identity.linuxfoundation.org,joebiden.com,jwatch.org,kingsford.co.nz,kingsfordcharcoal.com.au,lancenters.com,lists.linuxfoundation.org,m-stage.coolmathgames.com,m.coolmathgames.com,madebywe.com,minirodini.com,modcloth.net,orionlabs.io,puritanmedproducts.com,reviews.org,rg-video-staging.ruangguru.com,rg-video.ruangguru.com,ruangguru.com,scodle.com,stage.coolmathgames.com,staging.appblade.com,steelseries.com,stg.platform.eluniverso.com,test.brita.com,test.heap.io,test.joebiden.com,test.ruangguru.com,theforeman.org,video-cdn.quipper.com,videos.calcworkshop.com,vts.com,www.101network.com,www.autos101.com,www.brita.com,www.clorox.com,www.collider.com,www.coolmathgames.com,www.eluniverso.com,www.flinto.com,www.freshstep.com,www.heap.io,www.holagente.com,www.icsydney.com.au,www.joebiden.com,www.kingsford.co.nz,www.mrnatty.com,www.myjewellerystory.com.au,www.myjs.com,www.netacea.com,www.parenting101.com,www.puritanmedproducts.com,www.reviews.org,www.sba.sa,www.shashatcom.sa,www.uat.ontariocolleges.ca,www.vacation101.com,www.walterspeople.co.uk,www.westwayelectricsupply.com][JA3S: ae53107a2e47ea20c72ac44821a728bf][Issuer: C=BE, O=GlobalSign nv-sa, CN=GlobalSign CloudSSL CA - SHA256 - G3][Subject: C=US, ST=California, L=San Francisco, O=Fastly, Inc., CN=p2.shared.global.fastly.net][Firefox][Validity: 2019-11-19 01:31:22 - 2020-08-29 17:19:32][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256][Plen Bins: 12,16,0,4,0,4,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,0,0,0,0,0]
diff --git a/tests/cfgs/packets_limit_per_flow/config.txt b/tests/cfgs/packets_limit_per_flow/config.txt
new file mode 100644
index 000000000..df3eed5d2
--- /dev/null
+++ b/tests/cfgs/packets_limit_per_flow/config.txt
@@ -0,0 +1 @@
+--cfg=packets_limit_per_flow,4
diff --git a/tests/cfgs/packets_limit_per_flow/pcap/tls_verylong_certificate.pcap b/tests/cfgs/packets_limit_per_flow/pcap/tls_verylong_certificate.pcap
new file mode 120000
index 000000000..2f722f28e
--- /dev/null
+++ b/tests/cfgs/packets_limit_per_flow/pcap/tls_verylong_certificate.pcap
@@ -0,0 +1 @@
+../../default/pcap/tls_verylong_certificate.pcap \ No newline at end of file
diff --git a/tests/cfgs/packets_limit_per_flow/result/tls_verylong_certificate.pcap.out b/tests/cfgs/packets_limit_per_flow/result/tls_verylong_certificate.pcap.out
new file mode 100644
index 000000000..19f147637
--- /dev/null
+++ b/tests/cfgs/packets_limit_per_flow/result/tls_verylong_certificate.pcap.out
@@ -0,0 +1,33 @@
+DPI Packets (TCP): 5 (5.00 pkts/flow)
+Confidence DPI : 1 (flows)
+Num dissector calls: 1 (1.00 diss/flow)
+LRU cache ookla: 0/0/0 (insert/search/found)
+LRU cache bittorrent: 0/0/0 (insert/search/found)
+LRU cache zoom: 0/0/0 (insert/search/found)
+LRU cache stun: 0/0/0 (insert/search/found)
+LRU cache tls_cert: 0/0/0 (insert/search/found)
+LRU cache mining: 0/0/0 (insert/search/found)
+LRU cache msteams: 0/0/0 (insert/search/found)
+LRU cache stun_zoom: 0/0/0 (insert/search/found)
+Automa host: 1/1 (search/found)
+Automa domain: 1/0 (search/found)
+Automa tls cert: 0/0 (search/found)
+Automa risk mask: 0/0 (search/found)
+Automa common alpns: 1/1 (search/found)
+Patricia risk mask: 0/0 (search/found)
+Patricia risk mask IPv6: 0/0 (search/found)
+Patricia risk: 0/0 (search/found)
+Patricia risk IPv6: 0/0 (search/found)
+Patricia protocols: 2/0 (search/found)
+Patricia protocols IPv6: 0/0 (search/found)
+
+Cybersec 48 22229 1
+
+Safe 48 22229 1
+
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.1.160 1
+
+
+ 1 TCP 192.168.1.160:54804 <-> 151.101.66.49:443 [proto: 91.283/TLS.Cybersec][IP: 0/Unknown][Encrypted][Confidence: DPI][DPI packets: 5][cat: Cybersecurity/33][24 pkts/2404 bytes <-> 24 pkts/19825 bytes][Goodput ratio: 35/92][0.09 sec][Hostname/SNI: feodotracker.abuse.ch][(Advertised) ALPNs: http/1.1][bytes ratio: -0.784 (Download)][IAT c2s/s2c min/avg/max/stddev: 0/0 4/4 15/21 5/7][Pkt Len c2s/s2c min/avg/max/stddev: 54/66 100/826 583/1434 109/662][TLSv1.2][JA3C: 2a26b1a62e40d25d4de3babc9d532f30][JA4: t12d6707ht_2955a3196ffa_b1760ac0ffd7][Firefox][Plen Bins: 12,16,0,4,0,4,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,0,0,0,0,0]
diff --git a/tests/do.sh.in b/tests/do.sh.in
index b71618f9b..e8a08f035 100755
--- a/tests/do.sh.in
+++ b/tests/do.sh.in
@@ -30,7 +30,7 @@ PCRE2_ENABLED=@PCRE2_ENABLED@
PCRE_PCAPS="WebattackRCE.pcap"
NBPF_ENABLED=@NBPF_ENABLED@
NBPF_PCAPS="h323-overflow.pcap"
-READER="${CMD_PREFIX} ../../../example/ndpiReader${EXE_SUFFIX} -A -p ../../../example/protos.txt -c ../../../example/categories.txt -r ../../../example/risky_domains.txt -j ../../../example/ja3_fingerprints.csv -S ../../../example/sha1_fingerprints.csv -G ../../../lists -q -K JSON -k /dev/null -t -v 2"
+READER="${CMD_PREFIX} ../../../example/ndpiReader${EXE_SUFFIX} --cfg=filename.config,../../../example/config.txt -A -p ../../../example/protos.txt -c ../../../example/categories.txt -r ../../../example/risky_domains.txt -j ../../../example/ja3_fingerprints.csv -S ../../../example/sha1_fingerprints.csv -G ../../../lists -q -K JSON -k /dev/null -t -v 2"
RC=0
diff --git a/tests/ossfuzz.sh b/tests/ossfuzz.sh
index e2adb3bf8..d41454b2d 100644
--- a/tests/ossfuzz.sh
+++ b/tests/ossfuzz.sh
@@ -59,6 +59,7 @@ cp example/categories.txt $OUT/
cp example/risky_domains.txt $OUT/
cp example/ja3_fingerprints.csv $OUT/
cp example/sha1_fingerprints.csv $OUT/
+cp example/config.txt $OUT/
cp fuzz/ipv4_addresses.txt $OUT/
cp fuzz/bd_param.txt $OUT/
cp fuzz/splt_param.txt $OUT/