diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/include/ndpi_api.h | 5 | ||||
-rw-r--r-- | src/include/ndpi_private.h | 1 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 12 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 3 | ||||
-rw-r--r-- | src/lib/ndpi_utils.c | 60 | ||||
-rw-r--r-- | src/lib/protocols/rtp.c | 150 | ||||
-rw-r--r-- | src/lib/protocols/stun.c | 3 |
7 files changed, 198 insertions, 36 deletions
diff --git a/src/include/ndpi_api.h b/src/include/ndpi_api.h index 4a56da56f..467984f9f 100644 --- a/src/include/ndpi_api.h +++ b/src/include/ndpi_api.h @@ -602,10 +602,11 @@ extern "C" { /** * Return the name of a RTP payload type * - * @par payload_type = the RTP payload type + * @par payload_type = the RTP payload type + * @par evs_payload_type = EVS payload type (only in case payload_type is EVS) * @return The symbolic payload type or "Unknown" if not found */ - const char* ndpi_rtp_payload_type2str(u_int8_t payload_type); + const char* ndpi_rtp_payload_type2str(u_int8_t payload_type, u_int32_t evs_payload_type); /** * Check if subprotocols of the specified master protocol are just diff --git a/src/include/ndpi_private.h b/src/include/ndpi_private.h index afd2f48ac..e452df10a 100644 --- a/src/include/ndpi_private.h +++ b/src/include/ndpi_private.h @@ -296,6 +296,7 @@ struct ndpi_detection_module_config_struct { int stun_opportunistic_tls_enabled; int stun_max_packets_extra_dissection; + int rtp_max_packets_extra_dissection; int stun_mapped_address_enabled; int stun_response_origin_enabled; int stun_other_address_enabled; diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 8ca365d01..6b215aa70 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -1301,6 +1301,12 @@ struct ndpi_tls_obfuscated_heuristic_matching_set { u_int32_t pkts[4]; }; +struct rtp_info { + u_int8_t payload_type; + u_int32_t evs_subtype; + bool payload_detected; +}; + struct ndpi_flow_struct { u_int16_t detected_protocol_stack[NDPI_PROTOCOL_SIZE]; @@ -1601,10 +1607,8 @@ struct ndpi_flow_struct { char *user_agent; } ssdp; - struct { - u_int8_t payload_type; - } rtp; -} protos; + struct rtp_info rtp[2 /* directions */]; + } protos; /* **Packet** metadata for flows where monitoring is enabled. It is reset after each packet! */ struct ndpi_metadata_monitoring *monit; diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index c29ec6ebf..904d1d971 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -11791,7 +11791,8 @@ static const struct cfg_param { { "zoom", "max_packets_extra_dissection", "4", "0", "255", CFG_PARAM_INT, __OFF(zoom_max_packets_extra_dissection), NULL }, { "rtp", "search_for_stun", "disable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(rtp_search_for_stun), NULL }, - + { "rtp", "max_packets_extra_dissection", "32", "0", "255", CFG_PARAM_INT, __OFF(rtp_max_packets_extra_dissection), NULL }, + { "openvpn", "dpi.heuristics", "0x00", "0", "0x01", CFG_PARAM_INT, __OFF(openvpn_heuristics), NULL }, { "openvpn", "dpi.heuristics.num_messages", "10", "0", "255", CFG_PARAM_INT, __OFF(openvpn_heuristics_num_msgs), NULL }, { "openvpn", "subclassification_by_ip", "enable", NULL, NULL, CFG_PARAM_ENABLE_DISABLE, __OFF(openvpn_subclassification_by_ip), NULL }, diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c index 63effab29..69eaeb052 100644 --- a/src/lib/ndpi_utils.c +++ b/src/lib/ndpi_utils.c @@ -4236,7 +4236,8 @@ ndpi_protocol_qoe_category_t ndpi_find_protocol_qoe(struct ndpi_detection_module /* ************************************************************** */ -const char* ndpi_rtp_payload_type2str(u_int8_t payload_type) { +/* https://gitlab.com/wireshark/wireshark/-/blob/master/epan/dissectors/packet-rtp.c */ +const char* ndpi_rtp_payload_type2str(u_int8_t payload_type, u_int32_t evs_payload_type) { switch(payload_type) { case 0: return("ITU-T G.711 PCMU"); case 1: return("USA Federal Standard FS-1016"); @@ -4265,7 +4266,62 @@ const char* ndpi_rtp_payload_type2str(u_int8_t payload_type) { case 33: return("MPEG-II transport streams"); case 34: return("ITU-T H.263"); case 98: return("AMR-WB"); - case 127: return("EVS"); + case 118: return("AMR"); /* Adptive Multirate */ + case 126: /* Enhanced Voice Services */ + case 127: /* Enhanced Voice Services */ + { + switch(evs_payload_type) { + /* https://gitlab.com/wireshark/wireshark/-/blob/master/epan/dissectors/packet-evs.c */ + + case 0x0: return("AMR-WB IO 6.6 kbps"); + case 0x1: return("AMR-WB IO 8.85 kbps"); + case 0x2: return("AMR-WB IO 12.65 kbps"); + case 0x3: return("AMR-WB IO 14.24 kbps"); + case 0x4: return("AMR-WB IO 15.85 kbps"); + case 0x5: return("AMR-WB IO 18.25 kbps"); + case 0x6: return("AMR-WB IO 19.85 kbps"); + case 0x7: return("AMR-WB IO 23.05 kbps"); + case 0x8: return("AMR-WB IO 23.85 kbps"); + case 0x9: return("AMR-WB IO 2.0 kbps SID"); + + /* ** */ + /* Dummy SWB 30 offset */ + case 0x3+30: return("SWB 9.6 kbps"); + case 0x4+30: return("SWB 13.2 kbps"); + case 0x5+30: return("SWB 16.4 kbps"); + case 0x6+30: return("SWB 24.4 kbps"); + case 0x7+30: return("SWB 32 kbps"); + case 0x8+30: return("SWB 48 kbps"); + case 0x9+30: return("SWB 64 kbps"); + case 0xa+30: return("SWB 96 kbps"); + case 0xb+30: return("SWB 128 kbps"); + + + case 48: return("EVS Primary SID 2.4"); + case 136: return("EVS AMR-WB IO 6.6"); + case 144: return("EVS Primary 7.2"); + case 160: return("EVS Primary 8.0"); + case 184: return("EVS AMR-WB IO 8.85"); + case 192: return("EVS Primary 9.6"); + case 256: return("EVS AMR-WB IO 12.65"); + case 264: return("EVS Primary 13.2"); + case 288: return("EVS AMR-WB IO 14.25"); + case 320: return("EVS AMR-WB IO 15.85"); + case 328: return("EVS Primary 16.4"); + case 368: return("EVS AMR-WB IO 18.25"); + case 400: return("EVS AMR-WB IO 19.85"); + case 464: return("EVS AMR-WB IO 23.05"); + case 480: return("EVS AMR-WB IO 23.85"); + case 488: return("EVS Primary 24.4"); + case 640: return("EVS Primary 32.0"); + case 960: return("EVS Primary 48.0"); + case 1280: return("EVS Primary 64.0"); + case 1920: return("EVS Primary 96.0"); + case 2560: return("EVS Primary 128.0"); + default: return("EVS 13.2"); + } + } + break; default: return("Unknown"); } } diff --git a/src/lib/protocols/rtp.c b/src/lib/protocols/rtp.c index ffd2049d6..8e216bde6 100644 --- a/src/lib/protocols/rtp.c +++ b/src/lib/protocols/rtp.c @@ -32,6 +32,11 @@ #define RTP_MIN_HEADER 12 #define RTCP_MIN_HEADER 8 +static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow); + +/* *************************************************************** */ + /* https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml */ int is_valid_rtp_payload_type(uint8_t type) { @@ -40,6 +45,8 @@ int is_valid_rtp_payload_type(uint8_t type) return 1; } +/* *************************************************************** */ + u_int8_t rtp_get_stream_type(u_int8_t payloadType, u_int8_t *s_type, u_int16_t sub_proto) { /* General, from IANA */ @@ -201,10 +208,14 @@ u_int8_t rtp_get_stream_type(u_int8_t payloadType, u_int8_t *s_type, u_int16_t s return(0); } +/* *************************************************************** */ + static int is_valid_rtcp_payload_type(uint8_t type) { return (type >= 192 && type <= 213); } +/* *************************************************************** */ + int is_rtp_or_rtcp(struct ndpi_detection_module_struct *ndpi_struct, const u_int8_t *payload, u_int16_t payload_len, u_int16_t *seq) { @@ -214,7 +225,7 @@ int is_rtp_or_rtcp(struct ndpi_detection_module_struct *ndpi_struct, if(payload_len < 2) return NO_RTP_RTCP; - + if((payload[0] & 0xC0) != 0x80) { /* Version 2 */ NDPI_LOG_DBG(ndpi_struct, "Not version 2\n"); return NO_RTP_RTCP; @@ -239,8 +250,8 @@ int is_rtp_or_rtcp(struct ndpi_detection_module_struct *ndpi_struct, return NO_RTP_RTCP; } /* Check on padding doesn't work because: - * we may have multiple RTP packets in the same TCP/UDP datagram - * with SRTP, padding_length field is encrypted */ + * we may have multiple RTP packets in the same TCP/UDP datagram + * with SRTP, padding_length field is encrypted */ if(seq) *seq = ntohs(*(unsigned short *)&payload[2]); return IS_RTP; @@ -257,6 +268,17 @@ int is_rtp_or_rtcp(struct ndpi_detection_module_struct *ndpi_struct, return NO_RTP_RTCP; } +/* ************************************************************ */ + +static int rtp_search_again(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) { + /* printf("***** AGAIN *****\n"); */ + ndpi_rtp_search(ndpi_struct, flow); + + return(((flow->protos.rtp[0].payload_detected && flow->protos.rtp[1].payload_detected)) ? false :true); +} + +/* *************************************************************** */ static void ndpi_int_rtp_add_connection(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow, @@ -272,6 +294,16 @@ static void ndpi_int_rtp_add_connection(struct ndpi_detection_module_struct *ndp NDPI_LOG_DBG(ndpi_struct, "Enabling (STUN) extra dissection\n"); switch_extra_dissection_to_stun(ndpi_struct, flow, 1); } + } else if(proto == NDPI_PROTOCOL_RTP) { + if(flow->protos.rtp[0].payload_detected && flow->protos.rtp[1].payload_detected) + ; /* Nothing to do */ + else { + if(!flow->extra_packets_func) { + NDPI_LOG_DBG(ndpi_struct, "Enabling extra dissection\n"); + flow->max_extra_packets_to_check = ndpi_struct->cfg.rtp_max_packets_extra_dissection; + flow->extra_packets_func = rtp_search_again; + } + } } } @@ -286,15 +318,15 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t seq; if(packet->tcp != NULL) { - payload += 2; /* Skip the length field */ - payload_len -= 2; + payload += 2; /* Skip the length field */ + payload_len -= 2; } NDPI_LOG_DBG(ndpi_struct, "search RTP (stage %d/%d)\n", flow->rtp_stage, flow->rtcp_stage); /* * Let some "unknown" packets at the beginning: - * search for 3/4 consecutive RTP/RTCP packets. - * Wait a little longer (4 vs 3 pkts) for RTCP to try to tell if there are only - * RTCP packets in the flow or if RTP/RTCP are multiplexed together */ + * search for 3/4 consecutive RTP/RTCP packets. + * Wait a little longer (4 vs 3 pkts) for RTCP to try to tell if there are only + * RTCP packets in the flow or if RTP/RTCP are multiplexed together */ if(flow->packet_counter > 3 && flow->rtp_stage == 0 && @@ -307,8 +339,75 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct, is_rtp = is_rtp_or_rtcp(ndpi_struct, payload, payload_len, &seq); if(is_rtp == IS_RTP) { - flow->protos.rtp.payload_type = payload[1] & 0x7F; + u_int8_t packet_direction = current_pkt_from_client_to_server(ndpi_struct, flow) ? 0 : 1; + if(flow->protos.rtp[packet_direction].payload_type == 0x0) { + flow->protos.rtp[packet_direction].payload_type = payload[1] & 0x7F; + flow->protos.rtp[packet_direction].payload_detected = true; + + /* printf("********* [direction: %d] payload_type=%u\n", packet_direction, flow->protos.rtp[packet_direction].payload_type); */ + + if(((flow->protos.rtp[packet_direction].payload_type == 126 /* Enhanced Voice Services (EVS) */) + || (flow->protos.rtp[packet_direction].payload_type == 127 /* Enhanced Voice Services (EVS) */)) + && (payload_len > 12 /* RTP header */)) { + const u_int8_t *evs = &payload[12]; + u_int packet_len = payload_len - 12; + u_int num_bits = packet_len * 8; + + flow->flow_multimedia_types = ndpi_multimedia_audio_flow; + /* printf("********* %02X [bits %u]\n", evs[0], num_bits); */ + + if(num_bits == 56) { + /* A.2.1.3 Special case for 56 bit payload size (EVS Primary or EVS AMR-WB IO SID) */ + + if((evs[0] & 0x80) == 0) + flow->protos.rtp[packet_direction].evs_subtype = evs[0] & 0xF; + else + flow->protos.rtp[packet_direction].evs_subtype = evs[1] & 0xF; + } else { + + /* See ndpi_rtp_payload_type2str() */ + switch(num_bits) { + case 48: + case 136: + case 144: + case 160: + case 184: + case 192: + case 256: + case 264: + case 288: + case 320: + case 328: + case 368: + case 400: + case 464: + case 480: + case 488: + case 640: + case 960: + case 1280: + case 1920: + case 2560: + flow->protos.rtp[packet_direction].evs_subtype = num_bits; + break; + + default: + if((evs[0] >> 7) == 1) { + /* EVS Codec Mode Request (EVS-CMR) */ + u_int8_t d_bits = evs[0] & 0X0F; + + flow->protos.rtp[packet_direction].evs_subtype = d_bits + 30 /* dummy offset */; + } + break; + } + } + + if(flow->protos.rtp[0].payload_detected && flow->protos.rtp[1].payload_detected) + flow->extra_packets_func = NULL; /* Nothing to do */ + } + } + if(flow->rtp_stage == 2) { if(flow->l4_proto == IPPROTO_UDP && flow->l4.udp.line_pkts[0] >= 2 && flow->l4.udp.line_pkts[1] >= 2) { @@ -318,15 +417,16 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct, } else if(flow->rtp_seq_set[packet->packet_direction] && flow->rtp_seq[packet->packet_direction] == seq) { /* Simple heuristic to avoid false positives. tradeoff between: - * consecutive RTP packets should have different sequence number - * we should handle duplicated traffic */ + * consecutive RTP packets should have different sequence number + * we should handle duplicated traffic */ NDPI_LOG_DBG(ndpi_struct, "Same seq on consecutive pkts\n"); flow->rtp_stage = 0; flow->rtcp_stage = 0; NDPI_EXCLUDE_PROTO(ndpi_struct, flow); NDPI_EXCLUDE_PROTO_EXT(ndpi_struct, flow, NDPI_PROTOCOL_RTCP); } else { - rtp_get_stream_type(flow->protos.rtp.payload_type, &flow->flow_multimedia_types, NDPI_PROTOCOL_UNKNOWN); + rtp_get_stream_type(flow->protos.rtp[packet->packet_direction].payload_type, + &flow->flow_multimedia_types, NDPI_PROTOCOL_UNKNOWN); NDPI_LOG_INFO(ndpi_struct, "Found RTP\n"); ndpi_int_rtp_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_RTP); @@ -360,7 +460,7 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct, NDPI_EXCLUDE_PROTO(ndpi_struct, flow); NDPI_EXCLUDE_PROTO_EXT(ndpi_struct, flow, NDPI_PROTOCOL_RTCP); } - } + } } } @@ -374,11 +474,11 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct, * --------------------------------------------------------------- */ static void ndpi_search_rtp_tcp(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow) + struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &ndpi_struct->packet; const u_int8_t *payload = packet->payload; - + if(packet->payload_packet_len < 4){ /* (2) len field + (2) min rtp/rtcp*/ NDPI_EXCLUDE_PROTO(ndpi_struct, flow); NDPI_EXCLUDE_PROTO_EXT(ndpi_struct, flow, NDPI_PROTOCOL_RTCP); @@ -397,12 +497,12 @@ static void ndpi_search_rtp_tcp(struct ndpi_detection_module_struct *ndpi_struct /* *************************************************************** */ static void ndpi_search_rtp_udp(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow) + struct ndpi_flow_struct *flow) { struct ndpi_packet_struct *packet = &ndpi_struct->packet; u_int16_t source = ntohs(packet->udp->source); u_int16_t dest = ntohs(packet->udp->dest); - /* + /* * XXX: not sure if rtp/rtcp over tcp will also mix with Ethereum * for now, will not add it unitl we have a false positive. */ @@ -424,9 +524,9 @@ static void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, st struct ndpi_packet_struct *packet = &ndpi_struct->packet; if(packet->tcp != NULL) { ndpi_search_rtp_tcp(ndpi_struct, flow); - } else { - ndpi_search_rtp_udp(ndpi_struct, flow); - } + } else { + ndpi_search_rtp_udp(ndpi_struct, flow); + } } /* *************************************************************** */ @@ -434,11 +534,11 @@ static void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, st void init_rtp_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id) { ndpi_set_bitmask_protocol_detection("RTP", ndpi_struct, *id, - NDPI_PROTOCOL_RTP, - ndpi_search_rtp, - NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION, - SAVE_DETECTION_BITMASK_AS_UNKNOWN, - ADD_TO_DETECTION_BITMASK); + NDPI_PROTOCOL_RTP, + ndpi_search_rtp, + NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION, + SAVE_DETECTION_BITMASK_AS_UNKNOWN, + ADD_TO_DETECTION_BITMASK); *id += 1; } diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c index 2fb0c89b7..683559853 100644 --- a/src/lib/protocols/stun.c +++ b/src/lib/protocols/stun.c @@ -961,12 +961,11 @@ 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"); rtp_get_stream_type(packet->payload[1] & 0x7F, &flow->flow_multimedia_types, flow->detected_protocol_stack[0]); |