aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Deri <deri@ntop.org>2019-07-15 14:45:25 +0200
committerLuca Deri <deri@ntop.org>2019-07-15 14:45:25 +0200
commit5c758d4564edacd9b297ad7bf943fc857730a794 (patch)
treede14b800dbb09575f746b6fe5eec981c4705764c
parentfc531334ae86ccc30e7f7a0ca5f23d5d56a6d370 (diff)
Reworked output
-v 1 now prints only unknown flows -v 2 now prints all flows
-rw-r--r--example/ndpiReader.c755
-rwxr-xr-xtests/do.sh4
-rw-r--r--tests/pcap/nintendo.pcapbin349345 -> 349345 bytes
-rw-r--r--tests/pcap/skype-conference-call.pcapbin42911 -> 42911 bytes
-rw-r--r--tests/result/1kxun.pcap.out10
-rw-r--r--tests/result/6in4tunnel.pcap.out5
-rw-r--r--tests/result/Instagram.pcap.out5
-rw-r--r--tests/result/KakaoTalk_chat.pcap.out5
-rw-r--r--tests/result/KakaoTalk_talk.pcap.out5
-rw-r--r--tests/result/dnscrypt.pcap.out5
-rw-r--r--tests/result/facebook.pcap.out5
-rw-r--r--tests/result/google_ssl.pcap.out4
-rw-r--r--tests/result/http_ipv6.pcap.out5
-rw-r--r--tests/result/netflix.pcap.out5
-rw-r--r--tests/result/nintendo.pcap.out5
-rw-r--r--tests/result/ocs.pcap.out5
-rw-r--r--tests/result/skype.pcap.out5
-rw-r--r--tests/result/skype_no_unknown.pcap.out5
-rw-r--r--tests/result/snapchat.pcap.out5
-rw-r--r--tests/result/viber.pcap.out5
-rw-r--r--tests/result/waze.pcap.out5
-rw-r--r--tests/result/webex.pcap.out5
-rw-r--r--tests/result/wechat.pcap.out5
-rw-r--r--tests/result/weibo.pcap.out5
-rw-r--r--tests/result/whatsapp_login_call.pcap.out5
-rw-r--r--tests/result/whatsappfiles.pcap.out5
-rw-r--r--tests/result/youtubeupload.pcap.out5
27 files changed, 508 insertions, 370 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c
index aa0286025..2c2e69651 100644
--- a/example/ndpiReader.c
+++ b/example/ndpiReader.c
@@ -1932,6 +1932,395 @@ void printPortStats(struct port_stats *stats) {
}
}
+/* *********************************************** */
+
+static void printFlowsStats() {
+ if(verbose) {
+ int thread_id;
+ FILE *out = results_file ? results_file : stdout;
+ u_int32_t total_flows = 0;
+ ndpi_host_ja3_fingerprints *ja3ByHostsHashT = NULL; // outer hash table
+ ndpi_ja3_fingerprints_host *hostByJA3C_ht = NULL; // for client
+ ndpi_ja3_fingerprints_host *hostByJA3S_ht = NULL; // for server
+ int i;
+ ndpi_host_ja3_fingerprints *ja3ByHost_element = NULL;
+ ndpi_ja3_info *info_of_element = NULL;
+ ndpi_host_ja3_fingerprints *tmp = NULL;
+ ndpi_ja3_info *tmp2 = NULL;
+ unsigned int num_ja3_client;
+ unsigned int num_ja3_server;
+
+ for(thread_id = 0; thread_id < num_threads; thread_id++)
+ total_flows += ndpi_thread_info[thread_id].workflow->num_allocated_flows;
+
+ if((all_flows = (struct flow_info*)malloc(sizeof(struct flow_info)*total_flows)) == NULL) {
+ fprintf(out, "Fatal error: not enough memory\n");
+ exit(-1);
+ }
+
+ if(!json_flag) fprintf(out, "\n");
+
+ num_flows = 0;
+ for(thread_id = 0; thread_id < num_threads; thread_id++) {
+ for(i=0; i<NUM_ROOTS; i++)
+ ndpi_twalk(ndpi_thread_info[thread_id].workflow->ndpi_flows_root[i],
+ node_print_known_proto_walker, &thread_id);
+ }
+
+ if((verbose == 2) || (verbose == 3)) {
+ for(i = 0; i < num_flows; i++) {
+ ndpi_host_ja3_fingerprints *ja3ByHostFound = NULL;
+ ndpi_ja3_fingerprints_host *hostByJA3Found = NULL;
+
+ //check if this is a ssh-ssl flow
+ if(all_flows[i].flow->ssh_ssl.ja3_client[0] != '\0'){
+ //looking if the host is already in the hash table
+ HASH_FIND_INT(ja3ByHostsHashT, &(all_flows[i].flow->src_ip), ja3ByHostFound);
+
+ //host ip -> ja3
+ if(ja3ByHostFound == NULL){
+ //adding the new host
+ ndpi_host_ja3_fingerprints *newHost = malloc(sizeof(ndpi_host_ja3_fingerprints));
+ newHost->host_client_info_hasht = NULL;
+ newHost->host_server_info_hasht = NULL;
+ newHost->ip_string = all_flows[i].flow->src_name;
+ newHost->ip = all_flows[i].flow->src_ip;
+ newHost->dns_name = all_flows[i].flow->ssh_ssl.client_info;
+
+ ndpi_ja3_info *newJA3 = malloc(sizeof(ndpi_ja3_info));
+ newJA3->ja3 = all_flows[i].flow->ssh_ssl.ja3_client;
+ newJA3->unsafe_cipher = all_flows[i].flow->ssh_ssl.client_unsafe_cipher;
+ //adding the new ja3 fingerprint
+ HASH_ADD_KEYPTR(hh, newHost->host_client_info_hasht,
+ newJA3->ja3, strlen(newJA3->ja3), newJA3);
+ //adding the new host
+ HASH_ADD_INT(ja3ByHostsHashT, ip, newHost);
+ } else {
+ //host already in the hash table
+ ndpi_ja3_info *infoFound = NULL;
+
+ HASH_FIND_STR(ja3ByHostFound->host_client_info_hasht,
+ all_flows[i].flow->ssh_ssl.ja3_client, infoFound);
+
+ if(infoFound == NULL){
+ ndpi_ja3_info *newJA3 = malloc(sizeof(ndpi_ja3_info));
+ newJA3->ja3 = all_flows[i].flow->ssh_ssl.ja3_client;
+ newJA3->unsafe_cipher = all_flows[i].flow->ssh_ssl.client_unsafe_cipher;
+ HASH_ADD_KEYPTR(hh, ja3ByHostFound->host_client_info_hasht,
+ newJA3->ja3, strlen(newJA3->ja3), newJA3);
+ }
+ }
+
+ //ja3 -> host ip
+ HASH_FIND_STR(hostByJA3C_ht, all_flows[i].flow->ssh_ssl.ja3_client, hostByJA3Found);
+ if(hostByJA3Found == NULL){
+ ndpi_ip_dns *newHost = malloc(sizeof(ndpi_ip_dns));
+
+ newHost->ip = all_flows[i].flow->src_ip;
+ newHost->ip_string = all_flows[i].flow->src_name;
+ newHost->dns_name = all_flows[i].flow->ssh_ssl.client_info;;
+
+ ndpi_ja3_fingerprints_host *newElement = malloc(sizeof(ndpi_ja3_fingerprints_host));
+ newElement->ja3 = all_flows[i].flow->ssh_ssl.ja3_client;
+ newElement->unsafe_cipher = all_flows[i].flow->ssh_ssl.client_unsafe_cipher;
+ newElement->ipToDNS_ht = NULL;
+
+ HASH_ADD_INT(newElement->ipToDNS_ht, ip, newHost);
+ HASH_ADD_KEYPTR(hh, hostByJA3C_ht, newElement->ja3, strlen(newElement->ja3),
+ newElement);
+ } else {
+ ndpi_ip_dns *innerElement = NULL;
+ HASH_FIND_INT(hostByJA3Found->ipToDNS_ht, &(all_flows[i].flow->src_ip), innerElement);
+ if(innerElement == NULL){
+ ndpi_ip_dns *newInnerElement = malloc(sizeof(ndpi_ip_dns));
+ newInnerElement->ip = all_flows[i].flow->src_ip;
+ newInnerElement->ip_string = all_flows[i].flow->src_name;
+ newInnerElement->dns_name = all_flows[i].flow->ssh_ssl.client_info;
+ HASH_ADD_INT(hostByJA3Found->ipToDNS_ht, ip, newInnerElement);
+ }
+ }
+ }
+
+ if(all_flows[i].flow->ssh_ssl.ja3_server[0] != '\0'){
+ //looking if the host is already in the hash table
+ HASH_FIND_INT(ja3ByHostsHashT, &(all_flows[i].flow->dst_ip), ja3ByHostFound);
+ if(ja3ByHostFound == NULL){
+ //adding the new host in the hash table
+ ndpi_host_ja3_fingerprints *newHost = malloc(sizeof(ndpi_host_ja3_fingerprints));
+ newHost->host_client_info_hasht = NULL;
+ newHost->host_server_info_hasht = NULL;
+ newHost->ip_string = all_flows[i].flow->dst_name;
+ newHost->ip = all_flows[i].flow->dst_ip;
+ newHost->dns_name = all_flows[i].flow->ssh_ssl.server_info;
+
+ ndpi_ja3_info *newJA3 = malloc(sizeof(ndpi_ja3_info));
+ newJA3->ja3 = all_flows[i].flow->ssh_ssl.ja3_server;
+ newJA3->unsafe_cipher = all_flows[i].flow->ssh_ssl.server_unsafe_cipher;
+ //adding the new ja3 fingerprint
+ HASH_ADD_KEYPTR(hh, newHost->host_server_info_hasht, newJA3->ja3,
+ strlen(newJA3->ja3), newJA3);
+ //adding the new host
+ HASH_ADD_INT(ja3ByHostsHashT, ip, newHost);
+ } else {
+ //host already in the hashtable
+ ndpi_ja3_info *infoFound = NULL;
+ HASH_FIND_STR(ja3ByHostFound->host_server_info_hasht,
+ all_flows[i].flow->ssh_ssl.ja3_server, infoFound);
+ if(infoFound == NULL){
+ ndpi_ja3_info *newJA3 = malloc(sizeof(ndpi_ja3_info));
+ newJA3->ja3 = all_flows[i].flow->ssh_ssl.ja3_server;
+ newJA3->unsafe_cipher = all_flows[i].flow->ssh_ssl.server_unsafe_cipher;
+ HASH_ADD_KEYPTR(hh, ja3ByHostFound->host_server_info_hasht,
+ newJA3->ja3, strlen(newJA3->ja3), newJA3);
+ }
+ }
+
+ HASH_FIND_STR(hostByJA3S_ht, all_flows[i].flow->ssh_ssl.ja3_server, hostByJA3Found);
+ if(hostByJA3Found == NULL){
+ ndpi_ip_dns *newHost = malloc(sizeof(ndpi_ip_dns));
+
+ newHost->ip = all_flows[i].flow->dst_ip;
+ newHost->ip_string = all_flows[i].flow->dst_name;
+ newHost->dns_name = all_flows[i].flow->ssh_ssl.server_info;;
+
+ ndpi_ja3_fingerprints_host *newElement = malloc(sizeof(ndpi_ja3_fingerprints_host));
+ newElement->ja3 = all_flows[i].flow->ssh_ssl.ja3_server;
+ newElement->unsafe_cipher = all_flows[i].flow->ssh_ssl.server_unsafe_cipher;
+ newElement->ipToDNS_ht = NULL;
+
+ HASH_ADD_INT(newElement->ipToDNS_ht, ip, newHost);
+ HASH_ADD_KEYPTR(hh, hostByJA3S_ht, newElement->ja3, strlen(newElement->ja3),
+ newElement);
+ } else {
+ ndpi_ip_dns *innerElement = NULL;
+
+ HASH_FIND_INT(hostByJA3Found->ipToDNS_ht, &(all_flows[i].flow->dst_ip), innerElement);
+ if(innerElement == NULL){
+ ndpi_ip_dns *newInnerElement = malloc(sizeof(ndpi_ip_dns));
+ newInnerElement->ip = all_flows[i].flow->dst_ip;
+ newInnerElement->ip_string = all_flows[i].flow->dst_name;
+ newInnerElement->dns_name = all_flows[i].flow->ssh_ssl.server_info;
+ HASH_ADD_INT(hostByJA3Found->ipToDNS_ht, ip, newInnerElement);
+ }
+ }
+
+ }
+ }
+
+ if(ja3ByHostsHashT) {
+ ndpi_ja3_fingerprints_host *hostByJA3Element = NULL;
+ ndpi_ja3_fingerprints_host *tmp3 = NULL;
+ ndpi_ip_dns *innerHashEl = NULL;
+ ndpi_ip_dns *tmp4 = NULL;
+
+ if(verbose == 2) {
+ /* for each host the number of flow with a ja3 fingerprint is printed */
+ i = 1;
+
+ fprintf(out, "JA3 Host Stats: \n");
+ fprintf(out, "\t\t IP %-24s \t %-10s \n", "Address", "# JA3C");
+
+ for(ja3ByHost_element = ja3ByHostsHashT; ja3ByHost_element != NULL;
+ ja3ByHost_element = ja3ByHost_element->hh.next) {
+ num_ja3_client = HASH_COUNT(ja3ByHost_element->host_client_info_hasht);
+ num_ja3_server = HASH_COUNT(ja3ByHost_element->host_server_info_hasht);
+
+ if(num_ja3_client > 0) {
+ fprintf(out, "\t%d\t %-24s \t %-7d\n",
+ i,
+ ja3ByHost_element->ip_string,
+ num_ja3_client
+ );
+ i++;
+ }
+
+ }
+ } else if(verbose == 3) {
+ int i = 1;
+ int againstRepeat;
+ ndpi_ja3_fingerprints_host *hostByJA3Element = NULL;
+ ndpi_ja3_fingerprints_host *tmp3 = NULL;
+ ndpi_ip_dns *innerHashEl = NULL;
+ ndpi_ip_dns *tmp4 = NULL;
+
+ //for each host it is printted the JA3C and JA3S, along the server name (if any)
+ //and the security status
+
+ fprintf(out, "JA3C/JA3S Host Stats: \n");
+ fprintf(out, "\t%-7s %-24s %-34s %s\n", "", "IP", "JA3C", "JA3S");
+
+ //reminder
+ //ja3ByHostsHashT: hash table <ip, (ja3, ht_client, ht_server)>
+ //ja3ByHost_element: element of ja3ByHostsHashT
+ //info_of_element: element of the inner hash table of ja3ByHost_element
+ HASH_ITER(hh, ja3ByHostsHashT, ja3ByHost_element, tmp) {
+ num_ja3_client = HASH_COUNT(ja3ByHost_element->host_client_info_hasht);
+ num_ja3_server = HASH_COUNT(ja3ByHost_element->host_server_info_hasht);
+ againstRepeat = 0;
+ if(num_ja3_client > 0) {
+ HASH_ITER(hh, ja3ByHost_element->host_client_info_hasht, info_of_element, tmp2) {
+ fprintf(out, "\t%-7d %-24s %s %s\n",
+ i,
+ ja3ByHost_element->ip_string,
+ info_of_element->ja3,
+ print_cipher(info_of_element->unsafe_cipher)
+ );
+ againstRepeat = 1;
+ i++;
+ }
+ }
+
+ if(num_ja3_server > 0) {
+ HASH_ITER(hh, ja3ByHost_element->host_server_info_hasht, info_of_element, tmp2) {
+ fprintf(out, "\t%-7d %-24s %-34s %s %s %s%s%s\n",
+ i,
+ ja3ByHost_element->ip_string,
+ "",
+ info_of_element->ja3,
+ print_cipher(info_of_element->unsafe_cipher),
+ ja3ByHost_element->dns_name[0] ? "[" : "",
+ ja3ByHost_element->dns_name,
+ ja3ByHost_element->dns_name[0] ? "]" : ""
+ );
+ i++;
+ }
+ }
+ }
+
+ i = 1;
+
+ fprintf(out, "\nIP/JA3 Distribution:\n");
+ fprintf(out, "%-15s %-39s %-26s\n", "", "JA3", "IP");
+ HASH_ITER(hh, hostByJA3C_ht, hostByJA3Element, tmp3) {
+ againstRepeat = 0;
+ HASH_ITER(hh, hostByJA3Element->ipToDNS_ht, innerHashEl, tmp4) {
+ if(againstRepeat == 0) {
+ fprintf(out, "\t%-7d JA3C %s",
+ i,
+ hostByJA3Element->ja3
+ );
+ fprintf(out, " %-15s %s\n",
+ innerHashEl->ip_string,
+ print_cipher(hostByJA3Element->unsafe_cipher)
+ );
+ againstRepeat = 1;
+ i++;
+ } else {
+ fprintf(out, "\t%45s", "");
+ fprintf(out, " %-15s %s\n",
+ innerHashEl->ip_string,
+ print_cipher(hostByJA3Element->unsafe_cipher)
+ );
+ }
+ }
+ }
+ HASH_ITER(hh, hostByJA3S_ht, hostByJA3Element, tmp3) {
+ againstRepeat = 0;
+ HASH_ITER(hh, hostByJA3Element->ipToDNS_ht, innerHashEl, tmp4) {
+ if(againstRepeat == 0) {
+ fprintf(out, "\t%-7d JA3S %s",
+ i,
+ hostByJA3Element->ja3
+ );
+ fprintf(out, " %-15s %-10s %s%s%s\n",
+ innerHashEl->ip_string,
+ print_cipher(hostByJA3Element->unsafe_cipher),
+ innerHashEl->dns_name[0] ? "[" : "",
+ innerHashEl->dns_name,
+ innerHashEl->dns_name[0] ? "]" : ""
+ );
+ againstRepeat = 1;
+ i++;
+ } else {
+ fprintf(out, "\t%45s", "");
+ fprintf(out, " %-15s %-10s %s%s%s\n",
+ innerHashEl->ip_string,
+ print_cipher(hostByJA3Element->unsafe_cipher),
+ innerHashEl->dns_name[0] ? "[" : "",
+ innerHashEl->dns_name,
+ innerHashEl->dns_name[0] ? "]" : ""
+ );
+ }
+ }
+ }
+ }
+ fprintf(out, "\n\n");
+
+ //freeing the hash table
+ HASH_ITER(hh, ja3ByHostsHashT, ja3ByHost_element, tmp) {
+ HASH_ITER(hh, ja3ByHost_element->host_client_info_hasht, info_of_element, tmp2) {
+ HASH_DEL(ja3ByHost_element->host_client_info_hasht, info_of_element);
+ free(info_of_element);
+ }
+ HASH_ITER(hh, ja3ByHost_element->host_server_info_hasht, info_of_element, tmp2) {
+ HASH_DEL(ja3ByHost_element->host_server_info_hasht, info_of_element);
+ free(info_of_element);
+ }
+ HASH_DEL(ja3ByHostsHashT, ja3ByHost_element);
+ free(ja3ByHost_element);
+ }
+
+ HASH_ITER(hh, hostByJA3C_ht, hostByJA3Element, tmp3) {
+ HASH_ITER(hh, hostByJA3C_ht->ipToDNS_ht, innerHashEl, tmp4) {
+ HASH_DEL(hostByJA3Element->ipToDNS_ht, innerHashEl);
+ free(innerHashEl);
+ }
+ HASH_DEL(hostByJA3C_ht, hostByJA3Element);
+ free(hostByJA3Element);
+ }
+
+ hostByJA3Element = NULL;
+ HASH_ITER(hh, hostByJA3S_ht, hostByJA3Element, tmp3) {
+ HASH_ITER(hh, hostByJA3S_ht->ipToDNS_ht, innerHashEl, tmp4) {
+ HASH_DEL(hostByJA3Element->ipToDNS_ht, innerHashEl);
+ free(innerHashEl);
+ }
+ HASH_DEL(hostByJA3S_ht, hostByJA3Element);
+ free(hostByJA3Element);
+ }
+ }
+ }
+
+ /* Print all flows stats */
+
+ qsort(all_flows, num_flows, sizeof(struct flow_info), cmpFlows);
+
+ if(verbose > 1) {
+ for(i=0; i<num_flows; i++)
+ printFlow(i+1, all_flows[i].flow, all_flows[i].thread_id);
+ }
+
+ for(thread_id = 0; thread_id < num_threads; thread_id++) {
+ if(ndpi_thread_info[thread_id].workflow->stats.protocol_counter[0 /* 0 = Unknown */] > 0) {
+ if(!json_flag) {
+
+ fprintf(out, "\n\nUndetected flows:%s\n",
+ undetected_flows_deleted ? " (expired flows are not listed below)" : "");
+ }
+
+ if(json_flag)
+ json_flag = 2;
+ break;
+ }
+ }
+
+ num_flows = 0;
+ for(thread_id = 0; thread_id < num_threads; thread_id++) {
+ if(ndpi_thread_info[thread_id].workflow->stats.protocol_counter[0] > 0) {
+ for(i=0; i<NUM_ROOTS; i++)
+ ndpi_twalk(ndpi_thread_info[thread_id].workflow->ndpi_flows_root[i],
+ node_print_unknown_proto_walker, &thread_id);
+ }
+ }
+
+ qsort(all_flows, num_flows, sizeof(struct flow_info), cmpFlows);
+
+ for(i=0; i<num_flows; i++)
+ printFlow(i+1, all_flows[i].flow, all_flows[i].thread_id);
+
+ free(all_flows);
+ }
+}
/* *********************************************** */
@@ -2156,371 +2545,7 @@ static void printResults(u_int64_t processing_time_usec, u_int64_t setup_time_us
// printf("\n\nTotal Flow Traffic: %llu (diff: %llu)\n", total_flow_bytes, cumulative_stats.total_ip_bytes-total_flow_bytes);
- if((verbose == 1) || (verbose == 2)) {
- FILE *out = results_file ? results_file : stdout;
- u_int32_t total_flows = 0;
- ndpi_host_ja3_fingerprints *ja3ByHostsHashT = NULL; //outer hash table
- ndpi_ja3_fingerprints_host *hostByJA3C_ht = NULL; //for client
- ndpi_ja3_fingerprints_host *hostByJA3S_ht = NULL; //for server
- int i;
- ndpi_host_ja3_fingerprints *ja3ByHost_element = NULL;
- ndpi_ja3_info *info_of_element = NULL;
- ndpi_host_ja3_fingerprints *tmp = NULL;
- ndpi_ja3_info *tmp2 = NULL;
- unsigned int num_ja3_client;
- unsigned int num_ja3_server;
-
- for(thread_id = 0; thread_id < num_threads; thread_id++)
- total_flows += ndpi_thread_info[thread_id].workflow->num_allocated_flows;
-
- if((all_flows = (struct flow_info*)malloc(sizeof(struct flow_info)*total_flows)) == NULL) {
- printf("Fatal error: not enough memory\n");
- exit(-1);
- }
-
- if(!json_flag) fprintf(out, "\n");
-
- num_flows = 0;
- for(thread_id = 0; thread_id < num_threads; thread_id++) {
- for(i=0; i<NUM_ROOTS; i++)
- ndpi_twalk(ndpi_thread_info[thread_id].workflow->ndpi_flows_root[i], node_print_known_proto_walker, &thread_id);
- }
-
- for(i = 0; i < num_flows; i++){
- ndpi_host_ja3_fingerprints *ja3ByHostFound = NULL;
- ndpi_ja3_fingerprints_host *hostByJA3Found = NULL;
-
- //check if this is a ssh-ssl flow
- if(all_flows[i].flow->ssh_ssl.ja3_client[0] != '\0'){
- //looking if the host is already in the hash table
- HASH_FIND_INT(ja3ByHostsHashT, &(all_flows[i].flow->src_ip), ja3ByHostFound);
-
- //host ip -> ja3
- if(ja3ByHostFound == NULL){
- //adding the new host
- ndpi_host_ja3_fingerprints *newHost = malloc(sizeof(ndpi_host_ja3_fingerprints));
- newHost->host_client_info_hasht = NULL;
- newHost->host_server_info_hasht = NULL;
- newHost->ip_string = all_flows[i].flow->src_name;
- newHost->ip = all_flows[i].flow->src_ip;
- newHost->dns_name = all_flows[i].flow->ssh_ssl.client_info;
-
- ndpi_ja3_info *newJA3 = malloc(sizeof(ndpi_ja3_info));
- newJA3->ja3 = all_flows[i].flow->ssh_ssl.ja3_client;
- newJA3->unsafe_cipher = all_flows[i].flow->ssh_ssl.client_unsafe_cipher;
- //adding the new ja3 fingerprint
- HASH_ADD_KEYPTR(hh, newHost->host_client_info_hasht, newJA3->ja3, strlen(newJA3->ja3), newJA3);
- //adding the new host
- HASH_ADD_INT(ja3ByHostsHashT, ip, newHost);
- }else{
- //host already in the hash table
- ndpi_ja3_info *infoFound = NULL;
- HASH_FIND_STR(ja3ByHostFound->host_client_info_hasht, all_flows[i].flow->ssh_ssl.ja3_client, infoFound);
- if(infoFound == NULL){
- ndpi_ja3_info *newJA3 = malloc(sizeof(ndpi_ja3_info));
- newJA3->ja3 = all_flows[i].flow->ssh_ssl.ja3_client;
- newJA3->unsafe_cipher = all_flows[i].flow->ssh_ssl.client_unsafe_cipher;
- HASH_ADD_KEYPTR(hh, ja3ByHostFound->host_client_info_hasht, newJA3->ja3, strlen(newJA3->ja3), newJA3);
- }
- }
-
- //ja3 -> host ip
- HASH_FIND_STR(hostByJA3C_ht, all_flows[i].flow->ssh_ssl.ja3_client, hostByJA3Found);
- if(hostByJA3Found == NULL){
- ndpi_ip_dns *newHost = malloc(sizeof(ndpi_ip_dns));
-
- newHost->ip = all_flows[i].flow->src_ip;
- newHost->ip_string = all_flows[i].flow->src_name;
- newHost->dns_name = all_flows[i].flow->ssh_ssl.client_info;;
-
- ndpi_ja3_fingerprints_host *newElement = malloc(sizeof(ndpi_ja3_fingerprints_host));
- newElement->ja3 = all_flows[i].flow->ssh_ssl.ja3_client;
- newElement->unsafe_cipher = all_flows[i].flow->ssh_ssl.client_unsafe_cipher;
- newElement->ipToDNS_ht = NULL;
-
- HASH_ADD_INT(newElement->ipToDNS_ht, ip, newHost);
- HASH_ADD_KEYPTR(hh, hostByJA3C_ht, newElement->ja3, strlen(newElement->ja3), newElement);
- }else{
- ndpi_ip_dns *innerElement = NULL;
- HASH_FIND_INT(hostByJA3Found->ipToDNS_ht, &(all_flows[i].flow->src_ip), innerElement);
- if(innerElement == NULL){
- ndpi_ip_dns *newInnerElement = malloc(sizeof(ndpi_ip_dns));
- newInnerElement->ip = all_flows[i].flow->src_ip;
- newInnerElement->ip_string = all_flows[i].flow->src_name;
- newInnerElement->dns_name = all_flows[i].flow->ssh_ssl.client_info;
- HASH_ADD_INT(hostByJA3Found->ipToDNS_ht, ip, newInnerElement);
- }
- }
-
- }
- if(all_flows[i].flow->ssh_ssl.ja3_server[0] != '\0'){
- //looking if the host is already in the hash table
- HASH_FIND_INT(ja3ByHostsHashT, &(all_flows[i].flow->dst_ip), ja3ByHostFound);
- if(ja3ByHostFound == NULL){
- //adding the new host in the hash table
- ndpi_host_ja3_fingerprints *newHost = malloc(sizeof(ndpi_host_ja3_fingerprints));
- newHost->host_client_info_hasht = NULL;
- newHost->host_server_info_hasht = NULL;
- newHost->ip_string = all_flows[i].flow->dst_name;
- newHost->ip = all_flows[i].flow->dst_ip;
- newHost->dns_name = all_flows[i].flow->ssh_ssl.server_info;
-
- ndpi_ja3_info *newJA3 = malloc(sizeof(ndpi_ja3_info));
- newJA3->ja3 = all_flows[i].flow->ssh_ssl.ja3_server;
- newJA3->unsafe_cipher = all_flows[i].flow->ssh_ssl.server_unsafe_cipher;
- //adding the new ja3 fingerprint
- HASH_ADD_KEYPTR(hh, newHost->host_server_info_hasht, newJA3->ja3, strlen(newJA3->ja3), newJA3);
- //adding the new host
- HASH_ADD_INT(ja3ByHostsHashT, ip, newHost);
- }else{
- //host already in the hashtable
- ndpi_ja3_info *infoFound = NULL;
- HASH_FIND_STR(ja3ByHostFound->host_server_info_hasht, all_flows[i].flow->ssh_ssl.ja3_server, infoFound);
- if(infoFound == NULL){
- ndpi_ja3_info *newJA3 = malloc(sizeof(ndpi_ja3_info));
- newJA3->ja3 = all_flows[i].flow->ssh_ssl.ja3_server;
- newJA3->unsafe_cipher = all_flows[i].flow->ssh_ssl.server_unsafe_cipher;
- HASH_ADD_KEYPTR(hh, ja3ByHostFound->host_server_info_hasht, newJA3->ja3, strlen(newJA3->ja3), newJA3);
- }
- }
-
- HASH_FIND_STR(hostByJA3S_ht, all_flows[i].flow->ssh_ssl.ja3_server, hostByJA3Found);
- if(hostByJA3Found == NULL){
- ndpi_ip_dns *newHost = malloc(sizeof(ndpi_ip_dns));
-
- newHost->ip = all_flows[i].flow->dst_ip;
- newHost->ip_string = all_flows[i].flow->dst_name;
- newHost->dns_name = all_flows[i].flow->ssh_ssl.server_info;;
-
- ndpi_ja3_fingerprints_host *newElement = malloc(sizeof(ndpi_ja3_fingerprints_host));
- newElement->ja3 = all_flows[i].flow->ssh_ssl.ja3_server;
- newElement->unsafe_cipher = all_flows[i].flow->ssh_ssl.server_unsafe_cipher;
- newElement->ipToDNS_ht = NULL;
-
- HASH_ADD_INT(newElement->ipToDNS_ht, ip, newHost);
- HASH_ADD_KEYPTR(hh, hostByJA3S_ht, newElement->ja3, strlen(newElement->ja3), newElement);
- }else{
- ndpi_ip_dns *innerElement = NULL;
-
- HASH_FIND_INT(hostByJA3Found->ipToDNS_ht, &(all_flows[i].flow->dst_ip), innerElement);
- if(innerElement == NULL){
- ndpi_ip_dns *newInnerElement = malloc(sizeof(ndpi_ip_dns));
- newInnerElement->ip = all_flows[i].flow->dst_ip;
- newInnerElement->ip_string = all_flows[i].flow->dst_name;
- newInnerElement->dns_name = all_flows[i].flow->ssh_ssl.server_info;
- HASH_ADD_INT(hostByJA3Found->ipToDNS_ht, ip, newInnerElement);
- }
- }
-
- }
- }
-
- if(ja3ByHostsHashT) {
- ndpi_ja3_fingerprints_host *hostByJA3Element = NULL;
- ndpi_ja3_fingerprints_host *tmp3 = NULL;
- ndpi_ip_dns *innerHashEl = NULL;
- ndpi_ip_dns *tmp4 = NULL;
-
- if(verbose == 1) {
- /* for each host the number of flow with a ja3 fingerprint is printed */
- i = 1;
-
- printf("JA3 Host Stats: \n");
- printf("\t\t IP %-24s \t %-10s \n", "Address", "# JA3C");
-
- for(ja3ByHost_element = ja3ByHostsHashT; ja3ByHost_element != NULL; ja3ByHost_element = ja3ByHost_element->hh.next) {
- num_ja3_client = HASH_COUNT(ja3ByHost_element->host_client_info_hasht);
- num_ja3_server = HASH_COUNT(ja3ByHost_element->host_server_info_hasht);
-
- if(num_ja3_client > 0) {
- printf("\t%d\t %-24s \t %-7d\n",
- i,
- ja3ByHost_element->ip_string,
- num_ja3_client
- );
- i++;
- }
-
- }
- } else if(verbose == 2) {
- int i = 1;
- int againstRepeat;
- ndpi_ja3_fingerprints_host *hostByJA3Element = NULL;
- ndpi_ja3_fingerprints_host *tmp3 = NULL;
- ndpi_ip_dns *innerHashEl = NULL;
- ndpi_ip_dns *tmp4 = NULL;
-
- //for each host it is printted the JA3C and JA3S, along the server name (if any)
- //and the security status
-
- printf("JA3C/JA3S Host Stats: \n");
- printf("\t%-7s %-24s %-34s %s\n", "", "IP", "JA3C", "JA3S");
-
- //reminder
- //ja3ByHostsHashT: hash table <ip, (ja3, ht_client, ht_server)>
- //ja3ByHost_element: element of ja3ByHostsHashT
- //info_of_element: element of the inner hash table of ja3ByHost_element
- HASH_ITER(hh, ja3ByHostsHashT, ja3ByHost_element, tmp) {
- num_ja3_client = HASH_COUNT(ja3ByHost_element->host_client_info_hasht);
- num_ja3_server = HASH_COUNT(ja3ByHost_element->host_server_info_hasht);
- againstRepeat = 0;
- if(num_ja3_client > 0) {
- HASH_ITER(hh, ja3ByHost_element->host_client_info_hasht, info_of_element, tmp2) {
- printf("\t%-7d %-24s %s %s\n",
- i,
- ja3ByHost_element->ip_string,
- info_of_element->ja3,
- print_cipher(info_of_element->unsafe_cipher)
- );
- againstRepeat = 1;
- i++;
-
- }
- }
-
- if(num_ja3_server > 0) {
- HASH_ITER(hh, ja3ByHost_element->host_server_info_hasht, info_of_element, tmp2) {
- printf("\t%-7d %-24s %-34s %s %s %s%s%s\n",
- i,
- ja3ByHost_element->ip_string,
- "",
- info_of_element->ja3,
- print_cipher(info_of_element->unsafe_cipher),
- ja3ByHost_element->dns_name[0] ? "[" : "",
- ja3ByHost_element->dns_name,
- ja3ByHost_element->dns_name[0] ? "]" : ""
- );
- i++;
- }
- }
- }
-
- i = 1;
-
- printf("\nIP/JA3 Distribution:\n");
- printf("%-15s %-39s %-26s\n", "", "JA3", "IP");
- HASH_ITER(hh, hostByJA3C_ht, hostByJA3Element, tmp3) {
- againstRepeat = 0;
- HASH_ITER(hh, hostByJA3Element->ipToDNS_ht, innerHashEl, tmp4) {
- if(againstRepeat == 0) {
- printf("\t%-7d JA3C %s",
- i,
- hostByJA3Element->ja3
- );
- printf(" %-15s %s\n",
- innerHashEl->ip_string,
- print_cipher(hostByJA3Element->unsafe_cipher)
- );
- againstRepeat = 1;
- i++;
- } else {
- printf("\t%45s", "");
- printf(" %-15s %s\n",
- innerHashEl->ip_string,
- print_cipher(hostByJA3Element->unsafe_cipher)
- );
- }
- }
- }
- HASH_ITER(hh, hostByJA3S_ht, hostByJA3Element, tmp3) {
- againstRepeat = 0;
- HASH_ITER(hh, hostByJA3Element->ipToDNS_ht, innerHashEl, tmp4) {
- if(againstRepeat == 0) {
- printf("\t%-7d JA3S %s",
- i,
- hostByJA3Element->ja3
- );
- printf(" %-15s %-10s %s%s%s\n",
- innerHashEl->ip_string,
- print_cipher(hostByJA3Element->unsafe_cipher),
- innerHashEl->dns_name[0] ? "[" : "",
- innerHashEl->dns_name,
- innerHashEl->dns_name[0] ? "]" : ""
- );
- againstRepeat = 1;
- i++;
- }else{
- printf("\t%45s", "");
- printf(" %-15s %-10s %s%s%s\n",
- innerHashEl->ip_string,
- print_cipher(hostByJA3Element->unsafe_cipher),
- innerHashEl->dns_name[0] ? "[" : "",
- innerHashEl->dns_name,
- innerHashEl->dns_name[0] ? "]" : ""
- );
- }
- }
- }
- }
- printf("\n\n");
-
- //freeing the hash table
- HASH_ITER(hh, ja3ByHostsHashT, ja3ByHost_element, tmp) {
- HASH_ITER(hh, ja3ByHost_element->host_client_info_hasht, info_of_element, tmp2) {
- HASH_DEL(ja3ByHost_element->host_client_info_hasht, info_of_element);
- free(info_of_element);
- }
- HASH_ITER(hh, ja3ByHost_element->host_server_info_hasht, info_of_element, tmp2) {
- HASH_DEL(ja3ByHost_element->host_server_info_hasht, info_of_element);
- free(info_of_element);
- }
- HASH_DEL(ja3ByHostsHashT, ja3ByHost_element);
- free(ja3ByHost_element);
- }
-
- HASH_ITER(hh, hostByJA3C_ht, hostByJA3Element, tmp3) {
- HASH_ITER(hh, hostByJA3C_ht->ipToDNS_ht, innerHashEl, tmp4) {
- HASH_DEL(hostByJA3Element->ipToDNS_ht, innerHashEl);
- free(innerHashEl);
- }
- HASH_DEL(hostByJA3C_ht, hostByJA3Element);
- free(hostByJA3Element);
- }
- hostByJA3Element = NULL;
- HASH_ITER(hh, hostByJA3S_ht, hostByJA3Element, tmp3) {
- HASH_ITER(hh, hostByJA3S_ht->ipToDNS_ht, innerHashEl, tmp4) {
- HASH_DEL(hostByJA3Element->ipToDNS_ht, innerHashEl);
- free(innerHashEl);
- }
- HASH_DEL(hostByJA3S_ht, hostByJA3Element);
- free(hostByJA3Element);
- }
- }
-
- qsort(all_flows, num_flows, sizeof(struct flow_info), cmpFlows);
-
- for(i=0; i<num_flows; i++)
- printFlow(i+1, all_flows[i].flow, all_flows[i].thread_id);
-
- for(thread_id = 0; thread_id < num_threads; thread_id++) {
- if(ndpi_thread_info[thread_id].workflow->stats.protocol_counter[0 /* 0 = Unknown */] > 0) {
- if(!json_flag) {
- FILE *out = results_file ? results_file : stdout;
-
- fprintf(out, "\n\nUndetected flows:%s\n", undetected_flows_deleted ? " (expired flows are not listed below)" : "");
- }
-
- if(json_flag)
- json_flag = 2;
- break;
- }
- }
-
- num_flows = 0;
- for(thread_id = 0; thread_id < num_threads; thread_id++) {
- if(ndpi_thread_info[thread_id].workflow->stats.protocol_counter[0] > 0) {
- for(i=0; i<NUM_ROOTS; i++)
- ndpi_twalk(ndpi_thread_info[thread_id].workflow->ndpi_flows_root[i], node_print_unknown_proto_walker, &thread_id);
- }
- }
-
- qsort(all_flows, num_flows, sizeof(struct flow_info), cmpFlows);
-
- for(i=0; i<num_flows; i++)
- printFlow(i+1, all_flows[i].flow, all_flows[i].thread_id);
-
- free(all_flows);
- }
+ printFlowsStats();
if(json_flag != 0) {
#ifdef HAVE_JSON_C
diff --git a/tests/do.sh b/tests/do.sh
index a17878fb5..62b51288e 100755
--- a/tests/do.sh
+++ b/tests/do.sh
@@ -8,7 +8,7 @@ build_results() {
#echo $f
# create result files if not present
if [ ! -f result/$f.out ]; then
- CMD="$READER -q -i pcap/$f -w result/$f.out -v 1"
+ CMD="$READER -q -i pcap/$f -w result/$f.out -v 2"
$CMD
fi
done
@@ -17,7 +17,7 @@ build_results() {
check_results() {
for f in $PCAPS; do
if [ -f result/$f.out ]; then
- CMD="$READER -q -i pcap/$f -w /tmp/reader.out -v 1"
+ CMD="$READER -q -i pcap/$f -w /tmp/reader.out -v 2"
$CMD
NUM_DIFF=`diff result/$f.out /tmp/reader.out | wc -l`
diff --git a/tests/pcap/nintendo.pcap b/tests/pcap/nintendo.pcap
index 471fe212c..a352d521d 100644
--- a/tests/pcap/nintendo.pcap
+++ b/tests/pcap/nintendo.pcap
Binary files differ
diff --git a/tests/pcap/skype-conference-call.pcap b/tests/pcap/skype-conference-call.pcap
index ae03f375d..79671510f 100644
--- a/tests/pcap/skype-conference-call.pcap
+++ b/tests/pcap/skype-conference-call.pcap
Binary files differ
diff --git a/tests/result/1kxun.pcap.out b/tests/result/1kxun.pcap.out
index 3e5a68421..0bd98717d 100644
--- a/tests/result/1kxun.pcap.out
+++ b/tests/result/1kxun.pcap.out
@@ -8,13 +8,17 @@ SSDP 143 36951 13
DHCP 24 8208 5
QQ 28 5216 2
RTP 2 132 1
-SSL 82 14480 6
+SSL 105 21914 7
DHCPV6 10 980 3
Facebook 19 6840 2
Google 3 176 1
GenericProtocol 433 311919 14
LLMNR 89 6799 47
-WhatsAppVoice 23 7434 1
+
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.5.16 2
+
1 TCP 192.168.115.8:49613 <-> 183.131.48.144:80 [proto: 7/HTTP][cat: Web/5][260 pkts/15070 bytes <-> 159 pkts/168623 bytes][Host: 183.131.48.144]
2 TCP 192.168.115.8:49600 <-> 106.187.35.246:80 [proto: 7.137/HTTP.GenericProtocol][cat: Streaming/17][18 pkts/1722 bytes <-> 51 pkts/61707 bytes][Host: pic.1kxun.com]
@@ -29,7 +33,7 @@ WhatsAppVoice 23 7434 1
11 TCP 192.168.5.16:53628 <-> 203.69.81.73:80 [proto: 7/HTTP][cat: Web/5][6 pkts/676 bytes <-> 8 pkts/8482 bytes][Host: dl-obs.official.line.naver.jp]
12 UDP [fe80::9bd:81dd:2fdc:5750]:1900 -> [ff02::c]:1900 [proto: 12/SSDP][cat: System/18][16 pkts/8921 bytes -> 0 pkts/0 bytes]
13 UDP 192.168.5.49:1900 -> 239.255.255.250:1900 [proto: 12/SSDP][cat: System/18][16 pkts/8473 bytes -> 0 pkts/0 bytes]
- 14 TCP 119.235.235.84:443 <-> 192.168.5.16:53406 [proto: 189/WhatsAppVoice][cat: VoIP/10][13 pkts/6269 bytes <-> 10 pkts/1165 bytes]
+ 14 TCP 119.235.235.84:443 <-> 192.168.5.16:53406 [proto: 91/SSL][cat: Web/5][13 pkts/6269 bytes <-> 10 pkts/1165 bytes]
15 TCP 192.168.115.8:49608 <-> 203.205.151.234:80 [proto: 7.48/HTTP.QQ][cat: Chat/9][18 pkts/3550 bytes <-> 7 pkts/1400 bytes][Host: vv.video.qq.com]
16 UDP 192.168.119.1:67 -> 255.255.255.255:68 [proto: 18/DHCP][cat: Network/14][14 pkts/4788 bytes -> 0 pkts/0 bytes]
17 TCP 192.168.5.16:53580 <-> 31.13.87.36:443 [proto: 64.119/SSL_No_Cert.Facebook][cat: SocialNetwork/6][4 pkts/2050 bytes <-> 5 pkts/2297 bytes]
diff --git a/tests/result/6in4tunnel.pcap.out b/tests/result/6in4tunnel.pcap.out
index fb2ecaf39..0f68a4778 100644
--- a/tests/result/6in4tunnel.pcap.out
+++ b/tests/result/6in4tunnel.pcap.out
@@ -4,6 +4,11 @@ SSL 28 15397 1
ICMPV6 48 7862 3
Facebook 37 14726 3
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 2001:470:1f17:13f:3e97:eff:fe73:4dec 2
+
+
1 TCP [2001:470:1f17:13f:3e97:eff:fe73:4dec]:60205 <-> [2604:a880:1:20::224:b001]:443 [proto: 91/SSL][cat: Web/5][14 pkts/2312 bytes <-> 14 pkts/13085 bytes][TLSv1.2][JA3C: 812d8bce0f85487ba7834d36568ed586][server: mail.tomasu.net][JA3S: 389ed42c02ebecc32e73aa31def07e14][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
2 TCP [2001:470:1f17:13f:3e97:eff:fe73:4dec]:53234 <-> [2a03:2880:1010:6f03:face:b00c::2]:443 [proto: 91.119/SSL.Facebook][cat: SocialNetwork/6][18 pkts/6894 bytes <-> 15 pkts/7032 bytes][TLSv1.2][JA3C: eb7cdd4e7dea7a11b3016c3c9acbd2a3][server: *.facebook.com][JA3S: 6806b8fe92d7d465715d771eb102ff04][organization: Facebook, Inc.][Cipher: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]
3 ICMPV6 [2001:470:1f17:13f:3e97:eff:fe73:4dec]:0 <-> [2604:a880:1:20::224:b001]:0 [proto: 102/ICMPV6][cat: Network/14][23 pkts/3174 bytes <-> 23 pkts/3174 bytes]
diff --git a/tests/result/Instagram.pcap.out b/tests/result/Instagram.pcap.out
index 2d518cf06..9051db01b 100644
--- a/tests/result/Instagram.pcap.out
+++ b/tests/result/Instagram.pcap.out
@@ -6,6 +6,11 @@ Facebook 251 215986 5
Dropbox 5 725 2
Instagram 363 255094 16
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.0.103 1
+
+
1 TCP 31.13.86.52:80 <-> 192.168.0.103:58216 [proto: 7.119/HTTP.Facebook][cat: SocialNetwork/6][103 pkts/150456 bytes <-> 47 pkts/3102 bytes]
2 TCP 192.168.0.103:38816 <-> 46.33.70.160:80 [proto: 7.211/HTTP.Instagram][cat: SocialNetwork/6][13 pkts/1118 bytes <-> 39 pkts/57876 bytes][Host: photos-h.ak.instagram.com]
3 TCP 192.168.0.103:58052 <-> 82.85.26.162:80 [proto: 7.211/HTTP.Instagram][cat: SocialNetwork/6][37 pkts/2702 bytes <-> 38 pkts/54537 bytes][Host: photos-g.ak.instagram.com]
diff --git a/tests/result/KakaoTalk_chat.pcap.out b/tests/result/KakaoTalk_chat.pcap.out
index 82e8dedd2..9a3ee3041 100644
--- a/tests/result/KakaoTalk_chat.pcap.out
+++ b/tests/result/KakaoTalk_chat.pcap.out
@@ -8,6 +8,11 @@ HTTP_Proxy 26 3926 1
Amazon 8 2071 2
KakaoTalk 55 9990 15
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 10.24.82.188 2
+
+
1 TCP 10.24.82.188:43581 <-> 31.13.68.70:443 [proto: 91.119/SSL.Facebook][cat: SocialNetwork/6][17 pkts/3461 bytes <-> 17 pkts/6194 bytes][TLSv1.2][JA3C: 051d20e8adbe8dac78945de300764d5e][server: *.facebook.com][JA3S: 6806b8fe92d7d465715d771eb102ff04][organization: Facebook, Inc.][Cipher: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]
2 TCP 10.24.82.188:45211 <-> 31.13.68.84:443 [proto: 91.119/SSL.Facebook][cat: SocialNetwork/6][14 pkts/2575 bytes <-> 15 pkts/6502 bytes][TLSv1.2][JA3C: 051d20e8adbe8dac78945de300764d5e][server: *.facebook.com][JA3S: 6806b8fe92d7d465715d771eb102ff04][organization: Facebook, Inc.][Cipher: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]
3 TCP 10.24.82.188:45209 <-> 31.13.68.84:443 [proto: 91.119/SSL.Facebook][cat: SocialNetwork/6][10 pkts/2584 bytes <-> 9 pkts/5123 bytes][TLSv1.2][JA3C: 051d20e8adbe8dac78945de300764d5e][server: *.facebook.com][JA3S: 6806b8fe92d7d465715d771eb102ff04][organization: Facebook, Inc.][Cipher: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]
diff --git a/tests/result/KakaoTalk_talk.pcap.out b/tests/result/KakaoTalk_talk.pcap.out
index 5776808e1..37e9970a8 100644
--- a/tests/result/KakaoTalk_talk.pcap.out
+++ b/tests/result/KakaoTalk_talk.pcap.out
@@ -9,6 +9,11 @@ Tor 40 10538 1
Amazon 4 396 1
KakaoTalk_Voice 44 6196 2
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 10.24.82.188 2
+
+
1 UDP 10.24.82.188:11320 <-> 1.201.1.174:23044 [proto: 87/RTP][cat: Media/1][757 pkts/106335 bytes <-> 746 pkts/93906 bytes]
2 UDP 10.24.82.188:10268 <-> 1.201.1.174:23046 [proto: 87/RTP][cat: Media/1][746 pkts/93906 bytes <-> 742 pkts/104604 bytes]
3 TCP 10.24.82.188:58857 <-> 110.76.143.50:9001 [proto: 163/Tor][cat: VPN/2][22 pkts/5326 bytes <-> 18 pkts/5212 bytes]
diff --git a/tests/result/dnscrypt.pcap.out b/tests/result/dnscrypt.pcap.out
index 16cf3d40e..370b998cb 100644
--- a/tests/result/dnscrypt.pcap.out
+++ b/tests/result/dnscrypt.pcap.out
@@ -1,5 +1,10 @@
SSL 111 44676 4
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.43.167 2
+
+
1 TCP 192.168.43.167:50233 <-> 134.119.26.24:443 [proto: 91/SSL][cat: Web/5][18 pkts/1788 bytes <-> 21 pkts/14580 bytes][TLSv1.2][JA3C: b8f81673c0e1d29908346f3bab892b9b][server: simplednscrypt.org][JA3S: 76cc3e2d3028143b23ec18e27dbd7ca9][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
2 TCP 192.168.43.167:50259 <-> 134.119.26.24:443 [proto: 91/SSL][cat: Web/5][18 pkts/1988 bytes <-> 18 pkts/9290 bytes][TLSv1.2][JA3C: 83e04bc58d402f9633983cbf22724b02][server: simplednscrypt.org][JA3S: 76cc3e2d3028143b23ec18e27dbd7ca9][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
3 TCP 192.168.43.167:50253 <-> 134.119.26.24:443 [proto: 91/SSL][cat: Web/5][8 pkts/780 bytes <-> 10 pkts/7735 bytes][TLSv1.2][JA3C: 83e04bc58d402f9633983cbf22724b02][server: simplednscrypt.org][JA3S: 76cc3e2d3028143b23ec18e27dbd7ca9][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
diff --git a/tests/result/facebook.pcap.out b/tests/result/facebook.pcap.out
index 978287501..3a52bb53a 100644
--- a/tests/result/facebook.pcap.out
+++ b/tests/result/facebook.pcap.out
@@ -1,4 +1,9 @@
Facebook 60 30511 2
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.43.18 2
+
+
1 TCP 192.168.43.18:44614 <-> 31.13.86.36:443 [proto: 91.119/SSL.Facebook][cat: SocialNetwork/6][19 pkts/2664 bytes <-> 22 pkts/22102 bytes][TLSv1.2][JA3C: 5c60e71f1b8cd40e4d40ed5b6d666e3f][JA3S: 96681175a9547081bf3d417f1a572091][Cipher: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]
2 TCP 192.168.43.18:52066 <-> 66.220.156.68:443 [proto: 91.119/SSL.Facebook][cat: SocialNetwork/6][9 pkts/1345 bytes <-> 10 pkts/4400 bytes][TLSv1.2][JA3C: bfcc1a3891601edb4f137ab7ab25b840][server: *.facebook.com][JA3S: 2d1eb5817ece335c24904f516ad5da12][organization: Facebook, Inc.][Cipher: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]
diff --git a/tests/result/google_ssl.pcap.out b/tests/result/google_ssl.pcap.out
index 095d4c164..52d500449 100644
--- a/tests/result/google_ssl.pcap.out
+++ b/tests/result/google_ssl.pcap.out
@@ -1,3 +1,7 @@
Google 28 9108 1
+JA3 Host Stats:
+ IP Address # JA3C
+
+
1 TCP 172.31.3.224:42835 <-> 216.58.212.100:443 [proto: 91.126/SSL.Google][cat: Web/5][16 pkts/1512 bytes <-> 12 pkts/7596 bytes][TLSv1][server: www.google.com][JA3S: 7252ecc446aba4a3e474793ae320609a (INSECURE)][Cipher: TLS_RSA_WITH_RC4_128_SHA]
diff --git a/tests/result/http_ipv6.pcap.out b/tests/result/http_ipv6.pcap.out
index 6077b0799..b4bc6c1b1 100644
--- a/tests/result/http_ipv6.pcap.out
+++ b/tests/result/http_ipv6.pcap.out
@@ -4,6 +4,11 @@ Facebook 22 10202 2
Google 62 15977 1
QUIC 3 502 1
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 2a00:d40:1:3:7aac:c0ff:fea7:d4c 1
+
+
1 UDP [2a00:d40:1:3:7aac:c0ff:fea7:d4c]:45931 <-> [2a00:1450:4001:803::1017]:443 [proto: 188.126/QUIC.Google][cat: Web/5][33 pkts/7741 bytes <-> 29 pkts/8236 bytes][Host: www.google.it]
2 TCP [2a00:d40:1:3:7aac:c0ff:fea7:d4c]:37506 <-> [2a03:b0c0:3:d0::70:1001]:443 [proto: 91.26/SSL.ntop][cat: Network/14][14 pkts/3969 bytes <-> 12 pkts/11648 bytes][TLSv1][JA3C: d3e627f423a33ea41841c19b8af79293]
3 TCP [2a00:d40:1:3:7aac:c0ff:fea7:d4c]:37486 <-> [2a03:b0c0:3:d0::70:1001]:443 [proto: 91.26/SSL.ntop][cat: Network/14][11 pkts/1292 bytes <-> 8 pkts/5722 bytes][TLSv1][JA3C: d3e627f423a33ea41841c19b8af79293]
diff --git a/tests/result/netflix.pcap.out b/tests/result/netflix.pcap.out
index a6a4c49a0..44f330ddb 100644
--- a/tests/result/netflix.pcap.out
+++ b/tests/result/netflix.pcap.out
@@ -4,6 +4,11 @@ IGMP 1 60 1
NetFlix 6976 6151821 56
Amazon 2 126 1
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.1.7 4
+
+
1 TCP 192.168.1.7:53217 <-> 23.246.11.141:80 [proto: 7.133/HTTP.NetFlix][cat: Video/26][667 pkts/50462 bytes <-> 1205 pkts/1807875 bytes][Host: 23.246.11.141]
2 TCP 192.168.1.7:53183 <-> 23.246.3.140:80 [proto: 7.133/HTTP.NetFlix][cat: Video/26][502 pkts/40335 bytes <-> 805 pkts/1202445 bytes][Host: 23.246.3.140]
3 TCP 192.168.1.7:53210 <-> 23.246.11.133:80 [proto: 7.133/HTTP.NetFlix][cat: Video/26][293 pkts/23170 bytes <-> 495 pkts/736113 bytes][Host: 23.246.11.133]
diff --git a/tests/result/nintendo.pcap.out b/tests/result/nintendo.pcap.out
index 106433672..6f8786352 100644
--- a/tests/result/nintendo.pcap.out
+++ b/tests/result/nintendo.pcap.out
@@ -2,6 +2,11 @@ ICMP 30 2100 2
Nintendo 890 320242 12
Amazon 76 10811 7
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.12.114 1
+
+
1 UDP 192.168.12.114:55915 <-> 185.118.169.65:27520 [proto: 173/Nintendo][cat: Game/8][169 pkts/61414 bytes <-> 278 pkts/126260 bytes]
2 UDP 192.168.12.114:55915 <-> 93.237.131.235:56066 [proto: 173/Nintendo][cat: Game/8][122 pkts/48332 bytes <-> 35 pkts/5026 bytes]
3 UDP 192.168.12.114:55915 <-> 81.61.158.138:51769 [proto: 173/Nintendo][cat: Game/8][122 pkts/46476 bytes <-> 38 pkts/5268 bytes]
diff --git a/tests/result/ocs.pcap.out b/tests/result/ocs.pcap.out
index aba9b8de9..25ed25228 100644
--- a/tests/result/ocs.pcap.out
+++ b/tests/result/ocs.pcap.out
@@ -7,6 +7,11 @@ OCS 863 57552 7
PlayStore 1 72 1
GoogleServices 13 2277 2
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.180.2 4
+
+
1 TCP 192.168.180.2:49881 -> 178.248.208.54:80 [proto: 7.218/HTTP.OCS][cat: Media/1][751 pkts/44783 bytes -> 0 pkts/0 bytes][Host: ocu03.labgency.ws]
2 TCP 192.168.180.2:36680 -> 178.248.208.54:443 [proto: 91.218/SSL.OCS][cat: Media/1][20 pkts/6089 bytes -> 0 pkts/0 bytes][TLSv1][JA3C: 0534a22b266a64a5cc9a90f7b5c483cc]
3 TCP 192.168.180.2:42590 -> 178.248.208.210:80 [proto: 7.218/HTTP.OCS][cat: Media/1][83 pkts/5408 bytes -> 0 pkts/0 bytes][Host: www.ocs.fr]
diff --git a/tests/result/skype.pcap.out b/tests/result/skype.pcap.out
index 07806e8fb..d0961b760 100644
--- a/tests/result/skype.pcap.out
+++ b/tests/result/skype.pcap.out
@@ -15,6 +15,11 @@ Spotify 5 430 1
MS_OneDrive 387 198090 1
ApplePush 12 1877 1
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.1.34 1
+
+
1 TCP 192.168.1.34:50028 <-> 157.56.126.211:443 [proto: 91.221/SSL.MS_OneDrive][cat: Cloud/13][187 pkts/42539 bytes <-> 200 pkts/155551 bytes][TLSv1][server: *.gateway.messenger.live.com][JA3S: d9699a2032a6c5371343b7f7dfd94abe][Cipher: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA]
2 TCP 192.168.1.34:50108 <-> 157.56.52.28:40009 [proto: 125/Skype][cat: VoIP/10][231 pkts/60232 bytes <-> 241 pkts/104395 bytes]
3 UDP 192.168.0.254:1025 -> 239.255.255.250:1900 [proto: 12/SSDP][cat: System/18][79 pkts/29479 bytes -> 0 pkts/0 bytes]
diff --git a/tests/result/skype_no_unknown.pcap.out b/tests/result/skype_no_unknown.pcap.out
index e67fec364..17c7eb819 100644
--- a/tests/result/skype_no_unknown.pcap.out
+++ b/tests/result/skype_no_unknown.pcap.out
@@ -13,6 +13,11 @@ Apple 76 19581 1
MS_OneDrive 348 181687 1
ApplePush 8 1118 1
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.1.34 1
+
+
1 TCP 192.168.1.34:51230 <-> 157.56.126.211:443 [proto: 91.221/SSL.MS_OneDrive][cat: Cloud/13][166 pkts/39042 bytes <-> 182 pkts/142645 bytes][TLSv1][server: *.gateway.messenger.live.com][JA3S: d9699a2032a6c5371343b7f7dfd94abe][Cipher: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA]
2 TCP 192.168.1.34:51279 <-> 111.221.74.48:40008 [proto: 125/Skype][cat: VoIP/10][101 pkts/30681 bytes <-> 98 pkts/59934 bytes]
3 TCP 192.168.1.34:51227 <-> 17.172.100.36:443 [proto: 64.140/SSL_No_Cert.Apple][cat: Web/5][38 pkts/9082 bytes <-> 38 pkts/10499 bytes]
diff --git a/tests/result/snapchat.pcap.out b/tests/result/snapchat.pcap.out
index da61eeb97..c102086fb 100644
--- a/tests/result/snapchat.pcap.out
+++ b/tests/result/snapchat.pcap.out
@@ -1,6 +1,11 @@
Google 22 2879 1
Snapchat 34 7320 2
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 10.8.0.1 2
+
+
1 TCP 10.8.0.1:56193 <-> 74.125.136.141:443 [proto: 91.199/SSL.Snapchat][cat: SocialNetwork/6][9 pkts/2290 bytes <-> 8 pkts/1653 bytes][TLSv1.2][JA3C: fded31ac9b978e56ce306f8056092f2a][JA3S: 7bee5c1d424b7e5f943b06983bb11422][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
2 TCP 10.8.0.1:44536 <-> 74.125.136.141:443 [proto: 91.199/SSL.Snapchat][cat: SocialNetwork/6][9 pkts/2345 bytes <-> 8 pkts/1032 bytes][TLSv1.2][JA3C: fded31ac9b978e56ce306f8056092f2a][JA3S: 7bee5c1d424b7e5f943b06983bb11422][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
3 TCP 10.8.0.1:33233 <-> 74.125.136.141:443 [proto: 91.126/SSL.Google][cat: Web/5][11 pkts/1910 bytes <-> 11 pkts/969 bytes][TLSv1.2][JA3C: 36e9ceaa96dd810482573844f78a063f][JA3S: fbe78c619e7ea20046131294ad087f05][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
diff --git a/tests/result/viber.pcap.out b/tests/result/viber.pcap.out
index 750a91f31..31173c4a6 100644
--- a/tests/result/viber.pcap.out
+++ b/tests/result/viber.pcap.out
@@ -8,6 +8,11 @@ Google 32 9133 3
Viber 268 99524 9
Amazon 71 24849 3
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.0.17 2
+
+
1 TCP 192.168.0.17:53934 <-> 54.230.93.53:443 [proto: 91.144/SSL.Viber][cat: VoIP/10][43 pkts/4571 bytes <-> 46 pkts/60087 bytes][TLSv1.2][JA3C: d8c87b9bfde38897979e41242626c2f3][server: *.viber.com][JA3S: 76cc3e2d3028143b23ec18e27dbd7ca9][organization: Viber Media Sarl][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
2 TCP 192.168.0.17:57520 <-> 54.230.93.96:443 [proto: 91.144/SSL.Viber][cat: VoIP/10][12 pkts/1848 bytes <-> 12 pkts/9317 bytes][TLSv1.2][JA3C: d8c87b9bfde38897979e41242626c2f3][server: *.cdn.viber.com][JA3S: 76cc3e2d3028143b23ec18e27dbd7ca9][organization: Viber Media Sarl][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
3 TCP 192.168.0.17:49048 <-> 54.187.91.182:443 [proto: 91.178/SSL.Amazon][cat: Web/5][13 pkts/2823 bytes <-> 14 pkts/6552 bytes][TLSv1.2][JA3C: d8c87b9bfde38897979e41242626c2f3][server: *.apptimize.com][JA3S: 8d2a028aa94425f76ced7826b1f39039][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
diff --git a/tests/result/waze.pcap.out b/tests/result/waze.pcap.out
index b1ec85fa6..a72664fe7 100644
--- a/tests/result/waze.pcap.out
+++ b/tests/result/waze.pcap.out
@@ -6,6 +6,11 @@ Google 13 2142 1
Waze 484 289335 19
WhatsApp 15 1341 1
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 10.8.0.1 2
+
+
1 TCP 10.8.0.1:36100 <-> 46.51.173.182:443 [proto: 91.135/SSL.Waze][cat: Web/5][52 pkts/10860 bytes <-> 55 pkts/74852 bytes][TLSv1][JA3C: f392f120f1087cd2f8814539cf58cfa4][server: *.world.waze.com][JA3S: 714ac86d50db68420429ca897688f5f3 (WEAK)][Cipher: TLS_RSA_WITH_AES_256_CBC_SHA]
2 TCP 10.8.0.1:54915 <-> 65.39.128.135:80 [proto: 7/HTTP][cat: Web/5][19 pkts/1309 bytes <-> 18 pkts/61896 bytes][Host: xtra1.gpsonextra.net]
3 TCP 10.8.0.1:39021 <-> 52.17.114.219:443 [proto: 91.135/SSL.Waze][cat: Web/5][17 pkts/1962 bytes <-> 16 pkts/56934 bytes][TLSv1][JA3C: f392f120f1087cd2f8814539cf58cfa4][server: *.world.waze.com][JA3S: 39f74f5618836d3c5f7dcccc9f67ba75][Cipher: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA]
diff --git a/tests/result/webex.pcap.out b/tests/result/webex.pcap.out
index a193378c0..f8415c9eb 100644
--- a/tests/result/webex.pcap.out
+++ b/tests/result/webex.pcap.out
@@ -5,6 +5,11 @@ Google 17 6375 1
Webex 1380 818407 43
Amazon 33 9742 2
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 10.8.0.1 6
+
+
1 TCP 10.8.0.1:51155 <-> 62.109.224.120:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][256 pkts/14707 bytes <-> 257 pkts/329379 bytes][TLSv1][JA3C: 7cb93b2404a98399e9f84c74fef1fb8f][server: *.webex.com][JA3S: 91589ea825a2ee41810c85fab06d2ef6 (WEAK)][Cipher: TLS_RSA_WITH_AES_256_CBC_SHA]
2 TCP 10.8.0.1:41348 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][28 pkts/4815 bytes <-> 28 pkts/104881 bytes][TLSv1.2][JA3C: f9010d8c34749bdf7659b52227e6f91b][JA3S: c253ec3ad88e42f8da4032682892f9a0 (INSECURE)][Cipher: TLS_RSA_WITH_RC4_128_MD5]
3 TCP 10.8.0.1:41346 <-> 64.68.105.103:443 [proto: 91.141/SSL.Webex][cat: VoIP/10][48 pkts/11540 bytes <-> 47 pkts/80696 bytes][TLSv1.2][JA3C: f9010d8c34749bdf7659b52227e6f91b][server: *.webex.com][JA3S: c253ec3ad88e42f8da4032682892f9a0 (INSECURE)][organization: Cisco Systems, Inc.][Cipher: TLS_RSA_WITH_RC4_128_MD5]
diff --git a/tests/result/wechat.pcap.out b/tests/result/wechat.pcap.out
index aa6c0574d..87552d19b 100644
--- a/tests/result/wechat.pcap.out
+++ b/tests/result/wechat.pcap.out
@@ -13,6 +13,11 @@ LLMNR 12 944 6
WeChat 1251 606425 49
GoogleDocs 15 5114 2
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.1.103 3
+
+
1 TCP 203.205.151.162:443 <-> 192.168.1.103:54058 [proto: 64.197/SSL_No_Cert.WeChat][cat: SocialNetwork/6][88 pkts/15114 bytes <-> 91 pkts/61842 bytes]
2 TCP 192.168.1.103:54101 <-> 203.205.151.162:443 [proto: 91.197/SSL.WeChat][cat: SocialNetwork/6][46 pkts/12575 bytes <-> 40 pkts/53424 bytes][TLSv1.2][JA3C: e330bca99c8a5256ae126a55c4c725c5][server: web.wechat.com][JA3S: 699a80bdb17efe157c861f92c5bf5d1d][organization: Tencent Mobility Limited][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
3 TCP 192.168.1.103:54103 <-> 203.205.151.162:443 [proto: 91.197/SSL.WeChat][cat: SocialNetwork/6][50 pkts/23958 bytes <-> 46 pkts/39684 bytes][TLSv1.2][JA3C: e330bca99c8a5256ae126a55c4c725c5][server: web.wechat.com][JA3S: 699a80bdb17efe157c861f92c5bf5d1d][organization: Tencent Mobility Limited][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
diff --git a/tests/result/weibo.pcap.out b/tests/result/weibo.pcap.out
index 757e05465..c96c0eb3a 100644
--- a/tests/result/weibo.pcap.out
+++ b/tests/result/weibo.pcap.out
@@ -5,6 +5,11 @@ Google 33 4778 7
Amazon 2 132 1
Sina(Weibo) 419 258077 16
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.1.105 1
+
+
1 TCP 192.168.1.105:35803 <-> 93.188.134.246:80 [proto: 7.200/HTTP.Sina(Weibo)][cat: SocialNetwork/6][52 pkts/5367 bytes <-> 54 pkts/71536 bytes][Host: img.t.sinajs.cn]
2 TCP 192.168.1.105:35804 <-> 93.188.134.246:80 [proto: 7.200/HTTP.Sina(Weibo)][cat: SocialNetwork/6][32 pkts/3624 bytes <-> 40 pkts/50657 bytes][Host: img.t.sinajs.cn]
3 TCP 192.168.1.105:51698 <-> 93.188.134.137:80 [proto: 7.200/HTTP.Sina(Weibo)][cat: SocialNetwork/6][40 pkts/3462 bytes <-> 39 pkts/34030 bytes][Host: www.weibo.com]
diff --git a/tests/result/whatsapp_login_call.pcap.out b/tests/result/whatsapp_login_call.pcap.out
index 78f8758ea..ef3bad8f5 100644
--- a/tests/result/whatsapp_login_call.pcap.out
+++ b/tests/result/whatsapp_login_call.pcap.out
@@ -12,6 +12,11 @@ Spotify 3 258 1
WhatsAppVoice 70 9464 14
ApplePush 22 5926 1
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.2.4 1
+
+
1 UDP 192.168.2.4:51518 <-> 91.253.176.65:9344 [proto: 87/RTP][cat: Media/1][186 pkts/27025 bytes <-> 278 pkts/25895 bytes]
2 UDP 192.168.2.4:52794 <-> 91.253.176.65:9665 [proto: 87/RTP][cat: Media/1][141 pkts/17530 bytes <-> 57 pkts/12888 bytes]
3 TCP 192.168.2.4:49202 <-> 184.173.179.37:5222 [proto: 142/WhatsApp][cat: Chat/9][100 pkts/14711 bytes <-> 80 pkts/10163 bytes]
diff --git a/tests/result/whatsappfiles.pcap.out b/tests/result/whatsappfiles.pcap.out
index 4b596509d..e69d94801 100644
--- a/tests/result/whatsappfiles.pcap.out
+++ b/tests/result/whatsappfiles.pcap.out
@@ -1,4 +1,9 @@
WhatsAppFiles 620 452233 2
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.2.29 2
+
+
1 TCP 192.168.2.29:49698 <-> 185.60.216.53:443 [proto: 91.242/SSL.WhatsAppFiles][cat: Download-FileTransfer-FileSharing/7][132 pkts/9906 bytes <-> 178 pkts/237405 bytes][TLSv1.2][JA3C: 4e1a414c4f4c99097edd2a9a98e336c8][JA3S: 96681175a9547081bf3d417f1a572091][Cipher: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]
2 TCP 192.168.2.29:49674 <-> 185.60.216.53:443 [proto: 91.242/SSL.WhatsAppFiles][cat: Download-FileTransfer-FileSharing/7][161 pkts/189194 bytes <-> 149 pkts/15728 bytes][TLSv1.2][JA3C: 107144b88827da5da9ed42d8776ccdc5][server: *.whatsapp.net][JA3S: 2d1eb5817ece335c24904f516ad5da12][organization: Facebook, Inc.][Cipher: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]
diff --git a/tests/result/youtubeupload.pcap.out b/tests/result/youtubeupload.pcap.out
index 747b02dd5..2286e3ffb 100644
--- a/tests/result/youtubeupload.pcap.out
+++ b/tests/result/youtubeupload.pcap.out
@@ -1,5 +1,10 @@
YouTubeUpload 137 127038 3
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.2.27 1
+
+
1 UDP 192.168.2.27:51925 <-> 172.217.23.111:443 [proto: 188.136/QUIC.YouTubeUpload][cat: Media/1][80 pkts/100473 bytes <-> 20 pkts/6003 bytes][Host: upload.youtube.com]
2 UDP 192.168.2.27:62232 <-> 172.217.23.111:443 [proto: 188.136/QUIC.YouTubeUpload][cat: Media/1][13 pkts/8651 bytes <-> 11 pkts/6463 bytes][Host: upload.youtube.com]
3 TCP 192.168.2.27:57452 <-> 172.217.23.111:443 [proto: 91.136/SSL.YouTubeUpload][cat: Media/1][6 pkts/649 bytes <-> 7 pkts/4799 bytes][TLSv1.2][JA3C: bc6c386f480ee97b9d9e52d472b772d8][server: upload.video.google.com][JA3S: b26c652e0a402a24b5ca2a660e84f9d5][organization: Google Inc][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]