aboutsummaryrefslogtreecommitdiff
path: root/src/lib/protocols
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/protocols')
-rw-r--r--src/lib/protocols/btlib.c10
-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
5 files changed, 243 insertions, 189 deletions
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/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;