diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/ndpi_content_match.c.inc | 6 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 303 | ||||
-rw-r--r-- | src/lib/ndpi_serializer.c | 1107 | ||||
-rw-r--r-- | src/lib/ndpi_utils.c | 929 | ||||
-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 | ||||
-rw-r--r-- | src/lib/third_party/include/ndpi_md5.h | 18 | ||||
-rw-r--r-- | src/lib/third_party/src/ndpi_md5.c | 204 |
21 files changed, 2446 insertions, 1611 deletions
diff --git a/src/lib/ndpi_content_match.c.inc b/src/lib/ndpi_content_match.c.inc index 9c0356ec8..79ab8e5e4 100644 --- a/src/lib/ndpi_content_match.c.inc +++ b/src/lib/ndpi_content_match.c.inc @@ -8382,10 +8382,10 @@ ndpi_protocol_match host_match[] = { { "ntop.org", NULL, "ntop\\.org$", "ntop", NDPI_PROTOCOL_NTOP, NDPI_PROTOCOL_CATEGORY_NETWORK, NDPI_PROTOCOL_SAFE }, - { "docs.googleusercontent.com", NULL, "docs.googleusercontent" TLD, "GoogleDocs", NDPI_PROTOCOL_GOOGLE_DOCS, NDPI_PROTOCOL_CATEGORY_MEDIA, NDPI_PROTOCOL_ACCEPTABLE }, - { "docs.google.com", NULL, "docs.google" TLD, "GoogleDocs", NDPI_PROTOCOL_GOOGLE_DOCS, NDPI_PROTOCOL_CATEGORY_MEDIA, NDPI_PROTOCOL_ACCEPTABLE }, + { "docs.googleusercontent.com", NULL, "docs.googleusercontent" TLD, "GoogleDocs", NDPI_PROTOCOL_GOOGLE_DOCS, NDPI_PROTOCOL_CATEGORY_COLLABORATIVE, NDPI_PROTOCOL_ACCEPTABLE }, + { "docs.google.com", NULL, "docs.google" TLD, "GoogleDocs", NDPI_PROTOCOL_GOOGLE_DOCS, NDPI_PROTOCOL_CATEGORY_COLLABORATIVE, NDPI_PROTOCOL_ACCEPTABLE }, - { "drive-thirdparty.googleusercontent.com", NULL, "drive-thirdparty\\.googleusercontent" TLD, "GoogleDrive", NDPI_PROTOCOL_GOOGLE_DRIVE, NDPI_PROTOCOL_CATEGORY_COLLABORATIVE, NDPI_PROTOCOL_ACCEPTABLE }, + { "drive-thirdparty.googleusercontent.com", NULL, "drive-thirdparty\\.googleusercontent" TLD, "GoogleDrive", NDPI_PROTOCOL_GOOGLE_DRIVE, NDPI_PROTOCOL_CATEGORY_CLOUD, NDPI_PROTOCOL_ACCEPTABLE }, { "drive.google.com", NULL, "drive.google" TLD, "GoogleDrive", NDPI_PROTOCOL_GOOGLE_DRIVE, NDPI_PROTOCOL_CATEGORY_CLOUD, NDPI_PROTOCOL_ACCEPTABLE }, { "android.clients.google.com", NULL, "android\\.clients\\.google" TLD, "PlayStore", NDPI_PROTOCOL_PLAYSTORE, NDPI_PROTOCOL_CATEGORY_SW_UPDATE, NDPI_PROTOCOL_SAFE }, diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index 9b6bdc632..cca061856 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -51,6 +51,9 @@ #define NDPI_CONST_GENERIC_PROTOCOL_NAME "GenericProtocol" +/* stun.c */ +extern u_int32_t get_stun_lru_key(struct ndpi_flow_struct *flow); + static int _ndpi_debug_callbacks = 0; /* #define MATCH_DEBUG 1 */ @@ -846,7 +849,7 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp no_master, "XDMCP", NDPI_PROTOCOL_CATEGORY_REMOTE_ACCESS, ndpi_build_default_ports(ports_a, 177, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 177, 0, 0, 0, 0) /* UDP */); - ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SMBV1, + ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_DANGEROUS, NDPI_PROTOCOL_SMBV1, 0 /* can_have_a_subprotocol */, no_master, no_master, "SMBv1", NDPI_PROTOCOL_CATEGORY_SYSTEM_OS, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, @@ -1097,10 +1100,10 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); - custom_master[0] = NDPI_PROTOCOL_SSL, custom_master[1] = NDPI_PROTOCOL_UNKNOWN; - ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SSL_NO_CERT, + custom_master[0] = NDPI_PROTOCOL_TLS, custom_master[1] = NDPI_PROTOCOL_UNKNOWN; + ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_TLS_NO_CERT, 1 /* can_have_a_subprotocol */, custom_master, - no_master, "SSL_No_Cert", NDPI_PROTOCOL_CATEGORY_WEB, + no_master, "TLS_No_Cert", NDPI_PROTOCOL_CATEGORY_WEB, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_UNSAFE, NDPI_PROTOCOL_IRC, @@ -1241,10 +1244,10 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); - custom_master[0] = NDPI_PROTOCOL_SSL_NO_CERT, custom_master[1] = NDPI_PROTOCOL_UNKNOWN; - ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_SSL, + custom_master[0] = NDPI_PROTOCOL_TLS_NO_CERT, custom_master[1] = NDPI_PROTOCOL_UNKNOWN; + ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_SAFE, NDPI_PROTOCOL_TLS, 1 /* can_have_a_subprotocol */, no_master, - custom_master, "SSL", NDPI_PROTOCOL_CATEGORY_WEB, + custom_master, "TLS", NDPI_PROTOCOL_CATEGORY_WEB, ndpi_build_default_ports(ports_a, 443, 3001 /* ntop */, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SSH, @@ -1749,7 +1752,7 @@ static int ac_match_handler(AC_MATCH_t *m, AC_TEXT_t *txt, AC_REP_t *match) { #ifdef MATCH_DEBUG printf("Searching [to search: %s/%u][pattern: %s/%u] [len: %u][match_num: %u][%s]\n", - buf, txt->length, m->patterns->astring, m->patterns->length, min_len, + buf, (unigned int)txt->length, m->patterns->astring, m->patterns->length, min_len, m->match_num, m->patterns->astring); #endif @@ -1768,7 +1771,8 @@ static int ac_match_handler(AC_MATCH_t *m, AC_TEXT_t *txt, AC_REP_t *match) { to avoid matching aws.amazon.com whereas a.ws.amazon.com has to match */ - if(whatfound && (whatfound != buf) + if(whatfound + && (whatfound != buf) && (m->patterns->astring[0] != '.') /* The searched pattern does not start with . */ && strchr(m->patterns->astring, '.') /* The matched pattern has a . (e.g. numeric or sym IPs) */ && (whatfound[-1] != '.') @@ -2288,7 +2292,7 @@ int ndpi_get_custom_category_match(struct ndpi_detection_module_struct *ndpi_str if(!ndpi_struct->custom_categories.categories_loaded) return -1; - + snprintf(ipbuf, sizeof(ipbuf)-1, "%s", name_or_ip); ptr = strrchr(ipbuf, '/'); @@ -2337,6 +2341,9 @@ void ndpi_exit_detection_module(struct ndpi_detection_module_struct *ndpi_struct if(ndpi_struct->ookla_cache) ndpi_lru_free_cache(ndpi_struct->ookla_cache); + if(ndpi_struct->stun_cache) + ndpi_lru_free_cache(ndpi_struct->stun_cache); + if(ndpi_struct->protocols_ptree) ndpi_Destroy_Patricia((patricia_tree_t*)ndpi_struct->protocols_ptree, free_ptree_data); @@ -2810,8 +2817,8 @@ void ndpi_set_protocol_detection_bitmask2(struct ndpi_detection_module_struct *n /* STARCRAFT */ init_starcraft_dissector(ndpi_struct, &a, detection_bitmask); - /* SSL */ - init_ssl_dissector(ndpi_struct, &a, detection_bitmask); + /* TLS */ + init_tls_dissector(ndpi_struct, &a, detection_bitmask); /* STUN */ init_stun_dissector(ndpi_struct, &a, detection_bitmask); @@ -3630,125 +3637,124 @@ static int ndpi_init_packet_header(struct ndpi_detection_module_struct *ndpi_str } void ndpi_connection_tracking(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow) -{ - /* const for gcc code optimization and cleaner code */ - struct ndpi_packet_struct *packet = &flow->packet; - const struct ndpi_iphdr *iph = packet->iph; + struct ndpi_flow_struct *flow) { + if(!flow) { + return; + } else { + /* const for gcc code optimization and cleaner code */ + struct ndpi_packet_struct *packet = &flow->packet; + const struct ndpi_iphdr *iph = packet->iph; #ifdef NDPI_DETECTION_SUPPORT_IPV6 - const struct ndpi_ipv6hdr *iphv6 = packet->iphv6; + const struct ndpi_ipv6hdr *iphv6 = packet->iphv6; #endif - const struct ndpi_tcphdr *tcph = packet->tcp; - const struct ndpi_udphdr *udph = flow->packet.udp; + const struct ndpi_tcphdr *tcph = packet->tcp; + const struct ndpi_udphdr *udph = flow->packet.udp; - if (!flow) { - return; - } + packet->tcp_retransmission = 0, packet->packet_direction = 0; - packet->tcp_retransmission = 0, packet->packet_direction = 0; - - if(ndpi_struct->direction_detect_disable) { - packet->packet_direction = flow->packet_direction; - } else { - if(iph != NULL && ntohl(iph->saddr) < ntohl(iph->daddr)) - packet->packet_direction = 1; + if(ndpi_struct->direction_detect_disable) { + packet->packet_direction = flow->packet_direction; + } else { + if(iph != NULL && ntohl(iph->saddr) < ntohl(iph->daddr)) + packet->packet_direction = 1; #ifdef NDPI_DETECTION_SUPPORT_IPV6 - if(iphv6 != NULL && NDPI_COMPARE_IPV6_ADDRESS_STRUCTS(&iphv6->ip6_src, - &iphv6->ip6_dst) != 0) - packet->packet_direction = 1; + if(iphv6 != NULL && NDPI_COMPARE_IPV6_ADDRESS_STRUCTS(&iphv6->ip6_src, + &iphv6->ip6_dst) != 0) + packet->packet_direction = 1; #endif - } + } - packet->packet_lines_parsed_complete = 0; + packet->packet_lines_parsed_complete = 0; - if(flow->init_finished == 0) { - flow->init_finished = 1; - flow->setup_packet_direction = packet->packet_direction; - } + if(flow->init_finished == 0) { + flow->init_finished = 1; + flow->setup_packet_direction = packet->packet_direction; + } - if(tcph != NULL) { - /* reset retried bytes here before setting it */ - packet->num_retried_bytes = 0; + if(tcph != NULL) { + /* reset retried bytes here before setting it */ + packet->num_retried_bytes = 0; - if(!ndpi_struct->direction_detect_disable) - packet->packet_direction = (ntohs(tcph->source) < ntohs(tcph->dest)) ? 1 : 0; + if(!ndpi_struct->direction_detect_disable) + packet->packet_direction = (ntohs(tcph->source) < ntohs(tcph->dest)) ? 1 : 0; - if(tcph->syn != 0 && tcph->ack == 0 && flow->l4.tcp.seen_syn == 0 && flow->l4.tcp.seen_syn_ack == 0 - && flow->l4.tcp.seen_ack == 0) { - flow->l4.tcp.seen_syn = 1; - } - if(tcph->syn != 0 && tcph->ack != 0 && flow->l4.tcp.seen_syn == 1 && flow->l4.tcp.seen_syn_ack == 0 - && flow->l4.tcp.seen_ack == 0) { - flow->l4.tcp.seen_syn_ack = 1; - } - if(tcph->syn == 0 && tcph->ack == 1 && flow->l4.tcp.seen_syn == 1 && flow->l4.tcp.seen_syn_ack == 1 - && flow->l4.tcp.seen_ack == 0) { - flow->l4.tcp.seen_ack = 1; - } - if((flow->next_tcp_seq_nr[0] == 0 && flow->next_tcp_seq_nr[1] == 0) - || (flow->next_tcp_seq_nr[0] == 0 || flow->next_tcp_seq_nr[1] == 0)) { - /* initialize tcp sequence counters */ - /* the ack flag needs to be set to get valid sequence numbers from the other - * direction. Usually it will catch the second packet syn+ack but it works - * also for asymmetric traffic where it will use the first data packet - * - * if the syn flag is set add one to the sequence number, - * otherwise use the payload length. - */ - if(tcph->ack != 0) { - flow->next_tcp_seq_nr[flow->packet.packet_direction] = - ntohl(tcph->seq) + (tcph->syn ? 1 : packet->payload_packet_len); - - flow->next_tcp_seq_nr[1 -flow->packet.packet_direction] = ntohl(tcph->ack_seq); + if(tcph->syn != 0 && tcph->ack == 0 && flow->l4.tcp.seen_syn == 0 && flow->l4.tcp.seen_syn_ack == 0 + && flow->l4.tcp.seen_ack == 0) { + flow->l4.tcp.seen_syn = 1; + } + if(tcph->syn != 0 && tcph->ack != 0 && flow->l4.tcp.seen_syn == 1 && flow->l4.tcp.seen_syn_ack == 0 + && flow->l4.tcp.seen_ack == 0) { + flow->l4.tcp.seen_syn_ack = 1; } - } else if(packet->payload_packet_len > 0) { - /* check tcp sequence counters */ - if(((u_int32_t)(ntohl(tcph->seq) - flow->next_tcp_seq_nr[packet->packet_direction])) > - ndpi_struct->tcp_max_retransmission_window_size) { - - packet->tcp_retransmission = 1; - - /* CHECK IF PARTIAL RETRY IS HAPPENING */ - if((flow->next_tcp_seq_nr[packet->packet_direction] - ntohl(tcph->seq) < packet->payload_packet_len)) { - /* num_retried_bytes actual_payload_len hold info about the partial retry - analyzer which require this info can make use of this info - Other analyzer can use packet->payload_packet_len */ - packet->num_retried_bytes = (u_int16_t)(flow->next_tcp_seq_nr[packet->packet_direction] - ntohl(tcph->seq)); - packet->actual_payload_len = packet->payload_packet_len - packet->num_retried_bytes; + if(tcph->syn == 0 && tcph->ack == 1 && flow->l4.tcp.seen_syn == 1 && flow->l4.tcp.seen_syn_ack == 1 + && flow->l4.tcp.seen_ack == 0) { + flow->l4.tcp.seen_ack = 1; + } + if((flow->next_tcp_seq_nr[0] == 0 && flow->next_tcp_seq_nr[1] == 0) + || (flow->next_tcp_seq_nr[0] == 0 || flow->next_tcp_seq_nr[1] == 0)) { + /* initialize tcp sequence counters */ + /* the ack flag needs to be set to get valid sequence numbers from the other + * direction. Usually it will catch the second packet syn+ack but it works + * also for asymmetric traffic where it will use the first data packet + * + * if the syn flag is set add one to the sequence number, + * otherwise use the payload length. + */ + if(tcph->ack != 0) { + flow->next_tcp_seq_nr[flow->packet.packet_direction] = + ntohl(tcph->seq) + (tcph->syn ? 1 : packet->payload_packet_len); + + flow->next_tcp_seq_nr[1 -flow->packet.packet_direction] = ntohl(tcph->ack_seq); + } + } else if(packet->payload_packet_len > 0) { + /* check tcp sequence counters */ + if(((u_int32_t)(ntohl(tcph->seq) - flow->next_tcp_seq_nr[packet->packet_direction])) > + ndpi_struct->tcp_max_retransmission_window_size) { + + packet->tcp_retransmission = 1; + + /* CHECK IF PARTIAL RETRY IS HAPPENING */ + if((flow->next_tcp_seq_nr[packet->packet_direction] - ntohl(tcph->seq) < packet->payload_packet_len)) { + /* num_retried_bytes actual_payload_len hold info about the partial retry + analyzer which require this info can make use of this info + Other analyzer can use packet->payload_packet_len */ + packet->num_retried_bytes = (u_int16_t)(flow->next_tcp_seq_nr[packet->packet_direction] - ntohl(tcph->seq)); + packet->actual_payload_len = packet->payload_packet_len - packet->num_retried_bytes; + flow->next_tcp_seq_nr[packet->packet_direction] = ntohl(tcph->seq) + packet->payload_packet_len; + } + } + + /* normal path + actual_payload_len is initialized to payload_packet_len during tcp header parsing itself. + It will be changed only in case of retransmission */ + else { + packet->num_retried_bytes = 0; flow->next_tcp_seq_nr[packet->packet_direction] = ntohl(tcph->seq) + packet->payload_packet_len; } } - /* normal path - actual_payload_len is initialized to payload_packet_len during tcp header parsing itself. - It will be changed only in case of retransmission */ - else { - packet->num_retried_bytes = 0; - flow->next_tcp_seq_nr[packet->packet_direction] = ntohl(tcph->seq) + packet->payload_packet_len; + if(tcph->rst) { + flow->next_tcp_seq_nr[0] = 0; + flow->next_tcp_seq_nr[1] = 0; } + } else if(udph != NULL) { + if(!ndpi_struct->direction_detect_disable) + packet->packet_direction = (htons(udph->source) < htons(udph->dest)) ? 1 : 0; } - if(tcph->rst) { - flow->next_tcp_seq_nr[0] = 0; - flow->next_tcp_seq_nr[1] = 0; + if(flow->packet_counter < MAX_PACKET_COUNTER && packet->payload_packet_len) { + flow->packet_counter++; } - } else if(udph != NULL) { - if(!ndpi_struct->direction_detect_disable) - packet->packet_direction = (htons(udph->source) < htons(udph->dest)) ? 1 : 0; - } - - if(flow->packet_counter < MAX_PACKET_COUNTER && packet->payload_packet_len) { - flow->packet_counter++; - } - if(flow->packet_direction_counter[packet->packet_direction] < MAX_PACKET_COUNTER && packet->payload_packet_len) { - flow->packet_direction_counter[packet->packet_direction]++; - } + if(flow->packet_direction_counter[packet->packet_direction] < MAX_PACKET_COUNTER && packet->payload_packet_len) { + flow->packet_direction_counter[packet->packet_direction]++; + } - if(flow->byte_counter[packet->packet_direction] + packet->payload_packet_len > - flow->byte_counter[packet->packet_direction]) { - flow->byte_counter[packet->packet_direction] += packet->payload_packet_len; + if(flow->byte_counter[packet->packet_direction] + packet->payload_packet_len > + flow->byte_counter[packet->packet_direction]) { + flow->byte_counter[packet->packet_direction] += packet->payload_packet_len; + } } } @@ -3785,7 +3791,7 @@ void check_ndpi_other_flow_func(struct ndpi_detection_module_struct *ndpi_struct if((func != ndpi_struct->callback_buffer_non_tcp_udp[a].func) && (ndpi_struct->callback_buffer_non_tcp_udp[a].ndpi_selection_bitmask & *ndpi_selection_packet) == ndpi_struct->callback_buffer_non_tcp_udp[a].ndpi_selection_bitmask - && + && NDPI_BITMASK_COMPARE(flow->excluded_protocol_bitmask, ndpi_struct->callback_buffer_non_tcp_udp[a].excluded_protocol_bitmask) == 0 && NDPI_BITMASK_COMPARE(ndpi_struct->callback_buffer_non_tcp_udp[a].detection_bitmask, @@ -3938,7 +3944,7 @@ u_int16_t ndpi_guess_host_protocol_id(struct ndpi_detection_module_struct *ndpi_ struct in_addr addr; addr.s_addr = flow->packet.iph->saddr; - + /* guess host protocol */ ret = ndpi_network_ptree_match(ndpi_struct, &addr); @@ -4026,9 +4032,13 @@ ndpi_protocol ndpi_detection_giveup(struct ndpi_detection_module_struct *ndpi_st if(flow->guessed_protocol_id == NDPI_PROTOCOL_STUN) goto check_stun_export; + else if((flow->guessed_protocol_id == NDPI_PROTOCOL_HANGOUT_DUO) + || (flow->guessed_protocol_id == NDPI_PROTOCOL_MESSENGER) + || (flow->guessed_protocol_id == NDPI_PROTOCOL_WHATSAPP_VOICE)) + ndpi_set_detected_protocol(ndpi_struct, flow, flow->guessed_protocol_id, NDPI_PROTOCOL_UNKNOWN); else if((flow->l4.tcp.ssl_seen_client_cert == 1) && (flow->protos.stun_ssl.ssl.client_certificate[0] != '\0')) { - ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SSL, NDPI_PROTOCOL_UNKNOWN); + ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_TLS, NDPI_PROTOCOL_UNKNOWN); } else { ndpi_protocol ret_g = ndpi_get_partial_detection(ndpi_struct, flow); @@ -4042,7 +4052,7 @@ ndpi_protocol ndpi_detection_giveup(struct ndpi_detection_module_struct *ndpi_st if((flow->guessed_protocol_id == NDPI_PROTOCOL_UNKNOWN) && (flow->packet.l4_protocol == IPPROTO_TCP) && (flow->l4.tcp.ssl_stage > 1)) - flow->guessed_protocol_id = NDPI_PROTOCOL_SSL_NO_CERT; + flow->guessed_protocol_id = NDPI_PROTOCOL_TLS_NO_CERT; guessed_protocol_id = flow->guessed_protocol_id, guessed_host_protocol_id = flow->guessed_host_protocol_id; @@ -4102,10 +4112,11 @@ ndpi_protocol ndpi_detection_giveup(struct ndpi_detection_module_struct *ndpi_st // if(/* (flow->protos.stun_ssl.stun.num_processed_pkts >= NDPI_MIN_NUM_STUN_DETECTION) */ if(flow->protos.stun_ssl.stun.num_processed_pkts && flow->protos.stun_ssl.stun.is_skype) { ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE); - } else + } else { ndpi_set_detected_protocol(ndpi_struct, flow, flow->guessed_host_protocol_id, NDPI_PROTOCOL_STUN); + } } } @@ -4416,7 +4427,9 @@ void ndpi_fill_protocol_category(struct ndpi_detection_module_struct *ndpi_struc if((flow->l4.tcp.ssl_seen_client_cert == 1) && (flow->protos.stun_ssl.ssl.client_certificate[0] != '\0')) { unsigned long id; - int rc = ndpi_match_custom_category(ndpi_struct, (char *)flow->protos.stun_ssl.ssl.client_certificate, &id); + int rc = ndpi_match_custom_category(ndpi_struct, + (char *)flow->protos.stun_ssl.ssl.client_certificate, + &id); if(rc == 0) { flow->category = ret->category = (ndpi_protocol_category_t)id; @@ -4460,8 +4473,8 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct */ if(flow->check_extra_packets /* - && ((flow->detected_protocol_stack[0] == NDPI_PROTOCOL_SSL) - || (flow->detected_protocol_stack[1] == NDPI_PROTOCOL_SSL)) + && ((flow->detected_protocol_stack[0] == NDPI_PROTOCOL_TLS) + || (flow->detected_protocol_stack[1] == NDPI_PROTOCOL_TLS)) */ ) { ndpi_process_extra_packet(ndpi_struct, flow, packet, packetlen, current_tick_l, src, dst); @@ -4547,8 +4560,6 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct flow->guessed_host_protocol_id = ndpi_guess_host_protocol_id(ndpi_struct, flow); if(ndpi_struct->custom_categories.categories_loaded && flow->packet.iph) { - ndpi_protocol ret = { NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED }; - ndpi_fill_ip_protocol_category(ndpi_struct, flow->packet.iph->saddr, flow->packet.iph->daddr, &ret); flow->guessed_header_category = ret.category; } else @@ -4579,7 +4590,7 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct addr.s_addr = flow->packet.iph->saddr; flow->guessed_host_protocol_id = ndpi_network_ptree_match(ndpi_struct, &addr); - + if(flow->guessed_host_protocol_id == NDPI_PROTOCOL_UNKNOWN) { addr.s_addr = flow->packet.iph->daddr; flow->guessed_host_protocol_id = ndpi_network_ptree_match(ndpi_struct, &addr); @@ -4598,16 +4609,16 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct for(i=0; i<2; i++) { u_int16_t port = (i == 0) ? ntohs(flow->packet.tcp->dest) : ntohs(flow->packet.tcp->source); - + switch(port) { case 80: ret.master_protocol = NDPI_PROTOCOL_HTTP; break; case 443: - ret.master_protocol = NDPI_PROTOCOL_SSL; /* QUIC could also match */ + ret.master_protocol = NDPI_PROTOCOL_TLS; /* QUIC could also match */ break; } - + if(ret.master_protocol != NDPI_PROTOCOL_UNKNOWN) break; } @@ -5594,7 +5605,7 @@ ndpi_protocol ndpi_guess_undetected_protocol(struct ndpi_detection_module_struct else { ret.app_protocol = rc; - if(rc == NDPI_PROTOCOL_SSL) + if(rc == NDPI_PROTOCOL_TLS) goto check_guessed_skype; else { ret.category = ndpi_get_proto_category(ndpi_struct, ret); @@ -5928,7 +5939,7 @@ int ndpi_match_string_subprotocol(struct ndpi_detection_module_struct *ndpi_stru ret_match->protocol_id = match.number, ret_match->protocol_category = match.category, ret_match->protocol_breed = match.breed; - + return(match.number); } @@ -6095,23 +6106,25 @@ char* ndpi_revision() { return(NDPI_GIT_RELEASE); } #ifdef WIN32 -/* http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/port/gettimeofday.c;h=75a91993b74414c0a1c13a2a09ce739cb8aa8a08;hb=HEAD */ -int gettimeofday(struct timeval * tp, struct timezone * tzp) { - /* FILETIME of Jan 1 1970 00:00:00. */ - const unsigned __int64 epoch = (__int64)(116444736000000000); +/* https://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows */ +int gettimeofday(struct timeval * tp, struct timezone * tzp) +{ + // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's + // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) + // until 00:00:00 January 1, 1970 + static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); - FILETIME file_time; SYSTEMTIME system_time; - ULARGE_INTEGER ularge; + FILETIME file_time; + uint64_t time; - GetSystemTime(&system_time); - SystemTimeToFileTime(&system_time, &file_time); - ularge.LowPart = file_time.dwLowDateTime; - ularge.HighPart = file_time.dwHighDateTime; + GetSystemTime( &system_time ); + SystemTimeToFileTime( &system_time, &file_time ); + time = ((uint64_t)file_time.dwLowDateTime ) ; + time += ((uint64_t)file_time.dwHighDateTime) << 32; - tp->tv_sec = (long) ((ularge.QuadPart - epoch) / 10000000L); + tp->tv_sec = (long) ((time - EPOCH) / 10000000L); tp->tv_usec = (long) (system_time.wMilliseconds * 1000); - return 0; } #endif @@ -6178,7 +6191,8 @@ struct ndpi_lru_cache* ndpi_lru_cache_init(u_int32_t num_entries) { if(!c) return(NULL); - c->entries = (u_int32_t*)calloc(num_entries, sizeof(u_int32_t)); + c->entries = (struct ndpi_lru_cache_entry*)calloc(num_entries, + sizeof(struct ndpi_lru_cache_entry)); if(!c->entries) { free(c); @@ -6194,21 +6208,23 @@ void ndpi_lru_free_cache(struct ndpi_lru_cache *c) { free(c); } - -u_int8_t ndpi_lru_find_cache(struct ndpi_lru_cache *c, u_int32_t key, u_int8_t clean_key_when_found) { +u_int8_t ndpi_lru_find_cache(struct ndpi_lru_cache *c, u_int32_t key, u_int16_t *value, u_int8_t clean_key_when_found) { u_int32_t slot = key % c->num_entries; - if(c->entries[slot] == key) { - if(clean_key_when_found) c->entries[slot] = 0; + if(c->entries[slot].is_full) { + *value = c->entries[slot].value; + if(clean_key_when_found) c->entries[slot].is_full = 0; return(1); } else return(0); } -void ndpi_lru_add_to_cache(struct ndpi_lru_cache *c, u_int32_t key) { +void ndpi_lru_add_to_cache(struct ndpi_lru_cache *c, u_int32_t key, u_int16_t value) { u_int32_t slot = key % c->num_entries; - c->entries[slot] = key; + c->entries[slot].is_full = 1, + c->entries[slot].key = key, + c->entries[slot].value = value; } /* ******************************************************************** */ @@ -6236,4 +6252,3 @@ int ndpi_flowv6_flow_hash(u_int8_t l4_proto, struct ndpi_in6_addr *src_ip, struc } /* **************************************** */ - diff --git a/src/lib/ndpi_serializer.c b/src/lib/ndpi_serializer.c new file mode 100644 index 000000000..a6546a909 --- /dev/null +++ b/src/lib/ndpi_serializer.c @@ -0,0 +1,1107 @@ +/* + * ndpi_serializer.c + * + * 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 + * + * nDPI is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nDPI is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with nDPI. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifdef HAVE_CONFIG_H +#include "ndpi_config.h" +#endif + +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> + +#include "ndpi_api.h" +#include "ndpi_config.h" + +#include <time.h> +#ifndef WIN32 +#include <unistd.h> +#endif + +#if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ +#include <sys/endian.h> +#endif + +/* ********************************** */ + +static u_int64_t ndpi_htonll(u_int64_t v) { + union { u_int32_t lv[2]; u_int64_t llv; } u; + u.lv[0] = htonl(v >> 32); + u.lv[1] = htonl(v & 0xFFFFFFFFULL); + return u.llv; +} + +/* ********************************** */ + +static u_int64_t ndpi_ntohll(u_int64_t v) { + union { u_int32_t lv[2]; u_int64_t llv; } u; + u.llv = v; + return ((u_int64_t)ntohl(u.lv[0]) << 32) | (u_int64_t)ntohl(u.lv[1]); +} + +/* ********************************** */ + +/* + * Escapes a string to be suitable for a JSON value, adding double quotes, and terminating the string with a null byte. + * It is recommended to provide a destination buffer (dst) which is as large as double the source buffer (src) at least. + * Upon successful return, these functions return the number of characters printed (excluding the null byte used to terminate the string). + */ +static int ndpi_json_string_escape(const char *src, int src_len, char *dst, int dst_max_len) { + char c = 0; + int i, j = 0; + + dst[j++] = '"'; + + for (i = 0; i < src_len && j < dst_max_len; i++) { + + c = src[i]; + + switch (c) { + case '\\': + case '"': + case '/': + dst[j++] = '\\'; + dst[j++] = c; + break; + case '\b': + dst[j++] = '\\'; + dst[j++] = 'b'; + break; + case '\t': + dst[j++] = '\\'; + dst[j++] = 't'; + break; + case '\n': + dst[j++] = '\\'; + dst[j++] = 'n'; + break; + case '\f': + dst[j++] = '\\'; + dst[j++] = 'f'; + break; + case '\r': + dst[j++] = '\\'; + dst[j++] = 'r'; + break; + default: + if(c < ' ') + ; /* non printable */ + else + dst[j++] = c; + } + } + + dst[j++] = '"'; + dst[j+1] = '\0'; + + return j; +} + +/* ********************************** */ + +void ndpi_reset_serializer(ndpi_serializer *_serializer) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + + if(serializer->fmt == ndpi_serialization_format_json) { + u_int32_t buff_diff; + + serializer->size_used = 0; + buff_diff = serializer->buffer_size - serializer->size_used; + + /* Note: please keep a space at the beginning as it is used for arrays when an end-of-record is used */ + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, " {}"); + } else if(serializer->fmt == ndpi_serialization_format_csv) + serializer->size_used = 0; + else /* TLV */ + serializer->size_used = 2 * sizeof(u_int8_t); +} + +/* ********************************** */ + +int ndpi_init_serializer(ndpi_serializer *_serializer, + ndpi_serialization_format fmt) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + + memset(serializer, 0, sizeof(ndpi_private_serializer)); + + serializer->buffer_size = 8192; + serializer->buffer = (u_int8_t *) malloc(serializer->buffer_size * sizeof(u_int8_t)); + + if(serializer->buffer == NULL) + return(-1); + + serializer->fmt = fmt; + + serializer->buffer[0] = 1; /* version */ + serializer->buffer[1] = (u_int8_t) fmt; + + serializer->csv_separator[0] = ','; + serializer->csv_separator[1] = '\0'; + + ndpi_reset_serializer(_serializer); + + return(1); +} + +/* ********************************** */ + +char* ndpi_serializer_get_buffer(ndpi_serializer *_serializer, u_int32_t *buffer_len) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + char *buf = (char*)serializer->buffer; + + /* NULL terminate the buffer if there is space available */ + if(serializer->buffer_size > serializer->size_used) + serializer->buffer[serializer->size_used] = '\0'; + + *buffer_len = serializer->size_used; + + if(serializer->fmt == ndpi_serialization_format_json) { + while(buf[0] == '\0') + buf++, *buffer_len = *buffer_len - 1 ; + } + + return(buf); +} + +/* ********************************** */ + +u_int32_t ndpi_serializer_get_buffer_len(ndpi_serializer *_serializer) { + return(((ndpi_private_serializer*)_serializer)->size_used); +} + + /* ********************************** */ + +void ndpi_serializer_set_csv_separator(ndpi_serializer *_serializer, char separator) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + + serializer->csv_separator[0] = separator; +} + +/* ********************************** */ + +void ndpi_term_serializer(ndpi_serializer *_serializer) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + + if(serializer->buffer) { + free(serializer->buffer); + serializer->buffer_size = 0; + serializer->buffer = NULL; + } +} + +/* ********************************** */ + +static int ndpi_extend_serializer_buffer(ndpi_serializer *_serializer, u_int32_t min_len) { + u_int32_t new_size; + void *r; + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + + if(min_len < 1024) + min_len = 1024; + + new_size = serializer->buffer_size + min_len; + + r = realloc((void *) serializer->buffer, new_size); + + if(r == NULL) + return(-1); + + serializer->buffer = r; + serializer->buffer_size = new_size; + + return(0); +} + +/* ********************************** */ + +static void ndpi_serialize_single_uint32(ndpi_serializer *_serializer, + u_int32_t s) { + u_int32_t v = htonl(s); + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + + memcpy(&serializer->buffer[serializer->size_used], &v, sizeof(u_int32_t)); + serializer->size_used += sizeof(u_int32_t); +} + +/* ********************************** */ + +static void ndpi_serialize_single_uint64(ndpi_serializer *_serializer, + u_int64_t s) { + u_int64_t v = ndpi_htonll(s); + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + + memcpy(&serializer->buffer[serializer->size_used], &v, sizeof(u_int64_t)); + serializer->size_used += sizeof(u_int64_t); +} + +/* ********************************** */ + +/* TODO: fix portability across platforms */ +static void ndpi_serialize_single_float(ndpi_serializer *_serializer, float s) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + + memcpy(&serializer->buffer[serializer->size_used], &s, sizeof(s)); + serializer->size_used += sizeof(float); +} + +/* ********************************** */ + +static void ndpi_serialize_single_string(ndpi_serializer *_serializer, + const char *s, u_int16_t slen) { + u_int16_t l = htons(slen); + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + + memcpy(&serializer->buffer[serializer->size_used], &l, sizeof(u_int16_t)); + serializer->size_used += sizeof(u_int16_t); + + if(slen > 0) + memcpy(&serializer->buffer[serializer->size_used], s, slen); + + serializer->size_used += slen; +} + +/* ********************************** */ + +static void ndpi_deserialize_single_uint32(ndpi_serializer *_deserializer, + u_int32_t *s) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + *s = ntohl(*((u_int32_t *) &deserializer->buffer[deserializer->size_used])); + deserializer->size_used += sizeof(u_int32_t); +} + +/* ********************************** */ + +static void ndpi_deserialize_single_int32(ndpi_serializer *_deserializer, + int32_t *s) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + *s = ntohl(*((int32_t *) &deserializer->buffer[deserializer->size_used])); + deserializer->size_used += sizeof(int32_t); +} + +/* ********************************** */ + +static void ndpi_deserialize_single_uint64(ndpi_serializer *_deserializer, + u_int64_t *s) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + *s = ndpi_ntohll(*(u_int64_t*)&deserializer->buffer[deserializer->size_used]); + deserializer->size_used += sizeof(u_int64_t); +} + +/* ********************************** */ + +static void ndpi_deserialize_single_int64(ndpi_serializer *_deserializer, + int64_t *s) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + *s = ndpi_ntohll(*(int64_t*)&deserializer->buffer[deserializer->size_used]); + deserializer->size_used += sizeof(int64_t); +} + +/* ********************************** */ + +/* TODO: fix portability across platforms */ +static void ndpi_deserialize_single_float(ndpi_serializer *_deserializer, + float *s) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + *s = *(float*)&deserializer->buffer[deserializer->size_used]; + deserializer->size_used += sizeof(float); +} + +/* ********************************** */ + +static void ndpi_deserialize_single_string(ndpi_serializer *_deserializer, + ndpi_string *v) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + v->str_len = ntohs(*((u_int16_t *) &deserializer->buffer[deserializer->size_used])); + deserializer->size_used += sizeof(u_int16_t); + + v->str = (char *) &deserializer->buffer[deserializer->size_used]; + deserializer->size_used += v->str_len; +} + +/* ********************************** */ + +int ndpi_serialize_end_of_record(ndpi_serializer *_serializer) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; + u_int16_t needed = + sizeof(u_int8_t) /* type */; + + if(serializer->fmt == ndpi_serialization_format_json) + needed += 1; + + if(buff_diff < needed) { + if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + return(-1); + buff_diff = serializer->buffer_size - serializer->size_used; + } + + if(serializer->fmt == ndpi_serialization_format_json) { + if(!(serializer->status & NDPI_SERIALIZER_STATUS_ARRAY)) { + // serializer->json_buffer[0] = '['; + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], + buff_diff, "]"); + } + serializer->status |= NDPI_SERIALIZER_STATUS_ARRAY | NDPI_SERIALIZER_STATUS_EOR; + serializer->status &= ~NDPI_SERIALIZER_STATUS_COMMA; + } else { + serializer->buffer[serializer->size_used++] = ndpi_serialization_end_of_record; + } + + return(0); +} + +/* ********************************** */ + +static void ndpi_serialize_json_pre(ndpi_serializer *_serializer) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + + if(serializer->status & NDPI_SERIALIZER_STATUS_EOR) { + serializer->size_used--; /* Remove ']' */ + serializer->status &= ~NDPI_SERIALIZER_STATUS_EOR; + serializer->buffer[serializer->size_used++] = ','; + serializer->buffer[serializer->size_used++] = '{'; + } else { + if(serializer->status & NDPI_SERIALIZER_STATUS_ARRAY) + serializer->size_used--; /* Remove ']'*/ + serializer->size_used--; /* Remove '}'*/ + } + if(serializer->status & NDPI_SERIALIZER_STATUS_COMMA) + serializer->buffer[serializer->size_used++] = ','; +} + +/* ********************************** */ + +static void ndpi_serialize_json_post(ndpi_serializer *_serializer) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + + serializer->buffer[serializer->size_used++] = '}'; + if(serializer->status & NDPI_SERIALIZER_STATUS_ARRAY) + serializer->buffer[serializer->size_used++] = ']'; + + serializer->status |= NDPI_SERIALIZER_STATUS_COMMA; +} + +/* ********************************** */ + +int ndpi_serialize_uint32_uint32(ndpi_serializer *_serializer, + u_int32_t key, u_int32_t value) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; + u_int16_t needed = + sizeof(u_int8_t) /* type */ + + sizeof(u_int32_t) /* key */ + + sizeof(u_int32_t); + + if(serializer->fmt == ndpi_serialization_format_json) + needed += 24; + + if(buff_diff < needed) { + if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + return(-1); + buff_diff = serializer->buffer_size - serializer->size_used; + } + + if(serializer->fmt == ndpi_serialization_format_json) { + ndpi_serialize_json_pre(_serializer); + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, + "\"%u\":%u", key, value); + ndpi_serialize_json_post(_serializer); + } else if(serializer->fmt == ndpi_serialization_format_csv) { + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, + "%s%u", (serializer->size_used > 0) ? serializer->csv_separator : "", value); + } else { + serializer->buffer[serializer->size_used++] = ndpi_serialization_uint32_uint32; + + ndpi_serialize_single_uint32(_serializer, key); + ndpi_serialize_single_uint32(_serializer, value); + } + + return(0); +} + +/* ********************************** */ + +int ndpi_serialize_uint32_uint64(ndpi_serializer *_serializer, + u_int32_t key, u_int64_t value) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; + u_int16_t needed = + sizeof(u_int8_t) /* type */ + + sizeof(u_int32_t) /* key */ + + sizeof(u_int64_t); + + if(serializer->fmt == ndpi_serialization_format_json) + needed += 32; + + if(buff_diff < needed) { + if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + return(-1); + buff_diff = serializer->buffer_size - serializer->size_used; + } + + if(serializer->fmt == ndpi_serialization_format_json) { + ndpi_serialize_json_pre(_serializer); + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, + "\"%u\":%llu", key, (unsigned long long)value); + ndpi_serialize_json_post(_serializer); + } else if(serializer->fmt == ndpi_serialization_format_csv) { + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, + "%s%llu", + (serializer->size_used > 0) ? serializer->csv_separator : "", + (unsigned long long)value); + + } else { + serializer->buffer[serializer->size_used++] = ndpi_serialization_uint32_uint64; + + ndpi_serialize_single_uint32(_serializer, key); + ndpi_serialize_single_uint64(_serializer, value); + } + + return(0); +} + +/* ********************************** */ + +int ndpi_serialize_uint32_string(ndpi_serializer *_serializer, + u_int32_t key, const char *_value) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + const char *value = _value ? _value : ""; + u_int16_t slen = strlen(value); + u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; + u_int32_t needed = + sizeof(u_int8_t) /* type */ + + sizeof(u_int32_t) /* key */ + + sizeof(u_int16_t) /* len */ + + slen; + + if(serializer->fmt == ndpi_serialization_format_json) + needed += 24 + slen; + + if(buff_diff < needed) { + if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + return(-1); + buff_diff = serializer->buffer_size - serializer->size_used; + } + + if(serializer->fmt == ndpi_serialization_format_json) { + ndpi_serialize_json_pre(_serializer); + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, + "\"%u\":", key); + buff_diff = serializer->buffer_size - serializer->size_used; + serializer->size_used += ndpi_json_string_escape(value, slen, + (char *) &serializer->buffer[serializer->size_used], buff_diff); + buff_diff = serializer->buffer_size - serializer->size_used; + ndpi_serialize_json_post(_serializer); + } else if(serializer->fmt == ndpi_serialization_format_csv) { + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, + "%s%s", (serializer->size_used > 0) ? serializer->csv_separator : "", value); + } else { + serializer->buffer[serializer->size_used++] = ndpi_serialization_uint32_string; + + ndpi_serialize_single_uint32(_serializer, key); + ndpi_serialize_single_string(_serializer, value, slen); + } + + return(0); +} + +/* ********************************** */ + +int ndpi_serialize_string_int32(ndpi_serializer *_serializer, + const char *key, int32_t value) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + u_int16_t klen = strlen(key); + u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; + u_int32_t needed = + sizeof(u_int8_t) /* type */ + + sizeof(u_int16_t) /* key len */ + + klen /* key */ + + sizeof(u_int32_t); + + if(serializer->fmt == ndpi_serialization_format_json) + needed += 16 + klen; + + if(buff_diff < needed) { + if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + return(-1); + buff_diff = serializer->buffer_size - serializer->size_used; + } + + if(serializer->fmt == ndpi_serialization_format_json) { + ndpi_serialize_json_pre(_serializer); + serializer->size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer[serializer->size_used], buff_diff); + buff_diff = serializer->buffer_size - serializer->size_used; + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, + ":%d", value); + ndpi_serialize_json_post(_serializer); + } else if(serializer->fmt == ndpi_serialization_format_csv) { + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, + "%s%d", (serializer->size_used > 0) ? serializer->csv_separator : "", value); + } else { + serializer->buffer[serializer->size_used++] = ndpi_serialization_string_int32; + + ndpi_serialize_single_string(_serializer, key, klen); + ndpi_serialize_single_uint32(_serializer, value); + } + + return(0); +} + +/* ********************************** */ + +int ndpi_serialize_string_int64(ndpi_serializer *_serializer, + const char *key, int64_t value) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + u_int16_t klen = strlen(key); + u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; + u_int32_t needed = + sizeof(u_int8_t) /* type */ + + sizeof(u_int16_t) /* key len */ + + klen /* key */ + + sizeof(u_int32_t); + + if(serializer->fmt == ndpi_serialization_format_json) + needed += 16 + klen; + + if(buff_diff < needed) { + if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + return(-1); + buff_diff = serializer->buffer_size - serializer->size_used; + } + + if(serializer->fmt == ndpi_serialization_format_json) { + ndpi_serialize_json_pre(_serializer); + serializer->size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer[serializer->size_used], buff_diff); + buff_diff = serializer->buffer_size - serializer->size_used; + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, + ":%lld", (long long int)value); + ndpi_serialize_json_post(_serializer); + } else if(serializer->fmt == ndpi_serialization_format_csv) { + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, + "%s%lld", (serializer->size_used > 0) ? serializer->csv_separator : "", + (long long int)value); + } else { + serializer->buffer[serializer->size_used++] = ndpi_serialization_string_int64; + + ndpi_serialize_single_string(_serializer, key, klen); + ndpi_serialize_single_uint32(_serializer, value); + } + + return(0); +} + +/* ********************************** */ + +int ndpi_serialize_string_uint32(ndpi_serializer *_serializer, + const char *key, u_int32_t value) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + u_int16_t klen = strlen(key); + u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; + u_int32_t needed = + sizeof(u_int8_t) /* type */ + + sizeof(u_int16_t) /* key len */ + + klen /* key */ + + sizeof(u_int32_t); + + if(serializer->fmt == ndpi_serialization_format_json) + needed += 16 + klen; + + if(buff_diff < needed) { + if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + return(-1); + buff_diff = serializer->buffer_size - serializer->size_used; + } + + if(serializer->fmt == ndpi_serialization_format_json) { + ndpi_serialize_json_pre(_serializer); + serializer->size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer[serializer->size_used], buff_diff); + buff_diff = serializer->buffer_size - serializer->size_used; + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, + ":%u", value); + ndpi_serialize_json_post(_serializer); + } else if(serializer->fmt == ndpi_serialization_format_csv) { + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, + "%s%u", (serializer->size_used > 0) ? serializer->csv_separator : "", value); + } else { + serializer->buffer[serializer->size_used++] = ndpi_serialization_string_uint32; + + ndpi_serialize_single_string(_serializer, key, klen); + ndpi_serialize_single_uint32(_serializer, value); + } + + return(0); +} + +/* ********************************** */ + +int ndpi_serialize_string_uint32_format(ndpi_serializer *_serializer, + const char *key, u_int32_t value, + const char *format) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + + if(serializer->fmt == ndpi_serialization_format_json) { + /* + JSON supports base 10 numbers only + http://cjihrig.com/blog/json-overview/ + */ + + return(ndpi_serialize_string_uint32(_serializer, key, value)); + } else + return(ndpi_serialize_string_uint32_format(_serializer, key, value, format)); +} + +/* ********************************** */ + +int ndpi_serialize_string_uint64(ndpi_serializer *_serializer, + const char *key, u_int64_t value) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + u_int16_t klen = strlen(key); + u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; + u_int32_t needed = + sizeof(u_int8_t) /* type */ + + sizeof(u_int16_t) /* key len */ + + klen /* key */ + + sizeof(u_int64_t); + + if(serializer->fmt == ndpi_serialization_format_json) + needed += 32 + klen; + + if(buff_diff < needed) { + if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + return(-1); + buff_diff = serializer->buffer_size - serializer->size_used; + } + + if(serializer->fmt == ndpi_serialization_format_json) { + ndpi_serialize_json_pre(_serializer); + serializer->size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer[serializer->size_used], buff_diff); + buff_diff = serializer->buffer_size - serializer->size_used; + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, + ":%llu", (unsigned long long)value); + ndpi_serialize_json_post(_serializer); + } else if(serializer->fmt == ndpi_serialization_format_csv) { + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, + "%s%llu", (serializer->size_used > 0) ? serializer->csv_separator : "", + (unsigned long long)value); + } else { + serializer->buffer[serializer->size_used++] = ndpi_serialization_string_uint64; + + ndpi_serialize_single_string(_serializer, key, klen); + ndpi_serialize_single_uint64(_serializer, value); + } + + return(0); +} + +/* ********************************** */ + +int ndpi_serialize_string_float(ndpi_serializer *_serializer, + const char *key, float value, + const char *format /* e.f. "%.2f" */) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + u_int16_t klen = strlen(key); + u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; + u_int32_t needed = + sizeof(u_int8_t) /* type */ + + sizeof(u_int16_t) /* key len */ + + klen /* key */ + + sizeof(float); + + if(serializer->fmt == ndpi_serialization_format_json) + needed += 32 + klen; + + if(buff_diff < needed) { + if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + return(-1); + buff_diff = serializer->buffer_size - serializer->size_used; + } + + if(serializer->fmt == ndpi_serialization_format_json) { + ndpi_serialize_json_pre(_serializer); + serializer->size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer[serializer->size_used], buff_diff); + buff_diff = serializer->buffer_size - serializer->size_used; + + serializer->buffer[serializer->size_used] = ':'; + serializer->size_used++; + + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, format, value); + + ndpi_serialize_json_post(_serializer); + } else if(serializer->fmt == ndpi_serialization_format_csv) { + if(serializer->size_used > 0) + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, "%s", serializer->csv_separator); + + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, format, value); + } else { + serializer->buffer[serializer->size_used++] = ndpi_serialization_string_float; + + ndpi_serialize_single_string(_serializer, key, klen); + ndpi_serialize_single_float(_serializer, value); + } + + return(0); +} + +/* ********************************** */ + +int ndpi_serialize_string_string(ndpi_serializer *_serializer, + const char *key, const char *_value) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + const char *value = _value ? _value : ""; + u_int16_t klen = strlen(key), vlen = strlen(value); + u_int32_t needed = + sizeof(u_int8_t) /* type */ + + sizeof(u_int16_t) /* key len */ + + klen + + sizeof(u_int16_t) /* len */ + + vlen; + u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; + + if(serializer->fmt == ndpi_serialization_format_json) + needed += 16 + klen + vlen; + + if(buff_diff < needed) { + if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + return(-1); + buff_diff = serializer->buffer_size - serializer->size_used; + } + + if(serializer->fmt == ndpi_serialization_format_json) { + ndpi_serialize_json_pre(_serializer); + serializer->size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer[serializer->size_used], buff_diff); + buff_diff = serializer->buffer_size - serializer->size_used; + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, ":"); + buff_diff = serializer->buffer_size - serializer->size_used; + serializer->size_used += ndpi_json_string_escape(value, vlen, + (char *) &serializer->buffer[serializer->size_used], buff_diff); + buff_diff = serializer->buffer_size - serializer->size_used; + ndpi_serialize_json_post(_serializer); + } else if(serializer->fmt == ndpi_serialization_format_csv) { + serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, + "%s%s", (serializer->size_used > 0) ? serializer->csv_separator : "", + value); + } else { + serializer->buffer[serializer->size_used++] = ndpi_serialization_string_string; + + ndpi_serialize_single_string(_serializer, key, klen); + ndpi_serialize_single_string(_serializer, value, vlen); + } + + return(0); +} + +/* ********************************** */ +/* ********************************** */ + +int ndpi_init_deserializer_buf(ndpi_deserializer *_deserializer, + u_int8_t *serialized_buffer, + u_int32_t serialized_buffer_len) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + if(serialized_buffer_len < (2 * sizeof(u_int8_t))) + return(-1); + + deserializer->buffer = serialized_buffer; + + if(deserializer->buffer[0] != 1) + return(-2); /* Invalid version */ + + deserializer->buffer_size = serialized_buffer_len; + deserializer->fmt = deserializer->buffer[1]; + ndpi_reset_serializer(_deserializer); + + return(0); +} + +/* ********************************** */ + +int ndpi_init_deserializer(ndpi_deserializer *deserializer, + ndpi_serializer *_serializer) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + + return(ndpi_init_deserializer_buf(deserializer, + serializer->buffer, + serializer->size_used)); +} + +/* ********************************** */ + +ndpi_serialization_element_type ndpi_deserialize_get_nextitem_type(ndpi_deserializer *_deserializer) { + ndpi_serialization_element_type et; + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + if(deserializer->size_used >= deserializer->buffer_size) + return(ndpi_serialization_unknown); + + et = (ndpi_serialization_element_type) deserializer->buffer[deserializer->size_used]; + + return et; +} + +/* ********************************** */ + +int ndpi_deserialize_end_of_record(ndpi_deserializer *_deserializer) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_end_of_record) { + u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; + u_int16_t expected = + sizeof(u_int8_t) /* type */; + + if(buff_diff < expected) return(-2); + + deserializer->size_used++; /* Skip element type */ + + return(0); + } else + return(-1); +} + +/* ********************************** */ + +int ndpi_deserialize_uint32_uint32(ndpi_deserializer *_deserializer, + u_int32_t *key, u_int32_t *value) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_uint32_uint32) { + u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; + u_int16_t expected = + sizeof(u_int8_t) /* type */ + + sizeof(u_int32_t) /* key */ + + sizeof(u_int32_t); + + if(buff_diff < expected) return(-2); + + deserializer->size_used++; /* Skip element type */ + ndpi_deserialize_single_uint32(_deserializer, key); + ndpi_deserialize_single_uint32(_deserializer, value); + + return(0); + } else + return(-1); +} + +/* ********************************** */ + +int ndpi_deserialize_uint32_uint64(ndpi_deserializer *_deserializer, + u_int32_t *key, u_int64_t *value) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_uint32_uint64) { + u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; + u_int16_t expected = + sizeof(u_int8_t) /* type */ + + sizeof(u_int32_t) /* key */ + + sizeof(u_int64_t); + + if(buff_diff < expected) return(-2); + + deserializer->size_used++; /* Skip element type */ + ndpi_deserialize_single_uint32(_deserializer, key); + ndpi_deserialize_single_uint64(_deserializer, value); + + return(0); + } else + return(-1); +} + +/* ********************************** */ + +int ndpi_deserialize_uint32_string(ndpi_deserializer *_deserializer, + u_int32_t *key, ndpi_string *value) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_uint32_string) { + u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; + u_int32_t expected = + sizeof(u_int8_t) /* type */ + + sizeof(u_int32_t) /* key */ + + sizeof(u_int16_t) /* len */; + + if(buff_diff < expected) return(-2); + + deserializer->size_used++; /* Skip element type */ + ndpi_deserialize_single_uint32(_deserializer, key); + ndpi_deserialize_single_string(_deserializer, value); + + return(0); + } else + return(-1); +} + +/* ********************************** */ + +int ndpi_deserialize_string_int32(ndpi_deserializer *_deserializer, + ndpi_string *key, int32_t *value) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_string_int32) { + u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; + u_int32_t expected = + sizeof(u_int8_t) /* type */ + + sizeof(u_int16_t) /* key len */ + + sizeof(int32_t); + + if(buff_diff < expected) return(-2); + + deserializer->size_used++; /* Skip element type */ + ndpi_deserialize_single_string(_deserializer, key); + ndpi_deserialize_single_int32(_deserializer, value); + + return(0); + } else + return(-1); +} + +/* ********************************** */ + +int ndpi_deserialize_string_int64(ndpi_deserializer *_deserializer, + ndpi_string *key, int64_t *value) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_string_int64) { + u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; + u_int32_t expected = + sizeof(u_int8_t) /* type */ + + sizeof(u_int16_t) /* key len */ + + sizeof(int64_t); + + if(buff_diff < expected) return(-2); + + deserializer->size_used++; /* Skip element type */ + ndpi_deserialize_single_string(_deserializer, key); + ndpi_deserialize_single_int64(_deserializer, value); + + return(0); + } else + return(-1); +} + +/* ********************************** */ + +int ndpi_deserialize_string_uint32(ndpi_deserializer *_deserializer, + ndpi_string *key, u_int32_t *value) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_string_uint32) { + u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; + u_int32_t expected = + sizeof(u_int8_t) /* type */ + + sizeof(u_int16_t) /* key len */ + + sizeof(u_int32_t); + + if(buff_diff < expected) return(-2); + + deserializer->size_used++; /* Skip element type */ + ndpi_deserialize_single_string(_deserializer, key); + ndpi_deserialize_single_uint32(_deserializer, value); + + return(0); + } else + return(-1); +} + +/* ********************************** */ + +int ndpi_deserialize_string_uint64(ndpi_deserializer *_deserializer, + ndpi_string *key, u_int64_t *value) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_string_uint64) { + u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; + u_int32_t expected = + sizeof(u_int8_t) /* type */ + + sizeof(u_int16_t) /* key len */ + + sizeof(u_int64_t); + + if(buff_diff < expected) return(-2); + + deserializer->size_used++; /* Skip element type */ + ndpi_deserialize_single_string(_deserializer, key); + ndpi_deserialize_single_uint64(_deserializer, value); + + return(0); + } else + return(-1); +} + +/* ********************************** */ + +int ndpi_deserialize_string_float(ndpi_deserializer *_deserializer, + ndpi_string *key, float *value) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_string_float) { + u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; + u_int32_t expected = + sizeof(u_int8_t) /* type */ + + sizeof(u_int16_t) /* key len */ + + sizeof(float); + + if(buff_diff < expected) return(-2); + + deserializer->size_used++; /* Skip element type */ + ndpi_deserialize_single_string(_deserializer, key); + ndpi_deserialize_single_float(_deserializer, value); + + return(0); + } else + return(-1); +} + +/* ********************************** */ + +int ndpi_deserialize_string_string(ndpi_deserializer *_deserializer, + ndpi_string *key, ndpi_string *value) { + ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; + + if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_string_string) { + u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; + u_int32_t expected = + sizeof(u_int8_t) /* type */ + + sizeof(u_int16_t) /* key len */ + + sizeof(u_int16_t) /* len */; + + if(buff_diff < expected) return(-2); + + deserializer->size_used++; /* Skip element type */ + ndpi_deserialize_single_string(_deserializer, key); + ndpi_deserialize_single_string(_deserializer, value); + + return(0); + } else + return(-1); +} + +/* ********************************** */ diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c index 8959aa05e..14a82065a 100644 --- a/src/lib/ndpi_utils.c +++ b/src/lib/ndpi_utils.c @@ -1,5 +1,5 @@ /* - * ndpi_utils.cc + * ndpi_utils.c * * Copyright (C) 2011-19 - ntop.org * @@ -236,38 +236,38 @@ u_int8_t ndpi_ips_match(u_int32_t src, u_int32_t dst, * based upon ascii character sequences. */ static const u_char charmap[] = { - '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', - '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', - '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', - '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', - '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', - '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', - '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', - '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', - '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', - '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', - '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', - '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', - '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', - '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', - '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', - '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', - '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', - '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', - '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', - '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', - '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', - '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', - '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', - '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', - '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', - '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', - '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', - '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', - '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', - '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', - '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', - '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', + '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', + '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', + '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', + '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', + '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', + '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', + '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', + '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', + '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', + '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', + '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', + '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', + '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', + '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', + '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', + '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', + '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', + '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', + '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', + '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', + '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', + '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', + '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', + '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', + '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', + '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', + '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', + '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', + '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', }; int strcasecmp(const char *s1, const char *s2) { @@ -304,8 +304,8 @@ int strncasecmp(const char *s1, const char *s2, size_t n) { /* **************************************** */ u_int8_t ndpi_is_safe_ssl_cipher(u_int32_t cipher) { - /* https://community.qualys.com/thread/18212-how-does-qualys-determine-the-server-cipher-suites */ - /* INSECURE */ + /* https://community.qualys.com/thread/18212-how-does-qualys-determine-the-server-cipher-suites */ + /* INSECURE */ switch(cipher) { case 0xc011: return(NDPI_CIPHER_INSECURE); /* TLS_ECDHE_RSA_WITH_RC4_128_SHA */ case 0x0005: return(NDPI_CIPHER_INSECURE); /* TLS_RSA_WITH_RC4_128_SHA */ @@ -360,9 +360,9 @@ const char* ndpi_cipher2str(u_int32_t cipher) { case 0x000019: return("TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"); case 0x00001a: return("TLS_DH_anon_WITH_DES_CBC_SHA"); case 0x00001b: return("TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"); - case 0x00001c: return("SSL_FORTEZZA_KEA_WITH_NULL_SHA"); - case 0x00001d: return("SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA"); - /* case 0x00001e: return("SSL_FORTEZZA_KEA_WITH_RC4_128_SHA"); */ + case 0x00001c: return("TLS_FORTEZZA_KEA_WITH_NULL_SHA"); + case 0x00001d: return("TLS_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA"); + /* case 0x00001e: return("TLS_FORTEZZA_KEA_WITH_RC4_128_SHA"); */ case 0x00001E: return("TLS_KRB5_WITH_DES_CBC_SHA"); case 0x00001F: return("TLS_KRB5_WITH_3DES_EDE_CBC_SHA"); case 0x000020: return("TLS_KRB5_WITH_RC4_128_SHA"); @@ -576,10 +576,10 @@ const char* ndpi_cipher2str(u_int32_t cipher) { case 0x00E41D: return("TLS_DHE_PSK_WITH_SALSA20_SHA1"); case 0x00E41E: return("TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1"); case 0x00E41F: return("TLS_DHE_RSA_WITH_SALSA20_SHA1"); - case 0x00fefe: return("SSL_RSA_FIPS_WITH_DES_CBC_SHA"); - case 0x00feff: return("SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA"); - case 0x00ffe0: return("SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA"); - case 0x00ffe1: return("SSL_RSA_FIPS_WITH_DES_CBC_SHA"); + case 0x00fefe: return("TLS_RSA_FIPS_WITH_DES_CBC_SHA"); + case 0x00feff: return("TLS_RSA_FIPS_WITH_3DES_EDE_CBC_SHA"); + case 0x00ffe0: return("TLS_RSA_FIPS_WITH_3DES_EDE_CBC_SHA"); + case 0x00ffe1: return("TLS_RSA_FIPS_WITH_DES_CBC_SHA"); case 0x010080: return("SSL2_RC4_128_WITH_MD5"); case 0x020080: return("SSL2_RC4_128_EXPORT40_WITH_MD5"); case 0x030080: return("SSL2_RC2_128_CBC_WITH_MD5"); @@ -637,7 +637,7 @@ static int ndpi_find_non_eng_bigrams(struct ndpi_detection_module_struct *ndpi_s || ndpi_is_other_char(str[1]) ) return(1); - + s[0] = tolower(str[0]), s[1] = tolower(str[1]), s[2] = '\0'; return(ndpi_match_bigram(ndpi_struct, &ndpi_struct->bigrams_automa, s)); @@ -655,10 +655,10 @@ int ndpi_has_human_readeable_string(struct ndpi_detection_module_struct *ndpi_st if(buffer_size <= 0) return(0); - + outbuf_len--; outbuf[outbuf_len] = '\0'; - + for(i=0; i<buffer_size-2; i++) { if(ndpi_is_valid_char(buffer[i]) && ndpi_is_valid_char(buffer[i+1]) @@ -687,14 +687,14 @@ int ndpi_has_human_readeable_string(struct ndpi_detection_module_struct *ndpi_st being_o_idx = o_idx; outbuf[o_idx] = '\0'; } - + #ifdef PRINT_STRINGS printf(" [len: %u]%s\n", len, ret ? "<-- HIT" : ""); #endif if(ret) break; - + do_cr = 0, len = 0; } } @@ -713,11 +713,13 @@ char* ndpi_ssl_version2str(u_int16_t version) { static char v[8]; switch(version) { - case 0x300: return("SSLv3"); - case 0x301: return("TLSv1"); - case 0x302: return("TLSv1.1"); - case 0x303: return("TLSv1.2"); - case 0x304: return("TLSv1.3"); + case 0x0300: return("SSLv3"); + case 0x0301: return("TLSv1"); + case 0x0302: return("TLSv1.1"); + case 0x0303: return("TLSv1.2"); + case 0x0304: return("TLSv1.3"); + case 0xfeff: return("DTLSv1.0"); + case 0xfefd: return("DTLSv1.2"); } if((version >= 0x7f00) && (version <= 0x7fff)) @@ -728,826 +730,3 @@ char* ndpi_ssl_version2str(u_int16_t version) { } /* ********************************** */ -/* ********************************** */ - -static u_int64_t ndpi_htonll(u_int64_t v) { - union { u_int32_t lv[2]; u_int64_t llv; } u; - u.lv[0] = htonl(v >> 32); - u.lv[1] = htonl(v & 0xFFFFFFFFULL); - return u.llv; -} - -/* ********************************** */ - -static u_int64_t ndpi_ntohll(u_int64_t v) { - union { u_int32_t lv[2]; u_int64_t llv; } u; - u.llv = v; - return ((u_int64_t)ntohl(u.lv[0]) << 32) | (u_int64_t)ntohl(u.lv[1]); -} - -/* ********************************** */ - -/* - * Escapes a string to be suitable for a JSON value, adding double quotes, and terminating the string with a null byte. - * It is recommended to provide a destination buffer (dst) which is as large as double the source buffer (src) at least. - * Upon successful return, these functions return the number of characters printed (excluding the null byte used to terminate the string). - */ -static int ndpi_json_string_escape(const char *src, int src_len, char *dst, int dst_max_len) { - char c = 0; - int i, j = 0; - - dst[j++] = '"'; - - for (i = 0; i < src_len && j < dst_max_len; i++) { - - c = src[i]; - - switch (c) { - case '\\': - case '"': - case '/': - dst[j++] = '\\'; - dst[j++] = c; - break; - case '\b': - dst[j++] = '\\'; - dst[j++] = 'b'; - break; - case '\t': - dst[j++] = '\\'; - dst[j++] = 't'; - break; - case '\n': - dst[j++] = '\\'; - dst[j++] = 'n'; - break; - case '\f': - dst[j++] = '\\'; - dst[j++] = 'f'; - break; - case '\r': - dst[j++] = '\\'; - dst[j++] = 'r'; - break; - default: - if (c < ' ') - ; /* non printable */ - else - dst[j++] = c; - } - } - - dst[j++] = '"'; - dst[j+1] = '\0'; - - return j; -} - -/* ********************************** */ - -void ndpi_reset_serializer(ndpi_serializer *serializer) { - serializer->size_used = 2 * sizeof(u_int8_t); - if (serializer->fmt == ndpi_serialization_format_json) { - u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; - /* Note: please keep a space at the beginning as it is used for arrays when an end-of-record is used */ - serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, " {}"); - } -} - -/* ********************************** */ - -int ndpi_init_serializer(ndpi_serializer *serializer, - ndpi_serialization_format fmt) { - serializer->buffer_size = 8192; - serializer->buffer = (u_int8_t *) malloc(serializer->buffer_size * sizeof(u_int8_t)); - - if (serializer->buffer == NULL) - return(-1); - - serializer->fmt = fmt; - - serializer->buffer[0] = 1; /* version */ - serializer->buffer[1] = (u_int8_t) fmt; - - ndpi_reset_serializer(serializer); - - if (fmt == ndpi_serialization_format_json) - serializer->json_buffer = (char *) &serializer->buffer[2]; - - return(1); -} - -/* ********************************** */ - -void ndpi_term_serializer(ndpi_serializer *serializer) { - if(serializer->buffer) { - free(serializer->buffer); - serializer->buffer_size = 0; - serializer->buffer = NULL; - } -} - -/* ********************************** */ - -static int ndpi_extend_serializer_buffer(ndpi_serializer *serializer, u_int32_t min_len) { - u_int32_t new_size; - void *r; - - if (min_len < 1024) - min_len = 1024; - - new_size = serializer->buffer_size + min_len; - - r = realloc((void *) serializer->buffer, new_size); - - if(r == NULL) - return(-1); - - serializer->buffer = r; - serializer->buffer_size = new_size; - - return(0); -} - -/* ********************************** */ - -static void ndpi_serialize_single_uint32(ndpi_serializer *serializer, - u_int32_t s) { - - u_int32_t v = htonl(s); - - memcpy(&serializer->buffer[serializer->size_used], &v, sizeof(u_int32_t)); - serializer->size_used += sizeof(u_int32_t); -} - -/* ********************************** */ - -static void ndpi_serialize_single_uint64(ndpi_serializer *serializer, - u_int64_t s) { - - u_int64_t v = ndpi_htonll(s); - - memcpy(&serializer->buffer[serializer->size_used], &v, sizeof(u_int64_t)); - serializer->size_used += sizeof(u_int64_t); -} - -/* ********************************** */ - -static void ndpi_serialize_single_string(ndpi_serializer *serializer, - const char *s, u_int16_t slen) { - u_int16_t l = htons(slen); - - memcpy(&serializer->buffer[serializer->size_used], &l, sizeof(u_int16_t)); - serializer->size_used += sizeof(u_int16_t); - - if (slen > 0) - memcpy(&serializer->buffer[serializer->size_used], s, slen); - - serializer->size_used += slen; -} - -/* ********************************** */ - -static void ndpi_deserialize_single_uint32(ndpi_serializer *deserializer, - u_int32_t *s) { - *s = ntohl(*((u_int32_t *) &deserializer->buffer[deserializer->size_used])); - deserializer->size_used += sizeof(u_int32_t); -} - -/* ********************************** */ - -static void ndpi_deserialize_single_int32(ndpi_serializer *deserializer, - int32_t *s) { - *s = ntohl(*((int32_t *) &deserializer->buffer[deserializer->size_used])); - deserializer->size_used += sizeof(int32_t); -} - -/* ********************************** */ - -static void ndpi_deserialize_single_uint64(ndpi_serializer *deserializer, - u_int64_t *s) { - *s = ndpi_ntohll(*(u_int64_t*)&deserializer->buffer[deserializer->size_used]); - deserializer->size_used += sizeof(u_int64_t); -} - -/* ********************************** */ - -static void ndpi_deserialize_single_int64(ndpi_serializer *deserializer, - int64_t *s) { - *s = ndpi_ntohll(*(int64_t*)&deserializer->buffer[deserializer->size_used]); - deserializer->size_used += sizeof(int64_t); -} - -/* ********************************** */ - -static void ndpi_deserialize_single_string(ndpi_serializer *deserializer, - ndpi_string *v) { - v->str_len = ntohs(*((u_int16_t *) &deserializer->buffer[deserializer->size_used])); - deserializer->size_used += sizeof(u_int16_t); - - v->str = (char *) &deserializer->buffer[deserializer->size_used]; - deserializer->size_used += v->str_len; -} - -/* ********************************** */ - -int ndpi_serialize_end_of_record(ndpi_serializer *serializer) { - u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; - u_int16_t needed = - sizeof(u_int8_t) /* type */; - - if(serializer->fmt == ndpi_serialization_format_json) - needed += 1; - - if(buff_diff < needed) { - if (ndpi_extend_serializer_buffer(serializer, needed - buff_diff) < 0) - return(-1); - buff_diff = serializer->buffer_size - serializer->size_used; - } - - if(serializer->fmt == ndpi_serialization_format_json) { - if (!(serializer->status & NDPI_SERIALIZER_STATUS_ARRAY)) { - serializer->json_buffer[0] = '['; - serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, "]"); - } - serializer->status |= NDPI_SERIALIZER_STATUS_ARRAY | NDPI_SERIALIZER_STATUS_EOR; - serializer->status &= ~NDPI_SERIALIZER_STATUS_COMMA; - } else { - serializer->buffer[serializer->size_used++] = ndpi_serialization_end_of_record; - } - - return(0); -} - -/* ********************************** */ - -static void ndpi_serialize_json_pre(ndpi_serializer *serializer) { - if (serializer->status & NDPI_SERIALIZER_STATUS_EOR) { - serializer->size_used--; /* Remove ']' */ - serializer->status &= ~NDPI_SERIALIZER_STATUS_EOR; - serializer->buffer[serializer->size_used++] = ','; - serializer->buffer[serializer->size_used++] = '{'; - } else { - if (serializer->status & NDPI_SERIALIZER_STATUS_ARRAY) - serializer->size_used--; /* Remove ']'*/ - serializer->size_used--; /* Remove '}'*/ - } - if (serializer->status & NDPI_SERIALIZER_STATUS_COMMA) - serializer->buffer[serializer->size_used++] = ','; -} - -/* ********************************** */ - -static void ndpi_serialize_json_post(ndpi_serializer *serializer) { - serializer->buffer[serializer->size_used++] = '}'; - if (serializer->status & NDPI_SERIALIZER_STATUS_ARRAY) - serializer->buffer[serializer->size_used++] = ']'; - - serializer->status |= NDPI_SERIALIZER_STATUS_COMMA; -} - -/* ********************************** */ - -int ndpi_serialize_uint32_uint32(ndpi_serializer *serializer, - u_int32_t key, u_int32_t value) { - u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; - u_int16_t needed = - sizeof(u_int8_t) /* type */ + - sizeof(u_int32_t) /* key */ + - sizeof(u_int32_t); - - if(serializer->fmt == ndpi_serialization_format_json) - needed += 24; - - if(buff_diff < needed) { - if (ndpi_extend_serializer_buffer(serializer, needed - buff_diff) < 0) - return(-1); - buff_diff = serializer->buffer_size - serializer->size_used; - } - - if(serializer->fmt == ndpi_serialization_format_json) { - ndpi_serialize_json_pre(serializer); - serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, - "\"%u\":%u", key, value); - ndpi_serialize_json_post(serializer); - } else { - serializer->buffer[serializer->size_used++] = ndpi_serialization_uint32_uint32; - - ndpi_serialize_single_uint32(serializer, key); - ndpi_serialize_single_uint32(serializer, value); - } - - return(0); -} - -/* ********************************** */ - -int ndpi_serialize_uint32_uint64(ndpi_serializer *serializer, - u_int32_t key, u_int64_t value) { - u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; - u_int16_t needed = - sizeof(u_int8_t) /* type */ + - sizeof(u_int32_t) /* key */ + - sizeof(u_int64_t); - - if(serializer->fmt == ndpi_serialization_format_json) - needed += 32; - - if(buff_diff < needed) { - if (ndpi_extend_serializer_buffer(serializer, needed - buff_diff) < 0) - return(-1); - buff_diff = serializer->buffer_size - serializer->size_used; - } - - if(serializer->fmt == ndpi_serialization_format_json) { - ndpi_serialize_json_pre(serializer); - serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, - "\"%u\":%llu", key, (unsigned long long)value); - ndpi_serialize_json_post(serializer); - } else { - serializer->buffer[serializer->size_used++] = ndpi_serialization_uint32_uint64; - - ndpi_serialize_single_uint32(serializer, key); - ndpi_serialize_single_uint64(serializer, value); - } - - return(0); -} - -/* ********************************** */ - -int ndpi_serialize_uint32_string(ndpi_serializer *serializer, - u_int32_t key, const char *value) { - u_int16_t slen = strlen(value); - u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; - u_int32_t needed = - sizeof(u_int8_t) /* type */ + - sizeof(u_int32_t) /* key */ + - sizeof(u_int16_t) /* len */ + - slen; - - if(serializer->fmt == ndpi_serialization_format_json) - needed += 24 + slen; - - if(buff_diff < needed) { - if (ndpi_extend_serializer_buffer(serializer, needed - buff_diff) < 0) - return(-1); - buff_diff = serializer->buffer_size - serializer->size_used; - } - - if(serializer->fmt == ndpi_serialization_format_json) { - ndpi_serialize_json_pre(serializer); - serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, - "\"%u\":", key); - buff_diff = serializer->buffer_size - serializer->size_used; - serializer->size_used += ndpi_json_string_escape(value, slen, - (char *) &serializer->buffer[serializer->size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->size_used; - ndpi_serialize_json_post(serializer); - } else { - serializer->buffer[serializer->size_used++] = ndpi_serialization_uint32_string; - - ndpi_serialize_single_uint32(serializer, key); - ndpi_serialize_single_string(serializer, value, slen); - } - - return(0); -} - -/* ********************************** */ - -int ndpi_serialize_string_int32(ndpi_serializer *serializer, - const char *key, int32_t value) { - u_int16_t klen = strlen(key); - u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; - u_int32_t needed = - sizeof(u_int8_t) /* type */ + - sizeof(u_int16_t) /* key len */ + - klen /* key */ + - sizeof(u_int32_t); - - if(serializer->fmt == ndpi_serialization_format_json) - needed += 16 + klen; - - if(buff_diff < needed) { - if (ndpi_extend_serializer_buffer(serializer, needed - buff_diff) < 0) - return(-1); - buff_diff = serializer->buffer_size - serializer->size_used; - } - - if(serializer->fmt == ndpi_serialization_format_json) { - ndpi_serialize_json_pre(serializer); - serializer->size_used += ndpi_json_string_escape(key, klen, - (char *) &serializer->buffer[serializer->size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->size_used; - serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, - ":%d", value); - ndpi_serialize_json_post(serializer); - } else { - serializer->buffer[serializer->size_used++] = ndpi_serialization_string_int32; - - ndpi_serialize_single_string(serializer, key, klen); - ndpi_serialize_single_uint32(serializer, value); - } - - return(0); -} - -/* ********************************** */ - -int ndpi_serialize_string_int64(ndpi_serializer *serializer, - const char *key, int64_t value) { - u_int16_t klen = strlen(key); - u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; - u_int32_t needed = - sizeof(u_int8_t) /* type */ + - sizeof(u_int16_t) /* key len */ + - klen /* key */ + - sizeof(u_int32_t); - - if(serializer->fmt == ndpi_serialization_format_json) - needed += 16 + klen; - - if(buff_diff < needed) { - if (ndpi_extend_serializer_buffer(serializer, needed - buff_diff) < 0) - return(-1); - buff_diff = serializer->buffer_size - serializer->size_used; - } - - if(serializer->fmt == ndpi_serialization_format_json) { - ndpi_serialize_json_pre(serializer); - serializer->size_used += ndpi_json_string_escape(key, klen, - (char *) &serializer->buffer[serializer->size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->size_used; - serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, - ":%lld", value); - ndpi_serialize_json_post(serializer); - } else { - serializer->buffer[serializer->size_used++] = ndpi_serialization_string_int64; - - ndpi_serialize_single_string(serializer, key, klen); - ndpi_serialize_single_uint32(serializer, value); - } - - return(0); -} - -/* ********************************** */ - -int ndpi_serialize_string_uint32(ndpi_serializer *serializer, - const char *key, u_int32_t value) { - u_int16_t klen = strlen(key); - u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; - u_int32_t needed = - sizeof(u_int8_t) /* type */ + - sizeof(u_int16_t) /* key len */ + - klen /* key */ + - sizeof(u_int32_t); - - if(serializer->fmt == ndpi_serialization_format_json) - needed += 16 + klen; - - if(buff_diff < needed) { - if (ndpi_extend_serializer_buffer(serializer, needed - buff_diff) < 0) - return(-1); - buff_diff = serializer->buffer_size - serializer->size_used; - } - - if(serializer->fmt == ndpi_serialization_format_json) { - ndpi_serialize_json_pre(serializer); - serializer->size_used += ndpi_json_string_escape(key, klen, - (char *) &serializer->buffer[serializer->size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->size_used; - serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, - ":%u", value); - ndpi_serialize_json_post(serializer); - } else { - serializer->buffer[serializer->size_used++] = ndpi_serialization_string_uint32; - - ndpi_serialize_single_string(serializer, key, klen); - ndpi_serialize_single_uint32(serializer, value); - } - - return(0); -} - -/* ********************************** */ - -int ndpi_serialize_string_uint64(ndpi_serializer *serializer, - const char *key, u_int64_t value) { - u_int16_t klen = strlen(key); - u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; - u_int32_t needed = - sizeof(u_int8_t) /* type */ + - sizeof(u_int16_t) /* key len */ + - klen /* key */ + - sizeof(u_int64_t); - - if(serializer->fmt == ndpi_serialization_format_json) - needed += 32 + klen; - - if(buff_diff < needed) { - if (ndpi_extend_serializer_buffer(serializer, needed - buff_diff) < 0) - return(-1); - buff_diff = serializer->buffer_size - serializer->size_used; - } - - if(serializer->fmt == ndpi_serialization_format_json) { - ndpi_serialize_json_pre(serializer); - serializer->size_used += ndpi_json_string_escape(key, klen, - (char *) &serializer->buffer[serializer->size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->size_used; - serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, - ":%llu", (unsigned long long)value); - ndpi_serialize_json_post(serializer); - } else { - serializer->buffer[serializer->size_used++] = ndpi_serialization_string_uint64; - - ndpi_serialize_single_string(serializer, key, klen); - ndpi_serialize_single_uint64(serializer, value); - } - - return(0); -} - -/* ********************************** */ - -int ndpi_serialize_string_string(ndpi_serializer *serializer, - const char *key, const char *value) { - u_int16_t klen = strlen(key), vlen = strlen(value); - u_int32_t needed = - sizeof(u_int8_t) /* type */ + - sizeof(u_int16_t) /* key len */ + - klen + - sizeof(u_int16_t) /* len */ + - vlen; - u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; - - if(serializer->fmt == ndpi_serialization_format_json) - needed += 16 + klen + vlen; - - if(buff_diff < needed) { - if (ndpi_extend_serializer_buffer(serializer, needed - buff_diff) < 0) - return(-1); - buff_diff = serializer->buffer_size - serializer->size_used; - } - - if(serializer->fmt == ndpi_serialization_format_json) { - ndpi_serialize_json_pre(serializer); - serializer->size_used += ndpi_json_string_escape(key, klen, - (char *) &serializer->buffer[serializer->size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->size_used; - serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, ":"); - buff_diff = serializer->buffer_size - serializer->size_used; - serializer->size_used += ndpi_json_string_escape(value, vlen, - (char *) &serializer->buffer[serializer->size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->size_used; - ndpi_serialize_json_post(serializer); - } else { - serializer->buffer[serializer->size_used++] = ndpi_serialization_string_string; - - ndpi_serialize_single_string(serializer, key, klen); - ndpi_serialize_single_string(serializer, value, vlen); - } - - return(0); -} - -/* ********************************** */ -/* ********************************** */ - -int ndpi_init_deserializer_buf(ndpi_deserializer *deserializer, - u_int8_t *serialized_buffer, - u_int32_t serialized_buffer_len) { - if(serialized_buffer_len < (2 * sizeof(u_int8_t))) - return(-1); - - deserializer->buffer = serialized_buffer; - - if(deserializer->buffer[0] != 1) - return(-2); /* Invalid version */ - - deserializer->buffer_size = serialized_buffer_len; - deserializer->fmt = deserializer->buffer[1]; - ndpi_reset_serializer(deserializer); - - return(0); -} - -/* ********************************** */ - -int ndpi_init_deserializer(ndpi_deserializer *deserializer, - ndpi_serializer *serializer) { - return(ndpi_init_deserializer_buf(deserializer, - serializer->buffer, - serializer->size_used)); -} - -/* ********************************** */ - -ndpi_serialization_element_type ndpi_deserialize_get_nextitem_type(ndpi_deserializer *deserializer) { - ndpi_serialization_element_type et; - - if(deserializer->size_used >= deserializer->buffer_size) - return(ndpi_serialization_unknown); - - et = (ndpi_serialization_element_type) deserializer->buffer[deserializer->size_used]; - - return et; -} - -/* ********************************** */ - -int ndpi_deserialize_end_of_record(ndpi_deserializer *deserializer) { - if(ndpi_deserialize_get_nextitem_type(deserializer) == ndpi_serialization_end_of_record) { - u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; - u_int16_t expected = - sizeof(u_int8_t) /* type */; - - if(buff_diff < expected) return(-2); - - deserializer->size_used++; /* Skip element type */ - - return(0); - } else - return(-1); -} - -/* ********************************** */ - -int ndpi_deserialize_uint32_uint32(ndpi_deserializer *deserializer, - u_int32_t *key, u_int32_t *value) { - if(ndpi_deserialize_get_nextitem_type(deserializer) == ndpi_serialization_uint32_uint32) { - u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; - u_int16_t expected = - sizeof(u_int8_t) /* type */ + - sizeof(u_int32_t) /* key */ + - sizeof(u_int32_t); - - if(buff_diff < expected) return(-2); - - deserializer->size_used++; /* Skip element type */ - ndpi_deserialize_single_uint32(deserializer, key); - ndpi_deserialize_single_uint32(deserializer, value); - - return(0); - } else - return(-1); -} - -/* ********************************** */ - -int ndpi_deserialize_uint32_uint64(ndpi_deserializer *deserializer, - u_int32_t *key, u_int64_t *value) { - if(ndpi_deserialize_get_nextitem_type(deserializer) == ndpi_serialization_uint32_uint64) { - u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; - u_int16_t expected = - sizeof(u_int8_t) /* type */ + - sizeof(u_int32_t) /* key */ + - sizeof(u_int64_t); - - if(buff_diff < expected) return(-2); - - deserializer->size_used++; /* Skip element type */ - ndpi_deserialize_single_uint32(deserializer, key); - ndpi_deserialize_single_uint64(deserializer, value); - - return(0); - } else - return(-1); -} - -/* ********************************** */ - -int ndpi_deserialize_uint32_string(ndpi_deserializer *deserializer, - u_int32_t *key, ndpi_string *value) { - if(ndpi_deserialize_get_nextitem_type(deserializer) == ndpi_serialization_uint32_string) { - u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; - u_int32_t expected = - sizeof(u_int8_t) /* type */ + - sizeof(u_int32_t) /* key */ + - sizeof(u_int16_t) /* len */; - - if(buff_diff < expected) return(-2); - - deserializer->size_used++; /* Skip element type */ - ndpi_deserialize_single_uint32(deserializer, key); - ndpi_deserialize_single_string(deserializer, value); - - return(0); - } else - return(-1); -} - -/* ********************************** */ - -int ndpi_deserialize_string_int32(ndpi_deserializer *deserializer, - ndpi_string *key, int32_t *value) { - if(ndpi_deserialize_get_nextitem_type(deserializer) == ndpi_serialization_string_int32) { - u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; - u_int32_t expected = - sizeof(u_int8_t) /* type */ + - sizeof(u_int16_t) /* key len */ + - sizeof(int32_t); - - if(buff_diff < expected) return(-2); - - deserializer->size_used++; /* Skip element type */ - ndpi_deserialize_single_string(deserializer, key); - ndpi_deserialize_single_int32(deserializer, value); - - return(0); - } else - return(-1); -} - -/* ********************************** */ - -int ndpi_deserialize_string_int64(ndpi_deserializer *deserializer, - ndpi_string *key, int64_t *value) { - if(ndpi_deserialize_get_nextitem_type(deserializer) == ndpi_serialization_string_int64) { - u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; - u_int32_t expected = - sizeof(u_int8_t) /* type */ + - sizeof(u_int16_t) /* key len */ + - sizeof(int64_t); - - if(buff_diff < expected) return(-2); - - deserializer->size_used++; /* Skip element type */ - ndpi_deserialize_single_string(deserializer, key); - ndpi_deserialize_single_int64(deserializer, value); - - return(0); - } else - return(-1); -} - -/* ********************************** */ - -int ndpi_deserialize_string_uint32(ndpi_deserializer *deserializer, - ndpi_string *key, u_int32_t *value) { - if(ndpi_deserialize_get_nextitem_type(deserializer) == ndpi_serialization_string_uint32) { - u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; - u_int32_t expected = - sizeof(u_int8_t) /* type */ + - sizeof(u_int16_t) /* key len */ + - sizeof(u_int32_t); - - if(buff_diff < expected) return(-2); - - deserializer->size_used++; /* Skip element type */ - ndpi_deserialize_single_string(deserializer, key); - ndpi_deserialize_single_uint32(deserializer, value); - - return(0); - } else - return(-1); -} - -/* ********************************** */ - -int ndpi_deserialize_string_uint64(ndpi_deserializer *deserializer, - ndpi_string *key, u_int64_t *value) { - if(ndpi_deserialize_get_nextitem_type(deserializer) == ndpi_serialization_string_uint64) { - u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; - u_int32_t expected = - sizeof(u_int8_t) /* type */ + - sizeof(u_int16_t) /* key len */ + - sizeof(u_int64_t); - - if(buff_diff < expected) return(-2); - - deserializer->size_used++; /* Skip element type */ - ndpi_deserialize_single_string(deserializer, key); - ndpi_deserialize_single_uint64(deserializer, value); - - return(0); - } else - return(-1); -} - -/* ********************************** */ - -int ndpi_deserialize_string_string(ndpi_deserializer *deserializer, - ndpi_string *key, ndpi_string *value) { - if(ndpi_deserialize_get_nextitem_type(deserializer) == ndpi_serialization_string_string) { - u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; - u_int32_t expected = - sizeof(u_int8_t) /* type */ + - sizeof(u_int16_t) /* key len */ + - sizeof(u_int16_t) /* len */; - - if(buff_diff < expected) return(-2); - - deserializer->size_used++; /* Skip element type */ - ndpi_deserialize_single_string(deserializer, key); - ndpi_deserialize_single_string(deserializer, value); - - return(0); - } else - return(-1); -} - -/* ********************************** */ - 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); } diff --git a/src/lib/third_party/include/ndpi_md5.h b/src/lib/third_party/include/ndpi_md5.h new file mode 100644 index 000000000..f7dd9b946 --- /dev/null +++ b/src/lib/third_party/include/ndpi_md5.h @@ -0,0 +1,18 @@ +/* + Contributed code pasted here to make nDPI self-contained with no + external dependencies +*/ + +/* **************************************** */ + +typedef struct ndpi_MD5Context { + uint32_t buf[4]; + uint32_t bits[2]; + unsigned char in[64]; +} ndpi_MD5_CTX; + +/* **************************************** */ + +extern void ndpi_MD5Init(ndpi_MD5_CTX *ctx); +extern void ndpi_MD5Update(ndpi_MD5_CTX *ctx, unsigned char const *buf, unsigned len); +extern void ndpi_MD5Final(unsigned char digest[16], ndpi_MD5_CTX *ctx); diff --git a/src/lib/third_party/src/ndpi_md5.c b/src/lib/third_party/src/ndpi_md5.c new file mode 100644 index 000000000..fefe9d65f --- /dev/null +++ b/src/lib/third_party/src/ndpi_md5.c @@ -0,0 +1,204 @@ +/* + Contributed code pasted here to make nDPI self-contained with no + external dependencies +*/ + +#include "ndpi_api.h" +#include "ndpi_md5.h" + +/* **************************************** */ + +static int is_big_endian(void) { + static const int n = 1; + return ((char *) &n)[0] == 0; +} + +static void byte_reverse(unsigned char *buf, unsigned longs) { + // Forrest: MD5 expect LITTLE_ENDIAN, swap if BIG_ENDIAN + if (is_big_endian()) { + do { + u_int32_t t; + + t = (u_int32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + * (u_int32_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. +void ndpi_MD5Init(ndpi_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(u_int32_t buf[4], u_int32_t const in[16]) { + u_int32_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; +} + +/* **************************************** */ + +void ndpi_MD5Update(ndpi_MD5_CTX *ctx, unsigned char const *buf, unsigned len) { + u_int32_t t; + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((u_int32_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); + byte_reverse(ctx->in, 16); + MD5Transform(ctx->buf, (u_int32_t *) ctx->in); + buf += t; + len -= t; + } + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byte_reverse(ctx->in, 16); + MD5Transform(ctx->buf, (u_int32_t *) ctx->in); + buf += 64; + len -= 64; + } + + memcpy(ctx->in, buf, len); +} + +/* **************************************** */ + +void ndpi_MD5Final(unsigned char digest[16], ndpi_MD5_CTX *ctx) { + unsigned count; + unsigned char *p; + u_int32_t *c = (u_int32_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); + byte_reverse(ctx->in, 16); + MD5Transform(ctx->buf, (u_int32_t *) ctx->in); + memset(ctx->in, 0, 56); + } else { + memset(p, 0, count - 8); + } + byte_reverse(ctx->in, 14); + + c[14] = ctx->bits[0]; + c[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (u_int32_t *) ctx->in); + byte_reverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset((char *) ctx, 0, sizeof(*ctx)); +} + |