diff options
Diffstat (limited to 'src/lib/protocols')
-rw-r--r-- | src/lib/protocols/directconnect.c | 141 | ||||
-rw-r--r-- | src/lib/protocols/dns.c | 32 | ||||
-rw-r--r-- | src/lib/protocols/hangout.c | 28 | ||||
-rw-r--r-- | src/lib/protocols/http.c | 22 | ||||
-rw-r--r-- | src/lib/protocols/mail_imap.c | 2 | ||||
-rw-r--r-- | src/lib/protocols/msn.c | 6 | ||||
-rw-r--r-- | src/lib/protocols/ookla.c | 4 | ||||
-rw-r--r-- | src/lib/protocols/quic.c | 16 | ||||
-rw-r--r-- | src/lib/protocols/rtp.c | 107 | ||||
-rw-r--r-- | src/lib/protocols/ssh.c | 240 | ||||
-rw-r--r-- | src/lib/protocols/stun.c | 201 | ||||
-rw-r--r-- | src/lib/protocols/teamspeak.c | 45 | ||||
-rw-r--r-- | src/lib/protocols/tls.c (renamed from src/lib/protocols/ssl.c) | 632 | ||||
-rw-r--r-- | src/lib/protocols/tor.c | 12 | ||||
-rw-r--r-- | src/lib/protocols/yahoo.c | 2 |
15 files changed, 901 insertions, 589 deletions
diff --git a/src/lib/protocols/directconnect.c b/src/lib/protocols/directconnect.c index 19582724d..563540fba 100644 --- a/src/lib/protocols/directconnect.c +++ b/src/lib/protocols/directconnect.c @@ -58,9 +58,9 @@ static u_int16_t parse_binf_message(struct ndpi_detection_module_struct u_int16_t ssl_port = 0; while (i < payload_len) { i = skip_unknown_headers(payload, payload_len, i); - if ((i + 30) < payload_len) { - if (memcmp(&payload[i], "DCTM", 4) == 0) { - if (memcmp(&payload[i + 15], "ADCS", 4) == 0) { + if((i + 30) < payload_len) { + if(memcmp(&payload[i], "DCTM", 4) == 0) { + if(memcmp(&payload[i + 15], "ADCS", 4) == 0) { ssl_port = ntohs_ndpi_bytestream_to_number(&payload[i + 25], 5, &bytes_read); NDPI_LOG_DBG2(ndpi_struct, "DC ssl port parsed %d\n", ssl_port); } @@ -84,15 +84,15 @@ static void ndpi_int_directconnect_add_connection(struct ndpi_detection_module_s ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_DIRECTCONNECT, NDPI_PROTOCOL_UNKNOWN); - if (src != NULL) { + if(src != NULL) { src->directconnect_last_safe_access_time = packet->tick_timestamp; - if (connection_type == DIRECT_CONNECT_TYPE_PEER) { - if (packet->tcp != NULL + if(connection_type == DIRECT_CONNECT_TYPE_PEER) { + if(packet->tcp != NULL && flow->setup_packet_direction != packet->packet_direction && src->detected_directconnect_port == 0) { src->detected_directconnect_port = packet->tcp->source; NDPI_LOG_DBG2(ndpi_struct, "DC tcp PORT %u for src\n", ntohs(src->detected_directconnect_port)); } - if (packet->udp != NULL && src->detected_directconnect_udp_port == 0) { + if(packet->udp != NULL && src->detected_directconnect_udp_port == 0) { src->detected_directconnect_udp_port = packet->udp->source; NDPI_LOG_DBG2(ndpi_struct, "DC udp PORT %u for src\n", ntohs(src->detected_directconnect_port)); @@ -100,10 +100,10 @@ static void ndpi_int_directconnect_add_connection(struct ndpi_detection_module_s } } - if (dst != NULL) { + if(dst != NULL) { dst->directconnect_last_safe_access_time = packet->tick_timestamp; - if (connection_type == DIRECT_CONNECT_TYPE_PEER) { - if (packet->tcp != NULL + if(connection_type == DIRECT_CONNECT_TYPE_PEER) { + if(packet->tcp != NULL && flow->setup_packet_direction == packet->packet_direction && dst->detected_directconnect_port == 0) { /* DST PORT MARKING CAN LEAD TO PORT MISSDETECTIONS * seen at large customer http servers, where someone has send faked DC tcp packets @@ -121,35 +121,34 @@ static void ndpi_int_directconnect_add_connection(struct ndpi_detection_module_s } } -static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) -{ +static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; struct ndpi_id_struct *src = flow->src; struct ndpi_id_struct *dst = flow->dst; - if (flow->detected_protocol_stack[0] == NDPI_PROTOCOL_DIRECTCONNECT) { - if (packet->payload_packet_len >= 40 && memcmp(&packet->payload[0], "BINF", 4) == 0) { - u_int16_t ssl_port = 0; - ssl_port = parse_binf_message(ndpi_struct, &packet->payload[4], packet->payload_packet_len - 4); - if (dst != NULL && ssl_port) { + if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_DIRECTCONNECT) { + if(packet->payload_packet_len >= 40 && memcmp(&packet->payload[0], "BINF", 4) == 0) { + u_int16_t ssl_port = parse_binf_message(ndpi_struct, + &packet->payload[4], + packet->payload_packet_len - 4); + if(dst != NULL && ssl_port) dst->detected_directconnect_ssl_port = ssl_port; - } - if (src != NULL && ssl_port) { + + if(src != NULL && ssl_port) src->detected_directconnect_ssl_port = ssl_port; - } - - } - if ((packet->payload_packet_len >= 38 && packet->payload_packet_len <= 42) + + if((packet->payload_packet_len >= 38 && packet->payload_packet_len <= 42) && memcmp(&packet->payload[0], "DCTM", 4) == 0 && memcmp(&packet->payload[15], "ADCS", 4) == 0) { u_int16_t bytes_read = 0; - if (dst != NULL) { + if(dst != NULL) { dst->detected_directconnect_ssl_port = ntohs_ndpi_bytestream_to_number(&packet->payload[25], 5, &bytes_read); NDPI_LOG_DBG2(ndpi_struct, "DC ssl port parsed %d\n", ntohs(dst->detected_directconnect_ssl_port)); } - if (src != NULL) { + if(src != NULL) { src->detected_directconnect_ssl_port = ntohs_ndpi_bytestream_to_number(&packet->payload[25], 5, &bytes_read); NDPI_LOG_DBG2(ndpi_struct, "DC ssl port parsed %d\n", ntohs(src->detected_directconnect_ssl_port)); @@ -160,9 +159,9 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n return; } - if (src != NULL) { - if (src->detected_directconnect_port == packet->tcp->source) { - if ((u_int32_t) + if(src != NULL) { + if(src->detected_directconnect_port == packet->tcp->source) { + if((u_int32_t) (packet->tick_timestamp - src->directconnect_last_safe_access_time) < ndpi_struct->directconnect_connection_ip_tick_timeout) { src->directconnect_last_safe_access_time = packet->tick_timestamp; @@ -175,8 +174,8 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n return; } } - if (src->detected_directconnect_ssl_port == packet->tcp->dest) { - if ((u_int32_t) + if(src->detected_directconnect_ssl_port == packet->tcp->dest) { + if((u_int32_t) (packet->tick_timestamp - src->directconnect_last_safe_access_time) < ndpi_struct->directconnect_connection_ip_tick_timeout) { src->directconnect_last_safe_access_time = packet->tick_timestamp; @@ -192,9 +191,9 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n } - if (dst != NULL) { - if (dst->detected_directconnect_port == packet->tcp->dest) { - if ((u_int32_t) + if(dst != NULL) { + if(dst->detected_directconnect_port == packet->tcp->dest) { + if((u_int32_t) (packet->tick_timestamp - dst->directconnect_last_safe_access_time) < ndpi_struct->directconnect_connection_ip_tick_timeout) { dst->directconnect_last_safe_access_time = packet->tick_timestamp; @@ -207,8 +206,8 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n return; } } - if (dst->detected_directconnect_ssl_port == packet->tcp->dest) { - if ((u_int32_t) + if(dst->detected_directconnect_ssl_port == packet->tcp->dest) { + if((u_int32_t) (packet->tick_timestamp - dst->directconnect_last_safe_access_time) < ndpi_struct->directconnect_connection_ip_tick_timeout) { dst->directconnect_last_safe_access_time = packet->tick_timestamp; @@ -224,17 +223,17 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n } - if (flow->directconnect_stage == 0) { + if(flow->directconnect_stage == 0) { - if (packet->payload_packet_len > 6) { - if (packet->payload[0] == '$' + if(packet->payload_packet_len > 6) { + if(packet->payload[0] == '$' && packet->payload[packet->payload_packet_len - 1] == '|' && (memcmp(&packet->payload[1], "Lock ", 5) == 0)) { NDPI_LOG_DBG2(ndpi_struct, "maybe first dc connect to hub detected\n"); flow->directconnect_stage = 1; return; } - if (packet->payload_packet_len > 7 + if(packet->payload_packet_len > 7 && packet->payload[0] == '$' && packet->payload[packet->payload_packet_len - 1] == '|' && (memcmp(&packet->payload[1], "MyNick ", 7) == 0)) { @@ -244,15 +243,15 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n } } - if (packet->payload_packet_len >= 11) { + if(packet->payload_packet_len >= 11) { /* did not see this pattern in any trace */ - if (memcmp(&packet->payload[0], "HSUP ADBAS0", 11) == 0 + if(memcmp(&packet->payload[0], "HSUP ADBAS0", 11) == 0 || memcmp(&packet->payload[0], "HSUP ADBASE", 11) == 0) { NDPI_LOG_INFO(ndpi_struct, "found DC HSUP ADBAS0 E\n"); ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_TYPE_HUB); return; /* did not see this pattern in any trace */ - } else if (memcmp(&packet->payload[0], "CSUP ADBAS0", 11) == 0 || + } else if(memcmp(&packet->payload[0], "CSUP ADBAS0", 11) == 0 || memcmp(&packet->payload[0], "CSUP ADBASE", 11) == 0) { NDPI_LOG_INFO(ndpi_struct, "found DC CSUP ADBAS0 E\n"); ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_ADC_PEER); @@ -262,16 +261,16 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n } - } else if (flow->directconnect_stage == 1) { - if (packet->payload_packet_len >= 11) { + } else if(flow->directconnect_stage == 1) { + if(packet->payload_packet_len >= 11) { /* did not see this pattern in any trace */ - if (memcmp(&packet->payload[0], "HSUP ADBAS0", 11) == 0 + if(memcmp(&packet->payload[0], "HSUP ADBAS0", 11) == 0 || memcmp(&packet->payload[0], "HSUP ADBASE", 11) == 0) { NDPI_LOG_INFO(ndpi_struct, "found DC HSUP ADBAS E in second packet\n"); ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_TYPE_HUB); return; /* did not see this pattern in any trace */ - } else if (memcmp(&packet->payload[0], "CSUP ADBAS0", 11) == 0 || + } else if(memcmp(&packet->payload[0], "CSUP ADBAS0", 11) == 0 || memcmp(&packet->payload[0], "CSUP ADBASE", 11) == 0) { NDPI_LOG_INFO(ndpi_struct, "found DC HSUP ADBAS0 E in second packet\n"); ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_ADC_PEER); @@ -280,8 +279,8 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n } } /* get client hello answer or server message */ - if (packet->payload_packet_len > 6) { - if ((packet->payload[0] == '$' || packet->payload[0] == '<') + if(packet->payload_packet_len > 6) { + if((packet->payload[0] == '$' || packet->payload[0] == '<') && packet->payload[packet->payload_packet_len - 1] == '|') { NDPI_LOG_INFO(ndpi_struct, "found DC second\n"); ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_TYPE_HUB); @@ -291,10 +290,10 @@ static void ndpi_search_directconnect_tcp(struct ndpi_detection_module_struct *n } } - } else if (flow->directconnect_stage == 2) { + } else if(flow->directconnect_stage == 2) { /* get client hello answer or server message */ - if (packet->payload_packet_len > 6) { - if (packet->payload[0] == '$' && packet->payload[packet->payload_packet_len - 1] == '|') { + if(packet->payload_packet_len > 6) { + if(packet->payload[0] == '$' && packet->payload[packet->payload_packet_len - 1] == '|') { NDPI_LOG_INFO(ndpi_struct, "found DC between peers\n"); ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_TYPE_PEER); return; @@ -318,8 +317,8 @@ static void ndpi_search_directconnect_udp(struct ndpi_detection_module_struct struct ndpi_id_struct *dst = flow->dst; int pos, count = 0; - if (dst != NULL && dst->detected_directconnect_udp_port == packet->udp->dest) { - if ((u_int32_t) + if(dst != NULL && dst->detected_directconnect_udp_port == packet->udp->dest) { + if((u_int32_t) (packet->tick_timestamp - dst->directconnect_last_safe_access_time) < ndpi_struct->directconnect_connection_ip_tick_timeout) { @@ -334,21 +333,21 @@ static void ndpi_search_directconnect_udp(struct ndpi_detection_module_struct } } - if (packet->payload_packet_len > 58) { - if (src != NULL + if(packet->payload_packet_len > 58) { + if(src != NULL && NDPI_COMPARE_PROTOCOL_TO_BITMASK(src->detected_protocol_bitmask, NDPI_PROTOCOL_DIRECTCONNECT)) { - if (packet->payload[0] == '$' + if(packet->payload[0] == '$' && packet->payload[packet->payload_packet_len - 1] == '|' && memcmp(&packet->payload[1], "SR ", 3) == 0) { pos = packet->payload_packet_len - 2; - if (packet->payload[pos] == ')') { + if(packet->payload[pos] == ')') { while (pos > 0 && packet->payload[pos] != '(' && count < 21) { pos--; count++; } - if (packet->payload[pos] == '(') { + if(packet->payload[pos] == '(') { pos = pos - 44; - if (pos > 2 && memcmp(&packet->payload[pos], "TTH:", 4) == 0) { + if(pos > 2 && memcmp(&packet->payload[pos], "TTH:", 4) == 0) { NDPI_LOG_INFO(ndpi_struct, "found DC udp\n"); ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_TYPE_PEER); return; @@ -356,25 +355,25 @@ static void ndpi_search_directconnect_udp(struct ndpi_detection_module_struct } } flow->directconnect_stage++; - if (flow->directconnect_stage < 3) + if(flow->directconnect_stage < 3) return; } } - if (dst != NULL + if(dst != NULL && NDPI_COMPARE_PROTOCOL_TO_BITMASK(dst->detected_protocol_bitmask, NDPI_PROTOCOL_DIRECTCONNECT)) { - if (packet->payload[0] == '$' + if(packet->payload[0] == '$' && packet->payload[packet->payload_packet_len - 1] == '|' && memcmp(&packet->payload[1], "SR ", 3) == 0) { pos = packet->payload_packet_len - 2; - if (packet->payload[pos] == ')') { + if(packet->payload[pos] == ')') { while (pos > 0 && packet->payload[pos] != '(' && count < 21) { pos--; count++; } - if (packet->payload[pos] == '(') { + if(packet->payload[pos] == '(') { pos = pos - 44; - if (pos > 2 && memcmp(&packet->payload[pos], "TTH:", 4) == 0) { + if(pos > 2 && memcmp(&packet->payload[pos], "TTH:", 4) == 0) { NDPI_LOG_INFO(ndpi_struct, "found DC udp\n"); ndpi_int_directconnect_add_connection(ndpi_struct, flow, DIRECT_CONNECT_TYPE_PEER); return; @@ -382,7 +381,7 @@ static void ndpi_search_directconnect_udp(struct ndpi_detection_module_struct } } flow->directconnect_stage++; - if (flow->directconnect_stage < 3) + if(flow->directconnect_stage < 3) return; } } @@ -404,14 +403,14 @@ void ndpi_search_directconnect(struct ndpi_detection_module_struct NDPI_LOG_DBG(ndpi_struct, "search DC\n"); - if (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_DIRECTCONNECT) { - if (src != NULL && ((u_int32_t) + if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_DIRECTCONNECT) { + if(src != NULL && ((u_int32_t) (packet->tick_timestamp - src->directconnect_last_safe_access_time) < ndpi_struct->directconnect_connection_ip_tick_timeout)) { src->directconnect_last_safe_access_time = packet->tick_timestamp; - } else if (dst != NULL && ((u_int32_t) + } else if(dst != NULL && ((u_int32_t) (packet->tick_timestamp - dst->directconnect_last_safe_access_time) < ndpi_struct->directconnect_connection_ip_tick_timeout)) { @@ -423,9 +422,9 @@ void ndpi_search_directconnect(struct ndpi_detection_module_struct return; } - if (packet->tcp != NULL) { + if(packet->tcp != NULL) { ndpi_search_directconnect_tcp(ndpi_struct, flow); - } else if (packet->udp != NULL) { + } else if(packet->udp != NULL) { ndpi_search_directconnect_udp(ndpi_struct, flow); } } diff --git a/src/lib/protocols/dns.c b/src/lib/protocols/dns.c index dc97f3fe7..6a4a02f60 100644 --- a/src/lib/protocols/dns.c +++ b/src/lib/protocols/dns.c @@ -128,19 +128,17 @@ void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct nd || ((dns_header.num_answers == 0) && (dns_header.authority_rrs == 0)))) { /* This is a good query */ - if(dns_header.num_queries > 0) { - while(x < flow->packet.payload_packet_len) { - if(flow->packet.payload[x] == '\0') { - x++; - flow->protos.dns.query_type = get16(&x, flow->packet.payload); + while(x < flow->packet.payload_packet_len) { + if(flow->packet.payload[x] == '\0') { + x++; + flow->protos.dns.query_type = get16(&x, flow->packet.payload); #ifdef DNS_DEBUG - NDPI_LOG_DBG2(ndpi_struct, "query_type=%2d\n", flow->protos.dns.query_type); + NDPI_LOG_DBG2(ndpi_struct, "query_type=%2d\n", flow->protos.dns.query_type); #endif - break; - } else - x++; - } - } + break; + } else + x++; + } } else invalid = 1; } else { @@ -222,15 +220,19 @@ void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct nd off = sizeof(struct ndpi_dns_packet_header) + payload_offset; while(j < max_len && off < flow->packet.payload_packet_len && flow->packet.payload[off] != '\0') { - uint8_t c,cl = flow->packet.payload[off++]; + uint8_t c, cl = flow->packet.payload[off++]; + if( (cl & 0xc0) != 0 || // we not support compressed names in query - off + cl >= flow->packet.payload_packet_len) { - j = 0; break; + off + cl >= flow->packet.payload_packet_len) { + j = 0; + break; } + if(j && j < max_len) flow->host_server_name[j++] = '.'; + while(j < max_len && cl != 0) { c = flow->packet.payload[off++]; - flow->host_server_name[j++] = dns_validchar[c >> 5] & (1 << (c & 0x1f)) ? c:'_'; + flow->host_server_name[j++] = (dns_validchar[c >> 5] & (1 << (c & 0x1f))) ? c : '_'; cl--; } } diff --git a/src/lib/protocols/hangout.c b/src/lib/protocols/hangout.c index 99bf879cb..c96b36018 100644 --- a/src/lib/protocols/hangout.c +++ b/src/lib/protocols/hangout.c @@ -22,8 +22,12 @@ #define NDPI_CURRENT_PROTO NDPI_PROTOCOL_HANGOUT_DUO +/* #define DEBUG_LRU 1 */ + #include "ndpi_api.h" +/* stun.c */ +extern u_int32_t get_stun_lru_key(struct ndpi_flow_struct *flow); /* https://support.google.com/a/answer/1279090?hl=en */ #define HANGOUT_UDP_LOW_PORT 19302 @@ -85,11 +89,29 @@ void ndpi_search_hangout(struct ndpi_detection_module_struct *ndpi_struct, if((packet->payload_packet_len > 24) && is_google_flow(ndpi_struct, flow)) { if( - ((packet->udp != NULL) && (isHangoutUDPPort(ntohs(packet->udp->source)) || isHangoutUDPPort(ntohs(packet->udp->dest)))) + ((packet->udp != NULL) && (isHangoutUDPPort(ntohs(packet->udp->source)) + || isHangoutUDPPort(ntohs(packet->udp->dest)))) || - ((packet->tcp != NULL) && (isHangoutTCPPort(ntohs(packet->tcp->source)) || isHangoutTCPPort(ntohs(packet->tcp->dest))))) { + ((packet->tcp != NULL) && (isHangoutTCPPort(ntohs(packet->tcp->source)) + || isHangoutTCPPort(ntohs(packet->tcp->dest))))) { NDPI_LOG_INFO(ndpi_struct, "found Hangout\n"); - ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO, NDPI_PROTOCOL_UNKNOWN); + + /* Hangout is over STUN hence the LRU cache is shared */ + if(ndpi_struct->stun_cache == NULL) + ndpi_struct->stun_cache = ndpi_lru_cache_init(1024); + + if(ndpi_struct->stun_cache && flow->packet.iph && flow->packet.udp) { + u_int32_t key = get_stun_lru_key(flow); + +#ifdef DEBUG_LRU + printf("[LRU] ADDING %u / %u.%u\n", key, NDPI_PROTOCOL_STUN, NDPI_PROTOCOL_HANGOUT_DUO); +#endif + + ndpi_lru_add_to_cache(ndpi_struct->stun_cache, key, NDPI_PROTOCOL_HANGOUT_DUO); + } + + ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO, + NDPI_PROTOCOL_STUN); return; } } diff --git a/src/lib/protocols/http.c b/src/lib/protocols/http.c index 1e066c3ac..cd5f193db 100644 --- a/src/lib/protocols/http.c +++ b/src/lib/protocols/http.c @@ -35,7 +35,7 @@ static void ndpi_int_http_add_connection(struct ndpi_detection_module_struct *nd printf("[%s] [http_dont_dissect_response: %u]->> %s\n", __FUNCTION__, ndpi_struct->http_dont_dissect_response, flow->http.response_status_code); #endif - + if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) { /* This is HTTP and it is not a sub protocol (e.g. skype or dropbox) */ @@ -157,7 +157,7 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_ #endif /* Leave the statement below commented necessary in case of call to ndpi_get_partial_detection() */ - + /* if(!ndpi_struct->http_dont_dissect_response) */ { if((flow->http.url == NULL) && (packet->http_url_name.len > 0) @@ -320,7 +320,7 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_ /** check result of host subprotocol detection - + if "detected" in flow == 0 then "detected" = "guess" else "guess" = "detected" **/ @@ -338,7 +338,7 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_ if(flow->detected_protocol_stack[0] != flow->guessed_host_protocol_id) flow->guessed_host_protocol_id = flow->detected_protocol_stack[0]; } - + if((flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) && ((ndpi_struct->http_dont_dissect_response) || flow->http_detected) && (packet->http_origin.len > 0)) { @@ -480,17 +480,17 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct if(packet->payload_packet_len >= 12) { char buf[4]; - + /* Set server HTTP response code */ strncpy(buf, (char*)&packet->payload[9], 3); buf[3] = '\0'; - + flow->http.response_status_code = atoi(buf); /* https://en.wikipedia.org/wiki/List_of_HTTP_status_codes */ if((flow->http.response_status_code < 100) || (flow->http.response_status_code > 509)) flow->http.response_status_code = 0; /* Out of range */ } - + ndpi_int_http_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_HTTP); check_content_type_and_change_protocol(ndpi_struct, flow); return; @@ -533,14 +533,14 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct if(ndpi_struct->ookla_cache == NULL) ndpi_struct->ookla_cache = ndpi_lru_cache_init(1024); - + if(packet->iph != NULL && ndpi_struct->ookla_cache != NULL) { if(packet->tcp->source == htons(8080)) - ndpi_lru_add_to_cache(ndpi_struct->ookla_cache, packet->iph->saddr); + ndpi_lru_add_to_cache(ndpi_struct->ookla_cache, packet->iph->saddr, 1 /* dummy */); else - ndpi_lru_add_to_cache(ndpi_struct->ookla_cache, packet->iph->daddr); + ndpi_lru_add_to_cache(ndpi_struct->ookla_cache, packet->iph->daddr, 1 /* dummy */); } - + return; } diff --git a/src/lib/protocols/mail_imap.c b/src/lib/protocols/mail_imap.c index 65341cdc8..69d135943 100644 --- a/src/lib/protocols/mail_imap.c +++ b/src/lib/protocols/mail_imap.c @@ -48,7 +48,7 @@ void ndpi_search_mail_imap_tcp(struct ndpi_detection_module_struct *ndpi_struct, if (flow->l4.tcp.mail_imap_starttls == 2) { NDPI_LOG_DBG2(ndpi_struct, "starttls detected\n"); NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_MAIL_IMAP); - NDPI_DEL_PROTOCOL_FROM_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_SSL); + NDPI_DEL_PROTOCOL_FROM_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_TLS); return; } diff --git a/src/lib/protocols/msn.c b/src/lib/protocols/msn.c index 8ab45ad32..8d52d690b 100644 --- a/src/lib/protocols/msn.c +++ b/src/lib/protocols/msn.c @@ -62,7 +62,7 @@ static void ndpi_search_msn_tcp(struct ndpi_detection_module_struct *ndpi_struct u_int16_t plen; u_int16_t status = 0; - if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL) { + if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS) { NDPI_LOG_DBG2(ndpi_struct, "msn ssl ft test\n"); @@ -103,7 +103,7 @@ static void ndpi_search_msn_tcp(struct ndpi_detection_module_struct *ndpi_struct */ /* now we have a look at the first packet only. */ if(flow->packet_counter == 1 - || ((packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL) + || ((packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS) && flow->packet_counter <= 3) ) { @@ -497,7 +497,7 @@ void ndpi_search_msn(struct ndpi_detection_module_struct *ndpi_struct, struct nd // need to do the ceck when protocol == http too (POST /gateway ...) if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN || packet->detected_protocol_stack[0] == NDPI_PROTOCOL_HTTP - || packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL + || packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS || packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STUN ) ndpi_search_msn_tcp(ndpi_struct, flow); diff --git a/src/lib/protocols/ookla.c b/src/lib/protocols/ookla.c index 44746fbd3..f3c2108bc 100644 --- a/src/lib/protocols/ookla.c +++ b/src/lib/protocols/ookla.c @@ -38,7 +38,9 @@ void ndpi_search_ookla(struct ndpi_detection_module_struct* ndpi_struct, struct goto ookla_exclude; if(ndpi_struct->ookla_cache != NULL) { - if(ndpi_lru_find_cache(ndpi_struct->ookla_cache, addr, 0 /* Don't remove it as it can be used for other connections */)) { + u_int16_t dummy; + + if(ndpi_lru_find_cache(ndpi_struct->ookla_cache, addr, &dummy, 0 /* Don't remove it as it can be used for other connections */)) { NDPI_LOG_INFO(ndpi_struct, "found ookla tcp connection\n"); ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OOKLA, NDPI_PROTOCOL_UNKNOWN); return; diff --git a/src/lib/protocols/quic.c b/src/lib/protocols/quic.c index 6d4d45044..87378ea61 100644 --- a/src/lib/protocols/quic.c +++ b/src/lib/protocols/quic.c @@ -83,15 +83,27 @@ void ndpi_search_quic(struct ndpi_detection_module_struct *ndpi_struct, ) { int i; - if((packet->payload[1] == 'Q') && (packet->payload[2] == '0') && (packet->payload[3] == '4') - && (packet->payload[4] == '6')) + && (packet->payload[4] == '6') + && (version_len == 1) + ) quic_hlen = 18; /* TODO: Better handle Q046 */ else { + u_int16_t potential_stun_len = ntohs((*((u_int16_t*)&packet->payload[2]))); + if((version_len > 0) && (packet->payload[1+cid_len] != 'Q')) goto no_quic; + + if((version_len == 0) && ((packet->payload[0] & 0xC3 /* ignore CID len/packet number */) != 0)) + goto no_quic; + + + /* Heuristic to see if this packet could be a STUN packet */ + if((potential_stun_len /* STUN message len */ < udp_len) + && ((potential_stun_len+25 /* Attribute header overhead we assume is max */) /* STUN message len */ > udp_len)) + return; /* This could be STUN, let's skip this packet */ NDPI_LOG_INFO(ndpi_struct, "found QUIC\n"); ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_QUIC, NDPI_PROTOCOL_UNKNOWN); diff --git a/src/lib/protocols/rtp.c b/src/lib/protocols/rtp.c index bd0179287..90b73ab1e 100644 --- a/src/lib/protocols/rtp.c +++ b/src/lib/protocols/rtp.c @@ -58,14 +58,14 @@ static u_int8_t isValidMSRTPType(u_int8_t payloadType) { case 127: /* x-data */ return(1 /* RTP */); break; - + case 200: /* RTCP PACKET SENDER */ case 201: /* RTCP PACKET RECEIVER */ case 202: /* RTCP Source Description */ case 203: /* RTCP Bye */ return(2 /* RTCP */); break; - + default: return(0); } @@ -78,8 +78,10 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct, const u_int8_t * payload, const u_int16_t payload_len) { NDPI_LOG_DBG(ndpi_struct, "search RTP\n"); - if (payload_len < 2) + if((payload_len < 2) || flow->protos.stun_ssl.stun.num_binding_requests) { + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); return; + } //struct ndpi_packet_struct *packet = &flow->packet; u_int8_t payloadType, payload_type = payload[1] & 0x7F; @@ -91,17 +93,17 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct, && ((payload_type <= 34) || ((payload_type >= 96) && (payload_type <= 127)) /* http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml */ - ) - ) { + ) + ) { struct ndpi_packet_struct *packet = &flow->packet; - + if(packet->iph) { /* 125.209.252.xxx */ if(((ntohl(packet->iph->saddr) & 0xFFFFFF00 /* 255.255.255.0 */) == 0x7DD1FC00) || ((ntohl(packet->iph->daddr) & 0xFFFFFF00 /* 255.255.255.0 */) == 0x7DD1FC00)) { if((flow->packet.payload[0] == 0x80) && ((flow->packet.payload[1] == 0x78) || (flow->packet.payload[1] == 0xE8)) - ) { + ) { ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_LINE, NDPI_PROTOCOL_LINE); return; } @@ -112,7 +114,7 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct, ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_RTP, NDPI_PROTOCOL_UNKNOWN); return; } else if((payload_len >= 12) - && (((payload[0] & 0xFF) == 0x80) || ((payload[0] & 0xFF) == 0xA0)) /* RTP magic byte[1] */ + && (((payload[0] & 0xFF) == 0x80) || ((payload[0] & 0xFF) == 0xA0)) /* RTP magic byte[1] */ && (payloadType = isValidMSRTPType(payload[1] & 0xFF))) { if(payloadType == 1 /* RTP */) { NDPI_LOG_INFO(ndpi_struct, "Found Skype for Business (former MS Lync)\n"); @@ -126,7 +128,7 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct, return; #endif } - } + } /* No luck this time */ NDPI_EXCLUDE_PROTO(ndpi_struct, flow); @@ -139,7 +141,7 @@ void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, struct nd struct ndpi_packet_struct *packet = &flow->packet; /* printf("*** %s(pkt=%d)\n", __FUNCTION__, flow->packet_counter); */ - + if((packet->udp != NULL) /* && (ntohs(packet->udp->source) > 1023) */ && (ntohs(packet->udp->dest) > 1023)) @@ -204,14 +206,14 @@ u_int16_t update_seq(struct ndpi_detection_module_struct *ndpi_struct, struct nd u_int16_t delta = seq - flow->rtp_seqnum[direction]; - if (delta < RTP_MAX_OUT_OF_ORDER) { /* in order, with permissible gap */ + if(delta < RTP_MAX_OUT_OF_ORDER) { /* in order, with permissible gap */ flow->rtp_seqnum[direction] = seq; NDPI_LOG_DBG(ndpi_struct, "rtp_seqnum[%u] = %u (increased by %u)\n", - direction, seq, delta); + direction, seq, delta); return delta; } else { NDPI_LOG_DBG(ndpi_struct, "retransmission (dir %u, seqnum %u)\n", - direction, seq); + direction, seq); return 0; } } @@ -227,51 +229,51 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct, NDPI_LOG_DBG(ndpi_struct, "search rtp\n"); - if (payload_len == 4 && get_u_int32_t(packet->payload, 0) == 0 && flow->packet_counter < 8) { + if(payload_len == 4 && get_u_int32_t(packet->payload, 0) == 0 && flow->packet_counter < 8) { NDPI_LOG_DBG(ndpi_struct, "need next packet, maybe ClearSea out calls\n"); return; } - if (payload_len == 5 && memcmp(payload, "hello", 5) == 0) { + if(payload_len == 5 && memcmp(payload, "hello", 5) == 0) { NDPI_LOG_DBG(ndpi_struct, - "need next packet, initial hello packet of SIP out calls.\n"); + "need next packet, initial hello packet of SIP out calls.\n"); return; } - if (payload_len == 1 && payload[0] == 0) { + if(payload_len == 1 && payload[0] == 0) { NDPI_LOG_DBG(ndpi_struct, - "need next packet, payload_packet_len == 1 && payload[0] == 0.\n"); + "need next packet, payload_packet_len == 1 && payload[0] == 0.\n"); return; } - if (payload_len == 3 && memcmp(payload, "png", 3) == 0) { + if(payload_len == 3 && memcmp(payload, "png", 3) == 0) { /* weird packet found in Ninja GlobalIP trace */ NDPI_LOG_DBG(ndpi_struct, "skipping packet with len = 3 and png payload\n"); return; } - if (payload_len < 12) { + if(payload_len < 12) { NDPI_LOG_DBG(ndpi_struct, "minimal packet size for rtp packets: 12\n"); goto exclude_rtp; } - if (payload_len == 12 && get_u_int32_t(payload, 0) == 0 && get_u_int32_t(payload, 4) == 0 && get_u_int32_t(payload, 8) == 0) { + if(payload_len == 12 && get_u_int32_t(payload, 0) == 0 && get_u_int32_t(payload, 4) == 0 && get_u_int32_t(payload, 8) == 0) { NDPI_LOG_DBG(ndpi_struct, "skipping packet with len = 12 and only 0-bytes\n"); return; } - if ((payload[0] & 0xc0) == 0xc0 || (payload[0] & 0xc0) == 0x40 || (payload[0] & 0xc0) == 0x00) { + if((payload[0] & 0xc0) == 0xc0 || (payload[0] & 0xc0) == 0x40 || (payload[0] & 0xc0) == 0x00) { NDPI_LOG_DBG(ndpi_struct, "version = 3 || 1 || 0, maybe first rtp packet\n"); return; } - if ((payload[0] & 0xc0) != 0x80) { + if((payload[0] & 0xc0) != 0x80) { NDPI_LOG_DBG(ndpi_struct, "rtp version must be 2, first two bits of a packets must be 10\n"); goto exclude_rtp; } /* rtp_payload_type are the last seven bits of the second byte */ - if (flow->rtp_payload_type[packet->packet_direction] != (payload[1] & 0x7F)) { + if(flow->rtp_payload_type[packet->packet_direction] != (payload[1] & 0x7F)) { NDPI_LOG_DBG(ndpi_struct, "payload_type has changed, reset stages\n"); packet->packet_direction == 0 ? (flow->rtp_stage1 = 0) : (flow->rtp_stage2 = 0); } @@ -280,56 +282,56 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct, stage = (packet->packet_direction == 0 ? flow->rtp_stage1 : flow->rtp_stage2); - if (stage > 0) { + if(stage > 0) { NDPI_LOG_DBG(ndpi_struct, "stage = %u\n", packet->packet_direction == 0 ? flow->rtp_stage1 : flow->rtp_stage2); - if (flow->rtp_ssid[packet->packet_direction] != get_u_int32_t(payload, 8)) { + if(flow->rtp_ssid[packet->packet_direction] != get_u_int32_t(payload, 8)) { NDPI_LOG_DBG(ndpi_struct, "ssid has changed, goto exclude rtp\n"); goto exclude_rtp; } - if (seqnum == flow->rtp_seqnum[packet->packet_direction]) { + if(seqnum == flow->rtp_seqnum[packet->packet_direction]) { NDPI_LOG_DBG(ndpi_struct, "maybe \"retransmission\", need next packet\n"); return; - } else if ((u_int16_t) (seqnum - flow->rtp_seqnum[packet->packet_direction]) < RTP_MAX_OUT_OF_ORDER) { + } else if((u_int16_t) (seqnum - flow->rtp_seqnum[packet->packet_direction]) < RTP_MAX_OUT_OF_ORDER) { NDPI_LOG_DBG(ndpi_struct, - "new packet has larger sequence number (within valid range)\n"); + "new packet has larger sequence number (within valid range)\n"); update_seq(ndpi_struct, flow, packet->packet_direction, seqnum); - } else if ((u_int16_t) (flow->rtp_seqnum[packet->packet_direction] - seqnum) < RTP_MAX_OUT_OF_ORDER) { + } else if((u_int16_t) (flow->rtp_seqnum[packet->packet_direction] - seqnum) < RTP_MAX_OUT_OF_ORDER) { NDPI_LOG_DBG(ndpi_struct, - "new packet has smaller sequence number (within valid range)\n"); + "new packet has smaller sequence number (within valid range)\n"); init_seq(ndpi_struct, flow, packet->packet_direction, seqnum, 1); } else { NDPI_LOG_DBG(ndpi_struct, - "sequence number diff is too big, goto exclude rtp.\n"); + "sequence number diff is too big, goto exclude rtp.\n"); goto exclude_rtp; } } else { NDPI_LOG_DBG(ndpi_struct, "rtp_ssid[%u] = %u\n", packet->packet_direction, - flow->rtp_ssid[packet->packet_direction]); + flow->rtp_ssid[packet->packet_direction]); flow->rtp_ssid[packet->packet_direction] = get_u_int32_t(payload, 8); - if (flow->packet_counter < 3) { + if(flow->packet_counter < 3) { NDPI_LOG_DBG(ndpi_struct, "packet_counter < 3, need next packet\n"); } init_seq(ndpi_struct, flow, packet->packet_direction, seqnum, 1); } - if (seqnum <= 3) { + if(seqnum <= 3) { NDPI_LOG_DBG(ndpi_struct, "sequence_number = %u, too small, need next packet, return\n", seqnum); return; } - if (stage == 3) { + if(stage == 3) { NDPI_LOG_DBG(ndpi_struct, "add connection I\n"); ndpi_int_rtp_add_connection(ndpi_struct, flow); } else { packet->packet_direction == 0 ? flow->rtp_stage1++ : flow->rtp_stage2++; NDPI_LOG_DBG(ndpi_struct, "stage[%u]++; need next packet\n", - packet->packet_direction); + packet->packet_direction); } return; - exclude_rtp: - if (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STUN - || /* packet->real_protocol_read_only == NDPI_PROTOCOL_STUN */) { +exclude_rtp: + if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STUN + || /* packet->real_protocol_read_only == NDPI_PROTOCOL_STUN */) { NDPI_LOG_DBG(ndpi_struct, "STUN: is detected, need next packet\n"); return; } @@ -344,17 +346,17 @@ void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, struct nd struct ndpi_packet_struct *packet = &flow->packet; - if (packet->udp) { + if(packet->udp) { ndpi_rtp_search(ndpi_struct, flow, packet->payload, packet->payload_packet_len); - } else if (packet->tcp) { + } else if(packet->tcp) { /* skip special packets seen at yahoo traces */ - if (packet->payload_packet_len >= 20 && ntohs(get_u_int16_t(packet->payload, 2)) + 20 == packet->payload_packet_len && - packet->payload[0] == 0x90 && packet->payload[1] >= 0x01 && packet->payload[1] <= 0x07) { - if (flow->packet_counter == 2) + if(packet->payload_packet_len >= 20 && ntohs(get_u_int16_t(packet->payload, 2)) + 20 == packet->payload_packet_len && + packet->payload[0] == 0x90 && packet->payload[1] >= 0x01 && packet->payload[1] <= 0x07) { + if(flow->packet_counter == 2) flow->l4.tcp.rtp_special_packets_seen = 1; NDPI_LOG_DBG(ndpi_struct, - "skipping STUN-like, special yahoo packets with payload[0] == 0x90.\n"); + "skipping STUN-like, special yahoo packets with payload[0] == 0x90.\n"); return; } @@ -365,12 +367,12 @@ void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, struct nd * we can remove this restriction */ - if (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STUN - || packet->detected_protocol_stack[0] == NDPI_PROTOCOL_RTP) { + if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_STUN + || packet->detected_protocol_stack[0] == NDPI_PROTOCOL_RTP) { /* RTP may be encapsulated in TCP packets */ - if (packet->payload_packet_len >= 2 && ntohs(get_u_int16_t(packet->payload, 0)) + 2 == packet->payload_packet_len) { + if(packet->payload_packet_len >= 2 && ntohs(get_u_int16_t(packet->payload, 0)) + 2 == packet->payload_packet_len) { /* TODO there could be several RTP packets in a single TCP packet so maybe the detection could be * improved by checking only the RTP packet of given length */ @@ -381,9 +383,9 @@ void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, struct nd } } - if (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN && flow->l4.tcp.rtp_special_packets_seen == 1) { + if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN && flow->l4.tcp.rtp_special_packets_seen == 1) { - if (packet->payload_packet_len >= 4 && ntohl(get_u_int32_t(packet->payload, 0)) + 4 == packet->payload_packet_len) { + if(packet->payload_packet_len >= 4 && ntohl(get_u_int32_t(packet->payload, 0)) + 4 == packet->payload_packet_len) { /* TODO there could be several RTP packets in a single TCP packet so maybe the detection could be * improved by checking only the RTP packet of given length */ @@ -394,7 +396,7 @@ void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, struct nd } } - if (NDPI_FLOW_PROTOCOL_EXCLUDED(ndpi_struct, flow, NDPI_PROTOCOL_STUN)) { + if(NDPI_FLOW_PROTOCOL_EXCLUDED(ndpi_struct, flow, NDPI_PROTOCOL_STUN)) { NDPI_EXCLUDE_PROTO(ndpi_struct, flow); } else { NDPI_LOG_DBG(ndpi_struct, "STUN not yet excluded, need next packet\n"); @@ -416,4 +418,3 @@ void init_rtp_dissector(struct ndpi_detection_module_struct *ndpi_struct, *id += 1; } - diff --git a/src/lib/protocols/ssh.c b/src/lib/protocols/ssh.c index 1a20078c3..7e5ca5e62 100644 --- a/src/lib/protocols/ssh.c +++ b/src/lib/protocols/ssh.c @@ -2,7 +2,7 @@ * ssh.c * * Copyright (C) 2009-2011 by ipoque GmbH - * Copyright (C) 2011-18 - ntop.org + * Copyright (C) 2011-19 - ntop.org * * This file is part of nDPI, an open source deep packet inspection * library based on the OpenDPI and PACE technology by ipoque GmbH @@ -19,7 +19,7 @@ * * You should have received a copy of the GNU Lesser General Public License * along with nDPI. If not, see <http://www.gnu.org/licenses/>. - * + * */ #include "ndpi_protocol_ids.h" @@ -27,12 +27,134 @@ #define NDPI_CURRENT_PROTO NDPI_PROTOCOL_SSH #include "ndpi_api.h" +#include "ndpi_md5.h" + +/* + HASSH - https://github.com/salesforce/hassh + + https://github.com/salesforce/hassh/blob/master/python/hassh.py + + [server] + skex = packet.ssh.kex_algorithms + seastc = packet.ssh.encryption_algorithms_server_to_client + smastc = packet.ssh.mac_algorithms_server_to_client + scastc = packet.ssh.compression_algorithms_server_to_client + hasshs_str = ';'.join([skex, seastc, smastc, scastc]) + + [client] + ckex = packet.ssh.kex_algorithms + ceacts = packet.ssh.encryption_algorithms_client_to_server + cmacts = packet.ssh.mac_algorithms_client_to_server + ccacts = packet.ssh.compression_algorithms_client_to_server + hassh_str = ';'.join([ckex, ceacts, cmacts, ccacts]) +*/ + +/* #define SSH_DEBUG 1 */ + +/* ************************************************************************ */ static void ndpi_int_ssh_add_connection(struct ndpi_detection_module_struct - *ndpi_struct, struct ndpi_flow_struct *flow){ + *ndpi_struct, struct ndpi_flow_struct *flow) { ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SSH, NDPI_PROTOCOL_UNKNOWN); } +/* ************************************************************************ */ + +static u_int16_t concat_hash_string(struct ndpi_packet_struct *packet, + char *buf, u_int8_t client_hash) { + u_int16_t offset = 22, buf_out_len = 0; + u_int32_t len = ntohl(*(u_int32_t*)&packet->payload[offset]); + + if(len < (packet->payload_packet_len-offset)) { + /* ssh.kex_algorithms [C/S] */ + offset += 4; + strncpy(buf, (const char *)&packet->payload[offset], buf_out_len = len); + buf[buf_out_len++] = ';'; + offset += len; + + /* ssh.server_host_key_algorithms [None] */ + len = ntohl(*(u_int32_t*)&packet->payload[offset]); + offset += 4 + len; + + /* ssh.encryption_algorithms_client_to_server [C] */ + len = ntohl(*(u_int32_t*)&packet->payload[offset]); + + if(client_hash) { + offset += 4; + strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len); + buf_out_len += len; + buf[buf_out_len++] = ';'; + offset += len; + } else + offset += 4 + len; + + /* ssh.encryption_algorithms_server_to_client [S] */ + len = ntohl(*(u_int32_t*)&packet->payload[offset]); + if(!client_hash) { + offset += 4; + strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len); + buf_out_len += len; + buf[buf_out_len++] = ';'; + offset += len; + } else + offset += 4 + len; + + /* ssh.mac_algorithms_client_to_server [C] */ + len = ntohl(*(u_int32_t*)&packet->payload[offset]); + if(client_hash) { + offset += 4; + strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len); + buf_out_len += len; + buf[buf_out_len++] = ';'; + offset += len; + } else + offset += 4 + len; + + /* ssh.mac_algorithms_server_to_client [S] */ + len = ntohl(*(u_int32_t*)&packet->payload[offset]); + if(!client_hash) { + offset += 4; + strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len); + buf_out_len += len; + buf[buf_out_len++] = ';'; + offset += len; + } else + offset += 4 + len; + + /* ssh.compression_algorithms_client_to_server [C] */ + len = ntohl(*(u_int32_t*)&packet->payload[offset]); + if(client_hash) { + offset += 4; + strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len); + buf_out_len += len; + offset += len; + } else + offset += 4 + len; + + /* ssh.compression_algorithms_server_to_client [S] */ + len = ntohl(*(u_int32_t*)&packet->payload[offset]); + if(!client_hash) { + offset += 4; + strncpy(&buf[buf_out_len], (const char *)&packet->payload[offset], len); + buf_out_len += len; + offset += len; + } else + offset += 4 + len; + + /* ssh.languages_client_to_server [None] */ + + /* ssh.languages_server_to_client [None] */ + } + +#ifdef SSH_DEBUG + printf("\n[SSH] %s\n", buf); +#endif + + return(buf_out_len); +} + +/* ************************************************************************ */ + static void ndpi_ssh_zap_cr(char *str, int len) { len--; @@ -45,46 +167,132 @@ static void ndpi_ssh_zap_cr(char *str, int len) { } } -void ndpi_search_ssh_tcp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) -{ - struct ndpi_packet_struct *packet = &flow->packet; +/* ************************************************************************ */ + +void ndpi_search_ssh_tcp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { + struct ndpi_packet_struct *packet = &flow->packet; + +#ifdef SSH_DEBUG + printf("\n[SSH] [stage: %u]\n", flow->l4.tcp.ssh_stage); +#endif - if (flow->l4.tcp.ssh_stage == 0) { - if (packet->payload_packet_len > 7 && packet->payload_packet_len < 100 + if(flow->l4.tcp.ssh_stage == 0) { + if(packet->payload_packet_len > 7 && packet->payload_packet_len < 100 && memcmp(packet->payload, "SSH-", 4) == 0) { if(!ndpi_struct->disable_metadata_export) { - int len = ndpi_min(sizeof(flow->protos.ssh.client_signature)-1, packet->payload_packet_len); + int len = ndpi_min(sizeof(flow->protos.ssh.client_signature)-1, packet->payload_packet_len); + strncpy(flow->protos.ssh.client_signature, (const char *)packet->payload, len); flow->protos.ssh.client_signature[len] = '\0'; ndpi_ssh_zap_cr(flow->protos.ssh.client_signature, len); + +#ifdef SSH_DEBUG + printf("\n[SSH] [client_signature: %s]\n", flow->protos.ssh.client_signature); +#endif } - + NDPI_LOG_DBG2(ndpi_struct, "ssh stage 0 passed\n"); flow->l4.tcp.ssh_stage = 1 + packet->packet_direction; + flow->guessed_host_protocol_id = flow->guessed_protocol_id = NDPI_PROTOCOL_SSH; return; } - } else if (flow->l4.tcp.ssh_stage == (2 - packet->packet_direction)) { - if (packet->payload_packet_len > 7 && packet->payload_packet_len < 500 + } else if(flow->l4.tcp.ssh_stage == (2 - packet->packet_direction)) { + if(packet->payload_packet_len > 7 && packet->payload_packet_len < 500 && memcmp(packet->payload, "SSH-", 4) == 0) { if(!ndpi_struct->disable_metadata_export) { int len = ndpi_min(sizeof(flow->protos.ssh.server_signature)-1, packet->payload_packet_len); + strncpy(flow->protos.ssh.server_signature, (const char *)packet->payload, len); flow->protos.ssh.server_signature[len] = '\0'; ndpi_ssh_zap_cr(flow->protos.ssh.server_signature, len); + +#ifdef SSH_DEBUG + printf("\n[SSH] [server_signature: %s]\n", flow->protos.ssh.server_signature); +#endif + + NDPI_LOG_DBG2(ndpi_struct, "ssh stage 1 passed\n"); + flow->l4.tcp.ssh_stage++;; + flow->guessed_host_protocol_id = flow->guessed_protocol_id = NDPI_PROTOCOL_SSH; + } else { + NDPI_LOG_INFO(ndpi_struct, "found ssh\n"); + ndpi_int_ssh_add_connection(ndpi_struct, flow); } - - NDPI_LOG_INFO(ndpi_struct, "found ssh\n"); - - ndpi_int_ssh_add_connection(ndpi_struct, flow); + +#ifdef SSH_DEBUG + printf("\n[SSH] [completed stage: %u]\n", flow->l4.tcp.ssh_stage); +#endif + return; + } + } else { + u_int8_t msgcode = *(packet->payload + 5); + ndpi_MD5_CTX ctx; + +#ifdef SSH_DEBUG + printf("\n[SSH] [stage: %u][msg: %u]\n", flow->l4.tcp.ssh_stage, msgcode); +#endif + if(msgcode == 20 /* key exchange init */) { + char *hassh_buf = calloc(packet->payload_packet_len, sizeof(char)); + u_int i, len; + + if(hassh_buf) { + if(flow->l4.tcp.ssh_stage == 3) { + u_char fingerprint_client[16]; + + len = concat_hash_string(packet, hassh_buf, 1 /* client */); + + ndpi_MD5Init(&ctx); + ndpi_MD5Update(&ctx, (const unsigned char *)hassh_buf, len); + ndpi_MD5Final(fingerprint_client, &ctx); + +#ifdef SSH_DEBUG + { + printf("\n[SSH] [client][%s][", hassh_buf); + for(i=0; i<16; i++) printf("%02X", fingerprint_client[i]); + printf("]\n"); + } +#endif + for(i=0; i<16; i++) sprintf(&flow->protos.ssh.hassh_client[i*2], "%02X", fingerprint_client[i] & 0xFF); + flow->protos.ssh.hassh_client[32] = '\0'; + } else { + u_char fingerprint_server[16]; + + len = concat_hash_string(packet, hassh_buf, 0 /* server */); + + ndpi_MD5Init(&ctx); + ndpi_MD5Update(&ctx, (const unsigned char *)hassh_buf, len); + ndpi_MD5Final(fingerprint_server, &ctx); + +#ifdef SSH_DEBUG + { + printf("\n[SSH] [server][%s][", hassh_buf); + for(i=0; i<16; i++) printf("%02X", fingerprint_server[i]); + printf("]\n"); + } +#endif + + for(i=0; i<16; i++) sprintf(&flow->protos.ssh.hassh_server[i*2], "%02X", fingerprint_server[i] & 0xFF); + flow->protos.ssh.hassh_server[32] = '\0'; + } + + free(hassh_buf); + } } + + if(flow->l4.tcp.ssh_stage++ == 4) { + NDPI_LOG_INFO(ndpi_struct, "found ssh\n"); + ndpi_int_ssh_add_connection(ndpi_struct, flow); + } + + return; } NDPI_LOG_DBG(ndpi_struct, "excluding ssh at stage %d\n", flow->l4.tcp.ssh_stage); NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_SSH); } +/* ************************************************************************ */ void init_ssh_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) { diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c index 202b3d939..8334c667a 100644 --- a/src/lib/protocols/stun.c +++ b/src/lib/protocols/stun.c @@ -30,7 +30,9 @@ #define MAX_NUM_STUN_PKTS 8 -// #define DEBUG_STUN 1 +/* #define DEBUG_STUN 1 */ + +/* #define DEBUG_LRU 1 */ struct stun_packet_header { u_int16_t msg_type, msg_len; @@ -38,9 +40,43 @@ struct stun_packet_header { u_int8_t transaction_id[8]; }; +/* ************************************************************ */ + +u_int32_t get_stun_lru_key(struct ndpi_flow_struct *flow) { + return(flow->packet.iph->saddr + flow->packet.udp->source); +} + +/* ************************************************************ */ + static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *ndpi_struct, - u_int proto, struct ndpi_flow_struct *flow) { - ndpi_set_detected_protocol(ndpi_struct, flow, proto, NDPI_PROTOCOL_UNKNOWN); + struct ndpi_flow_struct *flow, + u_int app_proto, u_int proto) { + if(ndpi_struct->stun_cache == NULL) + ndpi_struct->stun_cache = ndpi_lru_cache_init(1024); + + if(ndpi_struct->stun_cache + && flow->packet.iph + && flow->packet.udp + && (app_proto != NDPI_PROTOCOL_UNKNOWN) + ) /* Cache flow sender info */ { + u_int32_t key = get_stun_lru_key(flow); + u_int16_t cached_proto; + + if(ndpi_lru_find_cache(ndpi_struct->stun_cache, key, &cached_proto, 0 /* Don't remove it as it can be used for other connections */)) { +#ifdef DEBUG_LRU + printf("[LRU] FOUND %u / %u: no need to cache %u.%u\n", key, cached_proto, proto, app_proto); +#endif + app_proto = cached_proto, proto = NDPI_PROTOCOL_STUN; + } else { +#ifdef DEBUG_LRU + printf("[LRU] ADDING %u / %u.%u\n", key, proto, app_proto); +#endif + + ndpi_lru_add_to_cache(ndpi_struct->stun_cache, key, app_proto); + } + } + + ndpi_set_detected_protocol(ndpi_struct, flow, app_proto, proto); } typedef enum { @@ -48,6 +84,7 @@ typedef enum { NDPI_IS_NOT_STUN } ndpi_int_stun_t; +/* ************************************************************ */ static int is_google_ip_address(u_int32_t host) { if( @@ -59,6 +96,29 @@ static int is_google_ip_address(u_int32_t host) { return(0); } +/* ************************************************************ */ + +/* + WhatsApp + 31.13.86.48 + 31.13.92.50 + 157.240.20.51 + 157.240.21.51 + 185.60.216.51 + + Messenger + 31.13.86.5 +*/ + +static int is_messenger_ip_address(u_int32_t host) { + if(host == 0x1F0D5605 /* 31.13.86.5 */) + return(1); + else + return(0); +} + +/* ************************************************************ */ + static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, const u_int8_t * payload, @@ -77,7 +137,7 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * *is_whatsapp = 0, *is_messenger = 0, *is_duo = 0; if(payload_length < sizeof(struct stun_packet_header)) { - /* This looks like an invlid packet */ + /* This looks like an invalid packet */ if(flow->protos.stun_ssl.stun.num_udp_pkts > 0) { *is_whatsapp = 1; @@ -98,18 +158,47 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * if(msg_type > 0x000C) return(NDPI_IS_NOT_STUN); + if(ndpi_struct->stun_cache) { + u_int16_t proto; + u_int32_t key = get_stun_lru_key(flow); + + if(ndpi_lru_find_cache(ndpi_struct->stun_cache, key, &proto, 0 /* Don't remove it as it can be used for other connections */)) { +#ifdef DEBUG_LRU + printf("[LRU] FOUND %u / %u\n", key, proto); +#endif + + flow->guessed_host_protocol_id = proto, flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; + return(NDPI_IS_STUN); + } else { +#ifdef DEBUG_LRU + printf("[LRU] NOT FOUND %u\n", key); +#endif + } + } else { +#ifdef DEBUG_LRU + printf("[LRU] NO/EMPTY CACHE\n"); +#endif + } + if(msg_type == 0x01 /* Binding Request */) { flow->protos.stun_ssl.stun.num_binding_requests++; - if((msg_len == 0) && (flow->guessed_host_protocol_id == NDPI_PROTOCOL_GOOGLE)) { + + if((msg_len == 0) && (flow->guessed_host_protocol_id == NDPI_PROTOCOL_GOOGLE)) flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO; - } + else + flow->guessed_host_protocol_id = NDPI_PROTOCOL_STUN; + + flow->protos.stun_ssl.stun.num_udp_pkts++; + + if(msg_len == 0) + return(NDPI_IS_NOT_STUN); /* This to keep analyzing STUN instead of giving up */ } if((msg_len == 0) && (flow->guessed_host_protocol_id == NDPI_PROTOCOL_UNKNOWN)) { NDPI_EXCLUDE_PROTO(ndpi_struct, flow); return(NDPI_IS_NOT_STUN); } - + flow->protos.stun_ssl.stun.num_udp_pkts++; /* @@ -131,9 +220,20 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * if((payload[0] != 0x80) && ((msg_len+20) > payload_length)) return(NDPI_IS_NOT_STUN); - else - flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; - + else { + switch(flow->guessed_protocol_id) { + case NDPI_PROTOCOL_HANGOUT_DUO: + case NDPI_PROTOCOL_MESSENGER: + case NDPI_PROTOCOL_WHATSAPP_VOICE: + /* Don't overwrite the protocol with sub-STUN protocols */ + break; + + default: + flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; + break; + } + } + if(payload_length == (msg_len+20)) { if(msg_type <= 0x000b) /* http://www.3cx.com/blog/voip-howto/stun-details/ */ { u_int offset = 20; @@ -157,6 +257,10 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * if(x != 0) len += 4-x; +#ifdef DEBUG_STUN + printf("==> Attribute: %04X\n", attribute); +#endif + switch(attribute) { case 0x0008: /* Message Integrity */ case 0x0020: /* XOR-MAPPED-ADDRESSES */ @@ -166,6 +270,28 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * /* These are the only messages apparently whatsapp voice can use */ break; + case 0x0014: /* Realm */ + { + u_int16_t realm_len = ntohs(*((u_int16_t*)&payload[offset+2])); + + if(flow->host_server_name[0] == '\0') { + u_int j, i = (realm_len > sizeof(flow->host_server_name)) ? sizeof(flow->host_server_name) : realm_len; + u_int k = offset+4; + + memset(flow->host_server_name, 0, sizeof(flow->host_server_name)); + + for(j=0; j<i; j++) + flow->host_server_name[j] = payload[k++]; + + if(strstr((char*)flow->host_server_name, "google.com") != NULL) { + *is_duo = 1; + flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO, flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; + return(NDPI_IS_STUN); + } + } + } + break; + case 0xC057: /* Messeger */ if(msg_type == 0x0001) { if((msg_len == 100) || (msg_len == 104)) { @@ -173,7 +299,12 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * return(NDPI_IS_STUN); } else if(msg_len == 76) { *is_duo = 1; - return(NDPI_IS_STUN); + + if(1) { + flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO, flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; + return(NDPI_IS_NOT_STUN); /* This case is found also with signal traffic */ + } else + return(NDPI_IS_STUN); } } break; @@ -185,6 +316,9 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * && (payload[offset+6] == 0x00) && (payload[offset+7] == 0x00)) { /* Either skype for business or "normal" skype with multiparty call */ +#ifdef DEBUG_STUN + printf("==> Skype found\n"); +#endif flow->protos.stun_ssl.stun.is_skype = 1; return(NDPI_IS_STUN); } @@ -201,6 +335,10 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * case 0x0800: /* printf("====>>>> %04X\n", attribute); */ flow->protos.stun_ssl.stun.is_skype = 1; +#ifdef DEBUG_STUN + printf("==> Skype (2) found\n"); +#endif + return(NDPI_IS_STUN); break; @@ -213,6 +351,10 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * && ((payload[offset+7] == 0x02) || (payload[offset+7] == 0x03)) ) { flow->protos.stun_ssl.stun.is_skype = 1; +#ifdef DEBUG_STUN + printf("==> Skype (3) found\n"); +#endif + return(NDPI_IS_STUN); } break; @@ -221,7 +363,7 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * can_this_be_whatsapp_voice = 0; flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO; break; - + default: /* This means this STUN packet cannot be confused with whatsapp voice */ #ifdef DEBUG_STUN @@ -249,15 +391,16 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * udp_stun_found: if(can_this_be_whatsapp_voice) { struct ndpi_packet_struct *packet = &flow->packet; - + flow->protos.stun_ssl.stun.num_processed_pkts++; #ifdef DEBUG_STUN printf("==>> NDPI_PROTOCOL_WHATSAPP_VOICE\n"); #endif - if((ntohs(packet->udp->source) == 3478) || (ntohs(packet->udp->dest) == 3478)) - flow->guessed_host_protocol_id = NDPI_PROTOCOL_WHATSAPP_VOICE; - else + if((ntohs(packet->udp->source) == 3478) || (ntohs(packet->udp->dest) == 3478)) { + flow->guessed_host_protocol_id = (is_messenger_ip_address(ntohl(packet->iph->saddr)) || is_messenger_ip_address(ntohl(packet->iph->daddr))) ? + NDPI_PROTOCOL_MESSENGER : NDPI_PROTOCOL_WHATSAPP_VOICE; + } else flow->guessed_host_protocol_id = (is_google_ip_address(ntohl(packet->iph->saddr)) || is_google_ip_address(ntohl(packet->iph->daddr))) ? NDPI_PROTOCOL_HANGOUT_DUO : NDPI_PROTOCOL_WHATSAPP_VOICE; return((flow->protos.stun_ssl.stun.num_udp_pkts < MAX_NUM_STUN_PKTS) ? NDPI_IS_NOT_STUN : NDPI_IS_STUN); @@ -295,23 +438,24 @@ void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct n if(ndpi_int_check_stun(ndpi_struct, flow, packet->payload + 2, packet->payload_packet_len - 2, &is_whatsapp, &is_messenger, &is_duo) == NDPI_IS_STUN) { - if(flow->guessed_protocol_id == 0) flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; + if(flow->guessed_protocol_id == NDPI_PROTOCOL_UNKNOWN) flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; if(is_messenger) { - ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_STUN); + ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_STUN); return; } else if(is_duo) { - ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO, NDPI_PROTOCOL_STUN); + ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO, NDPI_PROTOCOL_STUN); return; } else if(flow->protos.stun_ssl.stun.is_skype) { NDPI_LOG_INFO(ndpi_struct, "found Skype\n"); if((flow->protos.stun_ssl.stun.num_processed_pkts >= 8) || (flow->protos.stun_ssl.stun.num_binding_requests >= 4)) - ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE); + ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE); } else { NDPI_LOG_INFO(ndpi_struct, "found UDP stun\n"); /* Ummmmm we're in the TCP branch. This code looks bad */ - ndpi_int_stun_add_connection(ndpi_struct, - is_whatsapp ? (is_whatsapp == 1 ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_WHATSAPP_VIDEO) : NDPI_PROTOCOL_STUN, flow); + ndpi_int_stun_add_connection(ndpi_struct, flow, + is_whatsapp ? (is_whatsapp == 1 ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_WHATSAPP_VIDEO) : NDPI_PROTOCOL_STUN, + NDPI_PROTOCOL_UNKNOWN); } return; @@ -323,26 +467,25 @@ void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct n if(ndpi_int_check_stun(ndpi_struct, flow, packet->payload, packet->payload_packet_len, &is_whatsapp, &is_messenger, &is_duo) == NDPI_IS_STUN) { - if(flow->guessed_protocol_id == 0) flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; + if(flow->guessed_protocol_id == NDPI_PROTOCOL_UNKNOWN) flow->guessed_protocol_id = NDPI_PROTOCOL_STUN; if(is_messenger) { - ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_STUN); + ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_STUN); return; } else if(is_duo) { - ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO, NDPI_PROTOCOL_STUN); + ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO, NDPI_PROTOCOL_STUN); return; } else if(flow->protos.stun_ssl.stun.is_skype) { NDPI_LOG_INFO(ndpi_struct, "Found Skype\n"); /* flow->protos.stun_ssl.stun.num_binding_requests < 4) ? NDPI_PROTOCOL_SKYPE_CALL_IN : NDPI_PROTOCOL_SKYPE_CALL_OUT */ if((flow->protos.stun_ssl.stun.num_processed_pkts >= 8) || (flow->protos.stun_ssl.stun.num_binding_requests >= 4)) - ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE); + ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE); } else { NDPI_LOG_INFO(ndpi_struct, "found UDP stun\n"); - ndpi_int_stun_add_connection(ndpi_struct, + ndpi_int_stun_add_connection(ndpi_struct, flow, is_whatsapp ? (is_whatsapp == 1 ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_WHATSAPP_VIDEO) - : NDPI_PROTOCOL_STUN, - flow); + : NDPI_PROTOCOL_STUN, NDPI_PROTOCOL_UNKNOWN); } return; diff --git a/src/lib/protocols/teamspeak.c b/src/lib/protocols/teamspeak.c index 214a2fe99..170be1d7f 100644 --- a/src/lib/protocols/teamspeak.c +++ b/src/lib/protocols/teamspeak.c @@ -35,32 +35,43 @@ void ndpi_search_teamspeak(struct ndpi_detection_module_struct *ndpi_struct, str struct ndpi_packet_struct *packet = &flow->packet; NDPI_LOG_DBG(ndpi_struct, "search teamspeak\n"); + - if (packet->udp != NULL) { +#ifdef WEAK_DETECTION_CODE_DISABLED + if(packet->udp != NULL) { u_int16_t udport, usport; + usport = ntohs(packet->udp->source), udport = ntohs(packet->udp->dest); + /* http://www.imfirewall.com/en/protocols/teamSpeak.htm */ - if (((usport == 9987 || udport == 9987) || (usport == 8767 || udport == 8767)) && packet->payload_packet_len >= 20) { + if(((usport == 9987 || udport == 9987) || (usport == 8767 || udport == 8767)) && packet->payload_packet_len >= 20) { NDPI_LOG_INFO(ndpi_struct, "found TEAMSPEAK udp\n"); ndpi_int_teamspeak_add_connection(ndpi_struct, flow); } } - else if (packet->tcp != NULL) { - u_int16_t tdport, tsport; - tsport = ntohs(packet->tcp->source), tdport = ntohs(packet->tcp->dest); - /* https://github.com/Youx/soliloque-server/wiki/Connection-packet */ - if(packet->payload_packet_len >= 20) { - if (((memcmp(packet->payload, "\xf4\xbe\x03\x00", 4) == 0)) || - ((memcmp(packet->payload, "\xf4\xbe\x02\x00", 4) == 0)) || + else +#endif + + if(packet->tcp != NULL) { + u_int16_t tdport, tsport; + tsport = ntohs(packet->tcp->source), tdport = ntohs(packet->tcp->dest); + /* https://github.com/Youx/soliloque-server/wiki/Connection-packet */ + if(packet->payload_packet_len >= 20) { + if(((memcmp(packet->payload, "\xf4\xbe\x03\x00", 4) == 0)) || + ((memcmp(packet->payload, "\xf4\xbe\x02\x00", 4) == 0)) || ((memcmp(packet->payload, "\xf4\xbe\x01\x00", 4) == 0))) { - NDPI_LOG_INFO(ndpi_struct, "found TEAMSPEAK tcp\n"); - ndpi_int_teamspeak_add_connection(ndpi_struct, flow); - } /* http://www.imfirewall.com/en/protocols/teamSpeak.htm */ - } else if ((tsport == 14534 || tdport == 14534) || (tsport == 51234 || tdport == 51234)) { - NDPI_LOG_INFO(ndpi_struct, "found TEAMSPEAK\n"); - ndpi_int_teamspeak_add_connection(ndpi_struct, flow); - } - } + NDPI_LOG_INFO(ndpi_struct, "found TEAMSPEAK tcp\n"); + ndpi_int_teamspeak_add_connection(ndpi_struct, flow); + } /* http://www.imfirewall.com/en/protocols/teamSpeak.htm */ + } +#if WEAK_DETECTION_CODE_DISABLED + else if((tsport == 14534 || tdport == 14534) || (tsport == 51234 || tdport == 51234)) { + NDPI_LOG_INFO(ndpi_struct, "found TEAMSPEAK\n"); + ndpi_int_teamspeak_add_connection(ndpi_struct, flow); + } +#endif + } + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); return; } diff --git a/src/lib/protocols/ssl.c b/src/lib/protocols/tls.c index 18e8ca469..d9b7b0962 100644 --- a/src/lib/protocols/ssl.c +++ b/src/lib/protocols/tls.c @@ -1,7 +1,7 @@ /* - * ssl.c + * tls.c - SSL/TLS/DTLS dissector * - * Copyright (C) 2016-18 - ntop.org + * Copyright (C) 2016-19 - ntop.org * * This file is part of nDPI, an open source deep packet inspection * library based on the OpenDPI and PACE technology by ipoque GmbH @@ -23,13 +23,14 @@ #include "ndpi_protocol_ids.h" -#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_SSL +#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_TLS #include "ndpi_api.h" +#include "ndpi_md5.h" -/* #define CERTIFICATE_DEBUG 1 */ +// #define DEBUG_TLS 1 -#define NDPI_MAX_SSL_REQUEST_SIZE 10000 +#define NDPI_MAX_TLS_REQUEST_SIZE 10000 /* Skype.c */ extern u_int8_t is_skype_flow(struct ndpi_detection_module_struct *ndpi_struct, @@ -37,220 +38,23 @@ extern u_int8_t is_skype_flow(struct ndpi_detection_module_struct *ndpi_struct, /* **************************************** */ -typedef struct MD5Context { - uint32_t buf[4]; - uint32_t bits[2]; - unsigned char in[64]; -} MD5_CTX; - -/* **************************************** */ - -static int is_big_endian(void) { - static const int n = 1; - return ((char *) &n)[0] == 0; -} - -static void byteReverse(unsigned char *buf, unsigned longs) { - uint32_t t; - - // Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN - if (is_big_endian()) { - do { - t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | - ((unsigned) buf[1] << 8 | buf[0]); - * (uint32_t *) buf = t; - buf += 4; - } while (--longs); - } -} - -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) - -// Start MD5 accumulation. Set bit count to 0 and buffer to mysterious -// initialization constants. -static void MD5Init(MD5_CTX *ctx) { - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) { - uint32_t a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) { - uint32_t t; - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) - ctx->bits[1]++; - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; - - if (t) { - unsigned char *p = (unsigned char *) ctx->in + t; - - t = 64 - t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - buf += t; - len -= t; - } - - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - buf += 64; - len -= 64; - } - - memcpy(ctx->in, buf, len); -} - -static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) { - unsigned count; - unsigned char *p; - uint32_t *c = (uint32_t*)ctx->in; - - count = (ctx->bits[0] >> 3) & 0x3F; - - p = ctx->in + count; - *p++ = 0x80; - count = 64 - 1 - count; - if (count < 8) { - memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - memset(ctx->in, 0, 56); - } else { - memset(p, 0, count - 8); - } - byteReverse(ctx->in, 14); - - c[14] = ctx->bits[0]; - c[15] = ctx->bits[1]; - - MD5Transform(ctx->buf, (uint32_t *) ctx->in); - byteReverse((unsigned char *) ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset((char *) ctx, 0, sizeof(*ctx)); -} - -/* **************************************** */ - -static u_int32_t ndpi_ssl_refine_master_protocol(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow, u_int32_t protocol) -{ +static u_int32_t ndpi_tls_refine_master_protocol(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, u_int32_t protocol) { struct ndpi_packet_struct *packet = &flow->packet; if(((flow->l4.tcp.ssl_seen_client_cert == 1) && (flow->protos.stun_ssl.ssl.ja3_client[0] != '\0')) || ((flow->l4.tcp.ssl_seen_server_cert == 1) && (flow->protos.stun_ssl.ssl.ja3_server[0] != '\0')) // || (flow->host_server_name[0] != '\0') ) - protocol = NDPI_PROTOCOL_SSL; + protocol = NDPI_PROTOCOL_TLS; else - protocol = NDPI_PROTOCOL_SSL_NO_CERT; + protocol = NDPI_PROTOCOL_TLS_NO_CERT; if(packet->tcp != NULL) { switch(protocol) { - case NDPI_PROTOCOL_SSL: - case NDPI_PROTOCOL_SSL_NO_CERT: + case NDPI_PROTOCOL_TLS: + case NDPI_PROTOCOL_TLS_NO_CERT: { /* In case of SSL there are probably sub-protocols @@ -273,18 +77,21 @@ static u_int32_t ndpi_ssl_refine_master_protocol(struct ndpi_detection_module_st return protocol; } -static void ndpi_int_ssl_add_connection(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow, u_int32_t protocol) -{ - if((protocol != NDPI_PROTOCOL_SSL) - && (protocol != NDPI_PROTOCOL_SSL_NO_CERT)) { +/* **************************************** */ + +static void ndpi_int_tls_add_connection(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, u_int32_t protocol) { + if((protocol != NDPI_PROTOCOL_TLS) + && (protocol != NDPI_PROTOCOL_TLS_NO_CERT)) { ndpi_set_detected_protocol(ndpi_struct, flow, protocol, NDPI_PROTOCOL_UNKNOWN); } else { - protocol = ndpi_ssl_refine_master_protocol(ndpi_struct, flow, protocol); + protocol = ndpi_tls_refine_master_protocol(ndpi_struct, flow, protocol); ndpi_set_detected_protocol(ndpi_struct, flow, protocol, NDPI_PROTOCOL_UNKNOWN); } } +/* **************************************** */ + /* Can't call libc functions from kernel space, define some stub instead */ #define ndpi_isalpha(ch) (((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z')) @@ -296,8 +103,9 @@ static void ndpi_int_ssl_add_connection(struct ndpi_detection_module_struct *ndp ((ch) >= '[' && (ch) <= '`') || \ ((ch) >= '{' && (ch) <= '~')) -static void stripCertificateTrailer(char *buffer, int buffer_len) { +/* **************************************** */ +static void stripCertificateTrailer(char *buffer, int buffer_len) { int i, is_puny; // printf("->%s<-\n", buffer); @@ -346,42 +154,53 @@ static void stripCertificateTrailer(char *buffer, int buffer_len) { buffer[i] = tolower(buffer[i]); } +/* **************************************** */ + /* https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967 */ #define JA3_STR_LEN 1024 #define MAX_NUM_JA3 128 struct ja3_info { - u_int16_t ssl_version; + u_int16_t tls_version; u_int16_t num_cipher, cipher[MAX_NUM_JA3]; - u_int16_t num_ssl_extension, ssl_extension[MAX_NUM_JA3]; + u_int16_t num_tls_extension, tls_extension[MAX_NUM_JA3]; u_int16_t num_elliptic_curve, elliptic_curve[MAX_NUM_JA3]; u_int8_t num_elliptic_curve_point_format, elliptic_curve_point_format[MAX_NUM_JA3]; }; /* **************************************** */ -/* code fixes courtesy of Alexsandro Brahm <alex@digistar.com.br> */ -int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, +int getTLScertificate(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, char *buffer, int buffer_len) { struct ndpi_packet_struct *packet = &flow->packet; struct ja3_info ja3; + int i; u_int8_t invalid_ja3 = 0; - u_int16_t ssl_version = (packet->payload[1] << 8) + packet->payload[2], ja3_str_len; + u_int16_t pkt_tls_version = (packet->payload[1] << 8) + packet->payload[2], ja3_str_len; char ja3_str[JA3_STR_LEN]; - MD5_CTX ctx; + ndpi_MD5_CTX ctx; u_char md5_hash[16]; - flow->protos.stun_ssl.ssl.ssl_version = ssl_version; + if(packet->udp) { + /* Check if this is DTLS or return */ + if((packet->payload[1] != 0xfe) + || ((packet->payload[2] != 0xff) && (packet->payload[2] != 0xfd))) { + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + return(0); + } + } + + flow->protos.stun_ssl.ssl.ssl_version = pkt_tls_version; memset(&ja3, 0, sizeof(ja3)); -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS { - u_int16_t ssl_len = (packet->payload[3] << 8) + packet->payload[4]; + u_int16_t tls_len = (packet->payload[3] << 8) + packet->payload[4]; - printf("SSL Record [version: %u][len: %u]\n", ssl_version, ssl_len); + printf("SSL Record [version: 0x%04X][len: %u]\n", pkt_tls_version, tls_len); } #endif @@ -390,9 +209,21 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, Patches courtesy of Denys Fedoryshchenko <nuclearcat@nuclearcat.com> */ if(packet->payload[0] == 0x16 /* Handshake */) { - u_int16_t total_len = (packet->payload[3] << 8) + packet->payload[4] + 5 /* SSL Header */; - u_int8_t handshake_protocol = packet->payload[5]; /* handshake protocol a bit misleading, it is message type according TLS specs */ + u_int16_t total_len; + u_int8_t handshake_protocol, header_len; + + if(packet->tcp) { + header_len = 5; /* SSL Header */ + handshake_protocol = packet->payload[5]; /* handshake protocol a bit misleading, it is message type according TLS specs */ + total_len = (packet->payload[3] << 8) + packet->payload[4]; + } else { + header_len = 13; /* DTLS header */ + handshake_protocol = packet->payload[13]; + total_len = ntohs(*((u_int16_t*)&packet->payload[11])); + } + total_len += header_len; + memset(buffer, 0, buffer_len); /* Truncate total len, search at least in incomplete packet */ @@ -401,48 +232,58 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, /* At least "magic" 3 bytes, null for string end, otherwise no need to waste cpu cycles */ if(total_len > 4) { - int i; - -#ifdef CERTIFICATE_DEBUG + u_int16_t base_offset = packet->tcp ? 43 : 59; + +#ifdef DEBUG_TLS printf("SSL [len: %u][handshake_protocol: %02X]\n", packet->payload_packet_len, handshake_protocol); #endif - + if((handshake_protocol == 0x02) - || (handshake_protocol == 0xb) /* Server Hello and Certificate message types are interesting for us */) { + || (handshake_protocol == 0x0b) /* Server Hello and Certificate message types are interesting for us */) { u_int num_found = 0; - u_int16_t ssl_version = ntohs(*((u_int16_t*)&packet->payload[9])); + u_int16_t tls_version; + int i; - ja3.ssl_version = ssl_version; + if(packet->tcp) + tls_version = ntohs(*((u_int16_t*)&packet->payload[header_len+4])); + else + tls_version = ntohs(*((u_int16_t*)&packet->payload[header_len+12])); + + ja3.tls_version = tls_version; if(handshake_protocol == 0x02) { - u_int16_t offset = 43, extension_len, j; - u_int8_t session_id_len = packet->payload[43]; + u_int16_t offset = base_offset, extension_len, j; + u_int8_t session_id_len = packet->payload[offset]; -#ifdef CERTIFICATE_DEBUG - printf("SSL Server Hello [version: 0x%04X]\n", ssl_version); +#ifdef DEBUG_TLS + printf("SSL Server Hello [version: 0x%04X]\n", tls_version); #endif /* The server hello decides about the SSL version of this flow https://networkengineering.stackexchange.com/questions/55752/why-does-wireshark-show-version-tls-1-2-here-instead-of-tls-1-3 */ - flow->protos.stun_ssl.ssl.ssl_version = ssl_version; - - if(ssl_version < 0x7F15 /* TLS 1.3 lacks of session id */) - offset += session_id_len+1; + flow->protos.stun_ssl.ssl.ssl_version = tls_version; + if(packet->udp) + offset += 1; + else { + if(tls_version < 0x7F15 /* TLS 1.3 lacks of session id */) + offset += session_id_len+1; + } + ja3.num_cipher = 1, ja3.cipher[0] = ntohs(*((u_int16_t*)&packet->payload[offset])); flow->protos.stun_ssl.ssl.server_unsafe_cipher = ndpi_is_safe_ssl_cipher(ja3.cipher[0]); flow->protos.stun_ssl.ssl.server_cipher = ja3.cipher[0]; -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("SSL [server][session_id_len: %u][cipher: %04X]\n", session_id_len, ja3.cipher[0]); #endif offset += 2 + 1; extension_len = ntohs(*((u_int16_t*)&packet->payload[offset])); -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("SSL [server][extension_len: %u]\n", extension_len); #endif offset += 2; @@ -455,17 +296,17 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, id = ntohs(*((u_int16_t*)&packet->payload[offset])); len = ntohs(*((u_int16_t*)&packet->payload[offset+2])); - if(ja3.num_ssl_extension < MAX_NUM_JA3) - ja3.ssl_extension[ja3.num_ssl_extension++] = id; + if(ja3.num_tls_extension < MAX_NUM_JA3) + ja3.tls_extension[ja3.num_tls_extension++] = id; -#ifdef CERTIFICATE_DEBUG - printf("SSL [server][extension_id: %u]\n", id); +#ifdef DEBUG_TLS + printf("SSL [server][extension_id: %u/0x%04X]\n", id, id); #endif i += 4 + len, offset += 4 + len; } - ja3_str_len = snprintf(ja3_str, sizeof(ja3_str), "%u,", ja3.ssl_version); + ja3_str_len = snprintf(ja3_str, sizeof(ja3_str), "%u,", ja3.tls_version); for(i=0; i<ja3.num_cipher; i++) ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.cipher[i]); @@ -474,26 +315,26 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, /* ********** */ - for(i=0; i<ja3.num_ssl_extension; i++) - ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.ssl_extension[i]); + for(i=0; i<ja3.num_tls_extension; i++) + ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.tls_extension[i]); -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("SSL [server] %s\n", ja3_str); #endif -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("[JA3] Server: %s \n", ja3_str); #endif - MD5Init(&ctx); - MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str)); - MD5Final(md5_hash, &ctx); + ndpi_MD5Init(&ctx); + ndpi_MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str)); + ndpi_MD5Final(md5_hash, &ctx); for(i=0, j=0; i<16; i++) j += snprintf(&flow->protos.stun_ssl.ssl.ja3_server[j], sizeof(flow->protos.stun_ssl.ssl.ja3_server)-j, "%02x", md5_hash[i]); -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("[JA3] Server: %s \n", flow->protos.stun_ssl.ssl.ja3_server); #endif @@ -554,28 +395,46 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, } } } else if(handshake_protocol == 0x01 /* Client Hello */) { - u_int offset, base_offset = 43; + u_int offset; - if(base_offset + 2 <= packet->payload_packet_len) { - u_int16_t session_id_len = packet->payload[base_offset]; - u_int16_t ssl_version = ntohs(*((u_int16_t*)&packet->payload[9])); +#ifdef DEBUG_TLS + printf("[base_offset: %u][payload_packet_len: %u]\n", base_offset, packet->payload_packet_len); +#endif - ja3.ssl_version = ssl_version; + if(base_offset + 2 <= packet->payload_packet_len) { + u_int16_t session_id_len; + u_int16_t tls_version; + if(packet->tcp) + tls_version = ntohs(*((u_int16_t*)&packet->payload[header_len+4])); + else + tls_version = ntohs(*((u_int16_t*)&packet->payload[header_len+12])); + + session_id_len = packet->payload[base_offset]; + + ja3.tls_version = tls_version; + if((session_id_len+base_offset+2) <= total_len) { - u_int16_t cipher_len = packet->payload[session_id_len+base_offset+2] + (packet->payload[session_id_len+base_offset+1] << 8); - u_int16_t i, cipher_offset = base_offset + session_id_len + 3; + u_int16_t cipher_len, cipher_offset; -#ifdef CERTIFICATE_DEBUG - printf("Client SSL [client cipher_len: %u]\n", cipher_len); + if(packet->tcp) { + cipher_len = packet->payload[session_id_len+base_offset+2] + (packet->payload[session_id_len+base_offset+1] << 8); + cipher_offset = base_offset + session_id_len + 3; + } else { + cipher_len = ntohs(*((u_int16_t*)&packet->payload[base_offset+2])); + cipher_offset = base_offset+4; + } + +#ifdef DEBUG_TLS + printf("Client SSL [client cipher_len: %u][tls_version: 0x%04X]\n", cipher_len, tls_version); #endif if((cipher_offset+cipher_len) <= total_len) { for(i=0; i<cipher_len;) { u_int16_t *id = (u_int16_t*)&packet->payload[cipher_offset+i]; -#ifdef CERTIFICATE_DEBUG - printf("Client SSL [cipher suite: %u] [%u/%u]\n", ntohs(*id), i, cipher_len); +#ifdef DEBUG_TLS + printf("Client SSL [cipher suite: %u/0x%04X] [%u/%u]\n", ntohs(*id), ntohs(*id), i, cipher_len); #endif if((*id == 0) || (packet->payload[cipher_offset+i] != packet->payload[cipher_offset+i+1])) { /* @@ -587,7 +446,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, ja3.cipher[ja3.num_cipher++] = ntohs(*id); else { invalid_ja3 = 1; -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("Client SSL Invalid cipher %u\n", ja3.num_cipher); #endif } @@ -597,7 +456,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, } } else { invalid_ja3 = 1; -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("Client SSL Invalid len %u vs %u\n", (cipher_offset+cipher_len), total_len); #endif } @@ -610,11 +469,11 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t compression_len; u_int16_t extensions_len; - offset++; + offset += packet->tcp ? 1 : 2; compression_len = packet->payload[offset]; offset++; -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("Client SSL [compression_len: %u]\n", compression_len); #endif @@ -625,7 +484,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, extensions_len = ntohs(*((u_int16_t*)&packet->payload[offset])); offset += 2; -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("Client SSL [extensions_len: %u]\n", extensions_len); #endif @@ -644,19 +503,19 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, extension_len = ntohs(*((u_int16_t*)&packet->payload[offset+extension_offset])); extension_offset += 2; -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("Client SSL [extension_id: %u][extension_len: %u]\n", extension_id, extension_len); #endif if((extension_id == 0) || (packet->payload[extn_off] != packet->payload[extn_off+1])) { /* Skip GREASE */ - if(ja3.num_ssl_extension < MAX_NUM_JA3) - ja3.ssl_extension[ja3.num_ssl_extension++] = extension_id; + if(ja3.num_tls_extension < MAX_NUM_JA3) + ja3.tls_extension[ja3.num_tls_extension++] = extension_id; else { invalid_ja3 = 1; -#ifdef CERTIFICATE_DEBUG - printf("Client SSL Invalid extensions %u\n", ja3.num_ssl_extension); +#ifdef DEBUG_TLS + printf("Client SSL Invalid extensions %u\n", ja3.num_tls_extension); #endif } } @@ -676,9 +535,9 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, sizeof(flow->protos.stun_ssl.ssl.client_certificate), "%s", buffer); } } else if(extension_id == 10 /* supported groups */) { - u_int16_t i, s_offset = offset+extension_offset + 2; - -#ifdef CERTIFICATE_DEBUG + u_int16_t s_offset = offset+extension_offset + 2; + +#ifdef DEBUG_TLS printf("Client SSL [EllipticCurveGroups: len=%u]\n", extension_len); #endif @@ -686,8 +545,8 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, for(i=0; i<extension_len-2;) { u_int16_t s_group = ntohs(*((u_int16_t*)&packet->payload[s_offset+i])); -#ifdef CERTIFICATE_DEBUG - printf("Client SSL [EllipticCurve: %u]\n", s_group); +#ifdef DEBUG_TLS + printf("Client SSL [EllipticCurve: %u/0x%04X]\n", s_group, s_group); #endif if((s_group == 0) || (packet->payload[s_offset+i] != packet->payload[s_offset+i+1])) { /* Skip GREASE */ @@ -695,7 +554,7 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, ja3.elliptic_curve[ja3.num_elliptic_curve++] = s_group; else { invalid_ja3 = 1; -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("Client SSL Invalid num elliptic %u\n", ja3.num_elliptic_curve); #endif } @@ -705,21 +564,21 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, } } else { invalid_ja3 = 1; -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("Client SSL Invalid len %u vs %u\n", (s_offset+extension_len-1), total_len); #endif } } else if(extension_id == 11 /* ec_point_formats groups */) { - u_int16_t i, s_offset = offset+extension_offset + 1; - -#ifdef CERTIFICATE_DEBUG + u_int16_t s_offset = offset+extension_offset + 1; + +#ifdef DEBUG_TLS printf("Client SSL [EllipticCurveFormat: len=%u]\n", extension_len); #endif if((s_offset+extension_len) < total_len) { for(i=0; i<extension_len-1;i++) { u_int8_t s_group = packet->payload[s_offset+i]; -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("Client SSL [EllipticCurveFormat: %u]\n", s_group); #endif @@ -727,14 +586,14 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, ja3.elliptic_curve_point_format[ja3.num_elliptic_curve_point_format++] = s_group; else { invalid_ja3 = 1; -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("Client SSL Invalid num elliptic %u\n", ja3.num_elliptic_curve_point_format); #endif } } } else { invalid_ja3 = 1; -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("Client SSL Invalid len %u vs %u\n", s_offset+extension_len, total_len); #endif } @@ -742,13 +601,13 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, extension_offset += extension_len; -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("Client SSL [extension_offset/len: %u/%u]\n", extension_offset, extension_len); #endif } /* while */ if(!invalid_ja3) { - ja3_str_len = snprintf(ja3_str, sizeof(ja3_str), "%u,", ja3.ssl_version); + ja3_str_len = snprintf(ja3_str, sizeof(ja3_str), "%u,", ja3.tls_version); for(i=0; i<ja3.num_cipher; i++) { ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", @@ -759,9 +618,9 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, /* ********** */ - for(i=0; i<ja3.num_ssl_extension; i++) + for(i=0; i<ja3.num_tls_extension; i++) ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", - (i > 0) ? "-" : "", ja3.ssl_extension[i]); + (i > 0) ? "-" : "", ja3.tls_extension[i]); ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, ","); @@ -777,19 +636,20 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, ja3_str_len += snprintf(&ja3_str[ja3_str_len], sizeof(ja3_str)-ja3_str_len, "%s%u", (i > 0) ? "-" : "", ja3.elliptic_curve_point_format[i]); -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("[JA3] Client: %s \n", ja3_str); #endif - - MD5Init(&ctx); - MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str)); - MD5Final(md5_hash, &ctx); + + ndpi_MD5Init(&ctx); + ndpi_MD5Update(&ctx, (const unsigned char *)ja3_str, strlen(ja3_str)); + ndpi_MD5Final(md5_hash, &ctx); for(i=0, j=0; i<16; i++) j += snprintf(&flow->protos.stun_ssl.ssl.ja3_client[j], - sizeof(flow->protos.stun_ssl.ssl.ja3_client)-j, "%02x", md5_hash[i]); + sizeof(flow->protos.stun_ssl.ssl.ja3_client)-j, "%02x", + md5_hash[i]); -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("[JA3] Client: %s \n", flow->protos.stun_ssl.ssl.ja3_client); #endif } @@ -807,6 +667,8 @@ int getSSLcertificate(struct ndpi_detection_module_struct *ndpi_struct, return(0); /* Not found */ } +/* **************************************** */ + void getSSLorganization(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, char *buffer, int buffer_len) { @@ -862,7 +724,7 @@ void getSSLorganization(struct ndpi_detection_module_struct *ndpi_struct, if(is_printable == 1) { snprintf(flow->protos.stun_ssl.ssl.server_organization, sizeof(flow->protos.stun_ssl.ssl.server_organization), "%s", buffer); -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS printf("Certificate organization: %s\n", flow->protos.stun_ssl.ssl.server_organization); #endif } @@ -870,20 +732,24 @@ void getSSLorganization(struct ndpi_detection_module_struct *ndpi_struct, } } +/* **************************************** */ -int sslTryAndRetrieveServerCertificate(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { +int sslTryAndRetrieveServerCertificate(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; /* consider only specific SSL packets (handshake) */ if((packet->payload_packet_len > 9) && (packet->payload[0] == 0x16)) { char certificate[64]; - char organization[64]; int rc; certificate[0] = '\0'; - rc = getSSLcertificate(ndpi_struct, flow, certificate, sizeof(certificate)); + rc = getTLScertificate(ndpi_struct, flow, certificate, sizeof(certificate)); packet->ssl_certificate_num_checks++; + if(rc > 0) { + char organization[64]; + // try fetch server organization once server certificate is found organization[0] = '\0'; getSSLorganization(ndpi_struct, flow, organization, sizeof(organization)); @@ -893,20 +759,25 @@ int sslTryAndRetrieveServerCertificate(struct ndpi_detection_module_struct *ndpi /* 0 means we're done processing extra packets (since we found what we wanted) */ return 0; } + /* Client hello, Server Hello, and certificate packets probably all checked in this case */ - if((packet->ssl_certificate_num_checks >= 3) + if(((packet->ssl_certificate_num_checks >= 3) && (flow->l4.tcp.seen_syn) && (flow->l4.tcp.seen_syn_ack) && (flow->l4.tcp.seen_ack) /* We have seen the 3-way handshake */) - { - /* We're done processing extra packets since we've probably checked all possible cert packets */ + || (flow->protos.stun_ssl.ssl.ja3_server[0] != '\0') + ) { + /* We're done processing extra packets since we've probably checked all possible cert packets */ return 0; } } + /* 1 means keep looking for more packets */ return 1; } +/* **************************************** */ + void sslInitExtraPacketProcessing(int caseNum, struct ndpi_flow_struct *flow) { flow->check_extra_packets = 1; /* 0 is the case for waiting for the server certificate */ @@ -917,30 +788,33 @@ void sslInitExtraPacketProcessing(int caseNum, struct ndpi_flow_struct *flow) { } } -int sslDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { +/* **************************************** */ + +int tlsDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; if((packet->payload_packet_len > 9) && (packet->payload[0] == 0x16 /* consider only specific SSL packets (handshake) */)) { if((packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) - || (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL)) { + || (packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS)) { char certificate[64]; int rc; certificate[0] = '\0'; - rc = getSSLcertificate(ndpi_struct, flow, certificate, sizeof(certificate)); + rc = getTLScertificate(ndpi_struct, flow, certificate, sizeof(certificate)); packet->ssl_certificate_num_checks++; if(rc > 0) { packet->ssl_certificate_detected++; -#ifdef CERTIFICATE_DEBUG +#ifdef DEBUG_TLS NDPI_LOG_DBG2(ndpi_struct, "***** [SSL] %s\n", certificate); #endif ndpi_protocol_match_result ret_match; u_int32_t subproto = ndpi_match_host_subprotocol(ndpi_struct, flow, certificate, strlen(certificate), &ret_match, - NDPI_PROTOCOL_SSL); + NDPI_PROTOCOL_TLS); if(subproto != NDPI_PROTOCOL_UNKNOWN) { /* If we've detected the subprotocol from client certificate but haven't had a chance @@ -952,11 +826,11 @@ int sslDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_s } ndpi_set_detected_protocol(ndpi_struct, flow, subproto, - ndpi_ssl_refine_master_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SSL)); + ndpi_tls_refine_master_protocol(ndpi_struct, flow, NDPI_PROTOCOL_TLS)); return(rc); /* Fix courtesy of Gianluca Costa <g.costa@xplico.org> */ } - if(ndpi_is_ssl_tor(ndpi_struct, flow, certificate) != 0) + if(ndpi_is_tls_tor(ndpi_struct, flow, certificate) != 0) return(rc); } @@ -969,29 +843,30 @@ int sslDetectProtocolFromCertificate(struct ndpi_detection_module_struct *ndpi_s && (flow->protos.stun_ssl.ssl.server_certificate[0] != '\0')) /* || ((flow->l4.tcp.ssl_seen_client_cert == 1) && (flow->protos.stun_ssl.ssl.client_certificate[0] != '\0')) */ ) { - ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SSL); + ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_TLS); } } } return(0); } -static void ssl_mark_and_payload_search_for_other_protocols(struct ndpi_detection_module_struct - *ndpi_struct, struct ndpi_flow_struct *flow) -{ +/* **************************************** */ + +static void tls_mark_and_payload_search_for_other_protocols(struct ndpi_detection_module_struct + *ndpi_struct, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; u_int32_t a; u_int32_t end; if(NDPI_COMPARE_PROTOCOL_TO_BITMASK(ndpi_struct->detection_bitmask, NDPI_PROTOCOL_UNENCRYPTED_JABBER) != 0) - goto check_for_ssl_payload; + goto check_for_tls_payload; if(NDPI_COMPARE_PROTOCOL_TO_BITMASK(ndpi_struct->detection_bitmask, NDPI_PROTOCOL_OSCAR) != 0) - goto check_for_ssl_payload; + goto check_for_tls_payload; else - goto no_check_for_ssl_payload; + goto no_check_for_tls_payload; - check_for_ssl_payload: + check_for_tls_payload: end = packet->payload_packet_len - 20; for (a = 5; a < end; a++) { @@ -1000,7 +875,7 @@ static void ssl_mark_and_payload_search_for_other_protocols(struct ndpi_detectio if(NDPI_COMPARE_PROTOCOL_TO_BITMASK (ndpi_struct->detection_bitmask, NDPI_PROTOCOL_UNENCRYPTED_JABBER) != 0) { NDPI_LOG_INFO(ndpi_struct, "found ssl jabber unencrypted\n"); - ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_UNENCRYPTED_JABBER); + ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_UNENCRYPTED_JABBER); return; } } @@ -1027,7 +902,7 @@ static void ssl_mark_and_payload_search_for_other_protocols(struct ndpi_detectio flow->dst->oscar_last_safe_access_time = packet->tick_timestamp; } - ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_OSCAR); + ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_OSCAR); return; } } @@ -1037,31 +912,32 @@ static void ssl_mark_and_payload_search_for_other_protocols(struct ndpi_detectio (memcmp(&packet->payload[a], "my.screenname.aol.com", 21) == 0 || memcmp(&packet->payload[a], "sns-static.aolcdn.com", 21) == 0)) { NDPI_LOG_DBG(ndpi_struct, "found OSCAR SERVER SSL DETECTED\n"); - ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_OSCAR); + ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_OSCAR); return; } } } - no_check_for_ssl_payload: + no_check_for_tls_payload: if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) { NDPI_LOG_DBG(ndpi_struct, "found ssl connection\n"); - sslDetectProtocolFromCertificate(ndpi_struct, flow); + tlsDetectProtocolFromCertificate(ndpi_struct, flow); if(!packet->ssl_certificate_detected && (!(flow->l4.tcp.ssl_seen_client_cert && flow->l4.tcp.ssl_seen_server_cert))) { /* SSL without certificate (Skype, Ultrasurf?) */ NDPI_LOG_INFO(ndpi_struct, "found ssl NO_CERT\n"); - ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SSL_NO_CERT); + ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_TLS_NO_CERT); } else if(packet->ssl_certificate_num_checks >= 3) { NDPI_LOG_INFO(ndpi_struct, "found ssl\n"); - ndpi_int_ssl_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SSL); + ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_TLS); } } } +/* **************************************** */ -static u_int8_t ndpi_search_sslv3_direction1(struct ndpi_detection_module_struct *ndpi_struct, +static u_int8_t ndpi_search_tlsv3_direction1(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; @@ -1126,7 +1002,7 @@ static u_int8_t ndpi_search_sslv3_direction1(struct ndpi_detection_module_struct if(packet->payload_packet_len >= temp + 5 && (packet->payload[temp] == 0x14 || packet->payload[temp] == 0x16) && packet->payload[temp + 1] == 0x03) { u_int32_t temp2 = ntohs(get_u_int16_t(packet->payload, temp + 3)) + 5; - if(temp + temp2 > NDPI_MAX_SSL_REQUEST_SIZE) { + if(temp + temp2 > NDPI_MAX_TLS_REQUEST_SIZE) { return 1; } temp += temp2; @@ -1137,7 +1013,7 @@ static u_int8_t ndpi_search_sslv3_direction1(struct ndpi_detection_module_struct if(packet->payload_packet_len >= temp + 5 && packet->payload[temp] == 0x16 && packet->payload[temp + 1] == 0x03) { temp2 = ntohs(get_u_int16_t(packet->payload, temp + 3)) + 5; - if(temp + temp2 > NDPI_MAX_SSL_REQUEST_SIZE) { + if(temp + temp2 > NDPI_MAX_TLS_REQUEST_SIZE) { return 1; } temp += temp2; @@ -1148,7 +1024,7 @@ static u_int8_t ndpi_search_sslv3_direction1(struct ndpi_detection_module_struct if(packet->payload_packet_len >= temp + 5 && packet->payload[temp] == 0x16 && packet->payload[temp + 1] == 0x03) { temp2 = ntohs(get_u_int16_t(packet->payload, temp + 3)) + 5; - if(temp + temp2 > NDPI_MAX_SSL_REQUEST_SIZE) { + if(temp + temp2 > NDPI_MAX_TLS_REQUEST_SIZE) { return 1; } temp += temp2; @@ -1164,20 +1040,51 @@ static u_int8_t ndpi_search_sslv3_direction1(struct ndpi_detection_module_struct return 0; } -void ndpi_search_ssl_tcp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) -{ +/* **************************************** */ + +void ndpi_search_tls_tcp_udp(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; u_int8_t ret; - if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL) { + if(packet->udp != NULL) { + /* DTLS dissector */ +#ifdef DEBUG_TLS + int rc = /* sslTryAndRetrieveServerCertificate(...) */ +#endif + sslTryAndRetrieveServerCertificate(ndpi_struct, flow); + +#ifdef DEBUG_TLS + printf("==>> %u [rc: %u][len: %u][%s][version: %u]\n", + flow->guessed_host_protocol_id, rc, packet->payload_packet_len, flow->protos.stun_ssl.ssl.ja3_server, + flow->protos.stun_ssl.ssl.ssl_version); +#endif + + if(flow->protos.stun_ssl.ssl.ssl_version != 0) { + flow->guessed_protocol_id = NDPI_PROTOCOL_TLS; + + if(flow->protos.stun_ssl.stun.num_udp_pkts > 0) { + /* In Signal protocol STUN turns into DTLS... */ + ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SIGNAL); + } else if(flow->protos.stun_ssl.ssl.ja3_server[0] != '\0') { + /* Wait the server certificate the bless this flow as TLS */ + ndpi_int_tls_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_TLS); + } + } + + return; + } + + if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS) { if(flow->l4.tcp.ssl_stage == 3 && packet->payload_packet_len > 20 && flow->packet_counter < 5) { /* this should only happen, when we detected SSL with a packet that had parts of the certificate in subsequent packets * so go on checking for certificate patterns for a couple more packets */ NDPI_LOG_DBG2(ndpi_struct, "ssl flow but check another packet for patterns\n"); - ssl_mark_and_payload_search_for_other_protocols(ndpi_struct, flow); - if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL) { + tls_mark_and_payload_search_for_other_protocols(ndpi_struct, flow); + + if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS) { /* still ssl so check another packet */ return; } else { @@ -1185,11 +1092,12 @@ void ndpi_search_ssl_tcp(struct ndpi_detection_module_struct *ndpi_struct, struc return; } } + return; } NDPI_LOG_DBG(ndpi_struct, "search ssl\n"); - + /* Check if this is whatsapp first (this proto runs over port 443) */ if((packet->payload_packet_len > 5) && ((packet->payload[0] == 'W') @@ -1206,10 +1114,10 @@ void ndpi_search_ssl_tcp(struct ndpi_detection_module_struct *ndpi_struct, struc return; } else { /* No whatsapp, let's try SSL */ - if(sslDetectProtocolFromCertificate(ndpi_struct, flow) > 0) + if(tlsDetectProtocolFromCertificate(ndpi_struct, flow) > 0) return; - } - + } + if(packet->payload_packet_len > 40 && flow->l4.tcp.ssl_stage == 0) { NDPI_LOG_DBG2(ndpi_struct, "first ssl packet\n"); // SSLv2 Record @@ -1234,14 +1142,14 @@ void ndpi_search_ssl_tcp(struct ndpi_detection_module_struct *ndpi_struct, struc if(packet->payload[0] == 0x17 && packet->payload[1] == 0x03 && (packet->payload[2] == 0x00 || packet->payload[2] == 0x01 || packet->payload[2] == 0x02 || packet->payload[2] == 0x03)) { - if(packet->payload_packet_len - ntohs(get_u_int16_t(packet->payload, 3)) == 5) { - NDPI_LOG_DBG2(ndpi_struct, "TLS len match\n"); - flow->l4.tcp.ssl_stage = 1 + packet->packet_direction; - return; - } + if(packet->payload_packet_len - ntohs(get_u_int16_t(packet->payload, 3)) == 5) { + NDPI_LOG_DBG2(ndpi_struct, "TLS len match\n"); + flow->l4.tcp.ssl_stage = 1 + packet->packet_direction; + return; + } } } - + if(packet->payload_packet_len > 40 && flow->l4.tcp.ssl_stage == 1 + packet->packet_direction && flow->packet_direction_counter[packet->packet_direction] < 5) { @@ -1255,20 +1163,20 @@ void ndpi_search_ssl_tcp(struct ndpi_detection_module_struct *ndpi_struct, struc && (packet->payload[4] == 0x00 || packet->payload[4] == 0x01 || packet->payload[4] == 0x02) && (packet->payload_packet_len - 2) >= packet->payload[1]) { NDPI_LOG_DBG2(ndpi_struct, "sslv2 server len match\n"); - ssl_mark_and_payload_search_for_other_protocols(ndpi_struct, flow); + tls_mark_and_payload_search_for_other_protocols(ndpi_struct, flow); return; } - ret = ndpi_search_sslv3_direction1(ndpi_struct, flow); + ret = ndpi_search_tlsv3_direction1(ndpi_struct, flow); if(ret == 1) { NDPI_LOG_DBG2(ndpi_struct, "sslv3 server len match\n"); - ssl_mark_and_payload_search_for_other_protocols(ndpi_struct, flow); + tls_mark_and_payload_search_for_other_protocols(ndpi_struct, flow); return; } else if(ret == 2) { NDPI_LOG_DBG2(ndpi_struct, "sslv3 server len match with split packet -> check some more packets for SSL patterns\n"); - ssl_mark_and_payload_search_for_other_protocols(ndpi_struct, flow); - if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL) { + tls_mark_and_payload_search_for_other_protocols(ndpi_struct, flow); + if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS) { flow->l4.tcp.ssl_stage = 3; } return; @@ -1281,16 +1189,18 @@ void ndpi_search_ssl_tcp(struct ndpi_detection_module_struct *ndpi_struct, struc } NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + return; } +/* **************************************** */ -void init_ssl_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) -{ - ndpi_set_bitmask_protocol_detection("SSL", ndpi_struct, detection_bitmask, *id, - NDPI_PROTOCOL_SSL, - ndpi_search_ssl_tcp, - NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_WITH_PAYLOAD, +void init_tls_dissector(struct ndpi_detection_module_struct *ndpi_struct, + u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) { + ndpi_set_bitmask_protocol_detection("TLS", ndpi_struct, detection_bitmask, *id, + NDPI_PROTOCOL_TLS, + ndpi_search_tls_tcp_udp, + NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD, SAVE_DETECTION_BITMASK_AS_UNKNOWN, ADD_TO_DETECTION_BITMASK); diff --git a/src/lib/protocols/tor.c b/src/lib/protocols/tor.c index f1c6f586a..3b2dd06c4 100644 --- a/src/lib/protocols/tor.c +++ b/src/lib/protocols/tor.c @@ -18,12 +18,12 @@ static void ndpi_int_tor_add_connection(struct ndpi_detection_module_struct } -int ndpi_is_ssl_tor(struct ndpi_detection_module_struct *ndpi_struct, +int ndpi_is_tls_tor(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, char *certificate) { int prev_num = 0, numbers_found = 0, num_found = 0, i, len, num_impossible = 0; char dummy[48], *dot, *name; - - if(certificate == NULL) + + if((certificate == NULL) || (certificate[0] == '\0')) return(0); else len = strlen(certificate); @@ -96,11 +96,13 @@ int ndpi_is_ssl_tor(struct ndpi_detection_module_struct *ndpi_struct, void ndpi_search_tor(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &flow->packet; - u_int16_t dport = 0, sport = 0; NDPI_LOG_DBG(ndpi_struct, "search for TOR\n"); - if(packet->tcp != NULL) { + if((packet->tcp != NULL) + && (!packet->ssl_certificate_detected)) { + u_int16_t dport, sport; + sport = ntohs(packet->tcp->source), dport = ntohs(packet->tcp->dest); NDPI_LOG_DBG2(ndpi_struct, "calculating TOR over tcp\n"); diff --git a/src/lib/protocols/yahoo.c b/src/lib/protocols/yahoo.c index 3be953939..972466dc8 100644 --- a/src/lib/protocols/yahoo.c +++ b/src/lib/protocols/yahoo.c @@ -367,7 +367,7 @@ void ndpi_search_yahoo(struct ndpi_detection_module_struct *ndpi_struct, struct if(packet->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN || packet->detected_protocol_stack[0] == NDPI_PROTOCOL_HTTP - || packet->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL) { + || packet->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS) { /* search over TCP */ ndpi_search_yahoo_tcp(ndpi_struct, flow); } |