aboutsummaryrefslogtreecommitdiff
path: root/src/lib/protocols/stun.c
diff options
context:
space:
mode:
authorLuca <deri@ntop.org>2015-06-04 18:44:09 +0200
committerLuca <deri@ntop.org>2015-06-04 18:44:09 +0200
commit4ce9dec54ecb18b7eb5b9123bfbfc6c57aa35c6b (patch)
treeed6349cbe9da3a26e424a5ceb6e0a4d94d30fe40 /src/lib/protocols/stun.c
parenta31b0a3354d4a6f62ea9c338ed6f890136f1d3e6 (diff)
Reworked the STUN plugin
Added support for WhatsApp Voice vs WhatsApp (chat, no voice)
Diffstat (limited to 'src/lib/protocols/stun.c')
-rw-r--r--src/lib/protocols/stun.c110
1 files changed, 74 insertions, 36 deletions
diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c
index 09ec4a050..c613ae242 100644
--- a/src/lib/protocols/stun.c
+++ b/src/lib/protocols/stun.c
@@ -27,12 +27,20 @@
#ifdef NDPI_PROTOCOL_STUN
-static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
-{
- ndpi_int_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_STUN, NDPI_REAL_PROTOCOL);
-}
+#define MAX_NUM_STUN_PKTS 6
+struct stun_packet_header {
+ u_int16_t msg_type, msg_len;
+ u_int32_t cookie;
+ u_int8_t transaction_id[8];
+};
+
+static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
+ u_int proto,
+ struct ndpi_flow_struct *flow) {
+ ndpi_int_add_connection(ndpi_struct, flow, proto, NDPI_REAL_PROTOCOL);
+}
typedef enum {
NDPI_IS_STUN,
@@ -40,18 +48,30 @@ typedef enum {
} ndpi_int_stun_t;
static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *ndpi_struct,
- const u_int8_t * payload, const u_int16_t payload_length)
+ struct ndpi_flow_struct *flow,
+ const u_int8_t * payload,
+ const u_int16_t payload_length,
+ u_int8_t *is_whatsapp)
{
- u_int16_t a;
+ u_int16_t msg_type, msg_len;
+ struct stun_packet_header *h = (struct stun_packet_header*)payload;
+ if(payload_length < sizeof(struct stun_packet_header))
+ return(NDPI_IS_NOT_STUN);
- if((payload_length > 13)
- && (strncmp((const char*)payload, (const char*)"RSP/", 4) == 0)
+ if((strncmp((const char*)payload, (const char*)"RSP/", 4) == 0)
&& (strncmp((const char*)&payload[7], (const char*)" STUN_", 6) == 0)) {
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "Found stun.\n");
- return NDPI_IS_STUN;
+ goto udp_stun_found;
}
+
+ msg_type = ntohs(h->msg_type) & 0x3EEF, msg_len = ntohs(h->msg_len);
+ if((payload_length == (msg_len+20))
+ && ((msg_type <= 0x000b) /* http://www.3cx.com/blog/voip-howto/stun-details/ */))
+ goto udp_stun_found;
+
+#ifdef ORIGINAL_CODE
/*
* token list of message types and attribute types from
* http://wwwbs1.informatik.htw-dresden.de/svortrag/i02/Schoene/stun/stun.html
@@ -68,7 +88,7 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
* 0x8003, 0x8004 used by facetime
*/
- if (payload_length >= 20 && ntohs(get_u_int16_t(payload, 2)) + 20 == payload_length &&
+ if(payload_length >= 20 && ntohs(get_u_int16_t(payload, 2)) + 20 == payload_length &&
((payload[0] == 0x00 && (payload[1] >= 0x01 && payload[1] <= 0x04)) ||
(payload[0] == 0x01 &&
((payload[1] >= 0x01 && payload[1] <= 0x04) || (payload[1] >= 0x11 && payload[1] <= 0x15))))) {
@@ -77,16 +97,16 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
u_int8_t padding = 0;
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "len and type match.\n");
- if (payload_length == 20) {
+ if(payload_length == 20) {
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "found stun.\n");
- return NDPI_IS_STUN;
+ goto udp_stun_found;
}
a = 20;
while (a < payload_length) {
- if (old && payload_length >= a + 4
+ if(old && payload_length >= a + 4
&&
((payload[a] == 0x00
&& ((payload[a + 1] >= 0x01 && payload[a + 1] <= 0x16) || payload[a + 1] == 0x19
@@ -103,16 +123,16 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
a += ((payload[a + 2] << 8) + payload[a + 3] + 4);
mod = a % 4;
- if (mod) {
+ if(mod) {
padding = 4 - mod;
}
- if (a == payload_length || (padding && (a + padding) == payload_length)) {
+ if(a == payload_length || (padding && (a + padding) == payload_length)) {
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "found stun.\n");
- return NDPI_IS_STUN;
+ goto udp_stun_found;
}
- } else if (payload_length >= a + padding + 4
- &&
+ } else if(payload_length >= a + padding + 4
+ &&
((payload[a + padding] == 0x00
&& ((payload[a + 1 + padding] >= 0x01 && payload[a + 1 + padding] <= 0x16)
|| payload[a + 1 + padding] == 0x19 || payload[a + 1 + padding] == 0x20
@@ -125,7 +145,11 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
|| payload[a + 1 + padding] == 0x20 || payload[a + 1 + padding] == 0x22
|| payload[a + 1 + padding] == 0x28 || payload[a + 1 + padding] == 0x2a
|| payload[a + 1 + padding] == 0x29 || payload[a + 1 + padding] == 0x50
- || payload[a + 1 + padding] == 0x54 || payload[a + 1 + padding] == 0x55)))) {
+ || payload[a + 1 + padding] == 0x54 || payload[a + 1 + padding] == 0x55))
+ || ((payload[a + padding] == 0x40) && (payload[a + padding + 1] == 0x00))
+ )) {
+ if((payload[a + padding] == 0x40) && (payload[a + padding + 1] == 0x00))
+ goto udp_stun_found;
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "New STUN - attribute match.\n");
@@ -133,56 +157,70 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
a += ((payload[a + 2 + padding] << 8) + payload[a + 3 + padding] + 4);
padding = 0;
mod = a % 4;
- if (mod) {
+ if(mod) {
a += 4 - mod;
}
- if (a == payload_length) {
+ if(a == payload_length) {
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "found stun.\n");
- return NDPI_IS_STUN;
+ goto udp_stun_found;
}
} else {
break;
}
}
}
+#endif
+
- return NDPI_IS_NOT_STUN;
+ if((flow->num_stun_udp_pkts > 0) && ((payload[0] == 0x80) || (payload[0] == 0x81))) {
+ *is_whatsapp = 1;
+ return NDPI_IS_STUN; /* This is WhatsApp Voice */
+ } else
+ return NDPI_IS_NOT_STUN;
+
+ udp_stun_found:
+ flow->num_stun_udp_pkts++;
+
+ return((flow->num_stun_udp_pkts < MAX_NUM_STUN_PKTS) ? NDPI_IS_NOT_STUN : NDPI_IS_STUN);
}
void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
{
struct ndpi_packet_struct *packet = &flow->packet;
-
+ u_int8_t is_whatsapp = 0;
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "search stun.\n");
-
- if (packet->tcp) {
-
+ if(packet->tcp) {
/* STUN may be encapsulated in TCP packets */
- if (packet->payload_packet_len >= 2 + 20 &&
+ if(packet->payload_packet_len >= 2 + 20 &&
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 */
- if (ndpi_int_check_stun(ndpi_struct, packet->payload + 2, packet->payload_packet_len - 2) ==
- NDPI_IS_STUN) {
+ if(ndpi_int_check_stun(ndpi_struct, flow, packet->payload + 2,
+ packet->payload_packet_len - 2, &is_whatsapp) == NDPI_IS_STUN) {
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "found TCP stun.\n");
- ndpi_int_stun_add_connection(ndpi_struct, flow);
+ ndpi_int_stun_add_connection(ndpi_struct, NDPI_PROTOCOL_STUN, flow);
return;
}
}
}
- if (ndpi_int_check_stun(ndpi_struct, packet->payload, packet->payload_packet_len) == NDPI_IS_STUN) {
+
+ if(ndpi_int_check_stun(ndpi_struct, flow, packet->payload,
+ packet->payload_packet_len, &is_whatsapp) == NDPI_IS_STUN) {
NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "found UDP stun.\n");
- ndpi_int_stun_add_connection(ndpi_struct, flow);
+ ndpi_int_stun_add_connection(ndpi_struct,
+ is_whatsapp ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_STUN, flow);
return;
}
- NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "exclude stun.\n");
- NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_STUN);
+ if(flow->num_stun_udp_pkts >= MAX_NUM_STUN_PKTS) {
+ NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "exclude stun.\n");
+ NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_STUN);
+ }
}
#endif