diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/include/ndpi_typedefs.h | 4 | ||||
-rw-r--r-- | src/lib/ndpi_content_match.c.inc | 4 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 6 | ||||
-rw-r--r-- | src/lib/protocols/stun.c | 53 | ||||
-rw-r--r-- | src/lib/protocols/tls.c | 85 |
5 files changed, 107 insertions, 45 deletions
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 7f6e34b2c..7940a7d78 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -1306,6 +1306,7 @@ struct ndpi_detection_module_struct { int opportunistic_tls_imap_enabled; int opportunistic_tls_pop_enabled; int opportunistic_tls_ftp_enabled; + int opportunistic_tls_stun_enabled; u_int32_t monitoring_stun_pkts_to_process; u_int32_t monitoring_stun_flags; @@ -1458,8 +1459,7 @@ struct ndpi_flow_struct { } kerberos_buf; struct { - u_int8_t num_pkts, num_binding_requests; - u_int16_t num_processed_pkts; + u_int8_t num_pkts, num_binding_requests, num_processed_pkts, maybe_dtls; } stun; struct { diff --git a/src/lib/ndpi_content_match.c.inc b/src/lib/ndpi_content_match.c.inc index adeb8e4ad..f3731bfbf 100644 --- a/src/lib/ndpi_content_match.c.inc +++ b/src/lib/ndpi_content_match.c.inc @@ -1560,6 +1560,10 @@ static ndpi_tls_cert_name_match tls_certificate_match [] = { { "O=Riot Games, Inc.", NDPI_PROTOCOL_RIOTGAMES }, { "O=Riot Games Inc", NDPI_PROTOCOL_RIOTGAMES }, + { "CN=hangouts", NDPI_PROTOCOL_HANGOUT_DUO }, + { "CN=Snapchat Inc.", NDPI_PROTOCOL_SNAPCHAT_CALL }, + { "CN=NVIDIA GameStream", NDPI_PROTOCOL_GEFORCENOW }, + { NULL, 0 } }; diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index ac3227d74..e8cc046b4 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -3001,6 +3001,7 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs ndpi_str->opportunistic_tls_imap_enabled = 1; ndpi_str->opportunistic_tls_pop_enabled = 1; ndpi_str->opportunistic_tls_ftp_enabled = 1; + ndpi_str->opportunistic_tls_stun_enabled = 1; ndpi_str->monitoring_stun_pkts_to_process = 4; ndpi_str->monitoring_stun_flags = 0; @@ -9843,6 +9844,9 @@ int ndpi_set_opportunistic_tls(struct ndpi_detection_module_struct *ndpi_struct, case NDPI_PROTOCOL_FTP_CONTROL: ndpi_struct->opportunistic_tls_ftp_enabled = value; return 0; + case NDPI_PROTOCOL_STUN: + ndpi_struct->opportunistic_tls_stun_enabled = value; + return 0; default: return -1; } @@ -9865,6 +9869,8 @@ int ndpi_get_opportunistic_tls(struct ndpi_detection_module_struct *ndpi_struct, return ndpi_struct->opportunistic_tls_pop_enabled; case NDPI_PROTOCOL_FTP_CONTROL: return ndpi_struct->opportunistic_tls_ftp_enabled; + case NDPI_PROTOCOL_STUN: + return ndpi_struct->opportunistic_tls_stun_enabled; default: return -1; } diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c index e8cdaa699..1bd27643c 100644 --- a/src/lib/protocols/stun.c +++ b/src/lib/protocols/stun.c @@ -36,6 +36,10 @@ #define STUN_HDR_LEN 20 /* STUN message header length, Classic-STUN (RFC 3489) and STUN (RFC 8489) both */ +extern void switch_to_tls(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow); +extern int is_dtls(const u_int8_t *buf, u_int32_t buf_len, u_int32_t *block_len); + static int stun_monitoring(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { @@ -212,6 +216,7 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * u_int16_t *app_proto) { struct ndpi_packet_struct *packet = &ndpi_struct->packet; u_int16_t msg_type, msg_len; + u_int32_t unused; int rc; if(packet->iph && @@ -221,6 +226,31 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * return(NDPI_IS_NOT_STUN); } + /* If we're here it's because this does not look like STUN anymore + as this was a flow that started as STUN and turned into something + else. Let's investigate what is that about */ + if(flow->stun.num_pkts > 0 && is_dtls(payload, payload_length, &unused)) { +#ifdef DEBUG_STUN + printf("[STUN] DTLS?\n"); +#endif + /* Switching to TLS dissector is tricky, because we are calling one dissector + from another one, and that is not a common operation... + Additionally: + * at that point protocol stack is still empty + * we have room for only two protocols in flow->detected_protocol_stack[] so + we can't have something like STUN/DTLS/SNAPCHAT_CALL + * the easiest solution is skipping STUN, and let TLS dissector to set both + master (i.e. DTLS) and subprotocol (if any) */ + if(ndpi_struct->opportunistic_tls_stun_enabled) { + flow->stun.maybe_dtls = 1; + switch_to_tls(ndpi_struct, flow); + } + /* We don't want to mess up with TLS classification/results but we don't want to + exclude STUN right away to keep trying it in the case that this packet is + not a real DTLS one */ + return(NDPI_IS_NOT_STUN); + } + if(payload_length < STUN_HDR_LEN) { /* This looks like an invalid packet */ @@ -260,29 +290,6 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * #ifdef DEBUG_STUN printf("[STUN] msg_type = %04X\n", msg_type); #endif - - /* - If we're here it's because this does not look like STUN anymore - as this was a flow that started as STUN and turned into something - else. Let's investigate what is that about - */ - if(payload[0] == 0x16) { - /* Let's check if this is DTLS used by some socials */ - struct ndpi_packet_struct *packet = &ndpi_struct->packet; - u_int16_t total_len, version = htons(*((u_int16_t*) &packet->payload[1])); - - switch (version) { - case 0xFEFF: /* DTLS 1.0 */ - case 0xFEFD: /* DTLS 1.2 */ - total_len = ntohs(*((u_int16_t*) &packet->payload[11])) + 13; - - if(payload_length == total_len) { - flow->guessed_protocol_id = NDPI_PROTOCOL_DTLS; - return(NDPI_IS_NOT_STUN); - } - } - } - return(NDPI_IS_NOT_STUN); } diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c index e1b85db15..e2c20ee03 100644 --- a/src/lib/protocols/tls.c +++ b/src/lib/protocols/tls.c @@ -30,6 +30,8 @@ extern char *strptime(const char *s, const char *format, struct tm *tm); extern int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, uint32_t quic_version); +static void ndpi_search_tls_wrapper(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow); extern int http_process_user_agent(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, const u_int8_t *ua_ptr, u_int16_t ua_ptr_len); @@ -1188,6 +1190,36 @@ static int ndpi_search_tls_tcp(struct ndpi_detection_module_struct *ndpi_struct, /* **************************************** */ +int is_dtls(const u_int8_t *buf, u_int32_t buf_len, u_int32_t *block_len) { + if(buf_len <= 13) + return 0; + + if((buf[0] != 0x16 && buf[0] != 0x14 && buf[0] != 0x17) || /* Handshake, change-cipher-spec, Application-Data */ + !((buf[1] == 0xfe && buf[2] == 0xff) || /* Versions */ + (buf[1] == 0xfe && buf[2] == 0xfd) || + (buf[1] == 0x01 && buf[2] == 0x00))) { +#ifdef DEBUG_TLS + printf("[TLS] DTLS invalid block 0x%x or old version 0x%x-0x%x-0x%x\n", + buf[0], buf[1], buf[2], buf[3]); +#endif + return 0; + } + *block_len = ntohs(*((u_int16_t*)&buf[11])); +#ifdef DEBUG_TLS + printf("[TLS] DTLS block len: %d\n", *block_len); +#endif + if(*block_len == 0 || (*block_len + 12 >= buf_len)) { /* We might have multiple DTLS records */ +#ifdef DEBUG_TLS + printf("[TLS] DTLS invalid block len %d (buf_len %d)\n", + *block_len, buf_len); +#endif + return 0; + } + return 1; +} + +/* **************************************** */ + static int ndpi_search_tls_udp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &ndpi_struct->packet; @@ -1210,29 +1242,23 @@ static int ndpi_search_tls_udp(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t block_len; const u_int8_t *block = (const u_int8_t *)&p[processed]; - if((block[0] != 0x16 && block[0] != 0x14 && block[0] != 0x17) || /* Handshake, change-cipher-spec, Application-Data */ - !((block[1] == 0xfe && block[2] == 0xff) || - (block[1] == 0xfe && block[2] == 0xfd) || - (block[1] == 0x01 && block[2] == 0x00))) { -#ifdef DEBUG_TLS - printf("[TLS] DTLS invalid block 0x%x or old version 0x%x-0x%x-0x%x\n", - block[0], block[1], block[2], block[3]); -#endif - no_dtls = 1; - break; - } - block_len = ntohs(*((u_int16_t*)&block[11])); + if(!is_dtls(block, p_len, &block_len)) { + if(processed == 0 && /* First block */ + flow->stun.maybe_dtls == 1) { + /* Sometimes STUN packets are interleaved with TLS ones. Ignore STUN ones + since we already are after STUN dissection and we are interested only on + TLS stuff right now */ #ifdef DEBUG_TLS - printf("[TLS] DTLS block len: %d\n", block_len); -#endif - if(block_len == 0 || (processed + block_len + 12 >= p_len)) { -#ifdef DEBUG_TLS - printf("[TLS] DTLS invalid block len %d (processed %d, p_len %d)\n", - block_len, processed, p_len); + printf("Probably a stun packet. Keep going with TLS on next packets\n"); #endif + /* Note that we can immediately "return" because, being the first block, + we don't need to restore packet->payload and packet->payload_packet_len */ + return(1); /* Keep working */ + } no_dtls = 1; break; } + /* We process only handshake msgs */ if(block[0] == 0x16) { if(processed + block_len + 13 > p_len) { @@ -1358,8 +1384,9 @@ static void tlsInitExtraPacketProcessing(struct ndpi_detection_module_struct *nd struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &ndpi_struct->packet; - /* At most 12 packets should almost always be enough to find the server certificate if it's there */ - flow->max_extra_packets_to_check = 12 + (ndpi_struct->num_tls_blocks_to_follow*4); + /* At most 12 packets should almost always be enough to find the server certificate if it's there. + Exception: DTLS traffic with fragments, retransmissions and STUN packets */ + flow->max_extra_packets_to_check = ((packet->udp != NULL) ? 20 : 12) + (ndpi_struct->num_tls_blocks_to_follow*4); flow->extra_packets_func = (packet->udp != NULL) ? ndpi_search_tls_udp : ndpi_search_tls_tcp; } @@ -1385,6 +1412,24 @@ void switch_extra_dissection_to_tls(struct ndpi_detection_module_struct *ndpi_st /* **************************************** */ +void switch_to_tls(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) +{ +#ifdef DEBUG_TLS + printf("Switching to TLS\n"); +#endif + + /* Reset reassemblers */ + if(flow->tls_quic.message[0].buffer) + ndpi_free(flow->tls_quic.message[0].buffer); + memset(&flow->tls_quic.message[0], '\0', sizeof(flow->tls_quic.message[0])); + if(flow->tls_quic.message[1].buffer) + ndpi_free(flow->tls_quic.message[1].buffer); + memset(&flow->tls_quic.message[1], '\0', sizeof(flow->tls_quic.message[1])); + + ndpi_search_tls_wrapper(ndpi_struct, flow); +} + static void tls_subclassify_by_alpn(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { /* Right now we have only one rule so we can keep it trivial */ |