aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--example/ndpiReader.c21
-rw-r--r--example/ndpi_util.c46
-rw-r--r--example/ndpi_util.h1
-rw-r--r--src/include/ndpi_protocol_ids.h2
-rw-r--r--src/lib/ndpi_content_match.c.inc1
-rw-r--r--src/lib/ndpi_main.c4
-rw-r--r--src/lib/protocols/btlib.c10
-rw-r--r--src/lib/protocols/dhcp.c13
-rw-r--r--src/lib/protocols/memcached.c160
-rw-r--r--src/lib/protocols/openvpn.c69
-rw-r--r--src/lib/protocols/stun.c191
-rw-r--r--src/lib/protocols/viber.c2
-rw-r--r--tests/result/1kxun.pcap.out8
-rw-r--r--tests/result/wechat.pcap.out2
-rw-r--r--tests/result/whatsapp_login_call.pcap.out2
-rw-r--r--tests/result/whatsapp_login_chat.pcap.out2
16 files changed, 305 insertions, 229 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c
index 87d86eaa0..8551992bf 100644
--- a/example/ndpiReader.c
+++ b/example/ndpiReader.c
@@ -18,9 +18,7 @@
*
*/
-#ifdef HAVE_CONFIG_H
#include "ndpi_config.h"
-#endif
#ifdef linux
#define _GNU_SOURCE
@@ -848,6 +846,7 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa
if(flow->ssh_ssl.server_cipher != '\0') fprintf(out, "[%s]", ndpi_cipher2str(flow->ssh_ssl.server_cipher));;
if(flow->bittorent_hash[0] != '\0') fprintf(out, "[BT Hash: %s]", flow->bittorent_hash);
+ if(flow->dhcp_fingerprint[0] != '\0') fprintf(out, "[DHCP Fingerprint: %s]", flow->dhcp_fingerprint);
fprintf(out, "\n");
} else {
@@ -898,8 +897,8 @@ static void printFlow(u_int16_t id, struct ndpi_flow_info *flow, u_int16_t threa
if(flow->ssh_ssl.ja3_client[0] != '\0')
json_object_object_add(jObj,"ja3c",json_object_new_string(flow->ssh_ssl.ja3_client));
- if(flow->ja3_server[0] != '\0')
- json_object_object_add(jObj,"host.server.ja3",json_object_new_string(flow->ja3_server));
+ if(flow->ssh_ssl.ja3_server[0] != '\0')
+ json_object_object_add(jObj,"host.server.ja3",json_object_new_string(flow->ssh_ssl.ja3_server));
if(flow->ssh_ssl.client_info[0] != '\0')
json_object_object_add(sjObj, "client", json_object_new_string(flow->ssh_ssl.client_info));
@@ -1439,6 +1438,7 @@ static void node_idle_scan_walker(const void *node, ndpi_VISIT which, int depth,
}
}
+/* *********************************************** */
/**
* @brief On Protocol Discover - demo callback
@@ -1449,6 +1449,8 @@ static void on_protocol_discovered(struct ndpi_workflow * workflow,
;
}
+/* *********************************************** */
+
#if 0
/**
* @brief Print debug
@@ -1456,7 +1458,6 @@ static void on_protocol_discovered(struct ndpi_workflow * workflow,
static void debug_printf(u_int32_t protocol, void *id_struct,
ndpi_log_level_t log_level,
const char *format, ...) {
-
va_list va_ap;
#ifndef WIN32
struct tm result;
@@ -1490,6 +1491,8 @@ static void debug_printf(u_int32_t protocol, void *id_struct,
}
#endif
+/* *********************************************** */
+
/**
* @brief Setup for detection begin
*/
@@ -1577,6 +1580,7 @@ static void setupDetection(u_int16_t thread_id, pcap_t * pcap_handle) {
}
}
+/* *********************************************** */
/**
* @brief End of detection and free flow
@@ -1585,6 +1589,7 @@ static void terminateDetection(u_int16_t thread_id) {
ndpi_workflow_free(ndpi_thread_info[thread_id].workflow);
}
+/* *********************************************** */
/**
* @brief Traffic stats format
@@ -1621,6 +1626,7 @@ char* formatTraffic(float numBits, int bits, char *buf) {
return(buf);
}
+/* *********************************************** */
/**
* @brief Packets stats format
@@ -1639,6 +1645,7 @@ char* formatPackets(float numPkts, char *buf) {
return(buf);
}
+/* *********************************************** */
/**
* @brief JSON function init
@@ -1650,6 +1657,8 @@ static void json_init() {
jArray_topStats = json_object_new_array();
}
+/* *********************************************** */
+
static void json_open_stats_file() {
if((file_first_time && ((stats_fp = fopen(_statsFilePath,"w")) == NULL))
||
@@ -1660,6 +1669,8 @@ static void json_open_stats_file() {
else file_first_time = 0;
}
+/* *********************************************** */
+
static void json_close_stats_file() {
json_object *jObjFinal = json_object_new_object();
diff --git a/example/ndpi_util.c b/example/ndpi_util.c
index 896332e08..328047b90 100644
--- a/example/ndpi_util.c
+++ b/example/ndpi_util.c
@@ -178,18 +178,21 @@ struct ndpi_workflow* ndpi_workflow_init(const struct ndpi_workflow_prefs * pref
set_ndpi_flow_malloc(NULL), set_ndpi_flow_free(NULL);
/* TODO: just needed here to init ndpi malloc wrapper */
struct ndpi_detection_module_struct * module = ndpi_init_detection_module();
+ if (module == NULL) {
+ NDPI_LOG(0, NULL, NDPI_LOG_ERROR, "global structure initialization failed\n");
+ exit(-1);
+ }
struct ndpi_workflow * workflow = ndpi_calloc(1, sizeof(struct ndpi_workflow));
-
+ if (workflow == NULL) {
+ NDPI_LOG(0, NULL, NDPI_LOG_ERROR, "global structure initialization failed\n");
+ ndpi_free(module);
+ exit(-1);
+ }
workflow->pcap_handle = pcap_handle;
workflow->prefs = *prefs;
workflow->ndpi_struct = module;
- if(workflow->ndpi_struct == NULL) {
- NDPI_LOG(0, NULL, NDPI_LOG_ERROR, "global structure initialization failed\n");
- exit(-1);
- }
-
ndpi_set_log_level(module, nDPI_LogLevel);
if(_debug_protocols != NULL && ! _debug_protocols_ok) {
@@ -246,21 +249,21 @@ int ndpi_workflow_node_cmp(const void *a, const void *b) {
if(
(
- (fa->src_ip == fb->src_ip )
- && (fa->src_port == fb->src_port)
- && (fa->dst_ip == fb->dst_ip )
- && (fa->dst_port == fb->dst_port)
- )
+ (fa->src_ip == fb->src_ip )
+ && (fa->src_port == fb->src_port)
+ && (fa->dst_ip == fb->dst_ip )
+ && (fa->dst_port == fb->dst_port)
+ )
||
(
- (fa->src_ip == fb->dst_ip )
- && (fa->src_port == fb->dst_port)
- && (fa->dst_ip == fb->src_ip )
- && (fa->dst_port == fb->src_port)
- )
- )
+ (fa->src_ip == fb->dst_ip )
+ && (fa->src_port == fb->dst_port)
+ && (fa->dst_ip == fb->src_ip )
+ && (fa->dst_port == fb->src_port)
+ )
+ )
return(0);
-
+
if(fa->src_ip < fb->src_ip ) return(-1); else { if(fa->src_ip > fb->src_ip ) return(1); }
if(fa->src_port < fb->src_port) return(-1); else { if(fa->src_port > fb->src_port) return(1); }
if(fa->dst_ip < fb->dst_ip ) return(-1); else { if(fa->dst_ip > fb->dst_ip ) return(1); }
@@ -376,10 +379,10 @@ static struct ndpi_flow_info *get_ndpi_flow_info(struct ndpi_workflow * workflow
flow.src_ip = iph->saddr, flow.dst_ip = iph->daddr;
flow.src_port = htons(*sport), flow.dst_port = htons(*dport);
flow.hashval = hashval = flow.protocol + flow.vlan_id + flow.src_ip + flow.dst_ip + flow.src_port + flow.dst_port;
+ /* printf("hashval=%u [%u][%u][%u:%u][%u:%u]\n", hashval, flow.protocol, flow.vlan_id, flow.src_ip, flow.src_port, flow.dst_ip, flow.dst_port); */
idx = hashval % workflow->prefs.num_roots;
ret = ndpi_tfind(&flow, &workflow->ndpi_flows_root[idx], ndpi_workflow_node_cmp);
-
/* to avoid two nodes in one binary tree for a flow */
int is_changed = 0;
if(ret == NULL) {
@@ -530,8 +533,9 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
snprintf(flow->host_server_name, sizeof(flow->host_server_name), "%s",
flow->ndpi_flow->host_server_name);
- /* BITTORRENT */
- if(flow->detected_protocol.app_protocol == NDPI_PROTOCOL_BITTORRENT) {
+ if(flow->detected_protocol.app_protocol == NDPI_PROTOCOL_DHCP) {
+ snprintf(flow->dhcp_fingerprint, sizeof(flow->dhcp_fingerprint), "%s", flow->ndpi_flow->protos.dhcp.fingerprint);
+ } else if(flow->detected_protocol.app_protocol == NDPI_PROTOCOL_BITTORRENT) {
u_int i, j, n = 0;
for(i=0, j = 0; j < sizeof(flow->bittorent_hash)-1; i++) {
diff --git a/example/ndpi_util.h b/example/ndpi_util.h
index 301647b1c..dfcc98a72 100644
--- a/example/ndpi_util.h
+++ b/example/ndpi_util.h
@@ -95,6 +95,7 @@ typedef struct ndpi_flow_info {
char info[96];
char host_server_name[256];
char bittorent_hash[41];
+ char dhcp_fingerprint[48];
struct {
u_int16_t ssl_version;
diff --git a/src/include/ndpi_protocol_ids.h b/src/include/ndpi_protocol_ids.h
index 7e2f55711..b8b77ada4 100644
--- a/src/include/ndpi_protocol_ids.h
+++ b/src/include/ndpi_protocol_ids.h
@@ -79,8 +79,8 @@ typedef enum {
NDPI_PROTOCOL_MINING = 42, /* Bitcoin, Ethereum, ZCash, Monero */
NDPI_PROTOCOL_NEST_LOG_SINK = 43, /* Nest Log Sink (Nest Protect) - Darryl Sokoloski <darryl@egloo.ca> */
NDPI_PROTOCOL_MODBUS = 44, /* Modbus */
+ NDPI_PROTOCOL_WHATSAPP_VIDEO = 45,
- NDPI_PROTOCOL_FREE_45 = 45, /* Free */
NDPI_PROTOCOL_FREE_46 = 46, /* Free */
NDPI_PROTOCOL_XBOX = 47,
diff --git a/src/lib/ndpi_content_match.c.inc b/src/lib/ndpi_content_match.c.inc
index 730050a2e..a58d80e25 100644
--- a/src/lib/ndpi_content_match.c.inc
+++ b/src/lib/ndpi_content_match.c.inc
@@ -8485,6 +8485,7 @@ ndpi_protocol_match host_match[] = {
{ "audio-fa.scdn.co", NULL, "audio-fa\\.scdn" TLD, "Spotify", NDPI_PROTOCOL_SPOTIFY, NDPI_PROTOCOL_CATEGORY_MUSIC, NDPI_PROTOCOL_FUN },
{ "edge-mqtt.facebook.com", NULL, "edge-mqtt\\.facebook" TLD, "Messenger", NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_CATEGORY_CHAT, NDPI_PROTOCOL_FUN },
+ { "mqtt-mini.facebook.com", NULL, "mqtt-mini\\.facebook" TLD, "Messenger", NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_CATEGORY_CHAT, NDPI_PROTOCOL_FUN }, /* Messenger Lite */
{ "messenger.com", NULL, "messenger\\.com" TLD, "Messenger", NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_CATEGORY_CHAT, NDPI_PROTOCOL_FUN },
{ ".pandora.com", NULL, "\\.pandora" TLD, "Pandora", NDPI_PROTOCOL_PANDORA, NDPI_PROTOCOL_CATEGORY_STREAMING, NDPI_PROTOCOL_FUN },
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c
index 85fed4d0c..bf9c4069e 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -983,9 +983,9 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp
no_master, "Modbus", NDPI_PROTOCOL_CATEGORY_NETWORK, /* Perhaps IoT in the future */
ndpi_build_default_ports(ports_a, 502, 0, 0, 0, 0) /* TCP */,
ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */);
- ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_FREE_45,
+ ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_WHATSAPP_VIDEO,
0 /* can_have_a_subprotocol */, no_master,
- no_master, "Free", NDPI_PROTOCOL_CATEGORY_CUSTOM_1 /* dummy */,
+ no_master, "WhatsAppVideo", NDPI_PROTOCOL_CATEGORY_VOIP,
ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */,
ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */);
ndpi_set_proto_defaults(ndpi_mod, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_FREE_46,
diff --git a/src/lib/protocols/btlib.c b/src/lib/protocols/btlib.c
index ea06a6348..309a10717 100644
--- a/src/lib/protocols/btlib.c
+++ b/src/lib/protocols/btlib.c
@@ -64,7 +64,8 @@ static char *print20b(char *s,const u_int8_t *b) {
}
static char *print_id_ip_p(char *s, const struct bt_nodes_data *b) {
- u_int8_t *p = (void*)b;
+ u_int8_t *p = (u_int8_t*)b;
+
print20b(s,b->id);
snprintf(s+40,39," %d.%d.%d.%d:%u",
p[20], p[21], p[22], p[23], htons(b->port));
@@ -72,14 +73,16 @@ static char *print_id_ip_p(char *s, const struct bt_nodes_data *b) {
}
static char *print_ip_p(char *s, const struct bt_ipv4p *b,int np) {
- const u_int8_t *p = (const void*)b;
+ const u_int8_t *p = (const u_int8_t*)b;
+
snprintf(s,39,!np ? "%d.%d.%d.%d:%u":"%d.%d.%d.%d",
p[0], p[1], p[2], p[3], htons(b->port));
return s;
}
static char *print_ip6_p(char *s, const struct bt_ipv6p *b,int np) {
- u_int16_t *p = (void*)b;
+ u_int16_t *p = (u_int16_t*)b;
+
snprintf(s,79,!np ? "%x:%x:%x:%x:%x:%x:%x:%x.%u":"%x:%x:%x:%x:%x:%x:%x:%x",
htons(p[0]), htons(p[1]), htons(p[2]), htons(p[3]),
htons(p[4]), htons(p[5]), htons(p[6]), htons(p[7]),
@@ -507,6 +510,7 @@ const u_int8_t *bt_decode(const u_int8_t *b, size_t *l, int *ret, bt_parse_data_
cbd->level--;
return b;
}
+
bad_data:
*ret=-1;
return b;
diff --git a/src/lib/protocols/dhcp.c b/src/lib/protocols/dhcp.c
index 52415946b..14959bae8 100644
--- a/src/lib/protocols/dhcp.c
+++ b/src/lib/protocols/dhcp.c
@@ -104,10 +104,15 @@ void ndpi_search_dhcp_udp(struct ndpi_detection_module_struct *ndpi_struct, stru
u_int idx, offset = 0;
for(idx = 0; idx < len && offset < sizeof(flow->protos.dhcp.fingerprint) - 2; idx++) {
- snprintf((char*)&flow->protos.dhcp.fingerprint[offset],
- sizeof(flow->protos.dhcp.fingerprint) - offset,
- "%02X", dhcp->options[i+2+idx] & 0xFF);
- offset += 2;
+#if 1
+ offset += snprintf((char*)&flow->protos.dhcp.fingerprint[offset],
+ sizeof(flow->protos.dhcp.fingerprint) - offset,
+ "%s%u", (idx > 0) ? "," : "", dhcp->options[i+2+idx] & 0xFF);
+#else
+ offset += snprintf((char*)&flow->protos.dhcp.fingerprint[offset],
+ sizeof(flow->protos.dhcp.fingerprint) - offset,
+ "%02X", dhcp->options[i+2+idx] & 0xFF);
+#endif
}
flow->protos.dhcp.fingerprint[sizeof(flow->protos.dhcp.fingerprint) - 1] = '\0';
diff --git a/src/lib/protocols/memcached.c b/src/lib/protocols/memcached.c
index 44a8b0858..e527688ba 100644
--- a/src/lib/protocols/memcached.c
+++ b/src/lib/protocols/memcached.c
@@ -92,99 +92,99 @@
#define MEMCACHED_MATCH(cr) (cr ## _LEN > length || memcmp(offset, cr, cr ## _LEN))
static void ndpi_int_memcached_add_connection(struct ndpi_detection_module_struct
- *ndpi_struct, struct ndpi_flow_struct *flow)
+ *ndpi_struct, struct ndpi_flow_struct *flow)
{
- NDPI_LOG_INFO(ndpi_struct, "found memcached\n");
- ndpi_set_detected_protocol(ndpi_struct, flow,
- NDPI_PROTOCOL_MEMCACHED, NDPI_PROTOCOL_UNKNOWN);
+ NDPI_LOG_INFO(ndpi_struct, "found memcached\n");
+ ndpi_set_detected_protocol(ndpi_struct, flow,
+ NDPI_PROTOCOL_MEMCACHED, NDPI_PROTOCOL_UNKNOWN);
}
void ndpi_search_memcached(
- struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow)
+ struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow)
{
- struct ndpi_packet_struct *packet = &flow->packet;
- const u_int8_t *offset = packet->payload;
- const u_int16_t length = packet->payload_packet_len;
- u_int8_t *matches;
+ struct ndpi_packet_struct *packet = &flow->packet;
+ const u_int8_t *offset = packet->payload;
+ const u_int16_t length = packet->payload_packet_len;
+ u_int8_t *matches;
- NDPI_LOG_DBG(ndpi_struct, "search memcached\n");
+ NDPI_LOG_DBG(ndpi_struct, "search memcached\n");
- if (packet->tcp != NULL) {
- if (packet->payload_packet_len < MEMCACHED_MIN_LEN) {
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
- return;
- }
-
- matches = &flow->l4.tcp.memcached_matches;
+ if (packet->tcp != NULL) {
+ if (packet->payload_packet_len < MEMCACHED_MIN_LEN) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
}
- else if (packet->udp != NULL) {
- if (packet->payload_packet_len < MEMCACHED_MIN_UDP_LEN) {
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
- return;
- }
-
- if ((offset[4] == 0x00 && offset[5] == 0x00) ||
- offset[6] != 0x00 || offset[7] != 0x00) {
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
- return;
- }
-
- offset += MEMCACHED_UDP_HDR_LEN;
- matches = &flow->l4.udp.memcached_matches;
+
+ matches = &flow->l4.tcp.memcached_matches;
+ }
+ else if (packet->udp != NULL) {
+ if (packet->payload_packet_len < MEMCACHED_MIN_UDP_LEN) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
}
- else {
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
- return;
+
+ if ((offset[4] == 0x00 && offset[5] == 0x00) ||
+ offset[6] != 0x00 || offset[7] != 0x00) {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
}
- /* grep MCD memcached.c |\
- * egrep -v '(LEN|MATCH)' |\
- * sed -e 's/^#define //g' |\
- * awk '{ printf "else if (! MEMCACHED_MATCH(%s)) *matches += 1;\n",$1 }' */
-
- if (! MEMCACHED_MATCH(MCDC_SET)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDC_ADD)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDC_REPLACE)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDC_APPEND)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDC_PREPEND)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDC_CAS)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDC_GET)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDC_GETS)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDC_DELETE)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDC_INCR)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDC_DECR)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDC_TOUCH)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDC_GAT)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDC_GATS)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDC_STATS)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDR_ERROR)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDR_CLIENT_ERROR)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDR_SERVER_ERROR)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDR_STORED)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDR_NOT_STORED)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDR_EXISTS)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDR_NOT_FOUND)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDR_END)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDR_DELETED)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDR_TOUCHED)) *matches += 1;
- else if (! MEMCACHED_MATCH(MCDR_STAT)) *matches += 1;
-
- if (*matches >= MEMCACHED_MIN_MATCH)
- ndpi_int_memcached_add_connection(ndpi_struct, flow);
+ offset += MEMCACHED_UDP_HDR_LEN;
+ matches = &flow->l4.udp.memcached_matches;
+ }
+ else {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
+ }
+
+ /* grep MCD memcached.c |\
+ * egrep -v '(LEN|MATCH)' |\
+ * sed -e 's/^#define //g' |\
+ * awk '{ printf "else if (! MEMCACHED_MATCH(%s)) *matches += 1;\n",$1 }' */
+
+ if (! MEMCACHED_MATCH(MCDC_SET)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDC_ADD)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDC_REPLACE)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDC_APPEND)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDC_PREPEND)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDC_CAS)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDC_GET)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDC_GETS)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDC_DELETE)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDC_INCR)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDC_DECR)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDC_TOUCH)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDC_GAT)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDC_GATS)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDC_STATS)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDR_ERROR)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDR_CLIENT_ERROR)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDR_SERVER_ERROR)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDR_STORED)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDR_NOT_STORED)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDR_EXISTS)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDR_NOT_FOUND)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDR_END)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDR_DELETED)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDR_TOUCHED)) *matches += 1;
+ else if (! MEMCACHED_MATCH(MCDR_STAT)) *matches += 1;
+
+ if (*matches >= MEMCACHED_MIN_MATCH)
+ ndpi_int_memcached_add_connection(ndpi_struct, flow);
}
void init_memcached_dissector(
- struct ndpi_detection_module_struct *ndpi_struct,
- u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask)
+ struct ndpi_detection_module_struct *ndpi_struct,
+ u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask)
{
- ndpi_set_bitmask_protocol_detection("MEMCACHED",
- ndpi_struct, detection_bitmask, *id,
- NDPI_PROTOCOL_MEMCACHED,
- ndpi_search_memcached,
- NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD,
- SAVE_DETECTION_BITMASK_AS_UNKNOWN,
- ADD_TO_DETECTION_BITMASK);
-
- *id += 1;
+ ndpi_set_bitmask_protocol_detection("MEMCACHED",
+ ndpi_struct, detection_bitmask, *id,
+ NDPI_PROTOCOL_MEMCACHED,
+ ndpi_search_memcached,
+ NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD,
+ SAVE_DETECTION_BITMASK_AS_UNKNOWN,
+ ADD_TO_DETECTION_BITMASK);
+
+ *id += 1;
}
diff --git a/src/lib/protocols/openvpn.c b/src/lib/protocols/openvpn.c
index 6bd480ea1..b92eb5cf7 100644
--- a/src/lib/protocols/openvpn.c
+++ b/src/lib/protocols/openvpn.c
@@ -40,12 +40,19 @@
#define P_PACKET_ID_ARRAY_LEN_OFFSET(hmac_size) (P_HARD_RESET_PACKET_ID_OFFSET(hmac_size) + 8)
#define P_HARD_RESET_CLIENT_MAX_COUNT 5
+static void ndpi_int_openvpn_add_connection(struct ndpi_detection_module_struct
+ *ndpi_struct, struct ndpi_flow_struct *flow) {
+ NDPI_LOG_INFO(ndpi_struct, "found memcached\n");
+ ndpi_set_detected_protocol(ndpi_struct, flow,
+ NDPI_PROTOCOL_MEMCACHED, NDPI_PROTOCOL_UNKNOWN);
+}
+
static
#ifndef WIN32
inline
#endif
u_int32_t get_packet_id(const u_int8_t * payload, u_int8_t hms) {
- return ntohl(*(u_int32_t*)(payload + P_HARD_RESET_PACKET_ID_OFFSET(hms)));
+ return(ntohl(*(u_int32_t*)(payload + P_HARD_RESET_PACKET_ID_OFFSET(hms))));
}
static
@@ -54,11 +61,13 @@ inline
#endif
int8_t check_pkid_and_detect_hmac_size(const u_int8_t * payload) {
// try to guess
- if (get_packet_id(payload, P_HMAC_160) == 1)
+ if(get_packet_id(payload, P_HMAC_160) == 1)
return P_HMAC_160;
- if (get_packet_id(payload, P_HMAC_128) == 1)
+
+ if(get_packet_id(payload, P_HMAC_128) == 1)
return P_HMAC_128;
- return -1;
+
+ return(-1);
}
void ndpi_search_openvpn(struct ndpi_detection_module_struct* ndpi_struct,
@@ -71,17 +80,39 @@ void ndpi_search_openvpn(struct ndpi_detection_module_struct* ndpi_struct,
int8_t hmac_size;
int8_t failed = 0;
- if (packet->payload_packet_len >= 40) {
+ if(packet->payload_packet_len >= 40) {
// skip openvpn TCP transport packet size
- if (packet->tcp != NULL)
+ if(packet->tcp != NULL)
ovpn_payload += 2;
opcode = ovpn_payload[0] & P_OPCODE_MASK;
- if (flow->ovpn_counter < P_HARD_RESET_CLIENT_MAX_COUNT && (opcode == P_CONTROL_HARD_RESET_CLIENT_V1 ||
+ if(packet->udp) {
+#ifdef DEBUG
+ printf("[packet_id: %u][opcode: %u][Packet ID: %d][%u <-> %u][len: %u]\n",
+ flow->num_processed_pkts,
+ opcode, check_pkid_and_detect_hmac_size(ovpn_payload),
+ htons(packet->udp->source), htons(packet->udp->dest), packet->payload_packet_len);
+#endif
+
+ if(
+ (flow->num_processed_pkts == 1)
+ && (
+ ((packet->payload_packet_len == 112)
+ && ((opcode == 168) || (opcode == 192))
+ )
+ || ((packet->payload_packet_len == 80)
+ && ((opcode == 184) || (opcode == 88) || (opcode == 160) || (opcode == 168) || (opcode == 200)))
+ )) {
+ NDPI_LOG_INFO(ndpi_struct,"found openvpn\n");
+ ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OPENVPN, NDPI_PROTOCOL_UNKNOWN);
+ return;
+ }
+ }
+
+ if(flow->ovpn_counter < P_HARD_RESET_CLIENT_MAX_COUNT && (opcode == P_CONTROL_HARD_RESET_CLIENT_V1 ||
opcode == P_CONTROL_HARD_RESET_CLIENT_V2)) {
-
- if (check_pkid_and_detect_hmac_size(ovpn_payload) > 0) {
+ if(check_pkid_and_detect_hmac_size(ovpn_payload) > 0) {
memcpy(flow->ovpn_session_id, ovpn_payload+1, 8);
NDPI_LOG_DBG2(ndpi_struct,
@@ -89,20 +120,20 @@ void ndpi_search_openvpn(struct ndpi_detection_module_struct* ndpi_struct,
flow->ovpn_session_id[0], flow->ovpn_session_id[1], flow->ovpn_session_id[2], flow->ovpn_session_id[3],
flow->ovpn_session_id[4], flow->ovpn_session_id[5], flow->ovpn_session_id[6], flow->ovpn_session_id[7]);
}
- } else if (flow->ovpn_counter >= 1 && flow->ovpn_counter <= P_HARD_RESET_CLIENT_MAX_COUNT &&
+ } else if(flow->ovpn_counter >= 1 && flow->ovpn_counter <= P_HARD_RESET_CLIENT_MAX_COUNT &&
(opcode == P_CONTROL_HARD_RESET_SERVER_V1 || opcode == P_CONTROL_HARD_RESET_SERVER_V2)) {
hmac_size = check_pkid_and_detect_hmac_size(ovpn_payload);
- if (hmac_size > 0) {
+ if(hmac_size > 0) {
alen = ovpn_payload[P_PACKET_ID_ARRAY_LEN_OFFSET(hmac_size)];
session_remote = ovpn_payload + P_PACKET_ID_ARRAY_LEN_OFFSET(hmac_size) + 1 + alen * 4;
- if (memcmp(flow->ovpn_session_id, session_remote, 8) == 0) {
- NDPI_LOG_INFO(ndpi_struct,"found openvpn\n");
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OPENVPN, NDPI_PROTOCOL_UNKNOWN);
- }
- else {
+ if(memcmp(flow->ovpn_session_id, session_remote, 8) == 0) {
+ NDPI_LOG_INFO(ndpi_struct,"found openvpn\n");
+ ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_OPENVPN, NDPI_PROTOCOL_UNKNOWN);
+ return;
+ } else {
NDPI_LOG_DBG2(ndpi_struct,
"key mismatch: %02x%02x%02x%02x%02x%02x%02x%02x\n",
session_remote[0], session_remote[1], session_remote[2], session_remote[3],
@@ -116,14 +147,14 @@ void ndpi_search_openvpn(struct ndpi_detection_module_struct* ndpi_struct,
flow->ovpn_counter++;
- if (failed) {
+ if(failed) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
}
}
}
-void init_openvpn_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask)
-{
+void init_openvpn_dissector(struct ndpi_detection_module_struct *ndpi_struct,
+ u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) {
ndpi_set_bitmask_protocol_detection("OpenVPN", ndpi_struct, detection_bitmask, *id,
NDPI_PROTOCOL_OPENVPN,
ndpi_search_openvpn,
diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c
index c169a47db..97cf091f0 100644
--- a/src/lib/protocols/stun.c
+++ b/src/lib/protocols/stun.c
@@ -28,7 +28,7 @@
#include "ndpi_api.h"
-#define MAX_NUM_STUN_PKTS 10
+#define MAX_NUM_STUN_PKTS 8
struct stun_packet_header {
u_int16_t msg_type, msg_len;
@@ -53,10 +53,10 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
u_int8_t *is_whatsapp) {
u_int16_t msg_type, msg_len;
struct stun_packet_header *h = (struct stun_packet_header*)payload;
- u_int8_t can_this_be_whatsapp_voice = 1;
+ u_int8_t can_this_be_whatsapp_voice = 1, wa = 0;
flow->protos.stun_ssl.stun.num_processed_pkts++;
-
+
if(payload_length < sizeof(struct stun_packet_header)) {
if(flow->protos.stun_ssl.stun.num_udp_pkts > 0) {
*is_whatsapp = 1;
@@ -75,86 +75,104 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
if(ntohs(h->msg_type) == 0x01 /* Binding Request */)
flow->protos.stun_ssl.stun.num_binding_requests++;
-
- if((payload[0] != 0x80) && ((msg_len+20) > payload_length))
- return(NDPI_IS_NOT_STUN);
- if((payload_length == (msg_len+20))
- && ((msg_type <= 0x000b) /* http://www.3cx.com/blog/voip-howto/stun-details/ */)) {
- u_int offset = 20;
+ /* printf("[%02X][%02X][msg_len: %u][payload_length: %u]\n", payload[0], payload[1], msg_len, payload_length); */
- /*
- This can either be the standard RTCP or Ms Lync RTCP that
- later will become Ms Lync RTP. In this case we need to
- be careful before deciding about the protocol before dissecting the packet
-
- MS Lync = Skype
- https://en.wikipedia.org/wiki/Skype_for_Business
- */
+ if(((payload[0] == 0x80) && ((msg_len+20) <= payload_length)) /* WhatsApp Voice */) {
+ *is_whatsapp = 1;
+ return NDPI_IS_STUN; /* This is WhatsApp Voice */
+ } else if((payload[0] == 0x90) && ((msg_len+11) == payload_length) /* WhatsApp Video */) {
+ *is_whatsapp = 2;
+ return NDPI_IS_STUN; /* This is WhatsApp Video */
+ }
- while((offset+2) < payload_length) {
- u_int16_t attribute = ntohs(*((u_int16_t*)&payload[offset]));
- u_int16_t len = ntohs(*((u_int16_t*)&payload[offset+2]));
- u_int16_t x = (len + 4) % 4;
-
- if(x != 0)
- len += 4-x;
-
- switch(attribute) {
- case 0x0008: /* Message Integrity */
- case 0x0020: /* XOR-MAPPED-ADDRESSES */
- case 0x4002:
- /* These are the only messages apparently whatsapp voice can use */
- break;
-
- case 0x8054: /* Candidate Identifier */
- if((len == 4)
- && ((offset+7) < payload_length)
- && (payload[offset+5] == 0x00)
- && (payload[offset+6] == 0x00)
- && (payload[offset+7] == 0x00)) {
- /* Either skype for business or "normal" skype with multiparty call */
- flow->protos.stun_ssl.stun.is_skype = 1;
- return(NDPI_IS_STUN);
- }
- break;
-
- case 0x8055: /* MS Service Quality (skype?) */
- break;
-
- /* Proprietary fields found on skype calls */
- case 0x24DF:
- case 0x3802:
- case 0x8036:
- case 0x8095:
- case 0x0800:
- /* printf("====>>>> %04X\n", attribute); */
- flow->protos.stun_ssl.stun.is_skype = 1;
- return(NDPI_IS_STUN);
- break;
-
- case 0x8070: /* Implementation Version */
- if((len == 4)
- && ((offset+7) < payload_length)
- && (payload[offset+4] == 0x00)
- && (payload[offset+5] == 0x00)
- && (payload[offset+6] == 0x00)
- && ((payload[offset+7] == 0x02) || (payload[offset+7] == 0x03))
- ) {
+ if((payload[0] != 0x80) && ((msg_len+20) > payload_length))
+ return(NDPI_IS_NOT_STUN);
+
+ if(payload_length == (msg_len+20)) {
+ if(msg_type <= 0x000b) /* http://www.3cx.com/blog/voip-howto/stun-details/ */ {
+ u_int offset = 20;
+
+ // printf("[%02X][%02X][%02X][%02X][payload_length: %u]\n", payload[offset], payload[offset+1], payload[offset+2], payload[offset+3],payload_length);
+
+ /*
+ This can either be the standard RTCP or Ms Lync RTCP that
+ later will become Ms Lync RTP. In this case we need to
+ be careful before deciding about the protocol before dissecting the packet
+
+ MS Lync = Skype
+ https://en.wikipedia.org/wiki/Skype_for_Business
+ */
+
+ while((offset+2) < payload_length) {
+ u_int16_t attribute = ntohs(*((u_int16_t*)&payload[offset]));
+ u_int16_t len = ntohs(*((u_int16_t*)&payload[offset+2]));
+ u_int16_t x = (len + 4) % 4;
+
+ if(x != 0)
+ len += 4-x;
+
+ switch(attribute) {
+ case 0x0008: /* Message Integrity */
+ case 0x0020: /* XOR-MAPPED-ADDRESSES */
+ case 0x4000:
+ case 0x4002:
+ /* These are the only messages apparently whatsapp voice can use */
+ break;
+
+ case 0x8054: /* Candidate Identifier */
+ if((len == 4)
+ && ((offset+7) < payload_length)
+ && (payload[offset+5] == 0x00)
+ && (payload[offset+6] == 0x00)
+ && (payload[offset+7] == 0x00)) {
+ /* Either skype for business or "normal" skype with multiparty call */
+ flow->protos.stun_ssl.stun.is_skype = 1;
+ return(NDPI_IS_STUN);
+ }
+ break;
+
+ case 0x8055: /* MS Service Quality (skype?) */
+ break;
+
+ /* Proprietary fields found on skype calls */
+ case 0x24DF:
+ case 0x3802:
+ case 0x8036:
+ case 0x8095:
+ case 0x0800:
+ /* printf("====>>>> %04X\n", attribute); */
flow->protos.stun_ssl.stun.is_skype = 1;
return(NDPI_IS_STUN);
+ break;
+
+ case 0x8070: /* Implementation Version */
+ if((len == 4)
+ && ((offset+7) < payload_length)
+ && (payload[offset+4] == 0x00)
+ && (payload[offset+5] == 0x00)
+ && (payload[offset+6] == 0x00)
+ && ((payload[offset+7] == 0x02) || (payload[offset+7] == 0x03))
+ ) {
+ flow->protos.stun_ssl.stun.is_skype = 1;
+ return(NDPI_IS_STUN);
+ }
+ break;
+
+ default:
+ /* This means this STUN packet cannot be confused with whatsapp voice */
+ /* printf("==> %04X\n", attribute); */
+ can_this_be_whatsapp_voice = 0;
+ break;
}
- break;
- default:
- /* This means this STUN packet cannot be confused with whatsapp voice */
- can_this_be_whatsapp_voice = 0;
- break;
+ offset += len + 4;
}
-
- offset += len + 4;
+ goto udp_stun_found;
+ } else if(msg_type == 0x0800) {
+ *is_whatsapp = 1;
+ return NDPI_IS_STUN; /* This is WhatsApp */
}
- goto udp_stun_found;
}
if((flow->protos.stun_ssl.stun.num_udp_pkts > 0) && (msg_type <= 0x00FF)) {
@@ -163,7 +181,7 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
} else
return NDPI_IS_NOT_STUN;
- udp_stun_found:
+ udp_stun_found:
if(can_this_be_whatsapp_voice) {
flow->protos.stun_ssl.stun.num_udp_pkts++;
@@ -172,11 +190,11 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
/*
We cannot immediately say that this is STUN as there are other protocols
like GoogleHangout that might be candidates, thus we set the
- guessed protocol to STUN
+ guessed protocol to STUN
*/
flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
return(NDPI_IS_NOT_STUN);
- }
+ }
}
void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
@@ -187,11 +205,11 @@ void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct n
NDPI_LOG_DBG(ndpi_struct, "search stun\n");
if(packet->payload == NULL) return;
-
+
if(packet->tcp) {
/* STUN may be encapsulated in TCP packets */
if((packet->payload_packet_len >= 22)
- && ((ntohs(get_u_int16_t(packet->payload, 0)) + 2) == packet->payload_packet_len)) {
+ && ((ntohs(get_u_int16_t(packet->payload, 0)) + 2) == packet->payload_packet_len)) {
/* TODO there could be several STUN packets in a single TCP packet so maybe the detection could be
* improved by checking only the STUN packet of given length */
@@ -207,9 +225,9 @@ void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct n
} else {
NDPI_LOG_INFO(ndpi_struct, "found UDP stun\n"); /* Ummmmm we're in the TCP branch. This code looks bad */
ndpi_int_stun_add_connection(ndpi_struct,
- is_whatsapp ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_STUN, flow);
+ is_whatsapp ? (is_whatsapp == 1 ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_WHATSAPP_VIDEO) : NDPI_PROTOCOL_STUN, flow);
}
-
+
return;
}
}
@@ -218,24 +236,25 @@ void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct n
if(ndpi_int_check_stun(ndpi_struct, flow, packet->payload,
packet->payload_packet_len, &is_whatsapp) == NDPI_IS_STUN) {
if(flow->guessed_protocol_id == 0) flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
-
+
if(flow->protos.stun_ssl.stun.is_skype) {
NDPI_LOG_INFO(ndpi_struct, "Found Skype\n");
- /* flow->protos.stun_ssl.stun.num_binding_requests < 4) ? NDPI_PROTOCOL_SKYPE_CALL_IN : NDPI_PROTOCOL_SKYPE_CALL_OUT */
+ /* flow->protos.stun_ssl.stun.num_binding_requests < 4) ? NDPI_PROTOCOL_SKYPE_CALL_IN : NDPI_PROTOCOL_SKYPE_CALL_OUT */
if((flow->protos.stun_ssl.stun.num_processed_pkts >= 8) || (flow->protos.stun_ssl.stun.num_binding_requests >= 4))
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE);
} else {
NDPI_LOG_INFO(ndpi_struct, "found UDP stun\n");
ndpi_int_stun_add_connection(ndpi_struct,
- is_whatsapp ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_STUN, flow);
+ is_whatsapp ? (is_whatsapp == 1 ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_WHATSAPP_VIDEO) : NDPI_PROTOCOL_STUN,
+ flow);
}
-
+
return;
}
if(flow->protos.stun_ssl.stun.num_udp_pkts >= MAX_NUM_STUN_PKTS)
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
if(flow->packet_counter > 0) {
/* This might be a RTP stream: let's make sure we check it */
diff --git a/src/lib/protocols/viber.c b/src/lib/protocols/viber.c
index 65e227234..9aaa0e243 100644
--- a/src/lib/protocols/viber.c
+++ b/src/lib/protocols/viber.c
@@ -36,7 +36,7 @@ void ndpi_search_viber(struct ndpi_detection_module_struct *ndpi_struct, struct
if((packet->payload_packet_len == 12 && packet->payload[2] == 0x03 && packet->payload[3] == 0x00)
|| (packet->payload_packet_len == 20 && packet->payload[2] == 0x09 && packet->payload[3] == 0x00)
- || ((packet->payload_packet_len < 135) && (packet->payload[0] == 0x11))) {
+ ) {
NDPI_LOG_DBG(ndpi_struct, "found VIBER\n");
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_VIBER, NDPI_PROTOCOL_UNKNOWN);
return;
diff --git a/tests/result/1kxun.pcap.out b/tests/result/1kxun.pcap.out
index 387205dc0..12fba107e 100644
--- a/tests/result/1kxun.pcap.out
+++ b/tests/result/1kxun.pcap.out
@@ -53,8 +53,8 @@ LLMNR 89 6799 47
36 TCP 192.168.115.8:49607 <-> 218.244.135.170:9099 [proto: 7/HTTP][cat: Web/5][10 pkts/880 bytes <-> 3 pkts/572 bytes][Host: 218.244.135.170]
37 UDP 192.168.5.47:60267 -> 239.255.255.250:1900 [proto: 12/SSDP][cat: System/18][8 pkts/1432 bytes -> 0 pkts/0 bytes]
38 UDP 192.168.5.41:55312 -> 239.255.255.250:1900 [proto: 12/SSDP][cat: System/18][8 pkts/1400 bytes -> 0 pkts/0 bytes]
- 39 UDP 0.0.0.0:68 -> 255.255.255.255:67 [proto: 18/DHCP][cat: Network/14][4 pkts/1368 bytes -> 0 pkts/0 bytes][Host: shen]
- 40 UDP 192.168.5.16:68 <-> 192.168.119.1:67 [proto: 18/DHCP][cat: Network/14][2 pkts/684 bytes <-> 2 pkts/684 bytes][Host: macbook-air]
+ 39 UDP 0.0.0.0:68 -> 255.255.255.255:67 [proto: 18/DHCP][cat: Network/14][4 pkts/1368 bytes -> 0 pkts/0 bytes][Host: shen][DHCP Fingerprint: 1,121,3,6,15,119,252]
+ 40 UDP 192.168.5.16:68 <-> 192.168.119.1:67 [proto: 18/DHCP][cat: Network/14][2 pkts/684 bytes <-> 2 pkts/684 bytes][Host: macbook-air][DHCP Fingerprint: 1,3,6,15,119,95,252,44,46]
41 UDP 192.168.5.48:49701 -> 239.255.255.250:1900 [proto: 12/SSDP][cat: System/18][7 pkts/1253 bytes -> 0 pkts/0 bytes]
42 UDP 192.168.3.236:137 -> 192.168.255.255:137 [proto: 10/NetBIOS][cat: System/18][13 pkts/1196 bytes -> 0 pkts/0 bytes]
43 UDP 192.168.5.45:138 -> 192.168.255.255:138 [proto: 10/NetBIOS][cat: System/18][3 pkts/648 bytes -> 0 pkts/0 bytes]
@@ -64,8 +64,8 @@ LLMNR 89 6799 47
47 UDP [fe80::beee:7bff:fe0c:b3de]:546 -> [ff02::1:2]:547 [proto: 103/DHCPV6][cat: Network/14][4 pkts/392 bytes -> 0 pkts/0 bytes]
48 UDP 192.168.5.16:63372 <-> 168.95.1.1:53 [proto: 5/DNS][cat: Network/14][1 pkts/89 bytes <-> 1 pkts/289 bytes][Host: dl-obs.official.line.naver.jp]
49 TCP 192.168.115.8:49596 <-> 203.66.182.87:443 [proto: 91/SSL][cat: Web/5][4 pkts/220 bytes <-> 2 pkts/132 bytes]
- 50 UDP 192.168.5.9:68 -> 255.255.255.255:67 [proto: 18/DHCP][cat: Network/14][1 pkts/342 bytes -> 0 pkts/0 bytes][Host: joanna-pc]
- 51 UDP 192.168.5.41:68 -> 255.255.255.255:67 [proto: 18/DHCP][cat: Network/14][1 pkts/342 bytes -> 0 pkts/0 bytes][Host: kevin-pc]
+ 50 UDP 192.168.5.9:68 -> 255.255.255.255:67 [proto: 18/DHCP][cat: Network/14][1 pkts/342 bytes -> 0 pkts/0 bytes][Host: joanna-pc][DHCP Fingerprint: 1,15,3,6,44,46,47,31,33,121,249,43,252]
+ 51 UDP 192.168.5.41:68 -> 255.255.255.255:67 [proto: 18/DHCP][cat: Network/14][1 pkts/342 bytes -> 0 pkts/0 bytes][Host: kevin-pc][DHCP Fingerprint: 1,15,3,6,44,46,47,31,33,121,249,43,252]
52 UDP 192.168.115.8:60724 <-> 8.8.8.8:53 [proto: 5.137/DNS.GenericProtocol][cat: Streaming/17][2 pkts/146 bytes <-> 1 pkts/137 bytes][Host: pic.1kxun.com]
53 UDP 192.168.0.104:137 -> 192.168.255.255:137 [proto: 10/NetBIOS][cat: System/18][3 pkts/276 bytes -> 0 pkts/0 bytes]
54 UDP 192.168.115.8:51024 <-> 8.8.8.8:53 [proto: 5.137/DNS.GenericProtocol][cat: Streaming/17][2 pkts/160 bytes <-> 1 pkts/112 bytes][Host: jp.kankan.1kxun.mobi]
diff --git a/tests/result/wechat.pcap.out b/tests/result/wechat.pcap.out
index e8f1f0db9..7d306b94e 100644
--- a/tests/result/wechat.pcap.out
+++ b/tests/result/wechat.pcap.out
@@ -79,7 +79,7 @@ GoogleDocs 15 5114 2
64 TCP 192.168.1.103:58226 -> 203.205.147.171:443 [proto: 91.197/SSL.WeChat][cat: SocialNetwork/6][6 pkts/396 bytes -> 0 pkts/0 bytes]
65 UDP 192.168.1.103:53734 <-> 192.168.1.254:53 [proto: 5.126/DNS.Google][cat: Web/5][1 pkts/94 bytes <-> 1 pkts/272 bytes][Host: safebrowsing.googleusercontent.com]
66 TCP 192.168.1.103:58043 <-> 203.205.147.171:443 [proto: 91.197/SSL.WeChat][cat: SocialNetwork/6][3 pkts/206 bytes <-> 2 pkts/148 bytes]
- 67 UDP 0.0.0.0:68 -> 255.255.255.255:67 [proto: 18/DHCP][cat: Network/14][1 pkts/342 bytes -> 0 pkts/0 bytes][Host: iphonedimonica]
+ 67 UDP 0.0.0.0:68 -> 255.255.255.255:67 [proto: 18/DHCP][cat: Network/14][1 pkts/342 bytes -> 0 pkts/0 bytes][Host: iphonedimonica][DHCP Fingerprint: 1,121,3,6,15,119,252]
68 UDP 192.168.1.103:46078 <-> 192.168.1.254:53 [proto: 5.126/DNS.Google][cat: Web/5][1 pkts/75 bytes <-> 1 pkts/234 bytes][Host: ssl.gstatic.com]
69 UDP 192.168.1.103:60562 <-> 192.168.1.254:53 [proto: 5.126/DNS.Google][cat: Web/5][1 pkts/75 bytes <-> 1 pkts/234 bytes][Host: ssl.gstatic.com]
70 UDP 192.168.1.103:55862 <-> 192.168.1.254:53 [proto: 5.241/DNS.GoogleDocs][cat: Media/1][1 pkts/75 bytes <-> 1 pkts/227 bytes][Host: docs.google.com]
diff --git a/tests/result/whatsapp_login_call.pcap.out b/tests/result/whatsapp_login_call.pcap.out
index 8b9574a71..e35755516 100644
--- a/tests/result/whatsapp_login_call.pcap.out
+++ b/tests/result/whatsapp_login_call.pcap.out
@@ -20,7 +20,7 @@ ApplePush 22 5926 1
6 TCP 192.168.2.4:49205 <-> 17.173.66.102:443 [proto: 91.140/SSL.Apple][cat: Web/5][17 pkts/6166 bytes <-> 15 pkts/3539 bytes][TLSv1.2][JA3C: 799135475da362592a4be9199d258726][JA3S: c253ec3ad88e42f8da4032682892f9a0 (INSECURE)][TLS_RSA_WITH_RC4_128_MD5]
7 TCP 192.168.2.4:49193 <-> 17.110.229.14:5223 [proto: 238/ApplePush][cat: Cloud/13][11 pkts/4732 bytes <-> 11 pkts/1194 bytes]
8 UDP 192.168.2.4:51518 <-> 31.13.93.48:3478 [proto: 189/WhatsAppVoice][cat: VoIP/10][12 pkts/2341 bytes <-> 12 pkts/2484 bytes]
- 9 UDP 0.0.0.0:68 -> 255.255.255.255:67 [proto: 18/DHCP][cat: Network/14][10 pkts/3420 bytes -> 0 pkts/0 bytes][Host: lucas-imac]
+ 9 UDP 0.0.0.0:68 -> 255.255.255.255:67 [proto: 18/DHCP][cat: Network/14][10 pkts/3420 bytes -> 0 pkts/0 bytes][Host: lucas-imac][DHCP Fingerprint: 1,3,6,15,119,95,252,44,46]
10 UDP 192.168.2.4:52794 <-> 31.13.84.48:3478 [proto: 189/WhatsAppVoice][cat: VoIP/10][9 pkts/1842 bytes <-> 11 pkts/1151 bytes]
11 UDP 192.168.2.1:17500 -> 192.168.2.255:17500 [proto: 121/Dropbox][cat: Cloud/13][4 pkts/2176 bytes -> 0 pkts/0 bytes]
12 TCP 192.168.2.4:49199 <-> 17.172.100.70:993 [proto: 51.140/IMAPS.Apple][cat: Web/5][9 pkts/1130 bytes <-> 8 pkts/868 bytes]
diff --git a/tests/result/whatsapp_login_chat.pcap.out b/tests/result/whatsapp_login_chat.pcap.out
index 04aaaccf4..705d0b491 100644
--- a/tests/result/whatsapp_login_chat.pcap.out
+++ b/tests/result/whatsapp_login_chat.pcap.out
@@ -9,7 +9,7 @@ ApplePush 6 2095 1
1 TCP 192.168.2.4:49205 <-> 17.173.66.102:443 [proto: 91.140/SSL.Apple][cat: Web/5][24 pkts/15117 bytes <-> 20 pkts/6254 bytes]
2 TCP 192.168.2.4:49206 <-> 158.85.58.15:5222 [proto: 142/WhatsApp][cat: Chat/9][17 pkts/1794 bytes <-> 13 pkts/1169 bytes]
3 TCP 17.110.229.14:5223 -> 192.168.2.4:49193 [proto: 238/ApplePush][cat: Cloud/13][6 pkts/2095 bytes -> 0 pkts/0 bytes]
- 4 UDP 0.0.0.0:68 -> 255.255.255.255:67 [proto: 18/DHCP][cat: Network/14][6 pkts/2052 bytes -> 0 pkts/0 bytes][Host: lucas-imac]
+ 4 UDP 0.0.0.0:68 -> 255.255.255.255:67 [proto: 18/DHCP][cat: Network/14][6 pkts/2052 bytes -> 0 pkts/0 bytes][Host: lucas-imac][DHCP Fingerprint: 1,3,6,15,119,95,252,44,46]
5 UDP 192.168.2.1:17500 -> 192.168.2.255:17500 [proto: 121/Dropbox][cat: Cloud/13][2 pkts/1088 bytes -> 0 pkts/0 bytes]
6 UDP 192.168.2.4:61697 <-> 192.168.2.1:53 [proto: 5.142/DNS.WhatsApp][cat: Chat/9][1 pkts/76 bytes <-> 1 pkts/204 bytes][Host: e12.whatsapp.net]
7 UDP [fe80::189c:c31b:1298:224]:5353 -> [ff02::fb]:5353 [proto: 8/MDNS][cat: Network/14][1 pkts/111 bytes -> 0 pkts/0 bytes]