diff options
Diffstat (limited to 'src/lib/protocols/stun.c')
-rw-r--r-- | src/lib/protocols/stun.c | 201 |
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; |