Skip to content

Commit

Permalink
Add generic functions for library configuration
Browse files Browse the repository at this point in the history
This is a new way to provide (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 this function prototype is as
agnostic as possible.

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.

Two examples of how to extend the configuration 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
  • Loading branch information
IvanNardi committed Dec 1, 2023
1 parent c34bded commit 3c1f7ac
Show file tree
Hide file tree
Showing 14 changed files with 411 additions and 50 deletions.
9 changes: 9 additions & 0 deletions doc/configuration_parameters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

# Configuration knobs

TODO

| Protocol | Parameter | Default value | Min value | Max value | Description |
| ------ | ------ | ------ | ------ | ------ | ------ |
| 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)|
| "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 |
98 changes: 89 additions & 9 deletions example/ndpiReader.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,16 @@ u_int8_t enable_protocol_guess = 1, enable_payload_analyzer = 0, num_bin_cluster
u_int8_t verbose = 0, enable_flow_stats = 0;
int stun_monitoring_pkts_to_process = -1; /* Default */
int stun_monitoring_flags = -1; /* Default */

struct cfg {
char *proto;
char *param;
char *value;
};
#define MAX_NUM_CFGS 16
static struct cfg cfgs[MAX_NUM_CFGS];
static int num_cfgs = 0;

int nDPI_LogLevel = 0;
char *_debug_protocols = NULL;
char *_disabled_protocols = NULL;
Expand Down Expand Up @@ -594,11 +604,20 @@ static void help(u_int long_help) {
" --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"
" --stun-monitoring=<pkts>:<flags> | Configure STUN monitoring: keep monitoring STUN session for <pkts> more pkts looking for RTP\n"
" | (0:0 to disable the feature); set the specified features in <flags>\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,
max_num_reported_top_payloads, max_num_tcp_dissected_pkts, max_num_udp_dissected_pkts);

NDPI_PROTOCOL_BITMASK all;
ndpi_info_mod = ndpi_init_detection_module(init_prefs);
NDPI_BITMASK_SET_ALL(all);
ndpi_set_protocol_detection_bitmask2(ndpi_info_mod, &all);

printf("\nProtocols configuration parameters:\n");
ndpi_dump_config(ndpi_info_mod, stdout);

printf("\nLRU Cache names: ookla, bittorrent, zoom, stun, tls_cert, mining, msteams, stun_zoom\n");

#ifndef WIN32
Expand All @@ -621,24 +640,18 @@ 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;

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);
}
Expand All @@ -649,6 +662,8 @@ static void help(u_int long_help) {

#define OPTLONG_VALUE_STUN_MONITORING 2000

#define OPTLONG_VALUE_CFG 3000

static struct option longopts[] = {
/* mandatory extcap options */
{ "extcap-interfaces", no_argument, NULL, '0'},
Expand Down Expand Up @@ -694,6 +709,8 @@ static struct option longopts[] = {
{ "lru-cache-ttl", required_argument, NULL, OPTLONG_VALUE_LRU_CACHE_TTL},
{ "stun-monitoring", required_argument, NULL, OPTLONG_VALUE_STUN_MONITORING},

{ "cfg", required_argument, NULL, OPTLONG_VALUE_CFG},

{0, 0, 0, 0}
};

Expand Down Expand Up @@ -950,6 +967,42 @@ 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;

tmp_str = ndpi_strdup(param);
if(tmp_str) {
if(param[0] == ',') { /* First parameter might be missing */
s1_str = NULL;
s2_str = strtok_r(tmp_str, ",", &saveptr);
} else {
s1_str = strtok_r(tmp_str, ",", &saveptr);
if(s1_str) {
s2_str = strtok_r(NULL, ",", &saveptr);
}
}
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;
}

/* ********************************** */

/**
Expand All @@ -968,6 +1021,7 @@ static void parseOptions(int argc, char **argv) {
#endif
int cache_idx, cache_size, cache_ttl;
u_int32_t num_pkts, flags;
char *s1, *s2, *s3;

#ifdef USE_DPDK
{
Expand Down Expand Up @@ -1316,6 +1370,18 @@ static void parseOptions(int argc, char **argv) {
stun_monitoring_flags = flags;
break;

case OPTLONG_VALUE_CFG:
if(num_cfgs >= MAX_NUM_CFGS ||
parse_three_strings(optarg, &s1, &s2, &s3) == -1) {
printf("Invalid parameter [%s] [num:%d/%d]\n", optarg, num_cfgs, MAX_NUM_CFGS);
exit(1);
}
cfgs[num_cfgs].proto = s1;
cfgs[num_cfgs].param = s2;
cfgs[num_cfgs].value = s3;
num_cfgs++;
break;

default:
#ifdef DEBUG_TRACE
if(trace) fprintf(trace, " #### Unknown option -%c: skipping it #### \n", opt);
Expand Down Expand Up @@ -2669,7 +2735,7 @@ static void debug_printf(u_int32_t protocol, void *id_struct,
static void setupDetection(u_int16_t thread_id, pcap_t * pcap_handle) {
NDPI_PROTOCOL_BITMASK enabled_bitmask;
struct ndpi_workflow_prefs prefs;
int i;
int i, rc;

memset(&prefs, 0, sizeof(prefs));
prefs.decode_tunnels = decode_tunnels;
Expand Down Expand Up @@ -2757,6 +2823,14 @@ 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 != 0)
fprintf(stderr, "Error setting config [%s][%s][%s]: %d\n",
cfgs[i].proto, cfgs[i].param, cfgs[i].value, rc);
}

if(stun_monitoring_pkts_to_process != -1 &&
stun_monitoring_flags != -1)
ndpi_set_monitoring_state(ndpi_thread_info[thread_id].workflow->ndpi_struct, NDPI_PROTOCOL_STUN,
Expand Down Expand Up @@ -5684,6 +5758,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
Expand Down
9 changes: 9 additions & 0 deletions src/include/ndpi_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -2154,6 +2154,15 @@ extern "C" {

/* ******************************* */

int 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'))
Expand Down
1 change: 0 additions & 1 deletion src/include/ndpi_define.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down
9 changes: 8 additions & 1 deletion src/include/ndpi_typedefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1068,7 +1068,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;

Expand Down Expand Up @@ -1154,6 +1153,14 @@ struct ndpi_risk_information {
char *info;
};

struct ndpi_detection_module_config_struct {
int max_packets_to_process;

/* TLS */
int sha1_fingerprint_enabled;

};

struct ndpi_flow_struct {
u_int16_t detected_protocol_stack[NDPI_PROTOCOL_SIZE];

Expand Down
Loading

0 comments on commit 3c1f7ac

Please sign in to comment.