Skip to content

Commit

Permalink
STUN: keep monitoring/processing STUN flows
Browse files Browse the repository at this point in the history
Look for RTP packets in the STUN sessions.
TODO: tell RTP from RTCP
  • Loading branch information
IvanNardi committed Jun 17, 2023
1 parent ac06ba8 commit 58be36d
Show file tree
Hide file tree
Showing 17 changed files with 312 additions and 22 deletions.
47 changes: 45 additions & 2 deletions example/ndpiReader.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ static u_int8_t ignore_vlanid = 0;
/** User preferences **/
u_int8_t enable_protocol_guess = 1, enable_payload_analyzer = 0, num_bin_clusters = 0, extcap_exit = 0;
u_int8_t verbose = 0, enable_flow_stats = 0;
int stun_monitoring_pkts_to_process = -1; /* Default */
int stun_monitoring_flags = -1; /* Default */
int nDPI_LogLevel = 0;
char *_debug_protocols = NULL;
char *_disabled_protocols = NULL;
Expand Down Expand Up @@ -511,8 +513,10 @@ static void help(u_int long_help) {
" -A | Dump internal statistics (LRU caches / Patricia trees / Ahocarasick automas / ...\n"
" -M | Memory allocation stats on data-path (only by the library). It works only on single-thread configuration\n"
" -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"
" --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"
" --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"
,
human_readeable_string_len,
min_pattern_len, max_pattern_len, max_num_packets_per_flow, max_packet_payload_dissection,
Expand Down Expand Up @@ -566,6 +570,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_STUN_MONITORING 2000

static struct option longopts[] = {
/* mandatory extcap options */
{ "extcap-interfaces", no_argument, NULL, '0'},
Expand Down Expand Up @@ -608,6 +614,7 @@ 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},
{ "stun-monitoring", required_argument, NULL, OPTLONG_VALUE_STUN_MONITORING},

{0, 0, 0, 0}
};
Expand Down Expand Up @@ -844,6 +851,27 @@ static int parse_cache_param(char *param, int *cache_idx, int *param_value)
return -1;
}

static int parse_two_unsigned_integer(char *param, u_int32_t *num1, u_int32_t *num2)
{
char *saveptr, *tmp_str, *num1_str, *num2_str;

tmp_str = ndpi_strdup(param);
if(tmp_str) {
num1_str = strtok_r(tmp_str, ":", &saveptr);
if(num1_str) {
num2_str = strtok_r(NULL, ":", &saveptr);
if(num2_str) {
*num1 = atoi(num1_str);
*num2 = atoi(num2_str);
ndpi_free(tmp_str);
return 0;
}
}
}
ndpi_free(tmp_str);
return -1;
}

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

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

#ifdef USE_DPDK
{
Expand Down Expand Up @@ -1190,6 +1219,15 @@ static void parseOptions(int argc, char **argv) {
lru_cache_ttls[cache_idx] = cache_ttl;
break;

case OPTLONG_VALUE_STUN_MONITORING:
if(parse_two_unsigned_integer(optarg, &num_pkts, &flags) == -1) {
printf("Invalid parameter [%s]\n", optarg);
exit(1);
}
stun_monitoring_pkts_to_process = num_pkts;
stun_monitoring_flags = flags;
break;

default:
#ifdef DEBUG_TRACE
if(trace) fprintf(trace, " #### Unknown option -%c: skipping it #### \n", opt);
Expand Down Expand Up @@ -2625,6 +2663,11 @@ 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]);
}

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,
stun_monitoring_pkts_to_process, stun_monitoring_flags);

ndpi_finalize_initialization(ndpi_thread_info[thread_id].workflow->ndpi_struct);

if(enable_doh_dot_detection)
Expand Down
10 changes: 9 additions & 1 deletion fuzz/fuzz_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
struct ndpi_detection_module_struct *ndpi_info_mod;
struct ndpi_flow_struct flow;
u_int8_t protocol_was_guessed;
u_int32_t i, num;
u_int32_t i, num, num2;
u_int16_t random_proto, bool_value;
int random_value;
NDPI_PROTOCOL_BITMASK enabled_bitmask;
Expand All @@ -35,6 +35,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
6 + /* files */
((NDPI_LRUCACHE_MAX + 1) * 5) + /* LRU caches */
2 + 1 + 4 + /* ndpi_set_detection_preferences() */
1 + 3 + 1 + /* Monitoring */
7 + /* Opportunistic tls */
2 + /* Pid */
2 + /* Category */
Expand Down Expand Up @@ -98,6 +99,13 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
ndpi_set_detection_preferences(ndpi_info_mod, ndpi_pref_max_packets_to_process,
fuzzed_data.ConsumeIntegralInRange(0, (1 << 16)));

if(fuzzed_data.ConsumeBool()) {
ndpi_set_monitoring_state(ndpi_info_mod, NDPI_PROTOCOL_STUN,
fuzzed_data.ConsumeIntegralInRange(0, (1 << 16)),
fuzzed_data.ConsumeIntegralInRange(0, 7));
ndpi_get_monitoring_state(ndpi_info_mod, NDPI_PROTOCOL_STUN, &num, &num2);
}

ndpi_set_opportunistic_tls(ndpi_info_mod, NDPI_PROTOCOL_MAIL_SMTP, fuzzed_data.ConsumeBool());
ndpi_get_opportunistic_tls(ndpi_info_mod, NDPI_PROTOCOL_MAIL_SMTP);
ndpi_set_opportunistic_tls(ndpi_info_mod, NDPI_PROTOCOL_MAIL_IMAP, fuzzed_data.ConsumeBool());
Expand Down
6 changes: 6 additions & 0 deletions src/include/ndpi_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,12 @@ extern "C" {
u_int32_t ndpi_get_protocol_aggressiveness(struct ndpi_detection_module_struct *ndpi_struct,
u_int16_t proto);

int ndpi_set_monitoring_state(struct ndpi_detection_module_struct *ndpi_struct,
u_int16_t proto, u_int32_t num_pkts, u_int32_t flags);
int ndpi_get_monitoring_state(struct ndpi_detection_module_struct *ndpi_struct,
u_int16_t proto, u_int32_t *num_pkts, u_int32_t *flags);


/**
* Find a protocol id associated with a string automata
*
Expand Down
9 changes: 9 additions & 0 deletions src/include/ndpi_typedefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,12 @@ struct ndpi_lru_cache {
/* Ookla */
#define NDPI_AGGRESSIVENESS_OOKLA_TLS 0x01 /* Enable detection over TLS (using ookla cache) */


/* Monitoring flags */

/* Stun */
#define NDPI_MONITORING_STUN_SUBCLASSIFIED 0x01 /* Monitor STUN flows even if we have a valid sub-protocol */

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

struct ndpi_flow_tcp_struct {
Expand Down Expand Up @@ -1301,6 +1307,9 @@ struct ndpi_detection_module_struct {
int opportunistic_tls_pop_enabled;
int opportunistic_tls_ftp_enabled;

u_int32_t monitoring_stun_pkts_to_process;
u_int32_t monitoring_stun_flags;

u_int32_t aggressiveness_ookla;

int tcp_ack_paylod_heuristic;
Expand Down
43 changes: 43 additions & 0 deletions src/lib/ndpi_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,9 @@ u_int16_t ndpi_map_user_proto_id_to_ndpi_id(struct ndpi_detection_module_struct
u_int16_t user_proto_id) {

#ifdef NDPI_ENABLE_DEBUG_MESSAGES
#if 0 /* Too much verbose... */
NDPI_LOG_DBG2(ndpi_str, "[DEBUG] ***** %s(%u)\n", __FUNCTION__, user_proto_id);
#endif
#endif

if(user_proto_id < NDPI_MAX_SUPPORTED_PROTOCOLS)
Expand All @@ -356,7 +358,9 @@ u_int16_t ndpi_map_user_proto_id_to_ndpi_id(struct ndpi_detection_module_struct
u_int16_t ndpi_map_ndpi_id_to_user_proto_id(struct ndpi_detection_module_struct *ndpi_str,
u_int16_t ndpi_proto_id) {
#ifdef NDPI_ENABLE_DEBUG_MESSAGES
#if 0 /* Too much verbose... */
NDPI_LOG_DBG2(ndpi_str, "[DEBUG] ***** %s(%u)\n", __FUNCTION__, ndpi_proto_id);
#endif
#endif

if(ndpi_proto_id < NDPI_MAX_SUPPORTED_PROTOCOLS)
Expand Down Expand Up @@ -2996,6 +3000,9 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs
ndpi_str->opportunistic_tls_pop_enabled = 1;
ndpi_str->opportunistic_tls_ftp_enabled = 1;

ndpi_str->monitoring_stun_pkts_to_process = 4;
ndpi_str->monitoring_stun_flags = 0;

ndpi_str->aggressiveness_ookla = NDPI_AGGRESSIVENESS_OOKLA_TLS;

if(prefs & ndpi_enable_tcp_ack_payload_heuristic)
Expand Down Expand Up @@ -9776,6 +9783,42 @@ int ndpi_seen_flow_beginning(const struct ndpi_flow_struct *flow)

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

int ndpi_set_monitoring_state(struct ndpi_detection_module_struct *ndpi_struct,
u_int16_t proto, u_int32_t num_pkts, u_int32_t flags)
{
if(!ndpi_struct || num_pkts > 0xFFFF)
return -1;

switch(proto) {
case NDPI_PROTOCOL_STUN:
ndpi_struct->monitoring_stun_pkts_to_process = num_pkts;
ndpi_struct->monitoring_stun_flags = flags;
return 0;
default:
return -1;
}
}

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

int ndpi_get_monitoring_state(struct ndpi_detection_module_struct *ndpi_struct,
u_int16_t proto, u_int32_t *num_pkts, u_int32_t *flags)
{
if(!ndpi_struct || !num_pkts || !flags)
return -1;

switch(proto) {
case NDPI_PROTOCOL_STUN:
*num_pkts = ndpi_struct->monitoring_stun_pkts_to_process;
*flags = ndpi_struct->monitoring_stun_flags;
return 0;
default:
return -1;
}
}

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

int ndpi_set_opportunistic_tls(struct ndpi_detection_module_struct *ndpi_struct,
u_int16_t proto, int value)
{
Expand Down
20 changes: 14 additions & 6 deletions src/lib/protocols/rtp.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
if((payload_len < 2)
|| (d_port == 5355 /* LLMNR_PORT */)
|| (d_port == 5353 /* MDNS_PORT */)
|| flow->stun.num_binding_requests
) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return;
Expand Down Expand Up @@ -237,12 +236,21 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
/* It seems that it is a LINE stuff; let its dissector to evaluate */
return;
} else {
NDPI_LOG_INFO(ndpi_struct, "Found RTP\n");

isValidMSRTPType(payload_type, &flow->protos.rtp.stream_type);
ndpi_set_detected_protocol(ndpi_struct, flow,
NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_RTP,
NDPI_CONFIDENCE_DPI);

/* Previous pkts were STUN */
if(flow->stun.num_binding_requests > 0 ||
flow->stun.num_processed_pkts > 0) {
NDPI_LOG_INFO(ndpi_struct, "Found RTP (previous traffic was STUN)\n");
ndpi_set_detected_protocol(ndpi_struct, flow,
NDPI_PROTOCOL_RTP, NDPI_PROTOCOL_STUN,
NDPI_CONFIDENCE_DPI);
} else {
NDPI_LOG_INFO(ndpi_struct, "Found RTP\n");
ndpi_set_detected_protocol(ndpi_struct, flow,
NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_RTP,
NDPI_CONFIDENCE_DPI);
}
return;
}
}
Expand Down
48 changes: 48 additions & 0 deletions src/lib/protocols/stun.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,44 @@
// #define DEBUG_STUN 1
// #define DEBUG_LRU 1
// #define DEBUG_ZOOM_LRU 1
// #define DEBUG_MONITORING 1

#define STUN_HDR_LEN 20 /* STUN message header length, Classic-STUN (RFC 3489) and STUN (RFC 8489) both */

static int stun_monitoring(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow)
{
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
u_int8_t first_byte;

#ifdef DEBUG_MONITORING
printf("[STUN-MON] Packet counter %d\n", flow->packet_counter);
#endif

if(packet->payload_packet_len == 0)
return 1;

first_byte = packet->payload[0];

/* draft-ietf-avtcore-rfc7983bis */
if(first_byte >= 128 && first_byte <= 191) { /* TODO: should we tell RTP from RTCP? */
NDPI_LOG_INFO(ndpi_struct, "Found RTP over STUN\n");
if(flow->detected_protocol_stack[1] != NDPI_PROTOCOL_UNKNOWN) {
/* STUN/SUBPROTO -> SUBPROTO/RTP */
ndpi_set_detected_protocol(ndpi_struct, flow,
NDPI_PROTOCOL_RTP, flow->detected_protocol_stack[0],
NDPI_CONFIDENCE_DPI);
} else {
/* STUN -> STUN/RTP */
ndpi_set_detected_protocol(ndpi_struct, flow,
NDPI_PROTOCOL_RTP, NDPI_PROTOCOL_STUN,
NDPI_CONFIDENCE_DPI);
}
return 0; /* Stop */
}
return 1; /* Keep going */
}

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

u_int32_t get_stun_lru_key(struct ndpi_flow_struct *flow, u_int8_t rev) {
Expand Down Expand Up @@ -150,6 +185,17 @@ static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *nd
}

ndpi_set_detected_protocol(ndpi_struct, flow, app_proto, NDPI_PROTOCOL_STUN, confidence);

if(ndpi_struct->monitoring_stun_pkts_to_process > 0 &&
flow->l4_proto == IPPROTO_UDP /* TODO: support TCP. We need to pay some attention because:
* multiple msg in the same TCP segment
* same msg split across multiple segments */) {
if((ndpi_struct->monitoring_stun_flags & NDPI_MONITORING_STUN_SUBCLASSIFIED) ||
app_proto == NDPI_PROTOCOL_UNKNOWN /* No-subclassification */) {
flow->max_extra_packets_to_check = ndpi_struct->monitoring_stun_pkts_to_process;
flow->extra_packets_func = stun_monitoring;
}
}
}

typedef enum {
Expand Down Expand Up @@ -497,6 +543,8 @@ static void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, s

if(flow->packet_counter > 0) {
/* This might be a RTP stream: let's make sure we check it */
/* At this point the flow has not been fully classified as STUN yet */
NDPI_LOG_DBG(ndpi_struct, "re-enable RTP\n");
NDPI_CLR(&flow->excluded_protocol_bitmask, NDPI_PROTOCOL_RTP);
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/cfgs/default/result/geforcenow.pcapng.out
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Guessed flow protos: 0

DPI Packets (TCP): 7 (7.00 pkts/flow)
DPI Packets (UDP): 3 (3.00 pkts/flow)
DPI Packets (UDP): 7 (7.00 pkts/flow)
Confidence DPI : 2 (flows)
Num dissector calls: 133 (66.50 diss/flow)
LRU cache ookla: 0/0/0 (insert/search/found)
Expand Down Expand Up @@ -30,4 +30,4 @@ JA3 Host Stats:


1 TCP 192.168.1.245:57490 <-> 80.84.167.206:49100 [proto: 91.341/TLS.GeForceNow][IP: 342/Nvidia][Encrypted][Confidence: DPI][DPI packets: 7][cat: Game/8][27 pkts/8759 bytes <-> 27 pkts/39892 bytes][Goodput ratio: 80/96][1.34 sec][Hostname/SNI: 80-84-167-206.cloudmatchbeta.nvidiagrid.net][(Advertised) ALPNs: http/1.1][TLS Supported Versions: GREASE;TLSv1.3;TLSv1.2][bytes ratio: -0.640 (Download)][IAT c2s/s2c min/avg/max/stddev: 0/0 56/12 946/84 200/21][Pkt Len c2s/s2c min/avg/max/stddev: 66/66 324/1477 2962/2962 631/1355][Risk: ** Known Proto on Non Std Port **][Risk Score: 50][TLSv1.2][JA3C: 021c7413ddeb0d58973451b0e3b19eca][ServerNames: prod.cloudmatchbeta.nvidiagrid.net,*.cloudmatchbeta.nvidiagrid.net][JA3S: 098e26e2609212ac1bfac552fbe04127][Issuer: C=US, O=DigiCert Inc, CN=DigiCert TLS RSA SHA256 2020 CA1][Subject: C=US, ST=California, L=Santa Clara, O=NVIDIA Corporation, CN=prod.cloudmatchbeta.nvidiagrid.net][Certificate SHA-1: 8C:24:BC:2B:01:63:B9:AC:83:90:F3:A9:F9:EA:72:5E:F4:47:A2:77][Chrome][Validity: 2022-08-09 00:00:00 - 2023-08-09 23:59:59][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256][Plen Bins: 0,23,2,0,0,5,0,0,14,0,2,0,0,0,0,0,5,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,42]
2 UDP 192.168.1.245:52441 <-> 80.84.167.206:18452 [proto: 78/STUN][IP: 342/Nvidia][ClearText][Confidence: DPI][DPI packets: 3][cat: Network/14][21 pkts/3455 bytes <-> 33 pkts/16894 bytes][Goodput ratio: 74/92][1.03 sec][bytes ratio: -0.660 (Download)][IAT c2s/s2c min/avg/max/stddev: 0/0 51/30 360/689 91/130][Pkt Len c2s/s2c min/avg/max/stddev: 87/67 165/512 582/1222 101/514][Risk: ** Known Proto on Non Std Port **][Risk Score: 50][Risk Info: No server to client traffic][PLAIN TEXT (BffATDg/Gz0)][Plen Bins: 1,17,33,9,12,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,0,0,0,0,0,0,0,0,0,0,0]
2 UDP 192.168.1.245:52441 <-> 80.84.167.206:18452 [proto: 78/STUN][IP: 342/Nvidia][ClearText][Confidence: DPI][DPI packets: 7][cat: Network/14][21 pkts/3455 bytes <-> 33 pkts/16894 bytes][Goodput ratio: 74/92][1.03 sec][bytes ratio: -0.660 (Download)][IAT c2s/s2c min/avg/max/stddev: 0/0 51/30 360/689 91/130][Pkt Len c2s/s2c min/avg/max/stddev: 87/67 165/512 582/1222 101/514][Risk: ** Known Proto on Non Std Port **][Risk Score: 50][PLAIN TEXT (BffATDg/Gz0)][Plen Bins: 1,17,33,9,12,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,0,0,0,0,0,0,0,0,0,0,0]
Loading

0 comments on commit 58be36d

Please sign in to comment.