aboutsummaryrefslogtreecommitdiff
path: root/src/lib/protocols/stun.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/protocols/stun.c')
-rw-r--r--src/lib/protocols/stun.c201
1 files changed, 172 insertions, 29 deletions
diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c
index 202b3d939..8334c667a 100644
--- a/src/lib/protocols/stun.c
+++ b/src/lib/protocols/stun.c
@@ -30,7 +30,9 @@
#define MAX_NUM_STUN_PKTS 8
-// #define DEBUG_STUN 1
+/* #define DEBUG_STUN 1 */
+
+/* #define DEBUG_LRU 1 */
struct stun_packet_header {
u_int16_t msg_type, msg_len;
@@ -38,9 +40,43 @@ struct stun_packet_header {
u_int8_t transaction_id[8];
};
+/* ************************************************************ */
+
+u_int32_t get_stun_lru_key(struct ndpi_flow_struct *flow) {
+ return(flow->packet.iph->saddr + flow->packet.udp->source);
+}
+
+/* ************************************************************ */
+
static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
- u_int proto, struct ndpi_flow_struct *flow) {
- ndpi_set_detected_protocol(ndpi_struct, flow, proto, NDPI_PROTOCOL_UNKNOWN);
+ struct ndpi_flow_struct *flow,
+ u_int app_proto, u_int proto) {
+ if(ndpi_struct->stun_cache == NULL)
+ ndpi_struct->stun_cache = ndpi_lru_cache_init(1024);
+
+ if(ndpi_struct->stun_cache
+ && flow->packet.iph
+ && flow->packet.udp
+ && (app_proto != NDPI_PROTOCOL_UNKNOWN)
+ ) /* Cache flow sender info */ {
+ u_int32_t key = get_stun_lru_key(flow);
+ u_int16_t cached_proto;
+
+ if(ndpi_lru_find_cache(ndpi_struct->stun_cache, key, &cached_proto, 0 /* Don't remove it as it can be used for other connections */)) {
+#ifdef DEBUG_LRU
+ printf("[LRU] FOUND %u / %u: no need to cache %u.%u\n", key, cached_proto, proto, app_proto);
+#endif
+ app_proto = cached_proto, proto = NDPI_PROTOCOL_STUN;
+ } else {
+#ifdef DEBUG_LRU
+ printf("[LRU] ADDING %u / %u.%u\n", key, proto, app_proto);
+#endif
+
+ ndpi_lru_add_to_cache(ndpi_struct->stun_cache, key, app_proto);
+ }
+ }
+
+ ndpi_set_detected_protocol(ndpi_struct, flow, app_proto, proto);
}
typedef enum {
@@ -48,6 +84,7 @@ typedef enum {
NDPI_IS_NOT_STUN
} ndpi_int_stun_t;
+/* ************************************************************ */
static int is_google_ip_address(u_int32_t host) {
if(
@@ -59,6 +96,29 @@ static int is_google_ip_address(u_int32_t host) {
return(0);
}
+/* ************************************************************ */
+
+/*
+ WhatsApp
+ 31.13.86.48
+ 31.13.92.50
+ 157.240.20.51
+ 157.240.21.51
+ 185.60.216.51
+
+ Messenger
+ 31.13.86.5
+*/
+
+static int is_messenger_ip_address(u_int32_t host) {
+ if(host == 0x1F0D5605 /* 31.13.86.5 */)
+ return(1);
+ else
+ return(0);
+}
+
+/* ************************************************************ */
+
static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
const u_int8_t * payload,
@@ -77,7 +137,7 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
*is_whatsapp = 0, *is_messenger = 0, *is_duo = 0;
if(payload_length < sizeof(struct stun_packet_header)) {
- /* This looks like an invlid packet */
+ /* This looks like an invalid packet */
if(flow->protos.stun_ssl.stun.num_udp_pkts > 0) {
*is_whatsapp = 1;
@@ -98,18 +158,47 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
if(msg_type > 0x000C)
return(NDPI_IS_NOT_STUN);
+ if(ndpi_struct->stun_cache) {
+ u_int16_t proto;
+ u_int32_t key = get_stun_lru_key(flow);
+
+ if(ndpi_lru_find_cache(ndpi_struct->stun_cache, key, &proto, 0 /* Don't remove it as it can be used for other connections */)) {
+#ifdef DEBUG_LRU
+ printf("[LRU] FOUND %u / %u\n", key, proto);
+#endif
+
+ flow->guessed_host_protocol_id = proto, flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
+ return(NDPI_IS_STUN);
+ } else {
+#ifdef DEBUG_LRU
+ printf("[LRU] NOT FOUND %u\n", key);
+#endif
+ }
+ } else {
+#ifdef DEBUG_LRU
+ printf("[LRU] NO/EMPTY CACHE\n");
+#endif
+ }
+
if(msg_type == 0x01 /* Binding Request */) {
flow->protos.stun_ssl.stun.num_binding_requests++;
- if((msg_len == 0) && (flow->guessed_host_protocol_id == NDPI_PROTOCOL_GOOGLE)) {
+
+ if((msg_len == 0) && (flow->guessed_host_protocol_id == NDPI_PROTOCOL_GOOGLE))
flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO;
- }
+ else
+ flow->guessed_host_protocol_id = NDPI_PROTOCOL_STUN;
+
+ flow->protos.stun_ssl.stun.num_udp_pkts++;
+
+ if(msg_len == 0)
+ return(NDPI_IS_NOT_STUN); /* This to keep analyzing STUN instead of giving up */
}
if((msg_len == 0) && (flow->guessed_host_protocol_id == NDPI_PROTOCOL_UNKNOWN)) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return(NDPI_IS_NOT_STUN);
}
-
+
flow->protos.stun_ssl.stun.num_udp_pkts++;
/*
@@ -131,9 +220,20 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
if((payload[0] != 0x80) && ((msg_len+20) > payload_length))
return(NDPI_IS_NOT_STUN);
- else
- flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
-
+ else {
+ switch(flow->guessed_protocol_id) {
+ case NDPI_PROTOCOL_HANGOUT_DUO:
+ case NDPI_PROTOCOL_MESSENGER:
+ case NDPI_PROTOCOL_WHATSAPP_VOICE:
+ /* Don't overwrite the protocol with sub-STUN protocols */
+ break;
+
+ default:
+ flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
+ break;
+ }
+ }
+
if(payload_length == (msg_len+20)) {
if(msg_type <= 0x000b) /* http://www.3cx.com/blog/voip-howto/stun-details/ */ {
u_int offset = 20;
@@ -157,6 +257,10 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
if(x != 0)
len += 4-x;
+#ifdef DEBUG_STUN
+ printf("==> Attribute: %04X\n", attribute);
+#endif
+
switch(attribute) {
case 0x0008: /* Message Integrity */
case 0x0020: /* XOR-MAPPED-ADDRESSES */
@@ -166,6 +270,28 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
/* These are the only messages apparently whatsapp voice can use */
break;
+ case 0x0014: /* Realm */
+ {
+ u_int16_t realm_len = ntohs(*((u_int16_t*)&payload[offset+2]));
+
+ if(flow->host_server_name[0] == '\0') {
+ u_int j, i = (realm_len > sizeof(flow->host_server_name)) ? sizeof(flow->host_server_name) : realm_len;
+ u_int k = offset+4;
+
+ memset(flow->host_server_name, 0, sizeof(flow->host_server_name));
+
+ for(j=0; j<i; j++)
+ flow->host_server_name[j] = payload[k++];
+
+ if(strstr((char*)flow->host_server_name, "google.com") != NULL) {
+ *is_duo = 1;
+ flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO, flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
+ return(NDPI_IS_STUN);
+ }
+ }
+ }
+ break;
+
case 0xC057: /* Messeger */
if(msg_type == 0x0001) {
if((msg_len == 100) || (msg_len == 104)) {
@@ -173,7 +299,12 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
return(NDPI_IS_STUN);
} else if(msg_len == 76) {
*is_duo = 1;
- return(NDPI_IS_STUN);
+
+ if(1) {
+ flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO, flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
+ return(NDPI_IS_NOT_STUN); /* This case is found also with signal traffic */
+ } else
+ return(NDPI_IS_STUN);
}
}
break;
@@ -185,6 +316,9 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
&& (payload[offset+6] == 0x00)
&& (payload[offset+7] == 0x00)) {
/* Either skype for business or "normal" skype with multiparty call */
+#ifdef DEBUG_STUN
+ printf("==> Skype found\n");
+#endif
flow->protos.stun_ssl.stun.is_skype = 1;
return(NDPI_IS_STUN);
}
@@ -201,6 +335,10 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
case 0x0800:
/* printf("====>>>> %04X\n", attribute); */
flow->protos.stun_ssl.stun.is_skype = 1;
+#ifdef DEBUG_STUN
+ printf("==> Skype (2) found\n");
+#endif
+
return(NDPI_IS_STUN);
break;
@@ -213,6 +351,10 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
&& ((payload[offset+7] == 0x02) || (payload[offset+7] == 0x03))
) {
flow->protos.stun_ssl.stun.is_skype = 1;
+#ifdef DEBUG_STUN
+ printf("==> Skype (3) found\n");
+#endif
+
return(NDPI_IS_STUN);
}
break;
@@ -221,7 +363,7 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
can_this_be_whatsapp_voice = 0;
flow->guessed_host_protocol_id = NDPI_PROTOCOL_HANGOUT_DUO;
break;
-
+
default:
/* This means this STUN packet cannot be confused with whatsapp voice */
#ifdef DEBUG_STUN
@@ -249,15 +391,16 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
udp_stun_found:
if(can_this_be_whatsapp_voice) {
struct ndpi_packet_struct *packet = &flow->packet;
-
+
flow->protos.stun_ssl.stun.num_processed_pkts++;
#ifdef DEBUG_STUN
printf("==>> NDPI_PROTOCOL_WHATSAPP_VOICE\n");
#endif
- if((ntohs(packet->udp->source) == 3478) || (ntohs(packet->udp->dest) == 3478))
- flow->guessed_host_protocol_id = NDPI_PROTOCOL_WHATSAPP_VOICE;
- else
+ if((ntohs(packet->udp->source) == 3478) || (ntohs(packet->udp->dest) == 3478)) {
+ flow->guessed_host_protocol_id = (is_messenger_ip_address(ntohl(packet->iph->saddr)) || is_messenger_ip_address(ntohl(packet->iph->daddr))) ?
+ NDPI_PROTOCOL_MESSENGER : NDPI_PROTOCOL_WHATSAPP_VOICE;
+ } else
flow->guessed_host_protocol_id = (is_google_ip_address(ntohl(packet->iph->saddr)) || is_google_ip_address(ntohl(packet->iph->daddr)))
? NDPI_PROTOCOL_HANGOUT_DUO : NDPI_PROTOCOL_WHATSAPP_VOICE;
return((flow->protos.stun_ssl.stun.num_udp_pkts < MAX_NUM_STUN_PKTS) ? NDPI_IS_NOT_STUN : NDPI_IS_STUN);
@@ -295,23 +438,24 @@ void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct n
if(ndpi_int_check_stun(ndpi_struct, flow, packet->payload + 2,
packet->payload_packet_len - 2,
&is_whatsapp, &is_messenger, &is_duo) == NDPI_IS_STUN) {
- if(flow->guessed_protocol_id == 0) flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
+ if(flow->guessed_protocol_id == NDPI_PROTOCOL_UNKNOWN) flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
if(is_messenger) {
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_STUN);
+ ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_STUN);
return;
} else if(is_duo) {
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO, NDPI_PROTOCOL_STUN);
+ ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO, NDPI_PROTOCOL_STUN);
return;
} else if(flow->protos.stun_ssl.stun.is_skype) {
NDPI_LOG_INFO(ndpi_struct, "found Skype\n");
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);
+ ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SKYPE_CALL, NDPI_PROTOCOL_SKYPE);
} 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 ? (is_whatsapp == 1 ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_WHATSAPP_VIDEO) : NDPI_PROTOCOL_STUN, flow);
+ ndpi_int_stun_add_connection(ndpi_struct, flow,
+ is_whatsapp ? (is_whatsapp == 1 ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_WHATSAPP_VIDEO) : NDPI_PROTOCOL_STUN,
+ NDPI_PROTOCOL_UNKNOWN);
}
return;
@@ -323,26 +467,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, &is_messenger, &is_duo) == NDPI_IS_STUN) {
- if(flow->guessed_protocol_id == 0) flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
+ if(flow->guessed_protocol_id == NDPI_PROTOCOL_UNKNOWN) flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
if(is_messenger) {
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_STUN);
+ ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_MESSENGER, NDPI_PROTOCOL_STUN);
return;
} else if(is_duo) {
- ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO, NDPI_PROTOCOL_STUN);
+ ndpi_int_stun_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_HANGOUT_DUO, NDPI_PROTOCOL_STUN);
return;
} else 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 */
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);
+ ndpi_int_stun_add_connection(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,
+ ndpi_int_stun_add_connection(ndpi_struct, flow,
is_whatsapp ? (is_whatsapp == 1 ? NDPI_PROTOCOL_WHATSAPP_VOICE : NDPI_PROTOCOL_WHATSAPP_VIDEO)
- : NDPI_PROTOCOL_STUN,
- flow);
+ : NDPI_PROTOCOL_STUN, NDPI_PROTOCOL_UNKNOWN);
}
return;