diff options
Diffstat (limited to 'src/lib/protocols/stun.c')
-rw-r--r-- | src/lib/protocols/stun.c | 140 |
1 files changed, 108 insertions, 32 deletions
diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c index d5015cc60..d9045fb20 100644 --- a/src/lib/protocols/stun.c +++ b/src/lib/protocols/stun.c @@ -1,7 +1,7 @@ /* * stun.c * - * Copyright (C) 2011-24 - ntop.org + * Copyright (C) 2011-25 - ntop.org * * This file is part of nDPI, an open source deep packet inspection * library based on the OpenDPI and PACE technology by ipoque GmbH @@ -55,7 +55,8 @@ static u_int64_t get_stun_lru_key_raw6(u_int8_t *ip, u_int16_t port); static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, u_int16_t app_proto, - u_int16_t master_proto); + u_int16_t master_proto, + ndpi_protocol_category_t category); static int stun_search_again(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow); @@ -354,8 +355,8 @@ static void parse_xor_ip_port_attribute(struct ndpi_detection_module_struct *ndp int is_stun(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, - u_int16_t *app_proto) -{ + u_int16_t *app_proto, + ndpi_protocol_category_t *category) { struct ndpi_packet_struct *packet = &ndpi_struct->packet; u_int16_t msg_type, msg_len, method; int off; @@ -366,6 +367,8 @@ int is_stun(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t magic_cookie; u_int32_t transaction_id[3]; + *category = NDPI_PROTOCOL_CATEGORY_UNSPECIFIED; + if(payload_length < STUN_HDR_LEN) return(-1); @@ -559,8 +562,8 @@ int is_stun(struct ndpi_detection_module_struct *ndpi_struct, bool valid = true; ndpi_hostname_sni_set(flow, payload + off + 4, ndpi_min(len, payload_length - off - 4), NDPI_HOSTNAME_NORM_ALL); - NDPI_LOG_DBG(ndpi_struct, "Realm [%s]\n", flow->host_server_name); - + NDPI_LOG_DBG(ndpi_struct, "Realm [%s]\n", flow->host_server_name); + /* Some Realm contain junk, so let's validate it */ for(i=0; flow->host_server_name[i] != '\0'; i++) { if(flow->host_server_name[i] == '?') { @@ -578,11 +581,16 @@ int is_stun(struct ndpi_detection_module_struct *ndpi_struct, } else if(strstr(flow->host_server_name, "facebook") != NULL) { *app_proto = NDPI_PROTOCOL_FACEBOOK_VOIP; } else if(strstr(flow->host_server_name, "stripcdn.com") != NULL) { - *app_proto = NDPI_PROTOCOL_ADULT_CONTENT; + *category = NDPI_PROTOCOL_CATEGORY_ADULT_CONTENT; } else if(strstr(flow->host_server_name, "telegram") != NULL) { *app_proto = NDPI_PROTOCOL_TELEGRAM_VOIP; } else if(strstr(flow->host_server_name, "viber") != NULL) { *app_proto = NDPI_PROTOCOL_VIBER_VOIP; + } else if(strstr(flow->host_server_name, "turn.cloudflare.com") != NULL) { + /* The latest signal implementations hide behind cloudflare */ + if(signal_search_into_cache(ndpi_struct, flow)) { + *app_proto = NDPI_PROTOCOL_SIGNAL_VOIP; + } } } else flow->host_server_name[0] = '\0'; @@ -828,10 +836,14 @@ static int stun_search_again(struct ndpi_detection_module_struct *ndpi_struct, (flow->detected_protocol_stack[0] == NDPI_PROTOCOL_WHATSAPP_CALL && (msg_type == 0x0800 || msg_type == 0x0801 || msg_type == 0x0802 || msg_type == 0x0804 || msg_type == 0x0805))) { + ndpi_protocol_category_t category; + NDPI_LOG_DBG(ndpi_struct, "Still STUN\n"); - if(is_stun(ndpi_struct, flow, &app_proto) == 1) { /* To extract other metadata */ + + if(is_stun(ndpi_struct, flow, &app_proto, &category) == 1) { /* To extract other metadata */ if(is_new_subclassification_better(ndpi_struct, flow, app_proto)) { - ndpi_int_stun_add_connection(ndpi_struct, flow, app_proto, __get_master(flow)); + ndpi_int_stun_add_connection(ndpi_struct, flow, + app_proto, __get_master(flow), category); } } } else if(first_byte <= 15) { @@ -881,8 +893,7 @@ static int stun_search_again(struct ndpi_detection_module_struct *ndpi_struct, /* TODO: right way? It is a bit scary... do we need to reset something else too? */ reset_detected_protocol(flow); /* We keep the category related to STUN traffic */ - /* STUN often triggers this risk; clear it. TODO: clear other risks? */ - ndpi_unset_risk(flow, NDPI_KNOWN_PROTOCOL_ON_NON_STANDARD_PORT); + /* TODO: clear some risks? */ /* Give room for DTLS handshake, where we might have retransmissions and fragments */ @@ -900,7 +911,7 @@ static int stun_search_again(struct ndpi_detection_module_struct *ndpi_struct, NDPI_LOG_DBG(ndpi_struct, "Keeping old subclassification %d\n", old_proto_stack[0]); ndpi_int_stun_add_connection(ndpi_struct, flow, old_proto_stack[0] == NDPI_PROTOCOL_RTP ? NDPI_PROTOCOL_SRTP : old_proto_stack[0], - __get_master(flow)); + __get_master(flow), NDPI_PROTOCOL_CATEGORY_UNSPECIFIED); } /* If this is not a real DTLS packet, we need to restore the old state */ @@ -961,14 +972,20 @@ static int stun_search_again(struct ndpi_detection_module_struct *ndpi_struct, rtp_rtcp = is_rtp_or_rtcp(ndpi_struct, packet->payload, packet->payload_packet_len, NULL); if(rtp_rtcp == IS_RTP) { - NDPI_LOG_DBG(ndpi_struct, "RTP (dir %d) [%d/%d]\n", packet->packet_direction, flow->stun.rtp_counters[0], flow->stun.rtp_counters[1]); flow->stun.rtp_counters[packet->packet_direction]++; - + /* TODO: store RTP information in 'struct rtp_info' */ NDPI_LOG_INFO(ndpi_struct, "Found RTP over STUN\n"); + if(flow->stun.t_start != 0) { + flow->stun.t_end = ndpi_get_current_time(flow); + } else if(flow->stun.rtp_counters[0] != 0 && flow->stun.rtp_counters[1] != 0) { + flow->stun.t_start = ndpi_get_current_time(flow); + flow->stun.t_end = ndpi_get_current_time(flow); + } + rtp_get_stream_type(packet->payload[1] & 0x7F, &flow->flow_multimedia_types, flow->detected_protocol_stack[0]); if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_RTP && @@ -981,14 +998,15 @@ static int stun_search_again(struct ndpi_detection_module_struct *ndpi_struct, } else { /* STUN/SUBPROTO -> SRTP/SUBPROTO */ ndpi_int_stun_add_connection(ndpi_struct, flow, - flow->detected_protocol_stack[0], NDPI_PROTOCOL_SRTP); + flow->detected_protocol_stack[0], NDPI_PROTOCOL_SRTP, + NDPI_PROTOCOL_CATEGORY_UNSPECIFIED); } } else { /* STUN -> STUN/RTP, or DTLS -> DTLS/SRTP */ ndpi_int_stun_add_connection(ndpi_struct, flow, __get_master(flow) == NDPI_PROTOCOL_STUN ? NDPI_PROTOCOL_RTP: NDPI_PROTOCOL_SRTP, - __get_master(flow)); + __get_master(flow), NDPI_PROTOCOL_CATEGORY_UNSPECIFIED); } } else if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_RTCP && flow->detected_protocol_stack[1] == NDPI_PROTOCOL_UNKNOWN) { @@ -1132,7 +1150,8 @@ static u_int64_t get_stun_lru_key_raw6(u_int8_t *ip, u_int16_t port_host_order) static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, u_int16_t app_proto, - u_int16_t master_proto) { + u_int16_t master_proto, + ndpi_protocol_category_t category) { ndpi_confidence_t confidence = NDPI_CONFIDENCE_DPI; u_int16_t new_app_proto; @@ -1189,7 +1208,7 @@ static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *nd if(master_proto == NDPI_PROTOCOL_RTP || master_proto == NDPI_PROTOCOL_RTCP) { if(app_proto == NDPI_PROTOCOL_UNKNOWN) { app_proto = NDPI_PROTOCOL_RTP; - master_proto = NDPI_PROTOCOL_STUN; /* RTP|RTCP ->STUN/RTP */ + master_proto = NDPI_PROTOCOL_STUN; /* RTP|RTCP -> STUN/RTP */ } else { master_proto = NDPI_PROTOCOL_SRTP; } @@ -1199,6 +1218,9 @@ static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *nd if(is_subclassification_real_by_proto(app_proto)) add_to_cache(ndpi_struct, flow, app_proto); + if(category != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED) + flow->category = category; + if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN || app_proto != NDPI_PROTOCOL_UNKNOWN) { NDPI_LOG_DBG(ndpi_struct, "Setting %d/%d\n", master_proto, app_proto); @@ -1208,10 +1230,11 @@ static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *nd takes care of setting the category */ if(flow->extra_packets_func) { ndpi_protocol ret = { { master_proto, app_proto }, NDPI_PROTOCOL_UNKNOWN /* unused */, NDPI_PROTOCOL_CATEGORY_UNSPECIFIED, NULL}; + flow->category = ndpi_get_proto_category(ndpi_struct, ret); } } - + switch_extra_dissection_to_stun(ndpi_struct, flow, 1); } @@ -1239,6 +1262,7 @@ static void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, s { struct ndpi_packet_struct *packet = &ndpi_struct->packet; u_int16_t app_proto; + ndpi_protocol_category_t category; int rc; NDPI_LOG_DBG(ndpi_struct, "search stun\n"); @@ -1248,31 +1272,83 @@ static void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, s if(packet->iph && ((packet->iph->daddr == 0xFFFFFFFF /* 255.255.255.255 */) || ((ntohl(packet->iph->daddr) & 0xF0000000) == 0xE0000000 /* A multicast address */))) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow); return; } - rc = is_stun(ndpi_struct, flow, &app_proto); + rc = is_stun(ndpi_struct, flow, &app_proto, &category); if(rc == 1) { - ndpi_int_stun_add_connection(ndpi_struct, flow, app_proto, __get_master(flow)); + ndpi_int_stun_add_connection(ndpi_struct, flow, app_proto, + __get_master(flow), category); return; } /* TODO: can we stop earlier? */ if(flow->packet_counter > 5) - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow); } -/* ************************************************************ */ +/* ************************************************************* */ + +static u_int64_t get_signal_key(struct ndpi_flow_struct *flow) +{ + if(flow->is_ipv6) + return ndpi_quick_hash64((const char *)flow->c_address.v6, 16); + else + return flow->c_address.v4; +} + +/* ************************************************************* */ + +int signal_search_into_cache(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) +{ + u_int64_t key; + u_int16_t dummy; + + if(ndpi_struct->signal_cache) { + key = get_signal_key(flow); -void init_stun_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id) { - ndpi_set_bitmask_protocol_detection("STUN", ndpi_struct, *id, - NDPI_PROTOCOL_STUN, - ndpi_search_stun, - NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION, - SAVE_DETECTION_BITMASK_AS_UNKNOWN, - ADD_TO_DETECTION_BITMASK); + if(ndpi_lru_find_cache(ndpi_struct->signal_cache, key, + &dummy, 0 /* Don't remove it as it can be used for other connections */, + ndpi_get_current_time(flow))) { +#ifdef DEBUG_SIGNAL_LRU + printf("[LRU SIGNAL] Found %lu [%u <-> %u]\n", key, ntohs(flow->c_port), ntohs(flow->s_port)); +#endif + return 1; + } else { +#ifdef DEBUG_SIGNAL_LRU + printf("[LRU SIGNAL] Not found %lu [%u <-> %u]\n", key, ntohs(flow->c_port), ntohs(flow->s_port)); +#endif + } + } + + return 0; +} + +/* ************************************************************* */ + +void signal_add_to_cache(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) +{ + u_int64_t key; + + if(ndpi_struct->signal_cache) { + key = get_signal_key(flow); +#ifdef DEBUG_SIGNAL_LRU + printf("[LRU SIGNAL] ADDING %lu [%u <-> %u]\n", key, ntohs(flow->c_port), ntohs(flow->s_port)); +#endif + ndpi_lru_add_to_cache(ndpi_struct->signal_cache, key, 1 /* dummy */, + ndpi_get_current_time(flow)); + } +} + +/* ************************************************************ */ - *id += 1; +void init_stun_dissector(struct ndpi_detection_module_struct *ndpi_struct) { + register_dissector("STUN", ndpi_struct, + ndpi_search_stun, + NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION, + 1, NDPI_PROTOCOL_STUN); } |