diff options
Diffstat (limited to 'src/lib/protocols')
-rw-r--r-- | src/lib/protocols/bittorrent.c | 24 | ||||
-rw-r--r-- | src/lib/protocols/http.c | 225 | ||||
-rw-r--r-- | src/lib/protocols/kerberos.c | 46 | ||||
-rw-r--r-- | src/lib/protocols/spotify.c | 2 | ||||
-rw-r--r-- | src/lib/protocols/stun.c | 2 | ||||
-rw-r--r-- | src/lib/protocols/tls.c | 185 |
6 files changed, 330 insertions, 154 deletions
diff --git a/src/lib/protocols/bittorrent.c b/src/lib/protocols/bittorrent.c index f1c62d431..9f7620558 100644 --- a/src/lib/protocols/bittorrent.c +++ b/src/lib/protocols/bittorrent.c @@ -43,7 +43,7 @@ struct ndpi_utp_hdr { u_int16_t sequence_nr, ack_nr; }; -static u_int8_t is_utp_pkt(const u_int8_t *payload, u_int payload_len) { +static u_int8_t is_utpv1_pkt(const u_int8_t *payload, u_int payload_len) { struct ndpi_utp_hdr *h = (struct ndpi_utp_hdr*)payload; if(payload_len < sizeof(struct ndpi_utp_hdr)) return(0); @@ -52,6 +52,9 @@ static u_int8_t is_utp_pkt(const u_int8_t *payload, u_int payload_len) { if(h->next_extension > 2) return(0); if(ntohl(h->window_size) > 65565) return(0); + if((h->window_size == 0) && (payload_len != sizeof(struct ndpi_utp_hdr))) + return(0); + return(1); } @@ -433,14 +436,10 @@ void ndpi_search_bittorrent(struct ndpi_detection_module_struct *ndpi_struct, st u_int8_t v0_extension = packet->payload[17]; u_int8_t v0_flags = packet->payload[18]; - /* Check if this is protocol v1 */ - u_int8_t v1_version = packet->payload[0]; - u_int8_t v1_extension = packet->payload[1]; - u_int32_t v1_window_size = *((u_int32_t*)&packet->payload[12]); - - if(is_utp_pkt(packet->payload, packet->payload_packet_len)) + if(is_utpv1_pkt(packet->payload, packet->payload_packet_len)) { + bt_proto = ndpi_strnstr((const char *)&packet->payload[20], "BitTorrent protocol", packet->payload_packet_len-20); goto bittorrent_found; - else if((packet->payload[0]== 0x60) + } else if((packet->payload[0]== 0x60) && (packet->payload[1]== 0x0) && (packet->payload[2]== 0x0) && (packet->payload[3]== 0x0) @@ -448,14 +447,7 @@ void ndpi_search_bittorrent(struct ndpi_detection_module_struct *ndpi_struct, st /* Heuristic */ bt_proto = ndpi_strnstr((const char *)&packet->payload[20], "BitTorrent protocol", packet->payload_packet_len-20); goto bittorrent_found; - /* CSGO/DOTA conflict */ - } else if(flow->packet_counter > 8 && ((v1_version & 0x0f) == 1) - && ((v1_version >> 4) < 5 /* ST_NUM_STATES */) - && (v1_extension < 3 /* EXT_NUM_EXT */) - && (v1_window_size < 32768 /* 32k */) - ) { - bt_proto = ndpi_strnstr((const char *)&packet->payload[20], "BitTorrent protocol", packet->payload_packet_len-20); - goto bittorrent_found; + /* CSGO/DOTA conflict */ } else if((v0_flags < 6 /* ST_NUM_STATES */) && (v0_extension < 3 /* EXT_NUM_EXT */)) { u_int32_t ts = ntohl(*((u_int32_t*)&(packet->payload[4]))); u_int32_t now; diff --git a/src/lib/protocols/http.c b/src/lib/protocols/http.c index abd422007..7b83b91e7 100644 --- a/src/lib/protocols/http.c +++ b/src/lib/protocols/http.c @@ -28,20 +28,16 @@ #include "ndpi_api.h" #include <stdlib.h> -static const char* binary_file_mimes[] = { - "exe", - "vnd.ms-cab-compressed", - "vnd.microsoft.portable-executable" - "x-msdownload", - "x-dosexec", - NULL -}; +static const char* binary_file_mimes_e[] = { "exe", NULL }; +static const char* binary_file_mimes_v[] = { "vnd.ms-cab-compressed", "vnd.microsoft.portable-executable", NULL }; +static const char* binary_file_mimes_x[] = { "x-msdownload", "x-dosexec", NULL }; +#define ATTACHMENT_LEN 3 static const char* binary_file_ext[] = { - ".exe", - ".msi", - ".cab", - NULL + "exe", + "msi", + "cab", + NULL }; static void ndpi_search_http_tcp(struct ndpi_detection_module_struct *ndpi_struct, @@ -49,7 +45,7 @@ static void ndpi_search_http_tcp(struct ndpi_detection_module_struct *ndpi_struc /* *********************************************** */ -static void ndpi_analyze_content_signature(struct ndpi_flow_struct *flow) { +static void ndpi_analyze_content_signature(struct ndpi_flow_struct *flow) { if((flow->initial_binary_bytes_len >= 2) && (flow->initial_binary_bytes[0] == 0x4D) && (flow->initial_binary_bytes[1] == 0x5A)) NDPI_SET_BIT(flow->risk, NDPI_BINARY_APPLICATION_TRANSFER); /* Win executable */ else if((flow->initial_binary_bytes_len >= 4) && (flow->initial_binary_bytes[0] == 0x7F) && (flow->initial_binary_bytes[1] == 'E') @@ -65,7 +61,7 @@ static void ndpi_analyze_content_signature(struct ndpi_flow_struct *flow) { NDPI_SET_BIT(flow->risk, NDPI_BINARY_APPLICATION_TRANSFER); /* Unix script (e.g. #!/bin/sh) */ else if(flow->initial_binary_bytes_len >= 8) { u_int8_t exec_pattern[] = { 0x64, 0x65, 0x78, 0x0A, 0x30, 0x33, 0x35, 0x00 }; - + if(memcmp(flow->initial_binary_bytes, exec_pattern, 8) == 0) NDPI_SET_BIT(flow->risk, NDPI_BINARY_APPLICATION_TRANSFER); /* Dalvik Executable (Android) */ } @@ -85,7 +81,7 @@ static int ndpi_search_http_tcp_again(struct ndpi_detection_module_struct *ndpi_ && (flow->http.response_status_code != 0) ) { /* stop extra processing */ - + if(flow->initial_binary_bytes_len) ndpi_analyze_content_signature(flow); flow->extra_packets_func = NULL; /* We're good now */ return(0); @@ -106,47 +102,69 @@ static ndpi_protocol_category_t ndpi_http_check_content(struct ndpi_detection_mo u_int app_len = sizeof("application"); if(packet->content_line.len > app_len) { - const char *app = (const char *)&packet->content_line.ptr[app_len]; - u_int app_len_avail = packet->content_line.len-app_len; - - if(ndpi_strncasestr(app, "mpeg", app_len_avail) != NULL) { + const char *app = (const char *)&packet->content_line.ptr[app_len]; + u_int app_len_avail = packet->content_line.len-app_len; + + if(strncasecmp(app, "mpeg", app_len_avail) == 0) { flow->guessed_category = flow->category = NDPI_PROTOCOL_CATEGORY_STREAMING; return(flow->category); - } else { - for (int i = 0; binary_file_mimes[i] != NULL; i++) { - if (ndpi_strncasestr(app, binary_file_mimes[i], app_len_avail) != NULL) { - flow->guessed_category = flow->category = NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT; - NDPI_SET_BIT(flow->risk, NDPI_BINARY_APPLICATION_TRANSFER); - NDPI_LOG_INFO(ndpi_struct, "found executable HTTP transfer"); - return(flow->category); - } - } + } else if(app_len_avail > 3) { + const char** cmp_mimes = NULL; + + switch(app[0]) { + case 'e': cmp_mimes = binary_file_mimes_e; break; + case 'v': cmp_mimes = binary_file_mimes_v; break; + case 'x': cmp_mimes = binary_file_mimes_x; break; + } + + if(cmp_mimes != NULL) { + u_int8_t i; + + for(i = 0; cmp_mimes[i] != NULL; i++) { + if(strncasecmp(app, cmp_mimes[i], app_len_avail) == 0) { + flow->guessed_category = flow->category = NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT; + NDPI_SET_BIT(flow->risk, NDPI_BINARY_APPLICATION_TRANSFER); + NDPI_LOG_INFO(ndpi_struct, "found executable HTTP transfer"); + return(flow->category); + } + } + } } } /* check for attachment */ - if (packet->content_disposition_line.len > 0) { - uint8_t attachment_len = sizeof("attachment; filename"); - if (packet->content_disposition_line.len > attachment_len) { - uint8_t filename_len = packet->content_disposition_line.len - attachment_len; - for (int i = 0; binary_file_ext[i] != NULL; i++) { - if (ndpi_strncasestr((const char*)&packet->content_disposition_line.ptr[attachment_len], - binary_file_ext[i], filename_len)) { - flow->guessed_category = flow->category = NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT; - NDPI_SET_BIT(flow->risk, NDPI_BINARY_APPLICATION_TRANSFER); - NDPI_LOG_INFO(ndpi_struct, "found executable HTTP transfer"); - return(flow->category); - } + if (packet->content_disposition_line.len > 0) { + u_int8_t attachment_len = sizeof("attachment; filename"); + + if(packet->content_disposition_line.len > attachment_len) { + u_int8_t filename_len = packet->content_disposition_line.len - attachment_len; + + if(filename_len > ATTACHMENT_LEN) { + attachment_len += filename_len-ATTACHMENT_LEN-1; + + if((attachment_len+ATTACHMENT_LEN) <= packet->content_disposition_line.len) { + for(int i = 0; binary_file_ext[i] != NULL; i++) { + /* Use memcmp in case content-disposition contains binary data */ + if(memcmp((const char*)&packet->content_disposition_line.ptr[attachment_len], + binary_file_ext[i], ATTACHMENT_LEN) == 0) { + flow->guessed_category = flow->category = NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT; + NDPI_SET_BIT(flow->risk, NDPI_BINARY_APPLICATION_TRANSFER); + NDPI_LOG_INFO(ndpi_struct, "found executable HTTP transfer"); + return(flow->category); + } + } + } + } } } - } + switch(packet->content_line.ptr[0]) { case 'a': if(strncasecmp((const char *)packet->content_line.ptr, "audio", ndpi_min(packet->content_line.len, 5)) == 0) flow->guessed_category = flow->category = NDPI_PROTOCOL_CATEGORY_MEDIA; break; - + case 'v': if(strncasecmp((const char *)packet->content_line.ptr, "video", ndpi_min(packet->content_line.len, 5)) == 0) @@ -178,7 +196,6 @@ static void ndpi_int_http_add_connection(struct ndpi_detection_module_struct *nd if((flow->guessed_host_protocol_id == NDPI_PROTOCOL_UNKNOWN) || (http_protocol != NDPI_PROTOCOL_HTTP)) flow->guessed_host_protocol_id = http_protocol; - category = ndpi_http_check_content(ndpi_struct, flow); ndpi_int_reset_protocol(flow); ndpi_set_detected_protocol(ndpi_struct, flow, flow->guessed_host_protocol_id, NDPI_PROTOCOL_HTTP); @@ -186,7 +203,7 @@ static void ndpi_int_http_add_connection(struct ndpi_detection_module_struct *nd flow->check_extra_packets = 1; flow->max_extra_packets_to_check = 5; flow->extra_packets_func = ndpi_search_http_tcp_again; - flow->http_detected = 1, flow->guessed_category = flow->category = category; + flow->http_detected = 1; } /* ************************************************************* */ @@ -220,7 +237,7 @@ static void setHttpUserAgent(struct ndpi_detection_module_struct *ndpi_struct, * https://github.com/ua-parser/uap-core/blob/master/regexes.yaml */ snprintf((char*)flow->protos.http.detected_os, - sizeof(flow->protos.http.detected_os), "%s", ua); + sizeof(flow->protos.http.detected_os), "%s", ua); } /* ************************************************************* */ @@ -232,7 +249,7 @@ static void ndpi_http_parse_subprotocol(struct ndpi_detection_module_struct *ndp if(double_col) double_col[0] = '\0'; - ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HTTP, + ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HTTP, (char *)flow->host_server_name, strlen((const char *)flow->host_server_name)); } @@ -246,7 +263,7 @@ static void ndpi_check_user_agent(struct ndpi_detection_module_struct *ndpi_stru if((!ua) || (ua[0] == '\0')) return; // printf("[%s:%d] ==> '%s'\n", __FILE__, __LINE__, ua); - + if((strlen(ua) < 4) || (!strcmp(ua, "test")) || (!strcmp(ua, "<?")) @@ -262,13 +279,13 @@ static void ndpi_check_numeric_ip(struct ndpi_detection_module_struct *ndpi_stru char *ip, u_int ip_len) { char buf[22]; struct in_addr ip_addr; - + strncpy(buf, ip, ip_len); buf[ip_len] = '\0'; ip_addr.s_addr = inet_addr(buf); if(strcmp(inet_ntoa(ip_addr), buf) == 0) { - NDPI_SET_BIT(flow->risk, NDPI_HTTP_NUMERIC_IP_HOST); + NDPI_SET_BIT(flow->risk, NDPI_HTTP_NUMERIC_IP_HOST); } } @@ -301,9 +318,9 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_ int len = packet->http_url_name.len + packet->host_line.len + 1; if(isdigit(packet->host_line.ptr[0]) - && (packet->host_line.len < 21)) + && (packet->host_line.len < 21)) ndpi_check_numeric_ip(ndpi_struct, flow, (char*)packet->host_line.ptr, packet->host_line.len); - + flow->http.url = ndpi_malloc(len); if(flow->http.url) { strncpy(flow->http.url, (char*)packet->host_line.ptr, packet->host_line.len); @@ -352,7 +369,7 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_ strncpy(ua, (const char *)packet->user_agent_line.ptr, mlen); ua[mlen] = '\0'; - + if(strncmp(ua, "Mozilla", 7) == 0) { char *parent = strchr(ua, '('); @@ -517,7 +534,8 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_ strncpy(flow->http.content_type, (char*)packet->content_line.ptr, packet->content_line.len); flow->http.content_type[packet->content_line.len] = '\0'; - } + + flow->guessed_category = flow->category = ndpi_http_check_content(ndpi_struct, flow);} } if(flow->http_detected) { @@ -595,6 +613,106 @@ static void http_bitmask_exclude_other(struct ndpi_flow_struct *flow) NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_XBOX); } +/* *********************************************************************************************** */ + +/* Trick to speed-up detection */ +static const char* suspicious_http_header_keys_A[] = { "Arch", NULL}; +static const char* suspicious_http_header_keys_C[] = { "Cores", NULL}; +static const char* suspicious_http_header_keys_M[] = { "Mem", NULL}; +static const char* suspicious_http_header_keys_O[] = { "Os", "Osname", "Osversion", NULL}; +static const char* suspicious_http_header_keys_R[] = { "Root", NULL}; +static const char* suspicious_http_header_keys_S[] = { "S", NULL}; +static const char* suspicious_http_header_keys_T[] = { "TLS_version", NULL}; +static const char* suspicious_http_header_keys_U[] = { "Uuid", NULL}; +static const char* suspicious_http_header_keys_X[] = { "X-Hire-Me", NULL}; + +static int is_a_suspicious_header(const char* suspicious_headers[], struct ndpi_int_one_line_struct packet_line){ + int i; + unsigned int header_len; + const u_int8_t* header_limit; + + if((header_limit = memchr(packet_line.ptr, ':', packet_line.len))) { + header_len = header_limit - packet_line.ptr; + for(i=0; suspicious_headers[i] != NULL; i++){ + if(!strncasecmp((const char*) packet_line.ptr, + suspicious_headers[i], header_len)) + return 1; + } + } + + return 0; +} + +/* *********************************************************************************************** */ + +static void ndpi_check_http_header(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) { + u_int32_t i; + struct ndpi_packet_struct *packet = &flow->packet; + + for(i=0; (i < packet->parsed_lines) + && (packet->line[i].ptr != NULL) + && (packet->line[i].len > 0); i++) { + switch(packet->line[i].ptr[0]){ + case 'A': + if(is_a_suspicious_header(suspicious_http_header_keys_A, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'C': + if(is_a_suspicious_header(suspicious_http_header_keys_C, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'M': + if(is_a_suspicious_header(suspicious_http_header_keys_M, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'O': + if(is_a_suspicious_header(suspicious_http_header_keys_O, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'R': + if(is_a_suspicious_header(suspicious_http_header_keys_R, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'S': + if(is_a_suspicious_header(suspicious_http_header_keys_S, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'T': + if(is_a_suspicious_header(suspicious_http_header_keys_T, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'U': + if(is_a_suspicious_header(suspicious_http_header_keys_U, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'X': + if(is_a_suspicious_header(suspicious_http_header_keys_X, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + + break; + } + } +} + /*************************************************************************************************/ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct, @@ -694,6 +812,7 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct "Filename HTTP found: %d, we look for line info..\n", filename_start); ndpi_parse_packet_line_info(ndpi_struct, flow); + ndpi_check_http_header(ndpi_struct, flow); if(packet->parsed_lines <= 1) { NDPI_LOG_DBG2(ndpi_struct, diff --git a/src/lib/protocols/kerberos.c b/src/lib/protocols/kerberos.c index ff16545f5..f4c1a175a 100644 --- a/src/lib/protocols/kerberos.c +++ b/src/lib/protocols/kerberos.c @@ -202,11 +202,13 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct, if(body_offset < packet->payload_packet_len) { - u_int16_t name_offset; - - name_offset = body_offset + 13; - for(i=0; i<20; i++) if(packet->payload[name_offset] != 0x1b) name_offset++; /* ASN.1 */ - + u_int16_t name_offset = body_offset + 13; + + for(i=0; (i<20) && (name_offset < packet->payload_packet_len); i++) { + if(packet->payload[name_offset] != 0x1b) + name_offset++; /* ASN.1 */ + } + #ifdef KERBEROS_DEBUG printf("name_offset=%u [%02X %02X] [byte 0 must be 0x1b]\n", name_offset, packet->payload[name_offset], packet->payload[name_offset+1]); #endif @@ -256,30 +258,38 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct, } else snprintf(flow->protos.kerberos.username, sizeof(flow->protos.kerberos.username), "%s", cname_str); - for(i=0; i<14; i++) if(packet->payload[realm_offset] != 0x1b) realm_offset++; /* ASN.1 */ + for(i=0; (i < 14) && (realm_offset < packet->payload_packet_len); i++) { + if(packet->payload[realm_offset] != 0x1b) + realm_offset++; /* ASN.1 */ + } + #ifdef KERBEROS_DEBUG - printf("realm_offset=%u [%02X %02X] [byte 0 must be 0x1b]\n", realm_offset, packet->payload[realm_offset], packet->payload[realm_offset+1]); + printf("realm_offset=%u [%02X %02X] [byte 0 must be 0x1b]\n", realm_offset, + packet->payload[realm_offset], packet->payload[realm_offset+1]); #endif + realm_offset += 1; //if(num_cname == 2) realm_offset++; - realm_len = packet->payload[realm_offset]; + if(realm_offset < packet->payload_packet_len) { + realm_len = packet->payload[realm_offset]; - if((realm_offset+realm_len) < packet->payload_packet_len) { - char realm_str[48]; + if((realm_offset+realm_len) < packet->payload_packet_len) { + char realm_str[48]; - if(realm_len > sizeof(realm_str)-1) - realm_len = sizeof(realm_str)-1; + if(realm_len > sizeof(realm_str)-1) + realm_len = sizeof(realm_str)-1; - realm_offset += 1; + realm_offset += 1; - strncpy(realm_str, (char*)&packet->payload[realm_offset], realm_len); - realm_str[realm_len] = '\0'; - for(i=0; i<realm_len; i++) realm_str[i] = tolower(realm_str[i]); + strncpy(realm_str, (char*)&packet->payload[realm_offset], realm_len); + realm_str[realm_len] = '\0'; + for(i=0; i<realm_len; i++) realm_str[i] = tolower(realm_str[i]); #ifdef KERBEROS_DEBUG - printf("[AS-REQ][Kerberos Realm][len: %u][%s]\n", realm_len, realm_str); + printf("[AS-REQ][Kerberos Realm][len: %u][%s]\n", realm_len, realm_str); #endif - snprintf(flow->protos.kerberos.domain, sizeof(flow->protos.kerberos.domain), "%s", realm_str); + snprintf(flow->protos.kerberos.domain, sizeof(flow->protos.kerberos.domain), "%s", realm_str); + } } } } diff --git a/src/lib/protocols/spotify.c b/src/lib/protocols/spotify.c index a180a1ea7..d66109016 100644 --- a/src/lib/protocols/spotify.c +++ b/src/lib/protocols/spotify.c @@ -47,7 +47,7 @@ static void ndpi_check_spotify(struct ndpi_detection_module_struct *ndpi_struct, if((packet->udp->source == spotify_port) && (packet->udp->dest == spotify_port)) { - if(payload_len > 2) { + if(payload_len >= 7) { if(memcmp(packet->payload, "SpotUdp", 7) == 0) { NDPI_LOG_INFO(ndpi_struct, "found spotify udp dissector\n"); ndpi_int_spotify_add_connection(ndpi_struct, flow, 0); diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c index fd783d099..87d090daf 100644 --- a/src/lib/protocols/stun.c +++ b/src/lib/protocols/stun.c @@ -161,7 +161,7 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * /* This looks like an invalid packet */ if(flow->protos.stun_ssl.stun.num_udp_pkts > 0) { - flow->guessed_host_protocol_id = NDPI_PROTOCOL_WHATSAPP_CALL; + // flow->guessed_host_protocol_id = NDPI_PROTOCOL_WHATSAPP_CALL; return(NDPI_IS_STUN); } else return(NDPI_IS_NOT_STUN); diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c index 62b2e3cf8..222fa480d 100644 --- a/src/lib/protocols/tls.c +++ b/src/lib/protocols/tls.c @@ -34,13 +34,13 @@ extern char *strptime(const char *s, const char *format, struct tm *tm); extern int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow); -// #define DEBUG_TLS_MEMORY 1 -// #define DEBUG_TLS 1 - +// #define DEBUG_TLS_MEMORY 1 +// #define DEBUG_TLS 1 // #define DEBUG_CERTIFICATE_HASH -/* #define DEBUG_FINGERPRINT 1 */ +/* #define DEBUG_FINGERPRINT 1 */ +/* #define DEBUG_ENCRYPTED_SNI 1 */ /* NOTE @@ -390,77 +390,83 @@ static void processCertificateElements(struct ndpi_detection_module_struct *ndpi i += 3 /* skip the initial patten 55 1D 11 */; i++; /* skip the first type, 0x04 == BIT STRING, and jump to it's length */ - i += (packet->payload[i] & 0x80) ? (packet->payload[i] & 0x7F) : 0; /* skip BIT STRING length */ - i += 2; /* skip the second type, 0x30 == SEQUENCE, and jump to it's length */ - i += (packet->payload[i] & 0x80) ? (packet->payload[i] & 0x7F) : 0; /* skip SEQUENCE length */ - i++; - - while(i < packet->payload_packet_len) { - if(packet->payload[i] == 0x82) { - if((i < (packet->payload_packet_len - 1)) - && ((i + packet->payload[i + 1] + 2) < packet->payload_packet_len)) { - u_int8_t len = packet->payload[i + 1]; - char dNSName[256]; - - i += 2; - - /* The check "len > sizeof(dNSName) - 1" will be always false. If we add it, - the compiler is smart enough to detect it and throws a warning */ - if(len == 0 /* Looks something went wrong */) - break; + if(i < packet->payload_packet_len) { + i += (packet->payload[i] & 0x80) ? (packet->payload[i] & 0x7F) : 0; /* skip BIT STRING length */ + if(i < packet->payload_packet_len) { + i += 2; /* skip the second type, 0x30 == SEQUENCE, and jump to it's length */ + if(i < packet->payload_packet_len) { + i += (packet->payload[i] & 0x80) ? (packet->payload[i] & 0x7F) : 0; /* skip SEQUENCE length */ + i++; + + while(i < packet->payload_packet_len) { + if(packet->payload[i] == 0x82) { + if((i < (packet->payload_packet_len - 1)) + && ((i + packet->payload[i + 1] + 2) < packet->payload_packet_len)) { + u_int8_t len = packet->payload[i + 1]; + char dNSName[256]; + + i += 2; + + /* The check "len > sizeof(dNSName) - 1" will be always false. If we add it, + the compiler is smart enough to detect it and throws a warning */ + if(len == 0 /* Looks something went wrong */) + break; - strncpy(dNSName, (const char*)&packet->payload[i], len); - dNSName[len] = '\0'; + strncpy(dNSName, (const char*)&packet->payload[i], len); + dNSName[len] = '\0'; - cleanupServerName(dNSName, len); + cleanupServerName(dNSName, len); #if DEBUG_TLS - printf("[TLS] dNSName %s [%s]\n", dNSName, flow->protos.stun_ssl.ssl.client_requested_server_name); + printf("[TLS] dNSName %s [%s]\n", dNSName, flow->protos.stun_ssl.ssl.client_requested_server_name); #endif - if(matched_name == 0) { - if((dNSName[0] == '*') && strstr(flow->protos.stun_ssl.ssl.client_requested_server_name, &dNSName[1])) - matched_name = 1; - else if(strcmp(flow->protos.stun_ssl.ssl.client_requested_server_name, dNSName) == 0) - matched_name = 1; - } + if(matched_name == 0) { + if((dNSName[0] == '*') && strstr(flow->protos.stun_ssl.ssl.client_requested_server_name, &dNSName[1])) + matched_name = 1; + else if(strcmp(flow->protos.stun_ssl.ssl.client_requested_server_name, dNSName) == 0) + matched_name = 1; + } - if(flow->protos.stun_ssl.ssl.server_names == NULL) - flow->protos.stun_ssl.ssl.server_names = ndpi_strdup(dNSName), - flow->protos.stun_ssl.ssl.server_names_len = strlen(dNSName); - else { - u_int16_t dNSName_len = strlen(dNSName); - u_int16_t newstr_len = flow->protos.stun_ssl.ssl.server_names_len + dNSName_len + 1; - char *newstr = (char*)ndpi_realloc(flow->protos.stun_ssl.ssl.server_names, - flow->protos.stun_ssl.ssl.server_names_len+1, newstr_len+1); - - if(newstr) { - flow->protos.stun_ssl.ssl.server_names = newstr; - flow->protos.stun_ssl.ssl.server_names[flow->protos.stun_ssl.ssl.server_names_len] = ','; - strncpy(&flow->protos.stun_ssl.ssl.server_names[flow->protos.stun_ssl.ssl.server_names_len+1], - dNSName, dNSName_len+1); - flow->protos.stun_ssl.ssl.server_names[newstr_len] = '\0'; - flow->protos.stun_ssl.ssl.server_names_len = newstr_len; - } - } + if(flow->protos.stun_ssl.ssl.server_names == NULL) + flow->protos.stun_ssl.ssl.server_names = ndpi_strdup(dNSName), + flow->protos.stun_ssl.ssl.server_names_len = strlen(dNSName); + else { + u_int16_t dNSName_len = strlen(dNSName); + u_int16_t newstr_len = flow->protos.stun_ssl.ssl.server_names_len + dNSName_len + 1; + char *newstr = (char*)ndpi_realloc(flow->protos.stun_ssl.ssl.server_names, + flow->protos.stun_ssl.ssl.server_names_len+1, newstr_len+1); + + if(newstr) { + flow->protos.stun_ssl.ssl.server_names = newstr; + flow->protos.stun_ssl.ssl.server_names[flow->protos.stun_ssl.ssl.server_names_len] = ','; + strncpy(&flow->protos.stun_ssl.ssl.server_names[flow->protos.stun_ssl.ssl.server_names_len+1], + dNSName, dNSName_len+1); + flow->protos.stun_ssl.ssl.server_names[newstr_len] = '\0'; + flow->protos.stun_ssl.ssl.server_names_len = newstr_len; + } + } - if(!flow->l4.tcp.tls.subprotocol_detected) - if(ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_TLS, dNSName, len)) - flow->l4.tcp.tls.subprotocol_detected = 1; + if(!flow->l4.tcp.tls.subprotocol_detected) + if(ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_TLS, dNSName, len)) + flow->l4.tcp.tls.subprotocol_detected = 1; - i += len; - } else { + i += len; + } else { #if DEBUG_TLS - printf("[TLS] Leftover %u bytes", packet->payload_packet_len - i); + printf("[TLS] Leftover %u bytes", packet->payload_packet_len - i); #endif - break; + break; + } + } else { + break; + } + } /* while */ + + if(!matched_name) + NDPI_SET_BIT(flow->risk, NDPI_TLS_CERTIFICATE_MISMATCH); /* Certificate mismatch */ } - } else { - break; } - } /* while */ - - if(!matched_name) - NDPI_SET_BIT(flow->risk, NDPI_TLS_CERTIFICATE_MISMATCH); /* Certificate mismatch */ + } } } @@ -1252,10 +1258,59 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, if(flow->protos.stun_ssl.ssl.tls_supported_versions == NULL) flow->protos.stun_ssl.ssl.tls_supported_versions = ndpi_strdup(version_str); } - + } else if(extension_id == 65486 /* encrypted server name */) { + /* + - https://tools.ietf.org/html/draft-ietf-tls-esni-06 + - https://blog.cloudflare.com/encrypted-sni/ + */ + u_int16_t e_offset = offset+extension_offset; + u_int16_t initial_offset = e_offset; + u_int16_t e_sni_len, cipher_suite = ntohs(*((u_int16_t*)&packet->payload[e_offset])); + + flow->protos.stun_ssl.ssl.encrypted_sni.cipher_suite = cipher_suite; + + e_offset += 2; /* Cipher suite len */ + + /* Key Share Entry */ + e_offset += 2; /* Group */ + e_offset += ntohs(*((u_int16_t*)&packet->payload[e_offset])) + 2; /* Lenght */ + + if((e_offset+4) < packet->payload_packet_len) { + /* Record Digest */ + e_offset += ntohs(*((u_int16_t*)&packet->payload[e_offset])) + 2; /* Lenght */ + + if((e_offset+4) < packet->payload_packet_len) { + e_sni_len = ntohs(*((u_int16_t*)&packet->payload[e_offset])); + e_offset += 2; + + if((e_offset+e_sni_len-extension_len-initial_offset) >= 0) { +#ifdef DEBUG_ENCRYPTED_SNI + printf("Client SSL [Encrypted Server Name len: %u]\n", e_sni_len); +#endif + + if(flow->protos.stun_ssl.ssl.encrypted_sni.esni == NULL) { + flow->protos.stun_ssl.ssl.encrypted_sni.esni = (char*)ndpi_malloc(e_sni_len*2+1); + + if(flow->protos.stun_ssl.ssl.encrypted_sni.esni) { + u_int16_t i, off; + + for(i=e_offset, off=0; i<(e_offset+e_sni_len); i++) { + int rc = sprintf(&flow->protos.stun_ssl.ssl.encrypted_sni.esni[off], "%02X", packet->payload[i] & 0XFF); + + if(rc <= 0) { + flow->protos.stun_ssl.ssl.encrypted_sni.esni[off] = '\0'; + break; + } else + off += rc; + } + } + } + } + } + } } - extension_offset += extension_len; + extension_offset += extension_len; /* Move to the next extension */ #ifdef DEBUG_TLS printf("Client SSL [extension_offset/len: %u/%u]\n", extension_offset, extension_len); |