diff options
-rw-r--r-- | example/ndpiReader.c | 165 | ||||
-rw-r--r-- | example/reader_util.c | 10 | ||||
-rw-r--r-- | example/reader_util.h | 4 | ||||
-rw-r--r-- | python/ndpi.py | 352 | ||||
-rw-r--r-- | src/include/ndpi_api.h.in | 40 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 31 | ||||
-rw-r--r-- | src/lib/ndpi_content_match.c.inc | 17 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 179 | ||||
-rw-r--r-- | src/lib/ndpi_serializer.c | 917 | ||||
-rw-r--r-- | src/lib/ndpi_utils.c | 127 | ||||
-rw-r--r-- | src/lib/protocols/bittorrent.c | 24 | ||||
-rw-r--r-- | src/lib/protocols/http.c | 225 | ||||
-rw-r--r-- | src/lib/protocols/kerberos.c | 46 | ||||
-rw-r--r-- | src/lib/protocols/spotify.c | 2 | ||||
-rw-r--r-- | src/lib/protocols/stun.c | 2 | ||||
-rw-r--r-- | src/lib/protocols/tls.c | 185 | ||||
-rw-r--r-- | tests/pcap/encrypted_sni.pcap | bin | 0 -> 2382 bytes | |||
-rw-r--r-- | tests/pcap/imaps.pcap | bin | 0 -> 5540 bytes | |||
-rw-r--r-- | tests/result/encrypted_sni.pcap.out | 10 | ||||
-rw-r--r-- | tests/result/imaps.pcap.out | 8 | ||||
-rw-r--r-- | tests/result/teams.pcap.out | 20 |
21 files changed, 1582 insertions, 782 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c index 15f5d6f9a..eff6ca2c5 100644 --- a/example/ndpiReader.c +++ b/example/ndpiReader.c @@ -1244,6 +1244,11 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa if(flow->ssh_tls.tls_issuerDN) fprintf(out, "[Issuer: %s]", flow->ssh_tls.tls_issuerDN); if(flow->ssh_tls.tls_subjectDN) fprintf(out, "[Subject: %s]", flow->ssh_tls.tls_subjectDN); + if(flow->ssh_tls.encrypted_sni.esni) { + fprintf(out, "[ESNI: %s]", flow->ssh_tls.encrypted_sni.esni); + fprintf(out, "[ESNI Cipher: %s]", ndpi_cipher2str(flow->ssh_tls.encrypted_sni.cipher_suite)); + } + if((flow->detected_protocol.master_protocol == NDPI_PROTOCOL_TLS) || (flow->detected_protocol.app_protocol == NDPI_PROTOCOL_TLS)) { if(flow->ssh_tls.sha1_cert_fingerprint_set) { @@ -3079,86 +3084,128 @@ void serializerUnitTest() { ndpi_serializer serializer, deserializer; int i; u_int8_t trace = 0; + ndpi_serialization_format fmt = ndpi_serialization_format_tlv; - assert(ndpi_init_serializer(&serializer, ndpi_serialization_format_tlv) != -1); + //trace = 1; + //fmt = ndpi_serialization_format_json; + //fmt = ndpi_serialization_format_csv; + + assert(ndpi_init_serializer(&serializer, fmt) != -1); for(i=0; i<16; i++) { char kbuf[32], vbuf[32]; + snprintf(kbuf, sizeof(kbuf), "Key %d", i); + snprintf(vbuf, sizeof(vbuf), "Value %d", i); assert(ndpi_serialize_uint32_uint32(&serializer, i, i*i) != -1); - - snprintf(kbuf, sizeof(kbuf), "Hello %d", i); - snprintf(vbuf, sizeof(vbuf), "World %d", i); - assert(ndpi_serialize_uint32_string(&serializer, i, "Hello") != -1); + assert(ndpi_serialize_uint32_string(&serializer, i, "Data") != -1); assert(ndpi_serialize_string_string(&serializer, kbuf, vbuf) != -1); assert(ndpi_serialize_string_uint32(&serializer, kbuf, i*i) != -1); assert(ndpi_serialize_string_float(&serializer, kbuf, (float)(i*i), "%f") != -1); } - if(trace) - printf("Serialization size: %u\n", ndpi_serializer_get_buffer_len(&serializer)); + if (fmt == ndpi_serialization_format_json) { - assert(ndpi_init_deserializer(&deserializer, &serializer) != -1); + assert(ndpi_serialize_start_of_list(&serializer, "List") != -1); - while(1) { - ndpi_serialization_type kt, et; - et = ndpi_deserialize_get_item_type(&deserializer, &kt); + for(i=0; i<4; i++) { + char kbuf[32], vbuf[32]; + snprintf(kbuf, sizeof(kbuf), "Ignored"); + snprintf(vbuf, sizeof(vbuf), "Item %d", i); + assert(ndpi_serialize_uint32_uint32(&serializer, i, i*i) != -1); + assert(ndpi_serialize_string_string(&serializer, kbuf, vbuf) != -1); + assert(ndpi_serialize_string_float(&serializer, kbuf, (float)(i*i), "%f") != -1); + } + assert(ndpi_serialize_end_of_list(&serializer) != -1); + assert(ndpi_serialize_string_string(&serializer, "Last", "Ok") != -1); - if(et == ndpi_serialization_unknown) - break; - else { - u_int32_t k32, v32; - ndpi_string ks, vs; - float vf; - - switch(kt) { - case ndpi_serialization_uint32: - ndpi_deserialize_key_uint32(&deserializer, &k32); - if(trace) printf("%u=", k32); + if(trace) { + u_int32_t buffer_len = 0; + char *buffer = ndpi_serializer_get_buffer(&serializer, &buffer_len); + printf("%s\n", buffer); + exit(0); + } + + } else if (fmt == ndpi_serialization_format_csv) { + + if(trace) { + u_int32_t buffer_len = 0; + char *buffer; + + buffer = ndpi_serializer_get_header(&serializer, &buffer_len); + printf("%s\n", buffer); + + buffer = ndpi_serializer_get_buffer(&serializer, &buffer_len); + printf("%s\n", buffer); + + exit(0); + } + + } else { + if(trace) + printf("Serialization size: %u\n", ndpi_serializer_get_buffer_len(&serializer)); + + assert(ndpi_init_deserializer(&deserializer, &serializer) != -1); + + while(1) { + ndpi_serialization_type kt, et; + et = ndpi_deserialize_get_item_type(&deserializer, &kt); + + if(et == ndpi_serialization_unknown) + break; + else { + u_int32_t k32, v32; + ndpi_string ks, vs; + float vf; + + switch(kt) { + case ndpi_serialization_uint32: + ndpi_deserialize_key_uint32(&deserializer, &k32); + if(trace) printf("%u=", k32); break; - case ndpi_serialization_string: - ndpi_deserialize_key_string(&deserializer, &ks); - if (trace) { - u_int8_t bkp = ks.str[ks.str_len]; - ks.str[ks.str_len] = '\0'; - printf("%s=", ks.str); - ks.str[ks.str_len] = bkp; - } + case ndpi_serialization_string: + ndpi_deserialize_key_string(&deserializer, &ks); + if (trace) { + u_int8_t bkp = ks.str[ks.str_len]; + ks.str[ks.str_len] = '\0'; + printf("%s=", ks.str); + ks.str[ks.str_len] = bkp; + } break; - default: - printf("Unsupported TLV key type %u\n", kt); + default: + printf("Unsupported TLV key type %u\n", kt); return; - } - - switch(et) { - case ndpi_serialization_uint32: - assert(ndpi_deserialize_value_uint32(&deserializer, &v32) != -1); - if(trace) printf("%u\n", v32); - break; + } - case ndpi_serialization_string: - assert(ndpi_deserialize_value_string(&deserializer, &vs) != -1); - if(trace) { - u_int8_t bkp = vs.str[vs.str_len]; - vs.str[vs.str_len] = '\0'; - printf("%s\n", vs.str); - vs.str[vs.str_len] = bkp; - } - break; + switch(et) { + case ndpi_serialization_uint32: + assert(ndpi_deserialize_value_uint32(&deserializer, &v32) != -1); + if(trace) printf("%u\n", v32); + break; + + case ndpi_serialization_string: + assert(ndpi_deserialize_value_string(&deserializer, &vs) != -1); + if(trace) { + u_int8_t bkp = vs.str[vs.str_len]; + vs.str[vs.str_len] = '\0'; + printf("%s\n", vs.str); + vs.str[vs.str_len] = bkp; + } + break; - case ndpi_serialization_float: - assert(ndpi_deserialize_value_float(&deserializer, &vf) != -1); - if(trace) printf("%f\n", vf); - break; + case ndpi_serialization_float: + assert(ndpi_deserialize_value_float(&deserializer, &vf) != -1); + if(trace) printf("%f\n", vf); + break; - default: - if (trace) printf("\n"); - printf("serializerUnitTest: unsupported type %u detected!\n", et); - return; - break; + default: + if (trace) printf("\n"); + printf("serializerUnitTest: unsupported type %u detected!\n", et); + return; + } } - } - ndpi_deserialize_next(&deserializer); + ndpi_deserialize_next(&deserializer); + } } ndpi_term_serializer(&serializer); diff --git a/example/reader_util.c b/example/reader_util.c index 56cd74134..833f200bf 100644 --- a/example/reader_util.c +++ b/example/reader_util.c @@ -489,6 +489,11 @@ void ndpi_free_flow_tls_data(struct ndpi_flow_info *flow) { ndpi_free(flow->ssh_tls.tls_subjectDN); flow->ssh_tls.tls_subjectDN = NULL; } + + if(flow->ssh_tls.encrypted_sni.esni) { + ndpi_free(flow->ssh_tls.encrypted_sni.esni); + flow->ssh_tls.encrypted_sni.esni = NULL; + } } /* ***************************************************** */ @@ -1121,6 +1126,11 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl if(flow->ndpi_flow->protos.stun_ssl.ssl.subjectDN) flow->ssh_tls.tls_subjectDN = strdup(flow->ndpi_flow->protos.stun_ssl.ssl.subjectDN); + + if(flow->ndpi_flow->protos.stun_ssl.ssl.encrypted_sni.esni) { + flow->ssh_tls.encrypted_sni.esni = strdup(flow->ndpi_flow->protos.stun_ssl.ssl.encrypted_sni.esni); + flow->ssh_tls.encrypted_sni.cipher_suite = flow->ndpi_flow->protos.stun_ssl.ssl.encrypted_sni.cipher_suite; + } if(flow->ssh_tls.tls_supported_versions) { if((flow->ssh_tls.tls_supported_versions = ndpi_strdup(flow->ndpi_flow->protos.stun_ssl.ssl.tls_supported_versions)) != NULL) diff --git a/example/reader_util.h b/example/reader_util.h index 789729c33..f8302866f 100644 --- a/example/reader_util.h +++ b/example/reader_util.h @@ -204,6 +204,10 @@ typedef struct ndpi_flow_info { ja3_client[33], ja3_server[33], sha1_cert_fingerprint[20]; u_int8_t sha1_cert_fingerprint_set; + struct { + u_int16_t cipher_suite; + char *esni; + } encrypted_sni; time_t notBefore, notAfter; u_int16_t server_cipher; ndpi_cipher_weakness client_unsafe_cipher, server_unsafe_cipher; diff --git a/python/ndpi.py b/python/ndpi.py index 722911207..1c4d6c59f 100644 --- a/python/ndpi.py +++ b/python/ndpi.py @@ -16,9 +16,12 @@ If not, see <http://www.gnu.org/licenses/>. from os.path import abspath, dirname import cffi -import sys cc_ndpi_network_headers = """ +struct ptr_uint32 { + uint32_t value; +}; + struct ndpi_chdlc { uint8_t addr; /* 0x0F (Unicast) - 0x8F (Broadcast) */ @@ -143,6 +146,11 @@ struct ndpi_mpls_header uint32_t ttl:8, s:1, exp:3, label:20; }; +extern union mpls { + uint32_t u32; + struct ndpi_mpls_header mpls; +} mpls; + /* ++++++++++++++++++++++++ IP header ++++++++++++++++++++++++ */ struct ndpi_iphdr { uint8_t ihl:4, version:4; @@ -250,25 +258,25 @@ struct ndpi_vxlanhdr { }; struct tinc_cache_entry { - uint32_t src_address; - uint32_t dst_address; - uint16_t dst_port; + uint32_t src_address; + uint32_t dst_address; + uint16_t dst_port; }; """ cc_ndpi_stuctures = """ typedef enum { - NDPI_LOG_ERROR, - NDPI_LOG_TRACE, - NDPI_LOG_DEBUG, - NDPI_LOG_DEBUG_EXTRA + NDPI_LOG_ERROR, + NDPI_LOG_TRACE, + NDPI_LOG_DEBUG, + NDPI_LOG_DEBUG_EXTRA } ndpi_log_level_t; typedef enum { - ndpi_l4_proto_unknown = 0, - ndpi_l4_proto_tcp_only, - ndpi_l4_proto_udp_only, - ndpi_l4_proto_tcp_and_udp, + ndpi_l4_proto_unknown = 0, + ndpi_l4_proto_tcp_only, + ndpi_l4_proto_udp_only, + ndpi_l4_proto_tcp_and_udp, } ndpi_l4_proto_info; typedef enum { @@ -280,18 +288,33 @@ typedef enum { } ndpi_packet_tunnel; typedef enum { - ndpi_url_no_problem = 0, - ndpi_url_possible_xss, - ndpi_url_possible_sql_injection, - ndpi_url_possible_rce_injection -} ndpi_url_risk; + NDPI_NO_RISK = 0, + NDPI_URL_POSSIBLE_XSS, + NDPI_URL_POSSIBLE_SQL_INJECTION, + NDPI_URL_POSSIBLE_RCE_INJECTION, + NDPI_BINARY_APPLICATION_TRANSFER, + NDPI_KNOWN_PROTOCOL_ON_NON_STANDARD_PORT, + NDPI_TLS_SELFSIGNED_CERTIFICATE, + NDPI_TLS_OBSOLETE_VERSION, + NDPI_TLS_WEAK_CIPHER, + NDPI_TLS_CERTIFICATE_EXPIRED, + NDPI_TLS_CERTIFICATE_MISMATCH, + NDPI_HTTP_SUSPICIOUS_USER_AGENT, + NDPI_HTTP_NUMERIC_IP_HOST, + NDPI_HTTP_SUSPICIOUS_URL, + NDPI_HTTP_SUSPICIOUS_HEADER, + /* Leave this as last member */ + NDPI_MAX_RISK +} ndpi_risk_enum; + +typedef uint32_t ndpi_risk; /* NDPI_VISIT */ typedef enum { - ndpi_preorder, - ndpi_postorder, - ndpi_endorder, - ndpi_leaf + ndpi_preorder, + ndpi_postorder, + ndpi_endorder, + ndpi_leaf } ndpi_VISIT; /* NDPI_NODE */ @@ -353,16 +376,16 @@ struct bt_announce { // 192 bytes #define TINC_CACHE_MAX_SIZE 10 typedef enum { - NDPI_HTTP_METHOD_UNKNOWN = 0, - NDPI_HTTP_METHOD_OPTIONS, - NDPI_HTTP_METHOD_GET, - NDPI_HTTP_METHOD_HEAD, - NDPI_HTTP_METHOD_PATCH, - NDPI_HTTP_METHOD_POST, - NDPI_HTTP_METHOD_PUT, - NDPI_HTTP_METHOD_DELETE, - NDPI_HTTP_METHOD_TRACE, - NDPI_HTTP_METHOD_CONNECT + NDPI_HTTP_METHOD_UNKNOWN = 0, + NDPI_HTTP_METHOD_OPTIONS, + NDPI_HTTP_METHOD_GET, + NDPI_HTTP_METHOD_HEAD, + NDPI_HTTP_METHOD_PATCH, + NDPI_HTTP_METHOD_POST, + NDPI_HTTP_METHOD_PUT, + NDPI_HTTP_METHOD_DELETE, + NDPI_HTTP_METHOD_TRACE, + NDPI_HTTP_METHOD_CONNECT } ndpi_http_method; struct ndpi_lru_cache_entry { @@ -703,6 +726,7 @@ struct ndpi_packet_struct { struct ndpi_int_one_line_struct forwarded_line; struct ndpi_int_one_line_struct referer_line; struct ndpi_int_one_line_struct content_line; + struct ndpi_int_one_line_struct content_disposition_line; struct ndpi_int_one_line_struct accept_line; struct ndpi_int_one_line_struct user_agent_line; struct ndpi_int_one_line_struct http_url_name; @@ -714,8 +738,7 @@ struct ndpi_packet_struct { struct ndpi_int_one_line_struct http_x_session_type; struct ndpi_int_one_line_struct server_line; struct ndpi_int_one_line_struct http_method; - struct ndpi_int_one_line_struct http_response; /* the first "word" in this pointer is the - response code in the packet (200, etc) */ + struct ndpi_int_one_line_struct http_response; uint8_t http_num_headers; /* number of found (valid) header lines in HTTP request or response */ uint16_t l3_packet_len; @@ -731,7 +754,7 @@ struct ndpi_packet_struct { uint8_t tls_certificate_detected:4, tls_certificate_num_checks:4; uint8_t packet_lines_parsed_complete:1, - packet_direction:1, empty_line_position_set:1, pad:5; + packet_direction:1, empty_line_position_set:1, pad:5; }; struct ndpi_detection_module_struct; @@ -754,85 +777,87 @@ typedef struct { } ndpi_port_range; typedef enum { - NDPI_PROTOCOL_SAFE = 0, /* Surely doesn't provide risks for the network. (e.g., a news site) */ - NDPI_PROTOCOL_ACCEPTABLE, /* Probably doesn't provide risks, but could be malicious (e.g., Dropbox) */ - NDPI_PROTOCOL_FUN, /* Pure fun protocol, which may be prohibited by the user policy (e.g., Netflix) */ - NDPI_PROTOCOL_UNSAFE, /* Probably provides risks, but could be a normal traffic. Unencrypted protocols with clear pass should be here (e.g., telnet) */ - NDPI_PROTOCOL_POTENTIALLY_DANGEROUS, /* Possibly dangerous (ex. Tor). */ - NDPI_PROTOCOL_DANGEROUS, /* Surely is dangerous (ex. smbv1). Be prepared to troubles */ - NDPI_PROTOCOL_TRACKER_ADS, /* Trackers, Advertisements... */ - NDPI_PROTOCOL_UNRATED /* No idea, not implemented or impossible to classify */ + NDPI_PROTOCOL_SAFE = 0, /* Surely doesn't provide risks for the network. (e.g., a news site) */ + NDPI_PROTOCOL_ACCEPTABLE, /* Probably doesn't provide risks, but could be malicious (e.g., Dropbox) */ + NDPI_PROTOCOL_FUN, /* Pure fun protocol, which may be prohibited by the user policy */ + NDPI_PROTOCOL_UNSAFE, /* Probably provides risks, but could be a normal traffic. Unencrypted protocols + with clear pass should be here (e.g., telnet) */ + NDPI_PROTOCOL_POTENTIALLY_DANGEROUS, /* Possibly dangerous (ex. Tor). */ + NDPI_PROTOCOL_DANGEROUS, /* Surely is dangerous (ex. smbv1). Be prepared to troubles */ + NDPI_PROTOCOL_TRACKER_ADS, /* Trackers, Advertisements... */ + NDPI_PROTOCOL_UNRATED /* No idea, not implemented or impossible to classify */ } ndpi_protocol_breed_t; #define NUM_BREEDS 8 /* Abstract categories to group the protocols. */ typedef enum { - NDPI_PROTOCOL_CATEGORY_UNSPECIFIED = 0, /* For general services and unknown protocols */ - NDPI_PROTOCOL_CATEGORY_MEDIA, /* Multimedia and streaming */ - NDPI_PROTOCOL_CATEGORY_VPN, /* Virtual Private Networks */ - NDPI_PROTOCOL_CATEGORY_MAIL, /* Protocols to send/receive/sync emails */ - NDPI_PROTOCOL_CATEGORY_DATA_TRANSFER, /* AFS/NFS and similar protocols */ - NDPI_PROTOCOL_CATEGORY_WEB, /* Web/mobile protocols and services */ - NDPI_PROTOCOL_CATEGORY_SOCIAL_NETWORK, /* Social networks */ - NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, /* Download, FTP, file transfer/sharing */ - NDPI_PROTOCOL_CATEGORY_GAME, /* Online games */ - NDPI_PROTOCOL_CATEGORY_CHAT, /* Instant messaging */ - NDPI_PROTOCOL_CATEGORY_VOIP, /* Real-time communications and conferencing */ - NDPI_PROTOCOL_CATEGORY_DATABASE, /* Protocols for database communication */ - NDPI_PROTOCOL_CATEGORY_REMOTE_ACCESS, /* Remote access and control */ - NDPI_PROTOCOL_CATEGORY_CLOUD, /* Online cloud services */ - NDPI_PROTOCOL_CATEGORY_NETWORK, /* Network infrastructure protocols */ - NDPI_PROTOCOL_CATEGORY_COLLABORATIVE, /* Software for collaborative development, including Webmail */ - NDPI_PROTOCOL_CATEGORY_RPC, /* High level network communication protocols */ - NDPI_PROTOCOL_CATEGORY_STREAMING, /* Streaming protocols */ - NDPI_PROTOCOL_CATEGORY_SYSTEM_OS, /* System/Operating System level applications */ - NDPI_PROTOCOL_CATEGORY_SW_UPDATE, /* Software update */ - - /* See #define NUM_CUSTOM_CATEGORIES */ - NDPI_PROTOCOL_CATEGORY_CUSTOM_1, /* User custom category 1 */ - NDPI_PROTOCOL_CATEGORY_CUSTOM_2, /* User custom category 2 */ - NDPI_PROTOCOL_CATEGORY_CUSTOM_3, /* User custom category 3 */ - NDPI_PROTOCOL_CATEGORY_CUSTOM_4, /* User custom category 4 */ - NDPI_PROTOCOL_CATEGORY_CUSTOM_5, /* User custom category 5 */ - - /* Further categories... */ - NDPI_PROTOCOL_CATEGORY_MUSIC, - NDPI_PROTOCOL_CATEGORY_VIDEO, - NDPI_PROTOCOL_CATEGORY_SHOPPING, - NDPI_PROTOCOL_CATEGORY_PRODUCTIVITY, - NDPI_PROTOCOL_CATEGORY_FILE_SHARING, - - /* Some custom categories */ - CUSTOM_CATEGORY_MINING = 99, - CUSTOM_CATEGORY_MALWARE = 100, - CUSTOM_CATEGORY_ADVERTISEMENT = 101, - CUSTOM_CATEGORY_BANNED_SITE = 102, - CUSTOM_CATEGORY_SITE_UNAVAILABLE = 103, - CUSTOM_CATEGORY_ALLOWED_SITE = 104, - /* - The category below is used to track communications made by - security applications (e.g. sophosxl.net, spamhaus.org) - to track malware, spam etc. - */ - CUSTOM_CATEGORY_ANTIMALWARE = 105, - - /* - IMPORTANT - Please keep in sync with - static const char* categories[] = { ..} - in ndpi_main.c - */ - - NDPI_PROTOCOL_NUM_CATEGORIES /* - NOTE: Keep this as last member - Unused as value but useful to getting the number of elements - in this datastructure - */ + NDPI_PROTOCOL_CATEGORY_UNSPECIFIED = 0, /* For general services and unknown protocols */ + NDPI_PROTOCOL_CATEGORY_MEDIA, /* Multimedia and streaming */ + NDPI_PROTOCOL_CATEGORY_VPN, /* Virtual Private Networks */ + NDPI_PROTOCOL_CATEGORY_MAIL, /* Protocols to send/receive/sync emails */ + NDPI_PROTOCOL_CATEGORY_DATA_TRANSFER, /* AFS/NFS and similar protocols */ + NDPI_PROTOCOL_CATEGORY_WEB, /* Web/mobile protocols and services */ + NDPI_PROTOCOL_CATEGORY_SOCIAL_NETWORK, /* Social networks */ + NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT, /* Download, FTP, file transfer/sharing */ + NDPI_PROTOCOL_CATEGORY_GAME, /* Online games */ + NDPI_PROTOCOL_CATEGORY_CHAT, /* Instant messaging */ + NDPI_PROTOCOL_CATEGORY_VOIP, /* Real-time communications and conferencing */ + NDPI_PROTOCOL_CATEGORY_DATABASE, /* Protocols for database communication */ + NDPI_PROTOCOL_CATEGORY_REMOTE_ACCESS, /* Remote access and control */ + NDPI_PROTOCOL_CATEGORY_CLOUD, /* Online cloud services */ + NDPI_PROTOCOL_CATEGORY_NETWORK, /* Network infrastructure protocols */ + NDPI_PROTOCOL_CATEGORY_COLLABORATIVE, /* Software for collaborative development, including Webmail */ + NDPI_PROTOCOL_CATEGORY_RPC, /* High level network communication protocols */ + NDPI_PROTOCOL_CATEGORY_STREAMING, /* Streaming protocols */ + NDPI_PROTOCOL_CATEGORY_SYSTEM_OS, /* System/Operating System level applications */ + NDPI_PROTOCOL_CATEGORY_SW_UPDATE, /* Software update */ + + /* See #define NUM_CUSTOM_CATEGORIES */ + NDPI_PROTOCOL_CATEGORY_CUSTOM_1, /* User custom category 1 */ + NDPI_PROTOCOL_CATEGORY_CUSTOM_2, /* User custom category 2 */ + NDPI_PROTOCOL_CATEGORY_CUSTOM_3, /* User custom category 3 */ + NDPI_PROTOCOL_CATEGORY_CUSTOM_4, /* User custom category 4 */ + NDPI_PROTOCOL_CATEGORY_CUSTOM_5, /* User custom category 5 */ + + /* Further categories... */ + NDPI_PROTOCOL_CATEGORY_MUSIC, + NDPI_PROTOCOL_CATEGORY_VIDEO, + NDPI_PROTOCOL_CATEGORY_SHOPPING, + NDPI_PROTOCOL_CATEGORY_PRODUCTIVITY, + NDPI_PROTOCOL_CATEGORY_FILE_SHARING, + + /* Some custom categories */ + CUSTOM_CATEGORY_MINING = 99, + CUSTOM_CATEGORY_MALWARE = 100, + CUSTOM_CATEGORY_ADVERTISEMENT = 101, + CUSTOM_CATEGORY_BANNED_SITE = 102, + CUSTOM_CATEGORY_SITE_UNAVAILABLE = 103, + CUSTOM_CATEGORY_ALLOWED_SITE = 104, + /* + The category below is used to track communications made by + security applications (e.g. sophosxl.net, spamhaus.org) + to track malware, spam etc. + */ + CUSTOM_CATEGORY_ANTIMALWARE = 105, + + /* + IMPORTANT + Please keep in sync with + static const char* categories[] = { ..} + in ndpi_main.c + */ + + NDPI_PROTOCOL_NUM_CATEGORIES + /* + NOTE: Keep this as last member + Unused as value but useful to getting the number of elements + in this datastructure + */ } ndpi_protocol_category_t; typedef enum { - ndpi_pref_direction_detect_disable = 0, + ndpi_pref_direction_detect_disable = 0, } ndpi_detection_preference; /* ntop extensions */ @@ -842,6 +867,7 @@ typedef struct ndpi_proto_defaults { uint8_t can_have_a_subprotocol; uint16_t protoId, protoIdx; uint16_t master_tcp_protoId[2], master_udp_protoId[2]; /* The main protocols on which this sub-protocol sits on */ + uint16_t tcp_default_ports[5], udp_default_ports[5]; ndpi_protocol_breed_t protoBreed; void (*func) (struct ndpi_detection_module_struct *, struct ndpi_flow_struct *flow); } ndpi_proto_defaults_t; @@ -965,12 +991,13 @@ struct ndpi_detection_module_struct { /* NDPI_PROTOCOL_STUN and subprotocols */ struct ndpi_lru_cache *stun_cache; + /* NDPI_PROTOCOL_MSTEAMS */ + struct ndpi_lru_cache *msteams_cache; + ndpi_proto_defaults_t proto_defaults[512]; uint8_t direction_detect_disable:1, /* disable internal detection of packet direction */ _pad:7; - - void *hyperscan; /* Intel Hyperscan */ }; #define NDPI_CIPHER_SAFE 0 @@ -978,9 +1005,9 @@ struct ndpi_detection_module_struct { #define NDPI_CIPHER_INSECURE 2 typedef enum { - ndpi_cipher_safe = NDPI_CIPHER_SAFE, - ndpi_cipher_weak = NDPI_CIPHER_WEAK, - ndpi_cipher_insecure = NDPI_CIPHER_INSECURE + ndpi_cipher_safe = NDPI_CIPHER_SAFE, + ndpi_cipher_weak = NDPI_CIPHER_WEAK, + ndpi_cipher_insecure = NDPI_CIPHER_INSECURE } ndpi_cipher_weakness; struct ndpi_flow_struct { @@ -1019,6 +1046,9 @@ struct ndpi_flow_struct { struct ndpi_id_struct *server_id; /* HTTP host or DNS query */ uint8_t host_server_name[240]; + uint8_t initial_binary_bytes[8], initial_binary_bytes_len; + uint8_t risk_checked; + uint32_t risk; /* Issues found with this flow [bitmask of ndpi_risk] */ /* This structure below will not stay inside the protos @@ -1064,8 +1094,8 @@ struct ndpi_flow_struct { struct { struct { uint16_t ssl_version, server_names_len; - char client_requested_server_name[64], *server_names, server_organization[64], - *alpn, *tls_supported_versions; + char client_requested_server_name[64], *server_names, + *alpn, *tls_supported_versions, *issuerDN, *subjectDN; uint32_t notBefore, notAfter; char ja3_client[33], ja3_server[33]; uint16_t server_cipher; @@ -1208,10 +1238,6 @@ struct ndpi_flow_struct { /* NDPI_PROTOCOL_CSGO */ uint8_t csgo_strid[18],csgo_state,csgo_s2; uint32_t csgo_id2; - - /* NDPI_PROTOCOL_1KXUN || NDPI_PROTOCOL_IQIYI */ - uint16_t kxun_counter, iqiyi_counter; - /* internal structures to save functions calls */ struct ndpi_packet_struct packet; struct ndpi_flow_struct *flow; @@ -1220,14 +1246,14 @@ struct ndpi_flow_struct { }; typedef struct { - char *string_to_match, *string2_to_match, *pattern_to_match, *proto_name; + char *string_to_match, *proto_name; int protocol_id; ndpi_protocol_category_t protocol_category; ndpi_protocol_breed_t protocol_breed; } ndpi_protocol_match; typedef struct { - char *string_to_match, *hyperscan_string_to_match; + char *string_to_match; ndpi_protocol_category_t protocol_category; } ndpi_category_match; @@ -1239,11 +1265,10 @@ typedef struct { typedef uint32_t ndpi_init_prefs; -typedef enum - { - ndpi_no_prefs = 0, - ndpi_dont_load_tor_hosts, - } ndpi_prefs; +typedef enum { + ndpi_no_prefs = 0, + ndpi_dont_load_tor_hosts, +} ndpi_prefs; typedef struct { int protocol_id; @@ -1272,8 +1297,6 @@ struct ndpi_analyze_struct { #define MAX_SERIES_LEN 512 #define MIN_SERIES_LEN 8 -/* **************************************** */ - typedef struct ndpi_ptree ndpi_ptree_t; """ @@ -1300,23 +1323,44 @@ void ndpi_free(void *ptr); void * ndpi_flow_malloc(size_t size); void ndpi_flow_free(void *ptr); void ndpi_exit_detection_module(struct ndpi_detection_module_struct *ndpi_struct); -char* ndpi_protocol2name(struct ndpi_detection_module_struct *ndpi_mod, ndpi_protocol proto, char *buf, unsigned buf_len); +char* ndpi_protocol2name(struct ndpi_detection_module_struct *ndpi_mod, + ndpi_protocol proto, + char *buf, unsigned buf_len); const char* ndpi_category_get_name(struct ndpi_detection_module_struct *ndpi_mod, ndpi_protocol_category_t category); char* ndpi_revision(void); void ndpi_finalize_initalization(struct ndpi_detection_module_struct *ndpi_str); uint32_t ndpi_detection_get_sizeof_ndpi_flow_struct(void); uint32_t ndpi_detection_get_sizeof_ndpi_id_struct(void); +uint32_t ndpi_detection_get_sizeof_ndpi_flow_tcp_struct(void); +uint32_t ndpi_detection_get_sizeof_ndpi_flow_udp_struct(void); +uint8_t ndpi_extra_dissection_possible(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow); """ +def check_structures_size(flow_struct_defined, flow_struct_loaded, + id_struct_defined, id_struct_loaded, + tcp_flow_struct_defined, tcp_flow_struct_loaded, + udp_flow_struct_defined, udp_flow_struct_loaded): + """ Function used to check loaded structures sizes againt defined ones """ + errors = [] + if flow_struct_defined != flow_struct_loaded: + errors.append('ndpi_flow_struct') + if id_struct_defined != id_struct_loaded: + errors.append('ndpi_id_struct') + if tcp_flow_struct_defined != tcp_flow_struct_loaded: + errors.append('ndpi_tcp_flow_struct') + if udp_flow_struct_defined != udp_flow_struct_loaded: + errors.append('ndpi_udp_flow_struct') + return errors + + class NDPI(): - def __init__(self, libpath=None, max_tcp_dissections=10, max_udp_dissections=16): + """ ndpi module main class """ + + def __init__(self, libpath=None, max_tcp_dissections=80, max_udp_dissections=16, enable_guess=True): self._ffi = cffi.FFI() if libpath is None: - if "win" in sys.platform[:3]: - self._ndpi = self._ffi.dlopen(dirname(abspath(__file__)) + '/libs/libndpi.a') - else: - self._ndpi = self._ffi.dlopen(dirname(abspath(__file__)) + '/libs/libndpi.so') + self._ndpi = self._ffi.dlopen(dirname(abspath(__file__)) + '/libndpi.so') else: self._ndpi = self._ffi.dlopen(libpath) self._ffi.cdef(cc_ndpi_network_headers, packed=True) @@ -1329,47 +1373,81 @@ class NDPI(): all = self._ffi.new('NDPI_PROTOCOL_BITMASK*') self._ndpi.memset(self._ffi.cast("char *", all), 0xFF, self._ffi.sizeof("NDPI_PROTOCOL_BITMASK")) self._ndpi.ndpi_set_protocol_detection_bitmask2(self._mod, all) - self.SIZEOF_FLOW_STRUCT = self._ffi.sizeof("struct ndpi_flow_struct") - self.SIZEOF_ID_STRUCT = self._ffi.sizeof("struct ndpi_id_struct") + errors = check_structures_size(self._ffi.sizeof("struct ndpi_flow_struct"), + self._ndpi.ndpi_detection_get_sizeof_ndpi_flow_struct(), + self._ffi.sizeof("struct ndpi_id_struct"), + self._ndpi.ndpi_detection_get_sizeof_ndpi_id_struct(), + self._ffi.sizeof("struct ndpi_flow_tcp_struct"), + self._ndpi.ndpi_detection_get_sizeof_ndpi_flow_tcp_struct(), + self._ffi.sizeof("struct ndpi_flow_udp_struct"), + self._ndpi.ndpi_detection_get_sizeof_ndpi_flow_udp_struct()) + if len(errors) != 0: + raise ValueError('nDPI error: mismatch in the headers of following structures{}'.format(', '.join(errors))) + else: + self.SIZEOF_FLOW_STRUCT = self._ffi.sizeof("struct ndpi_flow_struct") + self.SIZEOF_ID_STRUCT = self._ffi.sizeof("struct ndpi_id_struct") self.NULL = self._ffi.NULL self.max_tcp_dissections = max_tcp_dissections self.max_udp_dissections = max_udp_dissections + self.enable_guess = enable_guess def new_ndpi_flow(self): + """ Create a new nDPI flow object """ f = self._ffi.cast('struct ndpi_flow_struct*', self._ndpi.ndpi_flow_malloc(self.SIZEOF_FLOW_STRUCT)) self._ndpi.memset(f, 0, self.SIZEOF_FLOW_STRUCT) return f def new_ndpi_id(self): + """ Create a new nDPI id object """ i = self._ffi.cast('struct ndpi_id_struct*', self._ndpi.ndpi_malloc(self.SIZEOF_ID_STRUCT)) self._ndpi.memset(i, 0, self.SIZEOF_ID_STRUCT) return i def ndpi_detection_process_packet(self, flow, packet, packetlen, current_tick, src, dst): - return self._ndpi.ndpi_detection_process_packet(self._mod, flow, packet, packetlen, current_tick, src, dst) + """ Main detection processing function """ + p = self._ndpi.ndpi_detection_process_packet(self._mod, flow, packet, packetlen, current_tick, src, dst) + return p def ndpi_detection_giveup(self, flow): - return self._ndpi.ndpi_detection_giveup(self._mod, flow, 1, self._ffi.new("uint8_t*", 0)) + """ Giveup detection function """ + return self._ndpi.ndpi_detection_giveup(self._mod, flow, self.enable_guess, self._ffi.new("uint8_t*", 0)) def ndpi_flow_free(self, flow): + """ Free nDPI flow object """ return self._ndpi.ndpi_flow_free(flow) def ndpi_free(self, ptr): + """ Free nDPI object """ return self._ndpi.ndpi_free(ptr) def get_str_field(self, ptr): - return self._ffi.string(ptr).decode('utf-8', errors='ignore') + """ Get fixed string size attribute """ + if ptr == self._ffi.NULL: + return '' + else: + return self._ffi.string(ptr).decode('utf-8', errors='ignore') - def get_buffer_field(self, ptr, l): - return bytes(self._ffi.buffer(ptr, l)).decode('utf-8', errors='ignore') + def get_buffer_field(self, ptr, li): + """ Get variable string size attribute """ + if ptr == self._ffi.NULL: + return '' + else: + return self._ffi.string(ptr, li).decode('utf-8', errors='ignore') def ndpi_protocol2name(self, proto): + """ Convert nDPI protocol object to readable name """ buf = self._ffi.new("char[32]") self._ndpi.ndpi_protocol2name(self._mod, proto, buf, self._ffi.sizeof(buf)) return self._ffi.string(buf).decode('utf-8', errors='ignore') def ndpi_category_get_name(self, category): + """ Convert nDPI protocol object to readable name """ return self._ffi.string(self._ndpi.ndpi_category_get_name(self._mod, category)).decode('utf-8', errors='ignore') + def ndpi_extra_dissection_possible(self, flow): + return self._ndpi.ndpi_extra_dissection_possible(self._mod, flow) + def ndpi_exit_detection_module(self): + """ Exit function for nDPI module """ self._ndpi.ndpi_exit_detection_module(self._mod) + self._ffi.dlclose(self._ndpi) diff --git a/src/include/ndpi_api.h.in b/src/include/ndpi_api.h.in index 6495c6825..5f8604f8e 100644 --- a/src/include/ndpi_api.h.in +++ b/src/include/ndpi_api.h.in @@ -137,7 +137,7 @@ extern "C" { * NULL if the substring is not found * */ - char* ndpi_strncasestr(const char *s, const char *find, size_t slen); + const char* ndpi_strncasestr(const char *s, const char *find, size_t slen); /** * Returns the nDPI protocol id for IP-based protocol detection @@ -191,7 +191,7 @@ extern "C" { /** * Completes the initialization (2nd step) * - * @return the initialized detection module + * @par ndpi_str = the struct created for the protocol detection * */ void ndpi_finalize_initalization(struct ndpi_detection_module_struct *ndpi_str); @@ -258,7 +258,7 @@ extern "C" { */ void ndpi_set_protocol_detection_bitmask2(struct ndpi_detection_module_struct *ndpi_struct, const NDPI_PROTOCOL_BITMASK * detection_bitmask); - + /** * Function to be called before we give up with detection for a given flow. * This function reduces the NDPI_UNKNOWN_PROTOCOL detection @@ -330,7 +330,7 @@ extern "C" { */ u_int16_t ndpi_get_flow_masterprotocol(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow); - + /** * API call that is called internally by ndpi_detection_process_packet or by apps * that want to avoid calling ndpi_detection_process_packet as they have already @@ -431,7 +431,7 @@ extern "C" { char *string_to_match, u_int string_to_match_len, ndpi_protocol_match_result *ret_match, - u_int16_t master_protocol_id); + u_int16_t master_protocol_id); /** * Check if the string content passed match with a protocol @@ -558,7 +558,7 @@ extern "C" { */ int ndpi_match_hostname_protocol(struct ndpi_detection_module_struct *ndpi_mod, struct ndpi_flow_struct *flow, - u_int16_t master_protocol, + u_int16_t master_protocol, char *name, u_int name_len); /** @@ -838,7 +838,7 @@ extern "C" { /* Tells to called on what l4 protocol given application protocol can be found */ ndpi_l4_proto_info ndpi_get_l4_proto_info(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t ndpi_proto_id); const char* ndpi_get_l4_proto_name(ndpi_l4_proto_info proto); - + ndpi_proto_defaults_t* ndpi_get_proto_defaults(struct ndpi_detection_module_struct *ndpi_mod); u_int ndpi_get_ndpi_num_supported_protocols(struct ndpi_detection_module_struct *ndpi_mod); u_int ndpi_get_ndpi_num_custom_protocols(struct ndpi_detection_module_struct *ndpi_mod); @@ -851,7 +851,7 @@ extern "C" { 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); void ndpi_lru_add_to_cache(struct ndpi_lru_cache *c, u_int32_t key, u_int16_t value); - + /** * Find a protocol id associated with a string automata * @@ -886,7 +886,7 @@ extern "C" { u_int16_t src_port, u_int16_t dst_port, u_int8_t icmp_type, u_int8_t icmp_code, u_char *hash_buf, u_int8_t hash_buf_len); u_int8_t ndpi_extra_dissection_possible(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow); + struct ndpi_flow_struct *flow); u_int8_t ndpi_is_safe_ssl_cipher(u_int32_t cipher); const char* ndpi_cipher2str(u_int32_t cipher); const char* ndpi_tunnel2str(ndpi_packet_tunnel tt); @@ -904,7 +904,10 @@ extern "C" { char* ndpi_base64_encode(unsigned char const* bytes_to_encode, size_t in_len); int ndpi_load_ipv4_ptree(struct ndpi_detection_module_struct *ndpi_str, const char *path, u_int16_t protocol_id); - + int ndpi_dpi2json(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + ndpi_protocol l7_protocol, + ndpi_serializer *serializer); int ndpi_flow2json(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, u_int8_t ip_version, @@ -949,7 +952,7 @@ extern "C" { int ndpi_serialize_string_int32(ndpi_serializer *serializer, const char *key, int32_t value); int ndpi_serialize_string_int64(ndpi_serializer *serializer, - const char *key, int64_t value); + const char *key, int64_t value); int ndpi_serialize_string_uint32(ndpi_serializer *serializer, const char *key, u_int32_t value); int ndpi_serialize_string_uint32_format(ndpi_serializer *serializer, @@ -973,6 +976,9 @@ extern "C" { int ndpi_serialize_raw_record(ndpi_serializer *_serializer, u_char *record, u_int32_t record_len); int ndpi_serialize_end_of_record(ndpi_serializer *serializer); + int ndpi_serialize_start_of_list(ndpi_serializer *serializer, + const char *key); + int ndpi_serialize_end_of_list(ndpi_serializer *serializer); int ndpi_serialize_start_of_block(ndpi_serializer *serializer, const char *key); int ndpi_serialize_end_of_block(ndpi_serializer *serializer); @@ -981,17 +987,18 @@ extern "C" { u_int32_t ndpi_serializer_get_internal_buffer_size(ndpi_serializer *serializer); int ndpi_serializer_set_buffer_len(ndpi_serializer *serializer, u_int32_t l); void ndpi_serializer_set_csv_separator(ndpi_serializer *serializer, char separator); + char* ndpi_serializer_get_header(ndpi_serializer *serializer, u_int32_t *buffer_len); void ndpi_serializer_create_snapshot(ndpi_serializer *serializer); void ndpi_serializer_rollback_snapshot(ndpi_serializer *serializer); - + /* Deserializer */ int ndpi_init_deserializer(ndpi_deserializer *deserializer, ndpi_serializer *serializer); int ndpi_init_deserializer_buf(ndpi_deserializer *deserializer, u_int8_t *serialized_buffer, u_int32_t serialized_buffer_len); - + ndpi_serialization_format ndpi_deserialize_get_format(ndpi_deserializer *_deserializer); ndpi_serialization_type ndpi_deserialize_get_item_type(ndpi_deserializer *deserializer, ndpi_serialization_type *key_type); int ndpi_deserialize_next(ndpi_deserializer *deserializer); @@ -1017,22 +1024,23 @@ extern "C" { float ndpi_data_average(struct ndpi_analyze_struct *s); float ndpi_data_window_average(struct ndpi_analyze_struct *s); - + float ndpi_data_entropy(struct ndpi_analyze_struct *s); float ndpi_data_variance(struct ndpi_analyze_struct *s); float ndpi_data_stddev(struct ndpi_analyze_struct *s); u_int32_t ndpi_data_min(struct ndpi_analyze_struct *s); u_int32_t ndpi_data_max(struct ndpi_analyze_struct *s); float ndpi_data_ratio(u_int32_t sent, u_int32_t rcvd); - + const char* ndpi_data_ratio2str(float ratio); - + void ndpi_data_print_window_values(struct ndpi_analyze_struct *s); /* debug */ ndpi_risk_enum ndpi_validate_url(char *url); u_int8_t ndpi_is_protocol_detected(struct ndpi_detection_module_struct *ndpi_str, ndpi_protocol proto); + void ndpi_serialize_risk(ndpi_serializer *serializer, struct ndpi_flow_struct *flow); const char* ndpi_risk2str(ndpi_risk_enum risk); #ifdef __cplusplus diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index bdcfebbe2..dc1aa208e 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -65,6 +65,7 @@ typedef enum { NDPI_HTTP_SUSPICIOUS_USER_AGENT, NDPI_HTTP_NUMERIC_IP_HOST, NDPI_HTTP_SUSPICIOUS_URL, + NDPI_HTTP_SUSPICIOUS_HEADER, /* Leave this as last member */ NDPI_MAX_RISK @@ -1111,6 +1112,9 @@ struct ndpi_detection_module_struct { /* NDPI_PROTOCOL_STUN and subprotocols */ struct ndpi_lru_cache *stun_cache; + /* NDPI_PROTOCOL_MSTEAMS */ + struct ndpi_lru_cache *msteams_cache; + ndpi_proto_defaults_t proto_defaults[NDPI_MAX_SUPPORTED_PROTOCOLS+NDPI_MAX_NUM_CUSTOM_PROTOCOLS]; u_int8_t direction_detect_disable:1, /* disable internal detection of packet direction */ @@ -1223,6 +1227,11 @@ struct ndpi_flow_struct { u_int32_t notBefore, notAfter; char ja3_client[33], ja3_server[33]; u_int16_t server_cipher; + + struct { + u_int16_t cipher_suite; + char *esni; + } encrypted_sni; ndpi_cipher_weakness server_unsafe_cipher; } ssl; @@ -1426,6 +1435,7 @@ typedef enum { ndpi_serialization_string } ndpi_serialization_type; +#define NDPI_SERIALIZER_DEFAULT_HEADER_SIZE 1024 #define NDPI_SERIALIZER_DEFAULT_BUFFER_SIZE 8192 #define NDPI_SERIALIZER_DEFAULT_BUFFER_INCR 1024 @@ -1434,18 +1444,31 @@ typedef enum { #define NDPI_SERIALIZER_STATUS_EOR (1 << 2) #define NDPI_SERIALIZER_STATUS_SOB (1 << 3) #define NDPI_SERIALIZER_STATUS_NOT_EMPTY (1 << 4) +#define NDPI_SERIALIZER_STATUS_LIST (1 << 5) +#define NDPI_SERIALIZER_STATUS_SOL (1 << 6) +#define NDPI_SERIALIZER_STATUS_HDR_DONE (1 << 7) typedef struct { - u_int32_t flags; u_int32_t size_used; +} ndpi_private_serializer_buffer_status; + +typedef struct { + u_int32_t flags; + ndpi_private_serializer_buffer_status buffer; + ndpi_private_serializer_buffer_status header; } ndpi_private_serializer_status; typedef struct { + u_int32_t initial_size; + u_int32_t size; + u_int8_t *data; +} ndpi_private_serializer_buffer; + +typedef struct { ndpi_private_serializer_status status; - u_int32_t initial_buffer_size; - u_int32_t buffer_size; + ndpi_private_serializer_buffer buffer; + ndpi_private_serializer_buffer header; ndpi_serialization_format fmt; - u_int8_t *buffer; char csv_separator[2]; u_int8_t has_snapshot; ndpi_private_serializer_status snapshot; diff --git a/src/lib/ndpi_content_match.c.inc b/src/lib/ndpi_content_match.c.inc index 4b6daa50b..32a6e840c 100644 --- a/src/lib/ndpi_content_match.c.inc +++ b/src/lib/ndpi_content_match.c.inc @@ -8390,8 +8390,11 @@ static ndpi_network host_protocol_list[] = { { 0xD0163900 /* 208.22.57.0/24 */, 24, NDPI_PROTOCOL_BLOOMBERG }, { 0x45BFC000 /* 69.191.192.0/18 */, 18, NDPI_PROTOCOL_BLOOMBERG }, - /* Microsoft - https://docs.microsoft.com/en-us/office365/enterprise/urls-and-ip-address-ranges + /* + Microsoft + + [JSON] https://endpoints.office.com/endpoints/worldwide?clientrequestid=b10c5ed1-bad1-445f-b386-b919946339a7 + [HTML] https://docs.microsoft.com/en-us/office365/enterprise/urls-and-ip-address-ranges */ { 0x0D6B0698 /* 13.107.6.152/31 */, 31, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x0D6B120A /* 13.107.18.10/31 */, 31, NDPI_PROTOCOL_MICROSOFT_365 }, @@ -8411,7 +8414,6 @@ static ndpi_network host_protocol_list[] = { { 0x1767A000 /* 23.103.160.0/20 */, 20, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x28600000 /* 40.96.0.0/13 */, 13, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x28680000 /* 40.104.0.0/15 */, 15, NDPI_PROTOCOL_MICROSOFT_365 }, - { 0x34600000 /* 52.96.0.0/14 */, 14, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x83FD21D7 /* 131.253.33.215/32 */, 32, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x84F50000 /* 132.245.0.0/16 */, 16, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x96AB2000 /* 150.171.32.0/22 */, 22, NDPI_PROTOCOL_MICROSOFT_365 }, @@ -8423,7 +8425,6 @@ static ndpi_network host_protocol_list[] = { { 0x1767A000 /* 23.103.160.0/20 */, 20, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x28600000 /* 40.96.0.0/13 */, 13, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x28680000 /* 40.104.0.0/15 */, 15, NDPI_PROTOCOL_MICROSOFT_365 }, - { 0x34600000 /* 52.96.0.0/14 */, 14, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x83FD21D7 /* 131.253.33.215/32 */, 32, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x84F50000 /* 132.245.0.0/16 */, 16, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x96AB2000 /* 150.171.32.0/22 */, 22, NDPI_PROTOCOL_MICROSOFT_365 }, @@ -8435,7 +8436,6 @@ static ndpi_network host_protocol_list[] = { { 0x1767A000 /* 23.103.160.0/20 */, 20, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x28600000 /* 40.96.0.0/13 */, 13, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x28680000 /* 40.104.0.0/15 */, 15, NDPI_PROTOCOL_MICROSOFT_365 }, - { 0x34600000 /* 52.96.0.0/14 */, 14, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x83FD21D7 /* 131.253.33.215/32 */, 32, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x84F50000 /* 132.245.0.0/16 */, 16, NDPI_PROTOCOL_MICROSOFT_365 }, { 0x96AB2000 /* 150.171.32.0/22 */, 22, NDPI_PROTOCOL_MICROSOFT_365 }, @@ -8673,6 +8673,8 @@ static ndpi_protocol_match host_match[] = { ".cloudfront.net", "Amazon", NDPI_PROTOCOL_AMAZON, NDPI_PROTOCOL_CATEGORY_WEB, NDPI_PROTOCOL_ACCEPTABLE }, { ".us-west-2.compute.amazonaws.com","Amazon", NDPI_PROTOCOL_AMAZON, NDPI_PROTOCOL_CATEGORY_WEB, NDPI_PROTOCOL_ACCEPTABLE }, + { ".teamviewer.com", "Teamviewer", NDPI_PROTOCOL_TEAMVIEWER, NDPI_PROTOCOL_CATEGORY_REMOTE_ACCESS, NDPI_PROTOCOL_ACCEPTABLE }, + /* Microsoft + Azure */ { ".azure.com", "Microsoft", NDPI_PROTOCOL_MICROSOFT, NDPI_PROTOCOL_CATEGORY_CLOUD, NDPI_PROTOCOL_SAFE }, { ".windows.net", "Microsoft", NDPI_PROTOCOL_MICROSOFT, NDPI_PROTOCOL_CATEGORY_CLOUD, NDPI_PROTOCOL_SAFE }, @@ -8768,6 +8770,10 @@ static ndpi_protocol_match host_match[] = /* http://check.googlezip.net/connect [check browser connectivity] */ // { ".googlezip.net", "Google", NDPI_PROTOCOL_GOOGLE, NDPI_PROTOCOL_CATEGORY_WEB, NDPI_PROTOCOL_SAFE }, + /* + https://github.com/bambenek/block-doh/blob/master/db.doh-redirect + https://github.com/curl/curl/wiki/DNS-over-HTTPS + */ { "dns.google", "DoH_DoT", NDPI_PROTOCOL_DOH_DOT, NDPI_PROTOCOL_CATEGORY_NETWORK, NDPI_PROTOCOL_ACCEPTABLE }, { "mozilla.cloudflare-dns.com", "DoH_DoT", NDPI_PROTOCOL_DOH_DOT, NDPI_PROTOCOL_CATEGORY_NETWORK, NDPI_PROTOCOL_ACCEPTABLE }, /* Firefox */ { "cloudflare-dns.com", "DoH_DoT", NDPI_PROTOCOL_DOH_DOT, NDPI_PROTOCOL_CATEGORY_NETWORK, NDPI_PROTOCOL_ACCEPTABLE }, @@ -8932,6 +8938,7 @@ static ndpi_protocol_match host_match[] = { ".spotify.", "Spotify", NDPI_PROTOCOL_SPOTIFY, NDPI_PROTOCOL_CATEGORY_MUSIC, NDPI_PROTOCOL_FUN }, { "audio-fa.scdn.co", "Spotify", NDPI_PROTOCOL_SPOTIFY, NDPI_PROTOCOL_CATEGORY_MUSIC, NDPI_PROTOCOL_FUN }, + { "spotifycdn.net", "Spotify", NDPI_PROTOCOL_SPOTIFY, NDPI_PROTOCOL_CATEGORY_MUSIC, NDPI_PROTOCOL_FUN }, { "edge-mqtt.facebook.com", "Messenger", NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_CATEGORY_CHAT, NDPI_PROTOCOL_ACCEPTABLE }, { "mqtt-mini.facebook.com", "Messenger", NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_CATEGORY_CHAT, NDPI_PROTOCOL_ACCEPTABLE }, /* Messenger Lite */ diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index ca557ea31..fed3c9831 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -1626,7 +1626,7 @@ u_int16_t ndpi_network_port_ptree_match(struct ndpi_detection_module_struct *ndp || (node->value.uv.additional_user_value == port)) return(node->value.uv.user_value); } - + return(NDPI_PROTOCOL_UNKNOWN); } @@ -2198,10 +2198,10 @@ int ndpi_match_custom_category(struct ndpi_detection_module_struct *ndpi_str, char *name, u_int name_len, ndpi_protocol_category_t *category) { ndpi_protocol_breed_t breed; - u_int16_t id; + u_int16_t id; int rc = ndpi_match_string_protocol_id(ndpi_str->custom_categories.hostnames.ac_automa, name, name_len, &id, category, &breed); - + return(rc); } @@ -2277,6 +2277,9 @@ void ndpi_exit_detection_module(struct ndpi_detection_module_struct *ndpi_str) { if(ndpi_str->stun_cache) ndpi_lru_free_cache(ndpi_str->stun_cache); + if(ndpi_str->msteams_cache) + ndpi_lru_free_cache(ndpi_str->msteams_cache); + if(ndpi_str->protocols_ptree) ndpi_Destroy_Patricia((patricia_tree_t *) ndpi_str->protocols_ptree, free_ptree_data); @@ -2315,7 +2318,7 @@ void ndpi_exit_detection_module(struct ndpi_detection_module_struct *ndpi_str) { #ifdef CUSTOM_NDPI_PROTOCOLS #include "../../../nDPI-custom/ndpi_exit_detection_module.c" #endif - + ndpi_free(ndpi_str); } } @@ -3491,12 +3494,17 @@ static u_int8_t ndpi_detection_get_l4_internal(struct ndpi_detection_module_stru return(0); } +/* ************************************************ */ + void ndpi_apply_flow_protocol_to_packet(struct ndpi_flow_struct *flow, struct ndpi_packet_struct *packet) { memcpy(&packet->detected_protocol_stack, &flow->detected_protocol_stack, sizeof(packet->detected_protocol_stack)); memcpy(&packet->protocol_stack_info, &flow->protocol_stack_info, sizeof(packet->protocol_stack_info)); } -static int ndpi_init_packet_header(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, +/* ************************************************ */ + +static int ndpi_init_packet_header(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow, unsigned short packetlen) { const struct ndpi_iphdr *decaps_iph = NULL; u_int16_t l3len; @@ -3634,7 +3642,10 @@ static int ndpi_init_packet_header(struct ndpi_detection_module_struct *ndpi_str return(0); } -void ndpi_connection_tracking(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow) { +/* ************************************************ */ + +void ndpi_connection_tracking(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow) { if(!flow) { return; } else { @@ -3756,10 +3767,12 @@ void ndpi_connection_tracking(struct ndpi_detection_module_struct *ndpi_str, str } } +/* ************************************************ */ + void check_ndpi_other_flow_func(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, NDPI_SELECTION_BITMASK_PROTOCOL_SIZE *ndpi_selection_packet) { if(!flow) - return; + return; void *func = NULL; u_int32_t a; @@ -3797,6 +3810,8 @@ void check_ndpi_other_flow_func(struct ndpi_detection_module_struct *ndpi_str, s } } +/* ************************************************ */ + void check_ndpi_udp_flow_func(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, NDPI_SELECTION_BITMASK_PROTOCOL_SIZE *ndpi_selection_packet) { void *func = NULL; @@ -3838,7 +3853,10 @@ void check_ndpi_udp_flow_func(struct ndpi_detection_module_struct *ndpi_str, str } } -void check_ndpi_tcp_flow_func(struct ndpi_detection_module_struct *ndpi_str, struct ndpi_flow_struct *flow, +/* ************************************************ */ + +void check_ndpi_tcp_flow_func(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow, NDPI_SELECTION_BITMASK_PROTOCOL_SIZE *ndpi_selection_packet) { void *func = NULL; u_int32_t a; @@ -3931,16 +3949,16 @@ u_int16_t ndpi_guess_host_protocol_id(struct ndpi_detection_module_struct *ndpi_ if(flow->packet.iph) { struct in_addr addr; u_int16_t sport, dport; - + addr.s_addr = flow->packet.iph->saddr; - + if((flow->l4_proto == IPPROTO_TCP) && flow->packet.tcp) sport = flow->packet.tcp->source, dport = flow->packet.tcp->dest; else if((flow->l4_proto == IPPROTO_UDP) && flow->packet.udp) sport = flow->packet.udp->source, dport = flow->packet.udp->dest; else sport = dport = 0; - + /* guess host protocol */ ret = ndpi_network_port_ptree_match(ndpi_str, &addr, sport); @@ -4342,11 +4360,79 @@ static void ndpi_reset_packet_line_info(struct ndpi_packet_struct *packet) { /* ********************************************************************************* */ -#if 0 -static u_int16_t ndpi_checK_flow_port(, u_int16_t sport, u_int16_t dport) { +static int ndpi_check_protocol_port_mismatch_exceptions(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow, + ndpi_default_ports_tree_node_t *expected_proto, + ndpi_protocol *returned_proto) { + /* + For TLS (and other protocols) it is not simple to guess the exact protocol so before + triggering an alert we need to make sure what we have exhausted all the possible + options available + */ + if(returned_proto->master_protocol == NDPI_PROTOCOL_TLS) { + switch(expected_proto->proto->protoId) { + case NDPI_PROTOCOL_MAIL_IMAPS: + case NDPI_PROTOCOL_MAIL_POPS: + case NDPI_PROTOCOL_MAIL_SMTPS: + return(1); /* This is a reasonable exception */ + break; + } + } + + return(0); +} + +/* ********************************************************************************* */ + +static void ndpi_reconcile_protocols(struct ndpi_detection_module_struct *ndpi_str, + struct ndpi_flow_struct *flow, + ndpi_protocol *ret) { + /* + Skype for a host doing MS Teams means MS Teams + (MS Teams uses Skype as transport protocol for voice/video) + */ + + switch(ret->app_protocol) { + case NDPI_PROTOCOL_MSTEAMS: + if(flow->packet.iph && flow->packet.tcp) { + // printf("====>> NDPI_PROTOCOL_MSTEAMS\n"); + + if(ndpi_str->msteams_cache == NULL) + ndpi_str->msteams_cache = ndpi_lru_cache_init(1024); + + if(ndpi_str->msteams_cache) + ndpi_lru_add_to_cache(ndpi_str->msteams_cache, + flow->packet.iph->saddr, + flow->packet.tick_timestamp & 0xFFFF /* 16 bit */); + } + break; + + case NDPI_PROTOCOL_SKYPE: + case NDPI_PROTOCOL_SKYPE_CALL: + if(flow->packet.iph + && flow->packet.udp + && ndpi_str->msteams_cache) { + u_int16_t when; + + if(ndpi_lru_find_cache(ndpi_str->msteams_cache, flow->packet.iph->saddr, + &when, 0 /* Don't remove it as it can be used for other connections */)) { + u_int16_t tdiff = (flow->packet.tick_timestamp & 0xFFFF) - when; + + if(tdiff < 60 /* sec */) { + // printf("====>> NDPI_PROTOCOL_SKYPE(_CALL) -> NDPI_PROTOCOL_MSTEAMS [%u]\n", tdiff); + ret->app_protocol = NDPI_PROTOCOL_MSTEAMS; + + /* Refresh cache */ + ndpi_lru_add_to_cache(ndpi_str->msteams_cache, + flow->packet.iph->saddr, + flow->packet.tick_timestamp & 0xFFFF /* 16 bit */); + } + } + } + break; + } /* switch */ } -#endif /* ********************************************************************************* */ @@ -4586,7 +4672,7 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct if((!flow->risk_checked) && (ret.master_protocol != NDPI_PROTOCOL_UNKNOWN)) { ndpi_default_ports_tree_node_t *found; u_int16_t *default_ports, sport, dport; - + if(flow->packet.udp) found = ndpi_get_guessed_protocol_id(ndpi_str, IPPROTO_UDP, sport = ntohs(flow->packet.udp->source), @@ -4596,7 +4682,7 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct found = ndpi_get_guessed_protocol_id(ndpi_str, IPPROTO_TCP, sport = ntohs(flow->packet.tcp->source), dport = ntohs(flow->packet.tcp->dest)), - default_ports = ndpi_str->proto_defaults[ret.master_protocol].tcp_default_ports; + default_ports = ndpi_str->proto_defaults[ret.master_protocol].tcp_default_ports; else found = NULL, default_ports = NULL; @@ -4604,10 +4690,12 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct && (found->proto->protoId != NDPI_PROTOCOL_UNKNOWN) && (found->proto->protoId != ret.master_protocol)) { // printf("******** %u / %u\n", found->proto->protoId, ret.master_protocol); - NDPI_SET_BIT(flow->risk, NDPI_KNOWN_PROTOCOL_ON_NON_STANDARD_PORT); + + if(!ndpi_check_protocol_port_mismatch_exceptions(ndpi_str, flow, found, &ret)) + NDPI_SET_BIT(flow->risk, NDPI_KNOWN_PROTOCOL_ON_NON_STANDARD_PORT); } else if(default_ports && (default_ports[0] != 0)) { u_int8_t found = 0, i; - + for(i=0; (i<MAX_DEFAULT_PORTS) && (default_ports[i] != 0); i++) { if((default_ports[i] == sport) || (default_ports[i] == dport)) { found = 1; @@ -4620,10 +4708,11 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct NDPI_SET_BIT(flow->risk, NDPI_KNOWN_PROTOCOL_ON_NON_STANDARD_PORT); } } - + flow->risk_checked = 1; } - + + ndpi_reconcile_protocols(ndpi_str, flow, &ret); invalidate_ptr: /* @@ -4749,29 +4838,34 @@ u_int32_t ndpi_bytestream_to_ipv4(const u_int8_t *str, u_int16_t max_chars_to_re u_int16_t read = 0; u_int16_t oldread; u_int32_t c; + /* ip address must be X.X.X.X with each X between 0 and 255 */ oldread = read; c = ndpi_bytestream_to_number(str, max_chars_to_read, &read); if(c > 255 || oldread == read || max_chars_to_read == read || str[read] != '.') return(0); + read++; val = c << 24; oldread = read; c = ndpi_bytestream_to_number(&str[read], max_chars_to_read - read, &read); if(c > 255 || oldread == read || max_chars_to_read == read || str[read] != '.') return(0); + read++; val = val + (c << 16); oldread = read; c = ndpi_bytestream_to_number(&str[read], max_chars_to_read - read, &read); if(c > 255 || oldread == read || max_chars_to_read == read || str[read] != '.') return(0); + read++; val = val + (c << 8); oldread = read; c = ndpi_bytestream_to_number(&str[read], max_chars_to_read - read, &read); if(c > 255 || oldread == read || max_chars_to_read == read) return(0); + val = val + c; *bytes_read = *bytes_read + read; @@ -4805,14 +4899,16 @@ void ndpi_parse_packet_line_info(struct ndpi_detection_module_struct *ndpi_str, if(get_u_int16_t(packet->payload, a) == ntohs(0x0d0a)) { /* If end of line char sequence CR+NL "\r\n", process line */ - if(get_u_int16_t(packet->payload, a+2) == ntohs(0x0d0a)) { + if(((a + 3) <= packet->payload_packet_len) + && (get_u_int16_t(packet->payload, a+2) == ntohs(0x0d0a))) { /* \r\n\r\n */ int diff; /* No unsigned ! */ u_int32_t a1 = a + 4; - diff = ndpi_min(packet->payload_packet_len-a1, sizeof(flow->initial_binary_bytes)); - + diff = packet->payload_packet_len - a1; + if(diff > 0) { + diff = ndpi_min(diff, sizeof(flow->initial_binary_bytes)); memcpy(&flow->initial_binary_bytes, &packet->payload[a1], diff); flow->initial_binary_bytes_len = diff; } @@ -5814,27 +5910,21 @@ char *ndpi_strnstr(const char *s, const char *find, size_t slen) { /* * Same as ndpi_strnstr but case-insensitive */ -char *ndpi_strncasestr(const char *s, const char *find, size_t slen) { - char c; - size_t len; - - if((c = *find++) != '\0') { - len = strlen(find); - do { - char sc; - - do { - if(slen-- < 1 || (sc = *s++) == '\0') - return(NULL); - } while (sc != c); - - if(len > slen) - return(NULL); - } while (strncasecmp(s, find, len) != 0); - - s--; +const char * ndpi_strncasestr(const char *str1, const char *str2, size_t len) { + size_t str1_len = strnlen(str1, len); + size_t str2_len = strlen(str2); + size_t i; + + for(i = 0; i < (str1_len - str2_len + 1); i++){ + if(str1[0] == '\0') + return NULL; + else if(strncasecmp(str1, str2, str2_len) == 0) + return(str1); + + str1++; } - return((char *) s); + + return NULL; } /* ****************************************************** */ @@ -6065,6 +6155,9 @@ void ndpi_free_flow(struct ndpi_flow_struct *flow) { if(flow->l4.tcp.tls.srv_cert_fingerprint_ctx) ndpi_free(flow->l4.tcp.tls.srv_cert_fingerprint_ctx); + + if(flow->protos.stun_ssl.ssl.encrypted_sni.esni) + ndpi_free(flow->protos.stun_ssl.ssl.encrypted_sni.esni); } if(flow->l4_proto == IPPROTO_TCP) { diff --git a/src/lib/ndpi_serializer.c b/src/lib/ndpi_serializer.c index d8a0d13fc..a50f98860 100644 --- a/src/lib/ndpi_serializer.c +++ b/src/lib/ndpi_serializer.c @@ -146,15 +146,27 @@ void ndpi_reset_serializer(ndpi_serializer *_serializer) { if(serializer->fmt == ndpi_serialization_format_json) { u_int32_t buff_diff; - serializer->status.size_used = 0; - buff_diff = serializer->buffer_size - serializer->status.size_used; + serializer->status.buffer.size_used = 0; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; /* Note: please keep a space at the beginning as it is used for arrays when an end-of-record is used */ - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, " {}"); - } else if(serializer->fmt == ndpi_serialization_format_csv) - serializer->status.size_used = 0; - else /* ndpi_serialization_format_tlv */ - serializer->status.size_used = 2 * sizeof(u_int8_t); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, " {}"); + } else if(serializer->fmt == ndpi_serialization_format_csv) { + serializer->status.header.size_used = 0; + serializer->status.buffer.size_used = 0; + } else { /* ndpi_serialization_format_tlv */ + serializer->status.buffer.size_used = 2 * sizeof(u_int8_t); + } +} + +/* ********************************** */ + +static int ndpi_init_serializer_buffer(ndpi_private_serializer_buffer *buffer, u_int32_t buffer_size) { + buffer->initial_size = buffer->size = buffer_size; + buffer->data = (u_int8_t *) calloc(buffer->size, sizeof(u_int8_t)); + if(buffer->data == NULL) + return -1; + return 0; } /* ********************************** */ @@ -166,16 +178,22 @@ int ndpi_init_serializer_ll(ndpi_serializer *_serializer, memset(serializer, 0, sizeof(ndpi_private_serializer)); - serializer->initial_buffer_size = serializer->buffer_size = buffer_size; - serializer->buffer = (u_int8_t *) calloc(serializer->buffer_size, sizeof(u_int8_t)); + serializer->fmt = fmt; - if(serializer->buffer == NULL) + if (ndpi_init_serializer_buffer(&serializer->buffer, buffer_size) != 0) return(-1); + + if(serializer->fmt == ndpi_serialization_format_json) { + /* nothing to do */ - serializer->fmt = fmt; + } else if (fmt == ndpi_serialization_format_csv) { + if (ndpi_init_serializer_buffer(&serializer->header, NDPI_SERIALIZER_DEFAULT_HEADER_SIZE) != 0) + return(-1); - serializer->buffer[0] = 1; /* version */ - serializer->buffer[1] = (u_int8_t) fmt; + } else /* ndpi_serialization_format_tlv */ { + serializer->buffer.data[0] = 1; /* version */ + serializer->buffer.data[1] = (u_int8_t) fmt; + } serializer->csv_separator[0] = ','; serializer->csv_separator[1] = '\0'; @@ -194,45 +212,106 @@ int ndpi_init_serializer(ndpi_serializer *_serializer, /* ********************************** */ -static inline int ndpi_extend_serializer_buffer(ndpi_serializer *_serializer, u_int32_t min_len) { +static inline int ndpi_extend_serializer_buffer(ndpi_private_serializer_buffer *buffer, u_int32_t min_len) { u_int32_t new_size; void *r; - ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; if(min_len < NDPI_SERIALIZER_DEFAULT_BUFFER_INCR) { - if(serializer->initial_buffer_size < NDPI_SERIALIZER_DEFAULT_BUFFER_INCR) { - if(min_len < serializer->initial_buffer_size) - min_len = serializer->initial_buffer_size; + if(buffer->initial_size < NDPI_SERIALIZER_DEFAULT_BUFFER_INCR) { + if(min_len < buffer->initial_size) + min_len = buffer->initial_size; } else { min_len = NDPI_SERIALIZER_DEFAULT_BUFFER_INCR; } } - new_size = serializer->buffer_size + min_len; + new_size = buffer->size + min_len; new_size = ((new_size / 4) + 1) * 4; /* required by zmq encryption */ - r = realloc((void *) serializer->buffer, new_size); + r = realloc((void *) buffer->data, new_size); if(r == NULL) return(-1); - serializer->buffer = r; - serializer->buffer_size = new_size; + buffer->data = r; + buffer->size = new_size; return(0); } /* ********************************** */ +static inline int ndpi_serializer_check_header_room(ndpi_private_serializer *serializer, u_int32_t needed) { + u_int32_t buff_diff = serializer->header.size - serializer->status.header.size_used; + + if (buff_diff < needed) + if (ndpi_extend_serializer_buffer(&serializer->header, needed - buff_diff) < 0) + return -1; + + buff_diff = serializer->header.size - serializer->status.header.size_used; + + return buff_diff; +} + +/* ********************************** */ + +static inline int ndpi_serializer_header_uint32(ndpi_private_serializer *serializer, u_int32_t key) { + int room; + + if (serializer->status.flags & NDPI_SERIALIZER_STATUS_HDR_DONE) + return 0; + + room = ndpi_serializer_check_header_room(serializer, 12); + + if (room < 0) + return -1; + + serializer->status.header.size_used += snprintf((char *) &serializer->header.data[serializer->status.header.size_used], + room, "%s%u", (serializer->status.header.size_used > 0) ? serializer->csv_separator : "", key); + + return 0; +} + +/* ********************************** */ + +static inline int ndpi_serializer_header_string(ndpi_private_serializer *serializer, const char *key, u_int16_t klen) { + int room; + + if (serializer->status.flags & NDPI_SERIALIZER_STATUS_HDR_DONE) + return 0; + + room = ndpi_serializer_check_header_room(serializer, klen + 4); + + if (room < 0) + return -1; + + if (serializer->status.header.size_used > 0) { + int slen = strlen(serializer->csv_separator); + memcpy(&serializer->header.data[serializer->status.header.size_used], serializer->csv_separator, slen); + serializer->status.header.size_used += slen; + } + + if (klen > 0) { + memcpy(&serializer->header.data[serializer->status.header.size_used], key, klen); + serializer->status.header.size_used += klen; + } + + serializer->header.data[serializer->status.header.size_used] = '\0'; + + return 0; +} + +/* ********************************** */ + 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; + char *buf = (char*)serializer->buffer.data; - /* NULL terminate the buffer if there is space available */ - if(serializer->buffer_size > serializer->status.size_used) - serializer->buffer[serializer->status.size_used] = '\0'; + /* NULL terminate the buffer */ + if(serializer->buffer.size > serializer->status.buffer.size_used) /* safety check */ + serializer->buffer.data[serializer->status.buffer.size_used] = '\0'; - *buffer_len = serializer->status.size_used; + *buffer_len = serializer->status.buffer.size_used; if(serializer->fmt == ndpi_serialization_format_json) { while((buf[0] == '\0') || (buf[0] == ' ')) @@ -245,13 +324,13 @@ char* ndpi_serializer_get_buffer(ndpi_serializer *_serializer, u_int32_t *buffer /* ********************************** */ u_int32_t ndpi_serializer_get_buffer_len(ndpi_serializer *_serializer) { - return(((ndpi_private_serializer*)_serializer)->status.size_used); + return(((ndpi_private_serializer*)_serializer)->status.buffer.size_used); } /* ********************************** */ u_int32_t ndpi_serializer_get_internal_buffer_size(ndpi_serializer *_serializer) { - return(((ndpi_private_serializer*)_serializer)->buffer_size); + return(((ndpi_private_serializer*)_serializer)->buffer.size); } /* ********************************** */ @@ -260,10 +339,10 @@ int ndpi_serializer_set_buffer_len(ndpi_serializer *_serializer, u_int32_t l) { ndpi_private_serializer *p = (ndpi_private_serializer*)_serializer; if(p) { - if(p->buffer_size <= l) + if(p->buffer.size <= l) return(-1); /* Invalid size */ - p->status.size_used = l; + p->status.buffer.size_used = l; return(0); } @@ -272,6 +351,27 @@ int ndpi_serializer_set_buffer_len(ndpi_serializer *_serializer, u_int32_t l) { /* ********************************** */ +/* Return the header automatically built from keys (CSV only) */ +char* ndpi_serializer_get_header(ndpi_serializer *_serializer, u_int32_t *buffer_len) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + char *buf = (char*)serializer->header.data; + + if(buf == NULL) { + *buffer_len = 0; + return ""; + } + + /* NULL terminate the buffer */ + if(serializer->header.size > serializer->status.header.size_used) /* safety check */ + serializer->header.data[serializer->status.header.size_used] = '\0'; + + *buffer_len = serializer->status.header.size_used; + + return(buf); +} + +/* ********************************** */ + void ndpi_serializer_set_csv_separator(ndpi_serializer *_serializer, char separator) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; @@ -283,10 +383,16 @@ void ndpi_serializer_set_csv_separator(ndpi_serializer *_serializer, char separa 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; + if(serializer->buffer.data) { + free(serializer->buffer.data); + serializer->buffer.size = 0; + serializer->buffer.data = NULL; + } + + if(serializer->header.data) { + free(serializer->header.data); + serializer->header.size = 0; + serializer->header.data = NULL; } } @@ -296,8 +402,8 @@ static inline void ndpi_serialize_single_uint8(ndpi_private_serializer *serializ u_int8_t s) { u_int8_t v = s; - memcpy(&serializer->buffer[serializer->status.size_used], &v, sizeof(u_int8_t)); - serializer->status.size_used += sizeof(u_int8_t); + memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], &v, sizeof(u_int8_t)); + serializer->status.buffer.size_used += sizeof(u_int8_t); } /* ********************************** */ @@ -306,8 +412,8 @@ static inline void ndpi_serialize_single_uint16(ndpi_private_serializer *seriali u_int16_t s) { u_int16_t v = htons(s); - memcpy(&serializer->buffer[serializer->status.size_used], &v, sizeof(u_int16_t)); - serializer->status.size_used += sizeof(u_int16_t); + memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], &v, sizeof(u_int16_t)); + serializer->status.buffer.size_used += sizeof(u_int16_t); } /* ********************************** */ @@ -316,8 +422,8 @@ static inline void ndpi_serialize_single_uint32(ndpi_private_serializer *seriali u_int32_t s) { u_int32_t v = htonl(s); - memcpy(&serializer->buffer[serializer->status.size_used], &v, sizeof(u_int32_t)); - serializer->status.size_used += sizeof(u_int32_t); + memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], &v, sizeof(u_int32_t)); + serializer->status.buffer.size_used += sizeof(u_int32_t); } /* ********************************** */ @@ -326,8 +432,8 @@ static inline void ndpi_serialize_single_uint64(ndpi_private_serializer *seriali u_int64_t s) { u_int64_t v = ndpi_htonll(s); - memcpy(&serializer->buffer[serializer->status.size_used], &v, sizeof(u_int64_t)); - serializer->status.size_used += sizeof(u_int64_t); + memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], &v, sizeof(u_int64_t)); + serializer->status.buffer.size_used += sizeof(u_int64_t); } /* ********************************** */ @@ -335,8 +441,8 @@ static inline void ndpi_serialize_single_uint64(ndpi_private_serializer *seriali /* TODO: fix portability across platforms */ static inline void ndpi_serialize_single_float(ndpi_private_serializer *serializer, float s) { - memcpy(&serializer->buffer[serializer->status.size_used], &s, sizeof(s)); - serializer->status.size_used += sizeof(float); + memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], &s, sizeof(s)); + serializer->status.buffer.size_used += sizeof(float); } /* ********************************** */ @@ -345,69 +451,69 @@ static inline void ndpi_serialize_single_string(ndpi_private_serializer *seriali const char *s, u_int16_t slen) { u_int16_t l = htons(slen); - memcpy(&serializer->buffer[serializer->status.size_used], &l, sizeof(u_int16_t)); - serializer->status.size_used += sizeof(u_int16_t); + memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], &l, sizeof(u_int16_t)); + serializer->status.buffer.size_used += sizeof(u_int16_t); if(slen > 0) - memcpy(&serializer->buffer[serializer->status.size_used], s, slen); + memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], s, slen); - serializer->status.size_used += slen; + serializer->status.buffer.size_used += slen; } /* ********************************** */ static inline void ndpi_deserialize_single_uint8(ndpi_private_deserializer *deserializer, u_int32_t offset, u_int8_t *s) { - *s = (*((u_int8_t *) &deserializer->buffer[offset])); + *s = (*((u_int8_t *) &deserializer->buffer.data[offset])); } /* ********************************** */ static inline void ndpi_deserialize_single_uint16(ndpi_private_deserializer *deserializer, u_int32_t offset, u_int16_t *s) { - *s = ntohs(*((u_int16_t *) &deserializer->buffer[offset])); + *s = ntohs(*((u_int16_t *) &deserializer->buffer.data[offset])); } /* ********************************** */ static inline void ndpi_deserialize_single_uint32(ndpi_private_deserializer *deserializer, u_int32_t offset, u_int32_t *s) { - *s = ntohl(*((u_int32_t *) &deserializer->buffer[offset])); + *s = ntohl(*((u_int32_t *) &deserializer->buffer.data[offset])); } /* ********************************** */ static inline void ndpi_deserialize_single_int8(ndpi_private_deserializer *deserializer, u_int32_t offset, int8_t *s) { - *s = (*((int8_t *) &deserializer->buffer[offset])); + *s = (*((int8_t *) &deserializer->buffer.data[offset])); } /* ********************************** */ static inline void ndpi_deserialize_single_int16(ndpi_private_deserializer *deserializer, u_int32_t offset, int16_t *s) { - *s = ntohs(*((int16_t *) &deserializer->buffer[offset])); + *s = ntohs(*((int16_t *) &deserializer->buffer.data[offset])); } /* ********************************** */ static inline void ndpi_deserialize_single_int32(ndpi_private_deserializer *deserializer, u_int32_t offset, int32_t *s) { - *s = ntohl(*((int32_t *) &deserializer->buffer[offset])); + *s = ntohl(*((int32_t *) &deserializer->buffer.data[offset])); } /* ********************************** */ static inline void ndpi_deserialize_single_uint64(ndpi_private_deserializer *deserializer, u_int32_t offset, u_int64_t *s) { - *s = ndpi_ntohll(*(u_int64_t*)&deserializer->buffer[offset]); + *s = ndpi_ntohll(*(u_int64_t*)&deserializer->buffer.data[offset]); } /* ********************************** */ static inline void ndpi_deserialize_single_int64(ndpi_private_deserializer *deserializer, u_int32_t offset, int64_t *s) { - *s = ndpi_ntohll(*(int64_t*)&deserializer->buffer[offset]); + *s = ndpi_ntohll(*(int64_t*)&deserializer->buffer.data[offset]); } /* ********************************** */ @@ -415,15 +521,15 @@ static inline void ndpi_deserialize_single_int64(ndpi_private_deserializer *dese /* TODO: fix portability across platforms */ static inline void ndpi_deserialize_single_float(ndpi_private_deserializer *deserializer, u_int32_t offset, float *s) { - *s = *(float*)&deserializer->buffer[offset]; + *s = *(float*)&deserializer->buffer.data[offset]; } /* ********************************** */ static inline void ndpi_deserialize_single_string(ndpi_private_deserializer *deserializer, u_int32_t offset, ndpi_string *v) { - v->str_len = ntohs(*((u_int16_t *) &deserializer->buffer[offset])); - v->str = (char *) &deserializer->buffer[offset + sizeof(u_int16_t)]; + v->str_len = ntohs(*((u_int16_t *) &deserializer->buffer.data[offset])); + v->str = (char *) &deserializer->buffer.data[offset + sizeof(u_int16_t)]; } /* ********************************** */ @@ -436,39 +542,39 @@ static inline void ndpi_deserialize_single_string(ndpi_private_deserializer *des int ndpi_serialize_raw_record(ndpi_serializer *_serializer, u_char *record, u_int32_t record_len) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int16_t needed = record_len; u_int8_t add_comma = 0; if(serializer->fmt == ndpi_serialization_format_json) { needed += 1; - if(serializer->status.size_used == 3) /* Empty buffer [{} */ - serializer->status.size_used = 2; /* Remove {} */ + if(serializer->status.buffer.size_used == 3) /* Empty buffer [{} */ + serializer->status.buffer.size_used = 2; /* Remove {} */ else needed += 2, add_comma = 1; } if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { if(add_comma) - serializer->buffer[serializer->status.size_used-1] = ','; + serializer->buffer.data[serializer->status.buffer.size_used-1] = ','; else - serializer->status.size_used--; + serializer->status.buffer.size_used--; } - memcpy(&serializer->buffer[serializer->status.size_used], record, record_len); - serializer->status.size_used += record_len; + memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], record, record_len); + serializer->status.buffer.size_used += record_len; if(serializer->fmt == ndpi_serialization_format_json) { - serializer->buffer[serializer->status.size_used] = ']'; - if(add_comma) serializer->status.size_used++; + serializer->buffer.data[serializer->status.buffer.size_used] = ']'; + if(add_comma) serializer->status.buffer.size_used++; } ndpi_serialize_end_of_record(_serializer); @@ -480,29 +586,31 @@ int ndpi_serialize_raw_record(ndpi_serializer *_serializer, 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->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.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) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } - if(serializer->fmt == ndpi_serialization_format_json) { + if(serializer->fmt == ndpi_serialization_format_csv) { + serializer->status.flags |= NDPI_SERIALIZER_STATUS_HDR_DONE; + } else if(serializer->fmt == ndpi_serialization_format_json) { if(!(serializer->status.flags & NDPI_SERIALIZER_STATUS_ARRAY)) { - serializer->buffer[0] = '['; - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], + serializer->buffer.data[0] = '['; + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "]"); } serializer->status.flags |= NDPI_SERIALIZER_STATUS_ARRAY | NDPI_SERIALIZER_STATUS_EOR; serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_COMMA; } else { - serializer->buffer[serializer->status.size_used++] = ndpi_serialization_end_of_record; + serializer->buffer.data[serializer->status.buffer.size_used++] = ndpi_serialization_end_of_record; } serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_NOT_EMPTY; @@ -516,19 +624,28 @@ static inline void ndpi_serialize_json_pre(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; if(serializer->status.flags & NDPI_SERIALIZER_STATUS_EOR) { - serializer->status.size_used--; /* Remove ']' */ + serializer->status.buffer.size_used--; /* Remove ']' */ serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_EOR; - serializer->buffer[serializer->status.size_used++] = ','; - serializer->buffer[serializer->status.size_used++] = '{'; + serializer->buffer.data[serializer->status.buffer.size_used++] = ','; + serializer->buffer.data[serializer->status.buffer.size_used++] = '{'; } else { if(serializer->status.flags & NDPI_SERIALIZER_STATUS_ARRAY) - serializer->status.size_used--; /* Remove ']'*/ - serializer->status.size_used--; /* Remove '}'*/ + serializer->status.buffer.size_used--; /* Remove ']' */ - if(serializer->status.flags & NDPI_SERIALIZER_STATUS_SOB) - serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_SOB; - else if(serializer->status.flags & NDPI_SERIALIZER_STATUS_COMMA) - serializer->buffer[serializer->status.size_used++] = ','; + serializer->status.buffer.size_used--; /* Remove '}' */ + + if(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST) { + serializer->status.buffer.size_used--; /* Remove ']' */ + if(serializer->status.flags & NDPI_SERIALIZER_STATUS_SOL) + serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_SOL; + else + serializer->buffer.data[serializer->status.buffer.size_used++] = ','; + } else { + if(serializer->status.flags & NDPI_SERIALIZER_STATUS_SOB) + serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_SOB; + else if(serializer->status.flags & NDPI_SERIALIZER_STATUS_COMMA) + serializer->buffer.data[serializer->status.buffer.size_used++] = ','; + } } } @@ -537,9 +654,13 @@ static inline void ndpi_serialize_json_pre(ndpi_serializer *_serializer) { static inline void ndpi_serialize_json_post(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - serializer->buffer[serializer->status.size_used++] = '}'; + if(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST) + serializer->buffer.data[serializer->status.buffer.size_used++] = ']'; + + serializer->buffer.data[serializer->status.buffer.size_used++] = '}'; + if(serializer->status.flags & NDPI_SERIALIZER_STATUS_ARRAY) - serializer->buffer[serializer->status.size_used++] = ']'; + serializer->buffer.data[serializer->status.buffer.size_used++] = ']'; serializer->status.flags |= NDPI_SERIALIZER_STATUS_COMMA; } @@ -568,7 +689,7 @@ static inline ndpi_serialization_type ndpi_serialize_key_uint32(ndpi_private_ser 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->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int16_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + @@ -578,23 +699,34 @@ int ndpi_serialize_uint32_uint32(ndpi_serializer *_serializer, needed += 24; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - "\"%u\":%u", key, value); + + if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) { + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], + buff_diff, "\"%u\":", key); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + } + + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], + buff_diff, "%u", value); + ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - "%s%u", (serializer->status.size_used > 0) ? serializer->csv_separator : "", value); + if (ndpi_serializer_header_uint32(serializer, key) < 0) return(-1); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, + "%s%u", (serializer->status.buffer.size_used > 0) ? serializer->csv_separator : "", value); } else { ndpi_serialization_type kt; u_int8_t type = 0; - u_int32_t type_offset = serializer->status.size_used++; + u_int32_t type_offset = serializer->status.buffer.size_used++; kt = ndpi_serialize_key_uint32(serializer, key); type = (kt << 4); @@ -610,7 +742,7 @@ int ndpi_serialize_uint32_uint32(ndpi_serializer *_serializer, type |= ndpi_serialization_uint32; } - serializer->buffer[type_offset] = type; + serializer->buffer.data[type_offset] = type; } serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY; @@ -622,7 +754,7 @@ int ndpi_serialize_uint32_uint32(ndpi_serializer *_serializer, 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->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int16_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + @@ -632,20 +764,31 @@ int ndpi_serialize_uint32_uint64(ndpi_serializer *_serializer, needed += 32; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - "\"%u\":%llu", key, (unsigned long long)value); + + if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) { + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, + "\"%u\":", key); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + } + + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, + "%llu", (unsigned long long)value); + ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, + if (ndpi_serializer_header_uint32(serializer, key) < 0) return(-1); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "%s%llu", - (serializer->status.size_used > 0) ? serializer->csv_separator : "", + (serializer->status.buffer.size_used > 0) ? serializer->csv_separator : "", (unsigned long long)value); } else { if(value <= 0xffffffff) { @@ -653,7 +796,7 @@ int ndpi_serialize_uint32_uint64(ndpi_serializer *_serializer, } else { ndpi_serialization_type kt; u_int8_t type = 0; - u_int32_t type_offset = serializer->status.size_used++; + u_int32_t type_offset = serializer->status.buffer.size_used++; kt = ndpi_serialize_key_uint32(serializer, key); type = (kt << 4); @@ -661,7 +804,7 @@ int ndpi_serialize_uint32_uint64(ndpi_serializer *_serializer, ndpi_serialize_single_uint64(serializer, value); type |= ndpi_serialization_uint64; - serializer->buffer[type_offset] = type; + serializer->buffer.data[type_offset] = type; } } @@ -674,7 +817,7 @@ int ndpi_serialize_uint32_uint64(ndpi_serializer *_serializer, int ndpi_serialize_uint32_int32(ndpi_serializer *_serializer, u_int32_t key, int32_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int16_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + @@ -684,23 +827,34 @@ int ndpi_serialize_uint32_int32(ndpi_serializer *_serializer, needed += 24; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - "\"%u\":%d", key, value); + + if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) { + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], + buff_diff, "\"%u\":", key); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + } + + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], + buff_diff, "%d", value); + ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - "%s%d", (serializer->status.size_used > 0) ? serializer->csv_separator : "", value); + if (ndpi_serializer_header_uint32(serializer, key) < 0) return(-1); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, + "%s%d", (serializer->status.buffer.size_used > 0) ? serializer->csv_separator : "", value); } else { ndpi_serialization_type kt; u_int8_t type = 0; - u_int32_t type_offset = serializer->status.size_used++; + u_int32_t type_offset = serializer->status.buffer.size_used++; kt = ndpi_serialize_key_uint32(serializer, key); type = (kt << 4); @@ -716,7 +870,7 @@ int ndpi_serialize_uint32_int32(ndpi_serializer *_serializer, type |= ndpi_serialization_int32; } - serializer->buffer[type_offset] = type; + serializer->buffer.data[type_offset] = type; } serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY; @@ -728,7 +882,7 @@ int ndpi_serialize_uint32_int32(ndpi_serializer *_serializer, int ndpi_serialize_uint32_int64(ndpi_serializer *_serializer, u_int32_t key, int64_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int16_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + @@ -738,20 +892,31 @@ int ndpi_serialize_uint32_int64(ndpi_serializer *_serializer, needed += 32; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - "\"%u\":%lld", key, (long long int)value); + + if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) { + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], + buff_diff, "\"%u\":", key); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + } + + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], + buff_diff, "%lld", (long long int)value); + ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, + if (ndpi_serializer_header_uint32(serializer, key) < 0) return(-1); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "%s%lld", - (serializer->status.size_used > 0) ? serializer->csv_separator : "", + (serializer->status.buffer.size_used > 0) ? serializer->csv_separator : "", (long long int)value); } @@ -761,7 +926,7 @@ int ndpi_serialize_uint32_int64(ndpi_serializer *_serializer, } else { ndpi_serialization_type kt; u_int8_t type = 0; - u_int32_t type_offset = serializer->status.size_used++; + u_int32_t type_offset = serializer->status.buffer.size_used++; kt = ndpi_serialize_key_uint32(serializer, key); type = (kt << 4); @@ -769,7 +934,7 @@ int ndpi_serialize_uint32_int64(ndpi_serializer *_serializer, ndpi_serialize_single_uint64(serializer, value); type |= ndpi_serialization_int64; - serializer->buffer[type_offset] = type; + serializer->buffer.data[type_offset] = type; } } @@ -783,7 +948,7 @@ int ndpi_serialize_uint32_float(ndpi_serializer *_serializer, u_int32_t key, float value, const char *format /* e.f. "%.2f" */) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int16_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + @@ -793,25 +958,32 @@ int ndpi_serialize_uint32_float(ndpi_serializer *_serializer, needed += 32; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "\"%u\":", key); - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, format, value); + + if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) { + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "\"%u\":", key); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + } + + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, format, value); + ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "%s", - (serializer->status.size_used > 0) ? serializer->csv_separator : ""); - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, format, value); + if (ndpi_serializer_header_uint32(serializer, key) < 0) return(-1); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "%s", + (serializer->status.buffer.size_used > 0) ? serializer->csv_separator : ""); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, format, value); } else { ndpi_serialization_type kt; u_int8_t type = 0; - u_int32_t type_offset = serializer->status.size_used++; + u_int32_t type_offset = serializer->status.buffer.size_used++; kt = ndpi_serialize_key_uint32(serializer, key); type = (kt << 4); @@ -819,7 +991,7 @@ int ndpi_serialize_uint32_float(ndpi_serializer *_serializer, ndpi_serialize_single_float(serializer, value); type |= ndpi_serialization_float; - serializer->buffer[type_offset] = type; + serializer->buffer.data[type_offset] = type; } serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY; @@ -831,7 +1003,7 @@ int ndpi_serialize_uint32_float(ndpi_serializer *_serializer, static int ndpi_serialize_uint32_binary(ndpi_serializer *_serializer, u_int32_t key, const char *value, u_int16_t slen) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int32_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + @@ -842,27 +1014,31 @@ static int ndpi_serialize_uint32_binary(ndpi_serializer *_serializer, needed += 24 + slen; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - "\"%u\":", key); - buff_diff = serializer->buffer_size - serializer->status.size_used; - serializer->status.size_used += ndpi_json_string_escape(value, slen, - (char *) &serializer->buffer[serializer->status.size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->status.size_used; + + if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) { + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], + buff_diff, "\"%u\":", key); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + } + serializer->status.buffer.size_used += ndpi_json_string_escape(value, slen, + (char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - "%s%s", (serializer->status.size_used > 0) ? serializer->csv_separator : "", value); + if (ndpi_serializer_header_uint32(serializer, key) < 0) return(-1); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, + "%s%s", (serializer->status.buffer.size_used > 0) ? serializer->csv_separator : "", value); } else { ndpi_serialization_type kt; u_int8_t type = 0; - u_int32_t type_offset = serializer->status.size_used++; + u_int32_t type_offset = serializer->status.buffer.size_used++; kt = ndpi_serialize_key_uint32(serializer, key); type = (kt << 4); @@ -870,7 +1046,7 @@ static int ndpi_serialize_uint32_binary(ndpi_serializer *_serializer, ndpi_serialize_single_string(serializer, value, slen); type |= ndpi_serialization_string; - serializer->buffer[type_offset] = type; + serializer->buffer.data[type_offset] = type; } serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY; @@ -890,7 +1066,7 @@ int ndpi_serialize_uint32_string(ndpi_serializer *_serializer, int ndpi_serialize_uint32_boolean(ndpi_serializer *_serializer, u_int32_t key, u_int8_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int32_t needed = 24; if(serializer->fmt != ndpi_serialization_format_json && @@ -898,19 +1074,30 @@ int ndpi_serialize_uint32_boolean(ndpi_serializer *_serializer, return -1; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - "\"%u\":%s", key, value ? "true" : "false"); + + if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) { + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], + buff_diff, "\"%u\":", key); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + } + + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], + buff_diff, "%s", value ? "true" : "false"); + ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - "%s%s", (serializer->status.size_used > 0) ? serializer->csv_separator : "", + if (ndpi_serializer_header_uint32(serializer, key) < 0) return(-1); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, + "%s%s", (serializer->status.buffer.size_used > 0) ? serializer->csv_separator : "", value ? "true" : "false"); } @@ -924,7 +1111,7 @@ static int ndpi_serialize_binary_int32(ndpi_serializer *_serializer, const char *key, u_int16_t klen, int32_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int32_t needed; if(ndpi_is_number(key, klen)) @@ -940,33 +1127,42 @@ static int ndpi_serialize_binary_int32(ndpi_serializer *_serializer, needed += 16 + klen; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); - serializer->status.size_used += ndpi_json_string_escape(key, klen, - (char *) &serializer->buffer[serializer->status.size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->status.size_used; - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - ":%d", value); + + if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) { + serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, ":"); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + } + + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "%d", value); + ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - "%s%d", (serializer->status.size_used > 0) ? serializer->csv_separator : "", value); + if (ndpi_serializer_header_string(serializer, key, klen) < 0) return(-1); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, + "%s%d", (serializer->status.buffer.size_used > 0) ? serializer->csv_separator : "", value); } else { if(value <= 127 && value >= -128) { - serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int8; + serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int8; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint8(serializer, value); } else if(value <= 32767 && value >= -32768) { - serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int16; + serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int16; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint16(serializer, value); } else { - serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int32; + serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int32; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint32(serializer, value); } @@ -990,7 +1186,7 @@ int ndpi_serialize_binary_int64(ndpi_serializer *_serializer, const char *key, u_int16_t klen, int64_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int32_t needed; if(ndpi_is_number(key, klen)) @@ -1006,28 +1202,39 @@ int ndpi_serialize_binary_int64(ndpi_serializer *_serializer, needed += 16 + klen; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); - serializer->status.size_used += ndpi_json_string_escape(key, klen, - (char *) &serializer->buffer[serializer->status.size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->status.size_used; - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - ":%lld", (long long int)value); + + if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) { + serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, + ":"); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + } + + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, + "%lld", (long long int)value); + ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - "%s%lld", (serializer->status.size_used > 0) ? serializer->csv_separator : "", + if (ndpi_serializer_header_string(serializer, key, klen) < 0) return(-1); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, + "%s%lld", (serializer->status.buffer.size_used > 0) ? serializer->csv_separator : "", (long long int)value); } else { if ((value & 0xFFFFFFFF) == value) { return(ndpi_serialize_string_int32(_serializer, key, value)); } else { - serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int64; + serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_int64; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint32(serializer, value); } @@ -1049,7 +1256,7 @@ int ndpi_serialize_string_int64(ndpi_serializer *_serializer, static int ndpi_serialize_binary_uint32(ndpi_serializer *_serializer, const char *key, u_int16_t klen, u_int32_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int32_t needed; if(ndpi_is_number(key, klen)) @@ -1065,33 +1272,45 @@ static int ndpi_serialize_binary_uint32(ndpi_serializer *_serializer, needed += 16 + klen; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); - serializer->status.size_used += ndpi_json_string_escape(key, klen, - (char *) &serializer->buffer[serializer->status.size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->status.size_used; - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - ":%u", value); + + if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) { + serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], + buff_diff, ":"); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + } + + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], + buff_diff, "%u", value); + ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - "%s%u", (serializer->status.size_used > 0) ? serializer->csv_separator : "", value); + if (ndpi_serializer_header_string(serializer, key, klen) < 0) return(-1); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, + "%s%u", (serializer->status.buffer.size_used > 0) ? serializer->csv_separator : "", value); } else { if(value <= 0xff) { - serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint8; + serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint8; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint8(serializer, value); } else if(value <= 0xffff) { - serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint16; + serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint16; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint16(serializer, value); } else { - serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint32; + serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint32; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint32(serializer, value); } @@ -1136,7 +1355,7 @@ static int ndpi_serialize_binary_uint64(ndpi_serializer *_serializer, const char *key, u_int16_t klen, u_int64_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int32_t needed; if(ndpi_is_number(key, klen)) @@ -1152,28 +1371,39 @@ static int ndpi_serialize_binary_uint64(ndpi_serializer *_serializer, needed += 32 + klen; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); - serializer->status.size_used += ndpi_json_string_escape(key, klen, - (char *) &serializer->buffer[serializer->status.size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->status.size_used; - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - ":%llu", (unsigned long long)value); + + if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) { + serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, + ":"); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + } + + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, + "%llu", (unsigned long long)value); + ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, - "%s%llu", (serializer->status.size_used > 0) ? serializer->csv_separator : "", + if (ndpi_serializer_header_string(serializer, key, klen) < 0) return(-1); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, + "%s%llu", (serializer->status.buffer.size_used > 0) ? serializer->csv_separator : "", (unsigned long long)value); } else { if(value <= 0xffffffff) { return(ndpi_serialize_string_uint32(_serializer, key, value)); } else { - serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint64; + serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_uint64; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_uint64(serializer, value); } @@ -1198,7 +1428,7 @@ static int ndpi_serialize_binary_float(ndpi_serializer *_serializer, float value, const char *format /* e.f. "%.2f" */) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int32_t needed; if(ndpi_is_number(key, klen)) @@ -1214,30 +1444,32 @@ static int ndpi_serialize_binary_float(ndpi_serializer *_serializer, needed += 32 + klen; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); - serializer->status.size_used += ndpi_json_string_escape(key, klen, - (char *) &serializer->buffer[serializer->status.size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->status.size_used; - serializer->buffer[serializer->status.size_used] = ':'; - serializer->status.size_used++; + if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) { + serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + serializer->buffer.data[serializer->status.buffer.size_used] = ':'; + serializer->status.buffer.size_used++; + } - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, format, value); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, format, value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { - if(serializer->status.size_used > 0) - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, "%s", serializer->csv_separator); - - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, format, value); + if (ndpi_serializer_header_string(serializer, key, klen) < 0) return(-1); + if(serializer->status.buffer.size_used > 0) + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "%s", serializer->csv_separator); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, format, value); } else { - serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_float; + serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_float; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_float(serializer, value); @@ -1266,7 +1498,7 @@ static int ndpi_serialize_binary_raw(ndpi_serializer *_serializer, u_int16_t vlen, u_int8_t escape) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int32_t needed; needed = @@ -1280,32 +1512,37 @@ static int ndpi_serialize_binary_raw(ndpi_serializer *_serializer, needed += 16 + klen + vlen; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); - serializer->status.size_used += ndpi_json_string_escape(key, klen, - (char *) &serializer->buffer[serializer->status.size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->status.size_used; - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, ":"); - buff_diff = serializer->buffer_size - serializer->status.size_used; + + if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) { + serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, ":"); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + } if (escape) - serializer->status.size_used += ndpi_json_string_escape(value, vlen, - (char *) &serializer->buffer[serializer->status.size_used], buff_diff); + serializer->status.buffer.size_used += ndpi_json_string_escape(value, vlen, + (char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff); else - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, value, vlen); + ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, + if (ndpi_serializer_header_string(serializer, key, klen) < 0) return(-1); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "%s%s", ndpi_serialize_is_not_empty(_serializer) ? serializer->csv_separator : "", value); } else { - serializer->buffer[serializer->status.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_string; + serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_string; ndpi_serialize_single_string(serializer, key, klen); ndpi_serialize_single_string(serializer, value, vlen); @@ -1362,7 +1599,7 @@ int ndpi_serialize_string_raw(ndpi_serializer *_serializer, int ndpi_serialize_string_boolean(ndpi_serializer *_serializer, const char *key, u_int8_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int16_t klen = strlen(key); u_int32_t needed; @@ -1376,21 +1613,31 @@ int ndpi_serialize_string_boolean(ndpi_serializer *_serializer, needed = klen + 16; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); - serializer->status.size_used += ndpi_json_string_escape(key, klen, - (char *) &serializer->buffer[serializer->status.size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->status.size_used; - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, ":%s", + + if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) { + serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, ":"); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + } + + serializer->status.buffer.size_used += snprintf((char *) + &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "%s", value ? "true" : "false"); + ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, + if (ndpi_serializer_header_string(serializer, key, strlen(key)) < 0) return(-1); + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "%s%s", ndpi_serialize_is_not_empty(_serializer) ? serializer->csv_separator : "", value ? "true" : "false"); } @@ -1401,11 +1648,63 @@ int ndpi_serialize_string_boolean(ndpi_serializer *_serializer, /* ********************************** */ +/* Serialize start of simple list (JSON only)*/ +int ndpi_serialize_start_of_list(ndpi_serializer *_serializer, + const char *key) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + u_int32_t needed, klen = strlen(key); + + if(serializer->fmt != ndpi_serialization_format_json) + return(-1); + + needed = 16 + klen; + + if(buff_diff < needed) { + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) + return(-1); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + } + + ndpi_serialize_json_pre(_serializer); + + serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, ": ["); + + serializer->status.flags |= NDPI_SERIALIZER_STATUS_LIST | NDPI_SERIALIZER_STATUS_SOL; + + ndpi_serialize_json_post(_serializer); + + return(0); +} + +/* ********************************** */ + +/* Serialize start of simple list (JSON only)*/ +int ndpi_serialize_end_of_list(ndpi_serializer *_serializer) { + ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; + + if(serializer->fmt != ndpi_serialization_format_json) + return(-1); + + if(serializer->status.flags & NDPI_SERIALIZER_STATUS_SOL) /* Empty list */ + serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_SOL; + + serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_LIST; + + return(0); +} + +/* ********************************** */ + /* Serialize start of nested block (JSON only)*/ int ndpi_serialize_start_of_block(ndpi_serializer *_serializer, const char *key) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int32_t needed, klen = strlen(key); if(serializer->fmt != ndpi_serialization_format_json) @@ -1414,17 +1713,17 @@ int ndpi_serialize_start_of_block(ndpi_serializer *_serializer, needed = 16 + klen; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } ndpi_serialize_json_pre(_serializer); - serializer->status.size_used += ndpi_json_string_escape(key, klen, - (char *) &serializer->buffer[serializer->status.size_used], buff_diff); - buff_diff = serializer->buffer_size - serializer->status.size_used; - serializer->status.size_used += snprintf((char *) &serializer->buffer[serializer->status.size_used], buff_diff, ": {"); - buff_diff = serializer->buffer_size - serializer->status.size_used; + serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen, + (char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; + serializer->status.buffer.size_used += snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, ": {"); + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; ndpi_serialize_json_post(_serializer); serializer->status.flags |= NDPI_SERIALIZER_STATUS_SOB; @@ -1434,10 +1733,10 @@ int ndpi_serialize_start_of_block(ndpi_serializer *_serializer, /* ********************************** */ -/* Serialize start of nested block (JSON only)*/ +/* Serialize end of nested block (JSON only)*/ int ndpi_serialize_end_of_block(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; u_int32_t needed; if(serializer->fmt != ndpi_serialization_format_json) @@ -1446,15 +1745,15 @@ int ndpi_serialize_end_of_block(ndpi_serializer *_serializer) { needed = 4; if(buff_diff < needed) { - if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0) return(-1); - buff_diff = serializer->buffer_size - serializer->status.size_used; + buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } if(serializer->status.flags & NDPI_SERIALIZER_STATUS_SOB) /* Empty block */ serializer->status.flags &= ~NDPI_SERIALIZER_STATUS_SOB; - // buff_diff = serializer->buffer_size - serializer->status.size_used; + // buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; ndpi_serialize_json_post(_serializer); return(0); @@ -1488,10 +1787,10 @@ void ndpi_serializer_rollback_snapshot(ndpi_serializer *_serializer) { if(serializer->fmt == ndpi_serialization_format_json) { if(serializer->status.flags & NDPI_SERIALIZER_STATUS_ARRAY) { - serializer->buffer[serializer->status.size_used-1] = ']'; + serializer->buffer.data[serializer->status.buffer.size_used-1] = ']'; } else { - serializer->buffer[0] = ' '; - serializer->buffer[serializer->status.size_used-1] = '}'; + serializer->buffer.data[0] = ' '; + serializer->buffer.data[serializer->status.buffer.size_used-1] = '}'; } } } @@ -1508,13 +1807,13 @@ int ndpi_init_deserializer_buf(ndpi_deserializer *_deserializer, if(serialized_buffer_len < (2 * sizeof(u_int8_t))) return(-1); - deserializer->buffer = serialized_buffer; + deserializer->buffer.data = serialized_buffer; - if(deserializer->buffer[0] != 1) + if(deserializer->buffer.data[0] != 1) return(-2); /* Invalid version */ - deserializer->buffer_size = serialized_buffer_len; - deserializer->fmt = deserializer->buffer[1]; + deserializer->buffer.size = serialized_buffer_len; + deserializer->fmt = deserializer->buffer.data[1]; ndpi_reset_serializer(_deserializer); return(0); @@ -1527,8 +1826,8 @@ int ndpi_init_deserializer(ndpi_deserializer *deserializer, ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; return(ndpi_init_deserializer_buf(deserializer, - serializer->buffer, - serializer->status.size_used)); + serializer->buffer.data, + serializer->status.buffer.size_used)); } /* ********************************** */ @@ -1543,10 +1842,10 @@ ndpi_serialization_format ndpi_deserialize_get_format(ndpi_deserializer *_deseri static inline ndpi_serialization_type ndpi_deserialize_get_key_subtype(ndpi_private_deserializer *deserializer) { u_int8_t type; - if(deserializer->status.size_used >= deserializer->buffer_size) + if(deserializer->status.buffer.size_used >= deserializer->buffer.size) return(ndpi_serialization_unknown); - type = deserializer->buffer[deserializer->status.size_used]; + type = deserializer->buffer.data[deserializer->status.buffer.size_used]; return((ndpi_serialization_type) (type >> 4)); } @@ -1556,10 +1855,10 @@ static inline ndpi_serialization_type ndpi_deserialize_get_key_subtype(ndpi_priv static inline ndpi_serialization_type ndpi_deserialize_get_value_subtype(ndpi_private_deserializer *deserializer) { u_int8_t type; - if(deserializer->status.size_used >= deserializer->buffer_size) + if(deserializer->status.buffer.size_used >= deserializer->buffer.size) return(ndpi_serialization_unknown); - type = deserializer->buffer[deserializer->status.size_used]; + type = deserializer->buffer.data[deserializer->status.buffer.size_used]; return(ndpi_serialization_type) (type & 0xf); } @@ -1605,13 +1904,13 @@ ndpi_serialization_type ndpi_deserialize_get_item_type(ndpi_deserializer *_deser /* ********************************** */ static inline int ndpi_deserialize_get_single_string_size(ndpi_private_deserializer *deserializer, u_int32_t offset) { - u_int32_t buff_diff = deserializer->buffer_size - offset; + u_int32_t buff_diff = deserializer->buffer.size - offset; u_int16_t expected, str_len; expected = sizeof(u_int16_t) /* len */; if(buff_diff < expected) return(-2); - str_len = ntohs(*((u_int16_t *) &deserializer->buffer[offset])); + str_len = ntohs(*((u_int16_t *) &deserializer->buffer.data[offset])); expected += str_len; if(buff_diff < expected) return(-2); @@ -1663,7 +1962,7 @@ static inline int ndpi_deserialize_get_single_size(ndpi_private_deserializer *de int ndpi_deserialize_next(ndpi_deserializer *_deserializer) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer *) _deserializer; - u_int32_t buff_diff = deserializer->buffer_size - deserializer->status.size_used; + u_int32_t buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used; ndpi_serialization_type kt, et; u_int16_t expected; int size; @@ -1673,20 +1972,20 @@ int ndpi_deserialize_next(ndpi_deserializer *_deserializer) { if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); expected += size; - deserializer->status.size_used += expected; + deserializer->status.buffer.size_used += expected; return(0); } @@ -1696,7 +1995,7 @@ int ndpi_deserialize_next(ndpi_deserializer *_deserializer) { int ndpi_deserialize_key_uint32(ndpi_deserializer *_deserializer, u_int32_t *key) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; - u_int32_t offset, buff_diff = deserializer->buffer_size - deserializer->status.size_used; + u_int32_t offset, buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used; ndpi_serialization_type kt; u_int16_t expected; u_int16_t v16; @@ -1708,10 +2007,10 @@ int ndpi_deserialize_key_uint32(ndpi_deserializer *_deserializer, kt = ndpi_deserialize_get_key_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); - offset = deserializer->status.size_used + expected; + offset = deserializer->status.buffer.size_used + expected; switch(kt) { case ndpi_serialization_uint32: @@ -1739,7 +2038,7 @@ int ndpi_deserialize_key_string(ndpi_deserializer *_deserializer, ndpi_string *key) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; ndpi_serialization_type kt; - u_int32_t buff_diff = deserializer->buffer_size - deserializer->status.size_used; + u_int32_t buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used; u_int16_t expected; int size; @@ -1748,10 +2047,10 @@ int ndpi_deserialize_key_string(ndpi_deserializer *_deserializer, kt = ndpi_deserialize_get_key_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); - ndpi_deserialize_single_string(deserializer, deserializer->status.size_used + expected, key); + ndpi_deserialize_single_string(deserializer, deserializer->status.buffer.size_used + expected, key); return(0); } @@ -1762,7 +2061,7 @@ int ndpi_deserialize_value_uint32(ndpi_deserializer *_deserializer, u_int32_t *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; ndpi_serialization_type kt, et; - u_int32_t offset, buff_diff = deserializer->buffer_size - deserializer->status.size_used; + u_int32_t offset, buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used; u_int16_t v16; u_int8_t v8; u_int16_t expected; @@ -1772,16 +2071,16 @@ int ndpi_deserialize_value_uint32(ndpi_deserializer *_deserializer, if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); - offset = deserializer->status.size_used + expected; + offset = deserializer->status.buffer.size_used + expected; switch(et) { case ndpi_serialization_uint32: @@ -1808,7 +2107,7 @@ int ndpi_deserialize_value_uint64(ndpi_deserializer *_deserializer, u_int64_t *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; ndpi_serialization_type kt, et; - u_int32_t buff_diff = deserializer->buffer_size - deserializer->status.size_used; + u_int32_t buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used; u_int32_t v32; u_int16_t expected; int size; @@ -1818,13 +2117,13 @@ int ndpi_deserialize_value_uint64(ndpi_deserializer *_deserializer, if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); if(et != ndpi_serialization_uint64) { @@ -1834,7 +2133,7 @@ int ndpi_deserialize_value_uint64(ndpi_deserializer *_deserializer, return(rc); } - ndpi_deserialize_single_uint64(deserializer, deserializer->status.size_used + expected, value); + ndpi_deserialize_single_uint64(deserializer, deserializer->status.buffer.size_used + expected, value); return(0); } @@ -1845,7 +2144,7 @@ int ndpi_deserialize_value_int32(ndpi_deserializer *_deserializer, int32_t *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; ndpi_serialization_type kt, et; - u_int32_t offset, buff_diff = deserializer->buffer_size - deserializer->status.size_used; + u_int32_t offset, buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used; int16_t v16; int8_t v8; u_int16_t expected; @@ -1855,16 +2154,16 @@ int ndpi_deserialize_value_int32(ndpi_deserializer *_deserializer, if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); - offset = deserializer->status.size_used + expected; + offset = deserializer->status.buffer.size_used + expected; switch(et) { case ndpi_serialization_int32: @@ -1891,7 +2190,7 @@ int ndpi_deserialize_value_int64(ndpi_deserializer *_deserializer, int64_t *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; ndpi_serialization_type kt, et; - u_int32_t buff_diff = deserializer->buffer_size - deserializer->status.size_used; + u_int32_t buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used; int32_t v32; u_int16_t expected; int size; @@ -1901,13 +2200,13 @@ int ndpi_deserialize_value_int64(ndpi_deserializer *_deserializer, if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); if(et != ndpi_serialization_int64) { @@ -1917,7 +2216,7 @@ int ndpi_deserialize_value_int64(ndpi_deserializer *_deserializer, return(rc); } - ndpi_deserialize_single_int64(deserializer, deserializer->status.size_used + expected, value); + ndpi_deserialize_single_int64(deserializer, deserializer->status.buffer.size_used + expected, value); return(0); } @@ -1928,7 +2227,7 @@ int ndpi_deserialize_value_float(ndpi_deserializer *_deserializer, float *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; ndpi_serialization_type kt, et; - u_int32_t buff_diff = deserializer->buffer_size - deserializer->status.size_used; + u_int32_t buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used; u_int16_t expected; int size; @@ -1936,19 +2235,19 @@ int ndpi_deserialize_value_float(ndpi_deserializer *_deserializer, if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); if(et != ndpi_serialization_float) return(-1); - ndpi_deserialize_single_float(deserializer, deserializer->status.size_used + expected, value); + ndpi_deserialize_single_float(deserializer, deserializer->status.buffer.size_used + expected, value); return(0); } @@ -1959,7 +2258,7 @@ int ndpi_deserialize_value_string(ndpi_deserializer *_deserializer, ndpi_string *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; ndpi_serialization_type kt, et; - u_int32_t buff_diff = deserializer->buffer_size - deserializer->status.size_used; + u_int32_t buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used; u_int16_t expected; int size; @@ -1967,19 +2266,19 @@ int ndpi_deserialize_value_string(ndpi_deserializer *_deserializer, if(buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); if(et != ndpi_serialization_string) return(-1); - ndpi_deserialize_single_string(deserializer, deserializer->status.size_used + expected, value); + ndpi_deserialize_single_string(deserializer, deserializer->status.buffer.size_used + expected, value); return(0); } @@ -1990,8 +2289,8 @@ int ndpi_deserialize_value_string(ndpi_deserializer *_deserializer, int ndpi_deserialize_clone_item(ndpi_deserializer *_deserializer, ndpi_serializer *_serializer) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer *) _deserializer; ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; - u_int32_t src_buff_diff = deserializer->buffer_size - deserializer->status.size_used; - u_int32_t dst_buff_diff = serializer->buffer_size - serializer->status.size_used; + u_int32_t src_buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used; + u_int32_t dst_buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; ndpi_serialization_type kt, et; u_int16_t expected; int size; @@ -2004,30 +2303,30 @@ int ndpi_deserialize_clone_item(ndpi_deserializer *_deserializer, ndpi_serialize if(src_buff_diff < expected) return(-2); kt = ndpi_deserialize_get_key_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); expected += size; et = ndpi_deserialize_get_value_subtype(deserializer); - size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.size_used + expected); + size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected); if(size < 0) return(-2); expected += size; if(dst_buff_diff < expected) { - if(ndpi_extend_serializer_buffer(_serializer, expected - dst_buff_diff) < 0) + if(ndpi_extend_serializer_buffer(&serializer->buffer, expected - dst_buff_diff) < 0) return(-1); - dst_buff_diff = serializer->buffer_size - serializer->status.size_used; + dst_buff_diff = serializer->buffer.size - serializer->status.buffer.size_used; } - memcpy(&serializer->buffer[serializer->status.size_used], - &deserializer->buffer[deserializer->status.size_used], + memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], + &deserializer->buffer.data[deserializer->status.buffer.size_used], expected); - serializer->status.size_used += expected; + serializer->status.buffer.size_used += expected; return(0); } diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c index 4a30b1954..00fb47dad 100644 --- a/src/lib/ndpi_utils.c +++ b/src/lib/ndpi_utils.c @@ -902,63 +902,44 @@ char* ndpi_base64_encode(unsigned char const* bytes_to_encode, size_t in_len) { } /* ********************************** */ -/* ********************************** */ -int ndpi_flow2json(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow, - u_int8_t ip_version, - u_int8_t l4_protocol, u_int16_t vlan_id, - u_int32_t src_v4, u_int32_t dst_v4, - struct ndpi_in6_addr *src_v6, struct ndpi_in6_addr *dst_v6, - u_int16_t src_port, u_int16_t dst_port, - ndpi_protocol l7_protocol, - ndpi_serializer *serializer) { - char buf[64], src_name[32], dst_name[32]; - - if(ndpi_init_serializer(serializer, ndpi_serialization_format_json) == -1) - return(-1); +void ndpi_serialize_risk(ndpi_serializer *serializer, + struct ndpi_flow_struct *flow) { + if(flow->risk != 0) { + u_int32_t i; - if(ip_version == 4) { - inet_ntop(AF_INET, &src_v4, src_name, sizeof(src_name)); - inet_ntop(AF_INET, &dst_v4, dst_name, sizeof(dst_name)); - } else { - inet_ntop(AF_INET6, src_v6, src_name, sizeof(src_name)); - inet_ntop(AF_INET6, dst_v6, dst_name, sizeof(dst_name)); - /* For consistency across platforms replace :0: with :: */ - ndpi_patchIPv6Address(src_name), ndpi_patchIPv6Address(dst_name); + ndpi_serialize_start_of_block(serializer, "flow_risk"); + + for(i = 0; i < NDPI_MAX_RISK; i++) { + ndpi_risk_enum r = (ndpi_risk_enum)i; + + if(NDPI_ISSET_BIT(flow->risk, r)) + ndpi_serialize_uint32_string(serializer, i, ndpi_risk2str(r)); + } + + ndpi_serialize_end_of_block(serializer); } +} - ndpi_serialize_string_string(serializer, "src_ip", src_name); - ndpi_serialize_string_string(serializer, "dest_ip", dst_name); - if(src_port) ndpi_serialize_string_uint32(serializer, "src_port", src_port); - if(dst_port) ndpi_serialize_string_uint32(serializer, "dst_port", dst_port); - - switch(l4_protocol) { - case IPPROTO_TCP: - ndpi_serialize_string_string(serializer, "proto", "TCP"); - break; - - case IPPROTO_UDP: - ndpi_serialize_string_string(serializer, "proto", "UDP"); - break; - - case IPPROTO_ICMP: - ndpi_serialize_string_string(serializer, "proto", "ICMP"); - break; +/* ********************************** */ +/* ********************************** */ - default: - ndpi_serialize_string_uint32(serializer, "proto", l4_protocol); - break; - } +/* NOTE: serializer must have been already initialized */ +int ndpi_dpi2json(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + ndpi_protocol l7_protocol, + ndpi_serializer *serializer) { + char buf[64]; + if(flow == NULL) return(-1); + ndpi_serialize_start_of_block(serializer, "ndpi"); + ndpi_serialize_risk(serializer, flow); ndpi_serialize_string_string(serializer, "proto", ndpi_protocol2name(ndpi_struct, l7_protocol, buf, sizeof(buf))); if(l7_protocol.category != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) ndpi_serialize_string_string(serializer, "category", ndpi_category_get_name(ndpi_struct, l7_protocol.category)); ndpi_serialize_end_of_block(serializer); - if(flow == NULL) return(0); - switch(l7_protocol.master_protocol ? l7_protocol.master_protocol : l7_protocol.app_protocol) { case NDPI_PROTOCOL_DHCP: ndpi_serialize_start_of_block(serializer, "dhcp"); @@ -1148,6 +1129,59 @@ int ndpi_flow2json(struct ndpi_detection_module_struct *ndpi_struct, /* ********************************** */ +/* NOTE: serializer is initialized by the function */ +int ndpi_flow2json(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + u_int8_t ip_version, + u_int8_t l4_protocol, u_int16_t vlan_id, + u_int32_t src_v4, u_int32_t dst_v4, + struct ndpi_in6_addr *src_v6, struct ndpi_in6_addr *dst_v6, + u_int16_t src_port, u_int16_t dst_port, + ndpi_protocol l7_protocol, + ndpi_serializer *serializer) { + char src_name[32], dst_name[32]; + + if(ndpi_init_serializer(serializer, ndpi_serialization_format_json) == -1) + return(-1); + + if(ip_version == 4) { + inet_ntop(AF_INET, &src_v4, src_name, sizeof(src_name)); + inet_ntop(AF_INET, &dst_v4, dst_name, sizeof(dst_name)); + } else { + inet_ntop(AF_INET6, src_v6, src_name, sizeof(src_name)); + inet_ntop(AF_INET6, dst_v6, dst_name, sizeof(dst_name)); + /* For consistency across platforms replace :0: with :: */ + ndpi_patchIPv6Address(src_name), ndpi_patchIPv6Address(dst_name); + } + + ndpi_serialize_string_string(serializer, "src_ip", src_name); + ndpi_serialize_string_string(serializer, "dest_ip", dst_name); + if(src_port) ndpi_serialize_string_uint32(serializer, "src_port", src_port); + if(dst_port) ndpi_serialize_string_uint32(serializer, "dst_port", dst_port); + + switch(l4_protocol) { + case IPPROTO_TCP: + ndpi_serialize_string_string(serializer, "proto", "TCP"); + break; + + case IPPROTO_UDP: + ndpi_serialize_string_string(serializer, "proto", "UDP"); + break; + + case IPPROTO_ICMP: + ndpi_serialize_string_string(serializer, "proto", "ICMP"); + break; + + default: + ndpi_serialize_string_uint32(serializer, "proto", l4_protocol); + break; + } + + return(ndpi_dpi2json(ndpi_struct, flow, l7_protocol, serializer)); +} + +/* ********************************** */ + const char* ndpi_tunnel2str(ndpi_packet_tunnel tt) { switch(tt) { case ndpi_no_tunnel: @@ -1457,6 +1491,9 @@ const char* ndpi_risk2str(ndpi_risk_enum risk) { case NDPI_HTTP_SUSPICIOUS_URL: return("HTTP Suspicious URL"); + + case NDPI_HTTP_SUSPICIOUS_HEADER: + return("HTTP Suspicious Header"); default: snprintf(buf, sizeof(buf), "%d", (int)risk); diff --git a/src/lib/protocols/bittorrent.c b/src/lib/protocols/bittorrent.c index f1c62d431..9f7620558 100644 --- a/src/lib/protocols/bittorrent.c +++ b/src/lib/protocols/bittorrent.c @@ -43,7 +43,7 @@ struct ndpi_utp_hdr { u_int16_t sequence_nr, ack_nr; }; -static u_int8_t is_utp_pkt(const u_int8_t *payload, u_int payload_len) { +static u_int8_t is_utpv1_pkt(const u_int8_t *payload, u_int payload_len) { struct ndpi_utp_hdr *h = (struct ndpi_utp_hdr*)payload; if(payload_len < sizeof(struct ndpi_utp_hdr)) return(0); @@ -52,6 +52,9 @@ static u_int8_t is_utp_pkt(const u_int8_t *payload, u_int payload_len) { if(h->next_extension > 2) return(0); if(ntohl(h->window_size) > 65565) return(0); + if((h->window_size == 0) && (payload_len != sizeof(struct ndpi_utp_hdr))) + return(0); + return(1); } @@ -433,14 +436,10 @@ void ndpi_search_bittorrent(struct ndpi_detection_module_struct *ndpi_struct, st u_int8_t v0_extension = packet->payload[17]; u_int8_t v0_flags = packet->payload[18]; - /* Check if this is protocol v1 */ - u_int8_t v1_version = packet->payload[0]; - u_int8_t v1_extension = packet->payload[1]; - u_int32_t v1_window_size = *((u_int32_t*)&packet->payload[12]); - - if(is_utp_pkt(packet->payload, packet->payload_packet_len)) + if(is_utpv1_pkt(packet->payload, packet->payload_packet_len)) { + bt_proto = ndpi_strnstr((const char *)&packet->payload[20], "BitTorrent protocol", packet->payload_packet_len-20); goto bittorrent_found; - else if((packet->payload[0]== 0x60) + } else if((packet->payload[0]== 0x60) && (packet->payload[1]== 0x0) && (packet->payload[2]== 0x0) && (packet->payload[3]== 0x0) @@ -448,14 +447,7 @@ void ndpi_search_bittorrent(struct ndpi_detection_module_struct *ndpi_struct, st /* Heuristic */ bt_proto = ndpi_strnstr((const char *)&packet->payload[20], "BitTorrent protocol", packet->payload_packet_len-20); goto bittorrent_found; - /* CSGO/DOTA conflict */ - } else if(flow->packet_counter > 8 && ((v1_version & 0x0f) == 1) - && ((v1_version >> 4) < 5 /* ST_NUM_STATES */) - && (v1_extension < 3 /* EXT_NUM_EXT */) - && (v1_window_size < 32768 /* 32k */) - ) { - bt_proto = ndpi_strnstr((const char *)&packet->payload[20], "BitTorrent protocol", packet->payload_packet_len-20); - goto bittorrent_found; + /* CSGO/DOTA conflict */ } else if((v0_flags < 6 /* ST_NUM_STATES */) && (v0_extension < 3 /* EXT_NUM_EXT */)) { u_int32_t ts = ntohl(*((u_int32_t*)&(packet->payload[4]))); u_int32_t now; diff --git a/src/lib/protocols/http.c b/src/lib/protocols/http.c index abd422007..7b83b91e7 100644 --- a/src/lib/protocols/http.c +++ b/src/lib/protocols/http.c @@ -28,20 +28,16 @@ #include "ndpi_api.h" #include <stdlib.h> -static const char* binary_file_mimes[] = { - "exe", - "vnd.ms-cab-compressed", - "vnd.microsoft.portable-executable" - "x-msdownload", - "x-dosexec", - NULL -}; +static const char* binary_file_mimes_e[] = { "exe", NULL }; +static const char* binary_file_mimes_v[] = { "vnd.ms-cab-compressed", "vnd.microsoft.portable-executable", NULL }; +static const char* binary_file_mimes_x[] = { "x-msdownload", "x-dosexec", NULL }; +#define ATTACHMENT_LEN 3 static const char* binary_file_ext[] = { - ".exe", - ".msi", - ".cab", - NULL + "exe", + "msi", + "cab", + NULL }; static void ndpi_search_http_tcp(struct ndpi_detection_module_struct *ndpi_struct, @@ -49,7 +45,7 @@ static void ndpi_search_http_tcp(struct ndpi_detection_module_struct *ndpi_struc /* *********************************************** */ -static void ndpi_analyze_content_signature(struct ndpi_flow_struct *flow) { +static void ndpi_analyze_content_signature(struct ndpi_flow_struct *flow) { if((flow->initial_binary_bytes_len >= 2) && (flow->initial_binary_bytes[0] == 0x4D) && (flow->initial_binary_bytes[1] == 0x5A)) NDPI_SET_BIT(flow->risk, NDPI_BINARY_APPLICATION_TRANSFER); /* Win executable */ else if((flow->initial_binary_bytes_len >= 4) && (flow->initial_binary_bytes[0] == 0x7F) && (flow->initial_binary_bytes[1] == 'E') @@ -65,7 +61,7 @@ static void ndpi_analyze_content_signature(struct ndpi_flow_struct *flow) { NDPI_SET_BIT(flow->risk, NDPI_BINARY_APPLICATION_TRANSFER); /* Unix script (e.g. #!/bin/sh) */ else if(flow->initial_binary_bytes_len >= 8) { u_int8_t exec_pattern[] = { 0x64, 0x65, 0x78, 0x0A, 0x30, 0x33, 0x35, 0x00 }; - + if(memcmp(flow->initial_binary_bytes, exec_pattern, 8) == 0) NDPI_SET_BIT(flow->risk, NDPI_BINARY_APPLICATION_TRANSFER); /* Dalvik Executable (Android) */ } @@ -85,7 +81,7 @@ static int ndpi_search_http_tcp_again(struct ndpi_detection_module_struct *ndpi_ && (flow->http.response_status_code != 0) ) { /* stop extra processing */ - + if(flow->initial_binary_bytes_len) ndpi_analyze_content_signature(flow); flow->extra_packets_func = NULL; /* We're good now */ return(0); @@ -106,47 +102,69 @@ static ndpi_protocol_category_t ndpi_http_check_content(struct ndpi_detection_mo u_int app_len = sizeof("application"); if(packet->content_line.len > app_len) { - const char *app = (const char *)&packet->content_line.ptr[app_len]; - u_int app_len_avail = packet->content_line.len-app_len; - - if(ndpi_strncasestr(app, "mpeg", app_len_avail) != NULL) { + const char *app = (const char *)&packet->content_line.ptr[app_len]; + u_int app_len_avail = packet->content_line.len-app_len; + + if(strncasecmp(app, "mpeg", app_len_avail) == 0) { flow->guessed_category = flow->category = NDPI_PROTOCOL_CATEGORY_STREAMING; return(flow->category); - } else { - for (int i = 0; binary_file_mimes[i] != NULL; i++) { - if (ndpi_strncasestr(app, binary_file_mimes[i], app_len_avail) != NULL) { - flow->guessed_category = flow->category = NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT; - NDPI_SET_BIT(flow->risk, NDPI_BINARY_APPLICATION_TRANSFER); - NDPI_LOG_INFO(ndpi_struct, "found executable HTTP transfer"); - return(flow->category); - } - } + } else if(app_len_avail > 3) { + const char** cmp_mimes = NULL; + + switch(app[0]) { + case 'e': cmp_mimes = binary_file_mimes_e; break; + case 'v': cmp_mimes = binary_file_mimes_v; break; + case 'x': cmp_mimes = binary_file_mimes_x; break; + } + + if(cmp_mimes != NULL) { + u_int8_t i; + + for(i = 0; cmp_mimes[i] != NULL; i++) { + if(strncasecmp(app, cmp_mimes[i], app_len_avail) == 0) { + flow->guessed_category = flow->category = NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT; + NDPI_SET_BIT(flow->risk, NDPI_BINARY_APPLICATION_TRANSFER); + NDPI_LOG_INFO(ndpi_struct, "found executable HTTP transfer"); + return(flow->category); + } + } + } } } /* check for attachment */ - if (packet->content_disposition_line.len > 0) { - uint8_t attachment_len = sizeof("attachment; filename"); - if (packet->content_disposition_line.len > attachment_len) { - uint8_t filename_len = packet->content_disposition_line.len - attachment_len; - for (int i = 0; binary_file_ext[i] != NULL; i++) { - if (ndpi_strncasestr((const char*)&packet->content_disposition_line.ptr[attachment_len], - binary_file_ext[i], filename_len)) { - flow->guessed_category = flow->category = NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT; - NDPI_SET_BIT(flow->risk, NDPI_BINARY_APPLICATION_TRANSFER); - NDPI_LOG_INFO(ndpi_struct, "found executable HTTP transfer"); - return(flow->category); - } + if (packet->content_disposition_line.len > 0) { + u_int8_t attachment_len = sizeof("attachment; filename"); + + if(packet->content_disposition_line.len > attachment_len) { + u_int8_t filename_len = packet->content_disposition_line.len - attachment_len; + + if(filename_len > ATTACHMENT_LEN) { + attachment_len += filename_len-ATTACHMENT_LEN-1; + + if((attachment_len+ATTACHMENT_LEN) <= packet->content_disposition_line.len) { + for(int i = 0; binary_file_ext[i] != NULL; i++) { + /* Use memcmp in case content-disposition contains binary data */ + if(memcmp((const char*)&packet->content_disposition_line.ptr[attachment_len], + binary_file_ext[i], ATTACHMENT_LEN) == 0) { + flow->guessed_category = flow->category = NDPI_PROTOCOL_CATEGORY_DOWNLOAD_FT; + NDPI_SET_BIT(flow->risk, NDPI_BINARY_APPLICATION_TRANSFER); + NDPI_LOG_INFO(ndpi_struct, "found executable HTTP transfer"); + return(flow->category); + } + } + } + } } } - } + switch(packet->content_line.ptr[0]) { case 'a': if(strncasecmp((const char *)packet->content_line.ptr, "audio", ndpi_min(packet->content_line.len, 5)) == 0) flow->guessed_category = flow->category = NDPI_PROTOCOL_CATEGORY_MEDIA; break; - + case 'v': if(strncasecmp((const char *)packet->content_line.ptr, "video", ndpi_min(packet->content_line.len, 5)) == 0) @@ -178,7 +196,6 @@ static void ndpi_int_http_add_connection(struct ndpi_detection_module_struct *nd if((flow->guessed_host_protocol_id == NDPI_PROTOCOL_UNKNOWN) || (http_protocol != NDPI_PROTOCOL_HTTP)) flow->guessed_host_protocol_id = http_protocol; - category = ndpi_http_check_content(ndpi_struct, flow); ndpi_int_reset_protocol(flow); ndpi_set_detected_protocol(ndpi_struct, flow, flow->guessed_host_protocol_id, NDPI_PROTOCOL_HTTP); @@ -186,7 +203,7 @@ static void ndpi_int_http_add_connection(struct ndpi_detection_module_struct *nd flow->check_extra_packets = 1; flow->max_extra_packets_to_check = 5; flow->extra_packets_func = ndpi_search_http_tcp_again; - flow->http_detected = 1, flow->guessed_category = flow->category = category; + flow->http_detected = 1; } /* ************************************************************* */ @@ -220,7 +237,7 @@ static void setHttpUserAgent(struct ndpi_detection_module_struct *ndpi_struct, * https://github.com/ua-parser/uap-core/blob/master/regexes.yaml */ snprintf((char*)flow->protos.http.detected_os, - sizeof(flow->protos.http.detected_os), "%s", ua); + sizeof(flow->protos.http.detected_os), "%s", ua); } /* ************************************************************* */ @@ -232,7 +249,7 @@ static void ndpi_http_parse_subprotocol(struct ndpi_detection_module_struct *ndp if(double_col) double_col[0] = '\0'; - ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HTTP, + ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HTTP, (char *)flow->host_server_name, strlen((const char *)flow->host_server_name)); } @@ -246,7 +263,7 @@ static void ndpi_check_user_agent(struct ndpi_detection_module_struct *ndpi_stru if((!ua) || (ua[0] == '\0')) return; // printf("[%s:%d] ==> '%s'\n", __FILE__, __LINE__, ua); - + if((strlen(ua) < 4) || (!strcmp(ua, "test")) || (!strcmp(ua, "<?")) @@ -262,13 +279,13 @@ static void ndpi_check_numeric_ip(struct ndpi_detection_module_struct *ndpi_stru char *ip, u_int ip_len) { char buf[22]; struct in_addr ip_addr; - + strncpy(buf, ip, ip_len); buf[ip_len] = '\0'; ip_addr.s_addr = inet_addr(buf); if(strcmp(inet_ntoa(ip_addr), buf) == 0) { - NDPI_SET_BIT(flow->risk, NDPI_HTTP_NUMERIC_IP_HOST); + NDPI_SET_BIT(flow->risk, NDPI_HTTP_NUMERIC_IP_HOST); } } @@ -301,9 +318,9 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_ int len = packet->http_url_name.len + packet->host_line.len + 1; if(isdigit(packet->host_line.ptr[0]) - && (packet->host_line.len < 21)) + && (packet->host_line.len < 21)) ndpi_check_numeric_ip(ndpi_struct, flow, (char*)packet->host_line.ptr, packet->host_line.len); - + flow->http.url = ndpi_malloc(len); if(flow->http.url) { strncpy(flow->http.url, (char*)packet->host_line.ptr, packet->host_line.len); @@ -352,7 +369,7 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_ strncpy(ua, (const char *)packet->user_agent_line.ptr, mlen); ua[mlen] = '\0'; - + if(strncmp(ua, "Mozilla", 7) == 0) { char *parent = strchr(ua, '('); @@ -517,7 +534,8 @@ static void check_content_type_and_change_protocol(struct ndpi_detection_module_ strncpy(flow->http.content_type, (char*)packet->content_line.ptr, packet->content_line.len); flow->http.content_type[packet->content_line.len] = '\0'; - } + + flow->guessed_category = flow->category = ndpi_http_check_content(ndpi_struct, flow);} } if(flow->http_detected) { @@ -595,6 +613,106 @@ static void http_bitmask_exclude_other(struct ndpi_flow_struct *flow) NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_XBOX); } +/* *********************************************************************************************** */ + +/* Trick to speed-up detection */ +static const char* suspicious_http_header_keys_A[] = { "Arch", NULL}; +static const char* suspicious_http_header_keys_C[] = { "Cores", NULL}; +static const char* suspicious_http_header_keys_M[] = { "Mem", NULL}; +static const char* suspicious_http_header_keys_O[] = { "Os", "Osname", "Osversion", NULL}; +static const char* suspicious_http_header_keys_R[] = { "Root", NULL}; +static const char* suspicious_http_header_keys_S[] = { "S", NULL}; +static const char* suspicious_http_header_keys_T[] = { "TLS_version", NULL}; +static const char* suspicious_http_header_keys_U[] = { "Uuid", NULL}; +static const char* suspicious_http_header_keys_X[] = { "X-Hire-Me", NULL}; + +static int is_a_suspicious_header(const char* suspicious_headers[], struct ndpi_int_one_line_struct packet_line){ + int i; + unsigned int header_len; + const u_int8_t* header_limit; + + if((header_limit = memchr(packet_line.ptr, ':', packet_line.len))) { + header_len = header_limit - packet_line.ptr; + for(i=0; suspicious_headers[i] != NULL; i++){ + if(!strncasecmp((const char*) packet_line.ptr, + suspicious_headers[i], header_len)) + return 1; + } + } + + return 0; +} + +/* *********************************************************************************************** */ + +static void ndpi_check_http_header(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) { + u_int32_t i; + struct ndpi_packet_struct *packet = &flow->packet; + + for(i=0; (i < packet->parsed_lines) + && (packet->line[i].ptr != NULL) + && (packet->line[i].len > 0); i++) { + switch(packet->line[i].ptr[0]){ + case 'A': + if(is_a_suspicious_header(suspicious_http_header_keys_A, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'C': + if(is_a_suspicious_header(suspicious_http_header_keys_C, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'M': + if(is_a_suspicious_header(suspicious_http_header_keys_M, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'O': + if(is_a_suspicious_header(suspicious_http_header_keys_O, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'R': + if(is_a_suspicious_header(suspicious_http_header_keys_R, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'S': + if(is_a_suspicious_header(suspicious_http_header_keys_S, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'T': + if(is_a_suspicious_header(suspicious_http_header_keys_T, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'U': + if(is_a_suspicious_header(suspicious_http_header_keys_U, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + break; + case 'X': + if(is_a_suspicious_header(suspicious_http_header_keys_X, packet->line[i])) { + NDPI_SET_BIT(flow->risk, NDPI_HTTP_SUSPICIOUS_HEADER); + return; + } + + break; + } + } +} + /*************************************************************************************************/ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct, @@ -694,6 +812,7 @@ static void ndpi_check_http_tcp(struct ndpi_detection_module_struct *ndpi_struct "Filename HTTP found: %d, we look for line info..\n", filename_start); ndpi_parse_packet_line_info(ndpi_struct, flow); + ndpi_check_http_header(ndpi_struct, flow); if(packet->parsed_lines <= 1) { NDPI_LOG_DBG2(ndpi_struct, diff --git a/src/lib/protocols/kerberos.c b/src/lib/protocols/kerberos.c index ff16545f5..f4c1a175a 100644 --- a/src/lib/protocols/kerberos.c +++ b/src/lib/protocols/kerberos.c @@ -202,11 +202,13 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct, if(body_offset < packet->payload_packet_len) { - u_int16_t name_offset; - - name_offset = body_offset + 13; - for(i=0; i<20; i++) if(packet->payload[name_offset] != 0x1b) name_offset++; /* ASN.1 */ - + u_int16_t name_offset = body_offset + 13; + + for(i=0; (i<20) && (name_offset < packet->payload_packet_len); i++) { + if(packet->payload[name_offset] != 0x1b) + name_offset++; /* ASN.1 */ + } + #ifdef KERBEROS_DEBUG printf("name_offset=%u [%02X %02X] [byte 0 must be 0x1b]\n", name_offset, packet->payload[name_offset], packet->payload[name_offset+1]); #endif @@ -256,30 +258,38 @@ void ndpi_search_kerberos(struct ndpi_detection_module_struct *ndpi_struct, } else snprintf(flow->protos.kerberos.username, sizeof(flow->protos.kerberos.username), "%s", cname_str); - for(i=0; i<14; i++) if(packet->payload[realm_offset] != 0x1b) realm_offset++; /* ASN.1 */ + for(i=0; (i < 14) && (realm_offset < packet->payload_packet_len); i++) { + if(packet->payload[realm_offset] != 0x1b) + realm_offset++; /* ASN.1 */ + } + #ifdef KERBEROS_DEBUG - printf("realm_offset=%u [%02X %02X] [byte 0 must be 0x1b]\n", realm_offset, packet->payload[realm_offset], packet->payload[realm_offset+1]); + printf("realm_offset=%u [%02X %02X] [byte 0 must be 0x1b]\n", realm_offset, + packet->payload[realm_offset], packet->payload[realm_offset+1]); #endif + realm_offset += 1; //if(num_cname == 2) realm_offset++; - realm_len = packet->payload[realm_offset]; + if(realm_offset < packet->payload_packet_len) { + realm_len = packet->payload[realm_offset]; - if((realm_offset+realm_len) < packet->payload_packet_len) { - char realm_str[48]; + if((realm_offset+realm_len) < packet->payload_packet_len) { + char realm_str[48]; - if(realm_len > sizeof(realm_str)-1) - realm_len = sizeof(realm_str)-1; + if(realm_len > sizeof(realm_str)-1) + realm_len = sizeof(realm_str)-1; - realm_offset += 1; + realm_offset += 1; - strncpy(realm_str, (char*)&packet->payload[realm_offset], realm_len); - realm_str[realm_len] = '\0'; - for(i=0; i<realm_len; i++) realm_str[i] = tolower(realm_str[i]); + strncpy(realm_str, (char*)&packet->payload[realm_offset], realm_len); + realm_str[realm_len] = '\0'; + for(i=0; i<realm_len; i++) realm_str[i] = tolower(realm_str[i]); #ifdef KERBEROS_DEBUG - printf("[AS-REQ][Kerberos Realm][len: %u][%s]\n", realm_len, realm_str); + printf("[AS-REQ][Kerberos Realm][len: %u][%s]\n", realm_len, realm_str); #endif - snprintf(flow->protos.kerberos.domain, sizeof(flow->protos.kerberos.domain), "%s", realm_str); + snprintf(flow->protos.kerberos.domain, sizeof(flow->protos.kerberos.domain), "%s", realm_str); + } } } } diff --git a/src/lib/protocols/spotify.c b/src/lib/protocols/spotify.c index a180a1ea7..d66109016 100644 --- a/src/lib/protocols/spotify.c +++ b/src/lib/protocols/spotify.c @@ -47,7 +47,7 @@ static void ndpi_check_spotify(struct ndpi_detection_module_struct *ndpi_struct, if((packet->udp->source == spotify_port) && (packet->udp->dest == spotify_port)) { - if(payload_len > 2) { + if(payload_len >= 7) { if(memcmp(packet->payload, "SpotUdp", 7) == 0) { NDPI_LOG_INFO(ndpi_struct, "found spotify udp dissector\n"); ndpi_int_spotify_add_connection(ndpi_struct, flow, 0); diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c index fd783d099..87d090daf 100644 --- a/src/lib/protocols/stun.c +++ b/src/lib/protocols/stun.c @@ -161,7 +161,7 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct * /* This looks like an invalid packet */ if(flow->protos.stun_ssl.stun.num_udp_pkts > 0) { - flow->guessed_host_protocol_id = NDPI_PROTOCOL_WHATSAPP_CALL; + // flow->guessed_host_protocol_id = NDPI_PROTOCOL_WHATSAPP_CALL; return(NDPI_IS_STUN); } else return(NDPI_IS_NOT_STUN); diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c index 62b2e3cf8..222fa480d 100644 --- a/src/lib/protocols/tls.c +++ b/src/lib/protocols/tls.c @@ -34,13 +34,13 @@ extern char *strptime(const char *s, const char *format, struct tm *tm); extern int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow); -// #define DEBUG_TLS_MEMORY 1 -// #define DEBUG_TLS 1 - +// #define DEBUG_TLS_MEMORY 1 +// #define DEBUG_TLS 1 // #define DEBUG_CERTIFICATE_HASH -/* #define DEBUG_FINGERPRINT 1 */ +/* #define DEBUG_FINGERPRINT 1 */ +/* #define DEBUG_ENCRYPTED_SNI 1 */ /* NOTE @@ -390,77 +390,83 @@ static void processCertificateElements(struct ndpi_detection_module_struct *ndpi i += 3 /* skip the initial patten 55 1D 11 */; i++; /* skip the first type, 0x04 == BIT STRING, and jump to it's length */ - i += (packet->payload[i] & 0x80) ? (packet->payload[i] & 0x7F) : 0; /* skip BIT STRING length */ - i += 2; /* skip the second type, 0x30 == SEQUENCE, and jump to it's length */ - i += (packet->payload[i] & 0x80) ? (packet->payload[i] & 0x7F) : 0; /* skip SEQUENCE length */ - i++; - - while(i < packet->payload_packet_len) { - if(packet->payload[i] == 0x82) { - if((i < (packet->payload_packet_len - 1)) - && ((i + packet->payload[i + 1] + 2) < packet->payload_packet_len)) { - u_int8_t len = packet->payload[i + 1]; - char dNSName[256]; - - i += 2; - - /* The check "len > sizeof(dNSName) - 1" will be always false. If we add it, - the compiler is smart enough to detect it and throws a warning */ - if(len == 0 /* Looks something went wrong */) - break; + if(i < packet->payload_packet_len) { + i += (packet->payload[i] & 0x80) ? (packet->payload[i] & 0x7F) : 0; /* skip BIT STRING length */ + if(i < packet->payload_packet_len) { + i += 2; /* skip the second type, 0x30 == SEQUENCE, and jump to it's length */ + if(i < packet->payload_packet_len) { + i += (packet->payload[i] & 0x80) ? (packet->payload[i] & 0x7F) : 0; /* skip SEQUENCE length */ + i++; + + while(i < packet->payload_packet_len) { + if(packet->payload[i] == 0x82) { + if((i < (packet->payload_packet_len - 1)) + && ((i + packet->payload[i + 1] + 2) < packet->payload_packet_len)) { + u_int8_t len = packet->payload[i + 1]; + char dNSName[256]; + + i += 2; + + /* The check "len > sizeof(dNSName) - 1" will be always false. If we add it, + the compiler is smart enough to detect it and throws a warning */ + if(len == 0 /* Looks something went wrong */) + break; - strncpy(dNSName, (const char*)&packet->payload[i], len); - dNSName[len] = '\0'; + strncpy(dNSName, (const char*)&packet->payload[i], len); + dNSName[len] = '\0'; - cleanupServerName(dNSName, len); + cleanupServerName(dNSName, len); #if DEBUG_TLS - printf("[TLS] dNSName %s [%s]\n", dNSName, flow->protos.stun_ssl.ssl.client_requested_server_name); + printf("[TLS] dNSName %s [%s]\n", dNSName, flow->protos.stun_ssl.ssl.client_requested_server_name); #endif - if(matched_name == 0) { - if((dNSName[0] == '*') && strstr(flow->protos.stun_ssl.ssl.client_requested_server_name, &dNSName[1])) - matched_name = 1; - else if(strcmp(flow->protos.stun_ssl.ssl.client_requested_server_name, dNSName) == 0) - matched_name = 1; - } + if(matched_name == 0) { + if((dNSName[0] == '*') && strstr(flow->protos.stun_ssl.ssl.client_requested_server_name, &dNSName[1])) + matched_name = 1; + else if(strcmp(flow->protos.stun_ssl.ssl.client_requested_server_name, dNSName) == 0) + matched_name = 1; + } - if(flow->protos.stun_ssl.ssl.server_names == NULL) - flow->protos.stun_ssl.ssl.server_names = ndpi_strdup(dNSName), - flow->protos.stun_ssl.ssl.server_names_len = strlen(dNSName); - else { - u_int16_t dNSName_len = strlen(dNSName); - u_int16_t newstr_len = flow->protos.stun_ssl.ssl.server_names_len + dNSName_len + 1; - char *newstr = (char*)ndpi_realloc(flow->protos.stun_ssl.ssl.server_names, - flow->protos.stun_ssl.ssl.server_names_len+1, newstr_len+1); - - if(newstr) { - flow->protos.stun_ssl.ssl.server_names = newstr; - flow->protos.stun_ssl.ssl.server_names[flow->protos.stun_ssl.ssl.server_names_len] = ','; - strncpy(&flow->protos.stun_ssl.ssl.server_names[flow->protos.stun_ssl.ssl.server_names_len+1], - dNSName, dNSName_len+1); - flow->protos.stun_ssl.ssl.server_names[newstr_len] = '\0'; - flow->protos.stun_ssl.ssl.server_names_len = newstr_len; - } - } + if(flow->protos.stun_ssl.ssl.server_names == NULL) + flow->protos.stun_ssl.ssl.server_names = ndpi_strdup(dNSName), + flow->protos.stun_ssl.ssl.server_names_len = strlen(dNSName); + else { + u_int16_t dNSName_len = strlen(dNSName); + u_int16_t newstr_len = flow->protos.stun_ssl.ssl.server_names_len + dNSName_len + 1; + char *newstr = (char*)ndpi_realloc(flow->protos.stun_ssl.ssl.server_names, + flow->protos.stun_ssl.ssl.server_names_len+1, newstr_len+1); + + if(newstr) { + flow->protos.stun_ssl.ssl.server_names = newstr; + flow->protos.stun_ssl.ssl.server_names[flow->protos.stun_ssl.ssl.server_names_len] = ','; + strncpy(&flow->protos.stun_ssl.ssl.server_names[flow->protos.stun_ssl.ssl.server_names_len+1], + dNSName, dNSName_len+1); + flow->protos.stun_ssl.ssl.server_names[newstr_len] = '\0'; + flow->protos.stun_ssl.ssl.server_names_len = newstr_len; + } + } - if(!flow->l4.tcp.tls.subprotocol_detected) - if(ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_TLS, dNSName, len)) - flow->l4.tcp.tls.subprotocol_detected = 1; + if(!flow->l4.tcp.tls.subprotocol_detected) + if(ndpi_match_hostname_protocol(ndpi_struct, flow, NDPI_PROTOCOL_TLS, dNSName, len)) + flow->l4.tcp.tls.subprotocol_detected = 1; - i += len; - } else { + i += len; + } else { #if DEBUG_TLS - printf("[TLS] Leftover %u bytes", packet->payload_packet_len - i); + printf("[TLS] Leftover %u bytes", packet->payload_packet_len - i); #endif - break; + break; + } + } else { + break; + } + } /* while */ + + if(!matched_name) + NDPI_SET_BIT(flow->risk, NDPI_TLS_CERTIFICATE_MISMATCH); /* Certificate mismatch */ } - } else { - break; } - } /* while */ - - if(!matched_name) - NDPI_SET_BIT(flow->risk, NDPI_TLS_CERTIFICATE_MISMATCH); /* Certificate mismatch */ + } } } @@ -1252,10 +1258,59 @@ int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct, if(flow->protos.stun_ssl.ssl.tls_supported_versions == NULL) flow->protos.stun_ssl.ssl.tls_supported_versions = ndpi_strdup(version_str); } - + } else if(extension_id == 65486 /* encrypted server name */) { + /* + - https://tools.ietf.org/html/draft-ietf-tls-esni-06 + - https://blog.cloudflare.com/encrypted-sni/ + */ + u_int16_t e_offset = offset+extension_offset; + u_int16_t initial_offset = e_offset; + u_int16_t e_sni_len, cipher_suite = ntohs(*((u_int16_t*)&packet->payload[e_offset])); + + flow->protos.stun_ssl.ssl.encrypted_sni.cipher_suite = cipher_suite; + + e_offset += 2; /* Cipher suite len */ + + /* Key Share Entry */ + e_offset += 2; /* Group */ + e_offset += ntohs(*((u_int16_t*)&packet->payload[e_offset])) + 2; /* Lenght */ + + if((e_offset+4) < packet->payload_packet_len) { + /* Record Digest */ + e_offset += ntohs(*((u_int16_t*)&packet->payload[e_offset])) + 2; /* Lenght */ + + if((e_offset+4) < packet->payload_packet_len) { + e_sni_len = ntohs(*((u_int16_t*)&packet->payload[e_offset])); + e_offset += 2; + + if((e_offset+e_sni_len-extension_len-initial_offset) >= 0) { +#ifdef DEBUG_ENCRYPTED_SNI + printf("Client SSL [Encrypted Server Name len: %u]\n", e_sni_len); +#endif + + if(flow->protos.stun_ssl.ssl.encrypted_sni.esni == NULL) { + flow->protos.stun_ssl.ssl.encrypted_sni.esni = (char*)ndpi_malloc(e_sni_len*2+1); + + if(flow->protos.stun_ssl.ssl.encrypted_sni.esni) { + u_int16_t i, off; + + for(i=e_offset, off=0; i<(e_offset+e_sni_len); i++) { + int rc = sprintf(&flow->protos.stun_ssl.ssl.encrypted_sni.esni[off], "%02X", packet->payload[i] & 0XFF); + + if(rc <= 0) { + flow->protos.stun_ssl.ssl.encrypted_sni.esni[off] = '\0'; + break; + } else + off += rc; + } + } + } + } + } + } } - extension_offset += extension_len; + extension_offset += extension_len; /* Move to the next extension */ #ifdef DEBUG_TLS printf("Client SSL [extension_offset/len: %u/%u]\n", extension_offset, extension_len); diff --git a/tests/pcap/encrypted_sni.pcap b/tests/pcap/encrypted_sni.pcap Binary files differnew file mode 100644 index 000000000..9f9f55dee --- /dev/null +++ b/tests/pcap/encrypted_sni.pcap diff --git a/tests/pcap/imaps.pcap b/tests/pcap/imaps.pcap Binary files differnew file mode 100644 index 000000000..c038b57e2 --- /dev/null +++ b/tests/pcap/imaps.pcap diff --git a/tests/result/encrypted_sni.pcap.out b/tests/result/encrypted_sni.pcap.out new file mode 100644 index 000000000..979a98615 --- /dev/null +++ b/tests/result/encrypted_sni.pcap.out @@ -0,0 +1,10 @@ +Cloudflare 3 2310 3 + +JA3 Host Stats: + IP Address # JA3C + 1 192.168.1.12 1 + + + 1 TCP 192.168.1.12:49886 -> 104.27.129.77:443 [proto: 91.220/TLS.Cloudflare][cat: Web/5][1 pkts/770 bytes -> 0 pkts/0 bytes][Goodput ratio: 93/0][< 1 sec][ALPN: h2;http/1.1][TLS Supported Versions: TLSv1.3;TLSv1.2;TLSv1.1;TLSv1][TLSv1.2][JA3C: e5ef852e686954ba9fe060fbfa881e15][ESNI: 9624CB3C4E230827F78CF5BF640D22DEA33FCC598EA6A32D939905586FBE997B9E68661F8956D4893072E19DE24CD1FB88A9F71FC4CC01BAB5C914FDF96A647D671B5E89859BAEEAB122218688496DF4DF0C328C3D5F940B109CEB2A2743D5CBE3594288A229B8C7E2F88303E3FE1A26A89E5001F2BD936890FEF78F06E05ECC063A68BDB8C18DFAC114CF1FECDB8BE1FC2FEECB2315D27998D682B129FD1E3EB5D7985DCBDC452A1082CCC038E0BF69570FEFAC6BC6FB951F89B6792CADA76403C02CEB5DCE1CE6EDDD16D5F7FB6B85D2B92485448DE0088E421E83F1E28B267FBE3B59AE0496FB845213C271D4C5AC5E9E7E5F6A3072445307FCCEB7306710459991C40CC4DC1FC325154C7974DD780371397805456A19AE23EE88475C1DF07697B666][ESNI Cipher: TLS_AES_128_GCM_SHA256][PLAIN TEXT (http/1.1)] + 2 TCP 192.168.1.12:49887 -> 104.16.125.175:443 [proto: 91.220/TLS.Cloudflare][cat: Web/5][1 pkts/770 bytes -> 0 pkts/0 bytes][Goodput ratio: 93/0][< 1 sec][ALPN: h2;http/1.1][TLS Supported Versions: TLSv1.3;TLSv1.2;TLSv1.1;TLSv1][TLSv1.2][JA3C: e5ef852e686954ba9fe060fbfa881e15][ESNI: B900004E39E84B98F5AE87B0A020EC49FED86F2B488B6AB28BDE9F957621F2774366DE90E65C4CA808668911624685EC4C6DC6C161A97CBE82281BC08427697AA3BE6A40E5F00ACF8B63E329317B0E4E85642D50AB8790E6197DA62D9F5B3239DCC59437797FE768A520C9D471FEABA1375DF61E4A39B09363CB109E7B24A793844896DDD16B6EE7DBE576D767161D782D7BF6FEC453A05A923D8D8E9BEFFC97E8E56C4F1AAB70FE99BC97819E1D908A5F3B3094F4BF25EB7A24A94FDBC3E107A423B8BB341F22900F7BBD87780E30B6ECF393FEB8FBFFEB54C79FA0673FE1AAD17B221D4BFF6450AA0CD4AF513066B66080B602147F3ACB7145A436C5689DA20BACB8BF9BABD851012556EC8F7BB9D74BFAAF25DCF4362A5775607C3CE5C2C29F183969][ESNI Cipher: TLS_AES_128_GCM_SHA256][PLAIN TEXT (http/1.1)] + 3 TCP 192.168.1.12:49897 -> 104.22.71.197:443 [proto: 91.220/TLS.Cloudflare][cat: Web/5][1 pkts/770 bytes -> 0 pkts/0 bytes][Goodput ratio: 93/0][< 1 sec][ALPN: h2;http/1.1][TLS Supported Versions: TLSv1.3;TLSv1.2;TLSv1.1;TLSv1][TLSv1.2][JA3C: e5ef852e686954ba9fe060fbfa881e15][ESNI: CD69AC727FFAA0EA70A12AA46E71537EB99234B996818C913C72A0AC1184BFA5DD3B617E013E4CA092B2E9CFB78BCD8D33CBAF12A974DFB78E49B8BF9A57997418EF14C87830961E3C8480D2A4BF27D61D911CEF4300924A9F36105748BAED845FF585E40406545BB35C6DAAD7896433EC4DFD6B6F49728DA85D707DB7AC784F55A6658DC6ADE3087B1E46BBBEDFA44F3E8754B31A6BCF8519D291D3629805FA826E43799EA6E33021CF0A83CA05717B00F37D69841934F5B5BF254C6467888A592C38A3007DB3B7D5CBB8DB742B657F8F973C050BAA817AA571393CD8A4BC0B2312460A77DD0510F4BBCE43D53BCF334E4E8C7570255BBD17714403F4B6925434CD67F96FA9E05D700776810EEB5786B1C8188A4D73F8208B614B93284A8093929594BE][ESNI Cipher: TLS_AES_128_GCM_SHA256][PLAIN TEXT (http/1.1)] diff --git a/tests/result/imaps.pcap.out b/tests/result/imaps.pcap.out new file mode 100644 index 000000000..85fa9f3ec --- /dev/null +++ b/tests/result/imaps.pcap.out @@ -0,0 +1,8 @@ +ntop 20 5196 1 + +JA3 Host Stats: + IP Address # JA3C + 1 192.168.1.8 1 + + + 1 TCP 192.168.1.8:50506 <-> 167.99.215.164:993 [proto: 91.26/TLS.ntop][cat: Network/14][10 pkts/1220 bytes <-> 10 pkts/3976 bytes][Goodput ratio: 45/83][0.33 sec][bytes ratio: -0.530 (Download)][IAT c2s/s2c min/avg/max/stddev: 0/0 33/22 77/43 26/19][Pkt Len c2s/s2c min/avg/max/stddev: 66/66 122/398 293/1506 78/557][TLSv1.2][Client: mail.ntop.org][JA3C: 4923a265be4d81c68ecda45bb89cdf6a][ServerNames: mail.ntop.org][JA3S: b653c251b0ee54c3088fe7bb997cf59d][Issuer: C=US, O=Let's Encrypt, CN=Let's Encrypt Authority X3][Subject: CN=mail.ntop.org][Certificate SHA-1: F1:9A:35:30:96:57:5E:56:81:28:2C:D9:45:A5:83:21:9E:E8:C5:DF][Validity: 2020-04-18 00:15:22 - 2020-07-17 00:15:22][Cipher: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384] diff --git a/tests/result/teams.pcap.out b/tests/result/teams.pcap.out index 92e596e91..ae3ed7fd0 100644 --- a/tests/result/teams.pcap.out +++ b/tests/result/teams.pcap.out @@ -2,7 +2,7 @@ Unknown 35 14201 2 DNS 14 1947 7 DHCP 7 2323 2 ntop 40 9816 3 -SkypeCall 93 19649 12 +SkypeCall 49 10800 4 ICMP 2 140 1 TLS 107 45011 5 Dropbox 18 11162 3 @@ -12,7 +12,7 @@ Spotify 1 82 1 Telegram 3 186 1 Microsoft 403 283797 11 Microsoft365 136 52120 6 -Teams 1870 1025774 25 +Teams 1914 1034623 33 JA3 Host Stats: IP Address # JA3C @@ -59,17 +59,17 @@ JA3 Host Stats: 38 TCP 192.168.1.6:50014 <-> 52.114.250.152:443 [proto: 91.250/TLS.Teams][cat: Collaborative/15][14 pkts/1347 bytes <-> 11 pkts/6975 bytes][Goodput ratio: 42/91][0.22 sec][bytes ratio: -0.676 (Download)][IAT c2s/s2c min/avg/max/stddev: 0/0 16/22 43/84 20/30][Pkt Len c2s/s2c min/avg/max/stddev: 54/60 96/634 289/1506 73/570][Risk: ** TLS Certificate Mismatch **][TLSv1.2][Client: 52.114.250.152][JA3C: e4d448cdfe06dc1243c1eb026c74ac9a][ServerNames: tr.teams.microsoft.com,*.tr.teams.microsoft.com,turn.teams.microsoft.com,*.turn.teams.microsoft.com,*.relay.teams.microsoft.com][JA3S: 986571066668055ae9481cb84fda634a][Issuer: C=US, ST=Washington, L=Redmond, O=Microsoft Corporation, OU=Microsoft IT, CN=Microsoft IT TLS CA 5][Subject: CN=tr.teams.microsoft.com][Certificate SHA-1: A7:90:8D:41:ED:24:D2:83:48:95:90:CE:18:D3:A6:C2:62:7A:07:75][Validity: 2019-05-24 14:10:26 - 2021-05-24 14:10:26][Cipher: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384] 39 TCP 192.168.1.6:60566 <-> 167.99.215.164:4434 [proto: 91.26/TLS.ntop][cat: Network/14][9 pkts/3029 bytes <-> 8 pkts/2213 bytes][Goodput ratio: 80/76][2.73 sec][ALPN: h2;http/1.1][TLS Supported Versions: TLSv1.3;TLSv1.2;TLSv1.1;TLSv1][bytes ratio: 0.156 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/1 351/431 1977/2053 668/728][Pkt Len c2s/s2c min/avg/max/stddev: 66/66 337/277 1012/1291 385/397][Risk: ** Known protocol on non standard port **][TLSv1.2][Client: dati.ntop.org][JA3C: 7120d65624bcd2e02ed4b01388d84cdb][JA3S: 410b9bedaf65dd26c6fe547154d60db4][Cipher: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384] 40 TCP 192.168.1.6:60546 <-> 167.99.215.164:4434 [proto: 91.26/TLS.ntop][cat: Network/14][10 pkts/2195 bytes <-> 10 pkts/2077 bytes][Goodput ratio: 69/68][5.38 sec][ALPN: h2;http/1.1][TLS Supported Versions: TLSv1.3;TLSv1.2;TLSv1.1;TLSv1][bytes ratio: 0.028 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/0 650/754 5000/5000 1645/1734][Pkt Len c2s/s2c min/avg/max/stddev: 66/66 220/208 1021/1292 308/364][Risk: ** Known protocol on non standard port **][TLSv1.2][Client: dati.ntop.org][JA3C: 7120d65624bcd2e02ed4b01388d84cdb][JA3S: 410b9bedaf65dd26c6fe547154d60db4][Cipher: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384] - 41 UDP 192.168.1.6:50036 <-> 52.114.250.137:3478 [proto: 78.38/STUN.SkypeCall][cat: VoIP/10][5 pkts/1390 bytes <-> 4 pkts/733 bytes][Goodput ratio: 85/77][4.06 sec][bytes ratio: 0.309 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/100 1003/774 2235/2092 994/932][Pkt Len c2s/s2c min/avg/max/stddev: 228/174 278/183 314/198 33/10][PLAIN TEXT (rtcmedia)] + 41 UDP 192.168.1.6:50036 <-> 52.114.250.137:3478 [proto: 78.250/STUN.Teams][cat: VoIP/10][5 pkts/1390 bytes <-> 4 pkts/733 bytes][Goodput ratio: 85/77][4.06 sec][bytes ratio: 0.309 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/100 1003/774 2235/2092 994/932][Pkt Len c2s/s2c min/avg/max/stddev: 228/174 278/183 314/198 33/10][PLAIN TEXT (rtcmedia)] 42 UDP 192.168.0.1:68 -> 255.255.255.255:67 [proto: 18/DHCP][cat: Network/14][6 pkts/1926 bytes -> 0 pkts/0 bytes][Goodput ratio: 87/0][25.01 sec][Host: tl-sg116e][bytes ratio: 1.000 (Upload)][IAT c2s/s2c min/avg/max/stddev: 4986/0 5001/0 5018/0 11/0][Pkt Len c2s/s2c min/avg/max/stddev: 321/0 321/0 321/0 0/0][DHCP Fingerprint: 1,3] - 43 UDP 192.168.1.6:50016 <-> 52.114.250.141:3478 [proto: 78.38/STUN.SkypeCall][cat: VoIP/10][4 pkts/1162 bytes <-> 3 pkts/546 bytes][Goodput ratio: 85/77][1.99 sec][bytes ratio: 0.361 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/98 611/101 1783/104 829/3][Pkt Len c2s/s2c min/avg/max/stddev: 256/174 290/182 314/198 25/11][PLAIN TEXT (rtcmedia)] + 43 UDP 192.168.1.6:50016 <-> 52.114.250.141:3478 [proto: 78.250/STUN.Teams][cat: VoIP/10][4 pkts/1162 bytes <-> 3 pkts/546 bytes][Goodput ratio: 85/77][1.99 sec][bytes ratio: 0.361 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/98 611/101 1783/104 829/3][Pkt Len c2s/s2c min/avg/max/stddev: 256/174 290/182 314/198 25/11][PLAIN TEXT (rtcmedia)] 44 TCP 93.62.150.157:443 <-> 192.168.1.6:60512 [proto: 91/TLS][cat: Web/5][2 pkts/1258 bytes <-> 2 pkts/108 bytes][Goodput ratio: 89/0][< 1 sec] - 45 UDP 192.168.1.6:50017 <-> 52.114.250.141:3478 [proto: 78.38/STUN.SkypeCall][cat: VoIP/10][3 pkts/594 bytes <-> 3 pkts/611 bytes][Goodput ratio: 79/79][4.05 sec][bytes ratio: -0.014 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 99/97 2002/2002 3906/3906 1904/1904][Pkt Len c2s/s2c min/avg/max/stddev: 110/187 198/204 256/229 63/18][PLAIN TEXT (The request did not contain a M)] - 46 UDP 192.168.1.6:50037 <-> 52.114.250.137:3478 [proto: 78.38/STUN.SkypeCall][cat: VoIP/10][3 pkts/594 bytes <-> 3 pkts/611 bytes][Goodput ratio: 79/79][4.05 sec][bytes ratio: -0.014 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 95/94 2000/2000 3905/3905 1905/1906][Pkt Len c2s/s2c min/avg/max/stddev: 110/187 198/204 256/229 63/18][PLAIN TEXT (The request did not contain a M)] + 45 UDP 192.168.1.6:50017 <-> 52.114.250.141:3478 [proto: 78.250/STUN.Teams][cat: VoIP/10][3 pkts/594 bytes <-> 3 pkts/611 bytes][Goodput ratio: 79/79][4.05 sec][bytes ratio: -0.014 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 99/97 2002/2002 3906/3906 1904/1904][Pkt Len c2s/s2c min/avg/max/stddev: 110/187 198/204 256/229 63/18][PLAIN TEXT (The request did not contain a M)] + 46 UDP 192.168.1.6:50037 <-> 52.114.250.137:3478 [proto: 78.250/STUN.Teams][cat: VoIP/10][3 pkts/594 bytes <-> 3 pkts/611 bytes][Goodput ratio: 79/79][4.05 sec][bytes ratio: -0.014 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 95/94 2000/2000 3905/3905 1905/1906][Pkt Len c2s/s2c min/avg/max/stddev: 110/187 198/204 256/229 63/18][PLAIN TEXT (The request did not contain a M)] 47 UDP 93.71.110.205:16333 <-> 192.168.1.6:50036 [proto: 78.38/STUN.SkypeCall][cat: VoIP/10][3 pkts/414 bytes <-> 5 pkts/634 bytes][Goodput ratio: 69/67][2.31 sec][bytes ratio: -0.210 (Download)][IAT c2s/s2c min/avg/max/stddev: 101/15 634/572 1166/1168 532/565][Pkt Len c2s/s2c min/avg/max/stddev: 130/88 138/127 154/158 11/27][Risk: ** Known protocol on non standard port **] - 48 UDP 192.168.1.6:50016 -> 192.168.0.4:50005 [proto: 78.38/STUN.SkypeCall][cat: VoIP/10][5 pkts/770 bytes -> 0 pkts/0 bytes][Goodput ratio: 73/0][1.22 sec][Risk: ** Known protocol on non standard port **] - 49 UDP 192.168.1.6:50036 -> 192.168.0.4:50020 [proto: 78.38/STUN.SkypeCall][cat: VoIP/10][5 pkts/770 bytes -> 0 pkts/0 bytes][Goodput ratio: 73/0][1.22 sec][Risk: ** Known protocol on non standard port **] - 50 UDP 192.168.1.6:50016 <-> 52.114.250.123:3478 [proto: 78.38/STUN.SkypeCall][cat: VoIP/10][1 pkts/110 bytes <-> 2 pkts/424 bytes][Goodput ratio: 61/80][0.12 sec][PLAIN TEXT (The request did not contain a M)] - 51 UDP 192.168.1.6:50036 <-> 52.114.250.123:3478 [proto: 78.38/STUN.SkypeCall][cat: VoIP/10][1 pkts/110 bytes <-> 2 pkts/424 bytes][Goodput ratio: 61/80][0.12 sec][PLAIN TEXT (The request did not contain a M)] + 48 UDP 192.168.1.6:50016 -> 192.168.0.4:50005 [proto: 78.250/STUN.Teams][cat: VoIP/10][5 pkts/770 bytes -> 0 pkts/0 bytes][Goodput ratio: 73/0][1.22 sec][Risk: ** Known protocol on non standard port **] + 49 UDP 192.168.1.6:50036 -> 192.168.0.4:50020 [proto: 78.250/STUN.Teams][cat: VoIP/10][5 pkts/770 bytes -> 0 pkts/0 bytes][Goodput ratio: 73/0][1.22 sec][Risk: ** Known protocol on non standard port **] + 50 UDP 192.168.1.6:50016 <-> 52.114.250.123:3478 [proto: 78.250/STUN.Teams][cat: VoIP/10][1 pkts/110 bytes <-> 2 pkts/424 bytes][Goodput ratio: 61/80][0.12 sec][PLAIN TEXT (The request did not contain a M)] + 51 UDP 192.168.1.6:50036 <-> 52.114.250.123:3478 [proto: 78.250/STUN.Teams][cat: VoIP/10][1 pkts/110 bytes <-> 2 pkts/424 bytes][Goodput ratio: 61/80][0.12 sec][PLAIN TEXT (The request did not contain a M)] 52 UDP 192.168.1.6:17500 -> 192.168.1.255:17500 [proto: 121/Dropbox][cat: Cloud/13][1 pkts/527 bytes -> 0 pkts/0 bytes][Goodput ratio: 92/0][< 1 sec][PLAIN TEXT (version)] 53 UDP 192.168.1.6:17500 -> 255.255.255.255:17500 [proto: 121/Dropbox][cat: Cloud/13][1 pkts/527 bytes -> 0 pkts/0 bytes][Goodput ratio: 92/0][< 1 sec][PLAIN TEXT (version)] 54 UDP 0.0.0.0:68 -> 255.255.255.255:67 [proto: 18/DHCP][cat: Network/14][1 pkts/397 bytes -> 0 pkts/0 bytes][Goodput ratio: 89/0][< 1 sec][PLAIN TEXT (6.10.1)] |