diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/include/ndpi_private.h | 2 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 3 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 2 | ||||
-rw-r--r-- | src/lib/protocols/zoom.c | 84 |
4 files changed, 75 insertions, 16 deletions
diff --git a/src/include/ndpi_private.h b/src/include/ndpi_private.h index 341d01900..36af7b277 100644 --- a/src/include/ndpi_private.h +++ b/src/include/ndpi_private.h @@ -257,6 +257,8 @@ struct ndpi_detection_module_config_struct { int ookla_aggressiveness; + int zoom_max_packets_extra_dissection; + NDPI_PROTOCOL_BITMASK debug_bitmask; NDPI_PROTOCOL_BITMASK ip_list_bitmask; diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 534b804fb..0c51fba1f 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -909,6 +909,9 @@ struct ndpi_flow_udp_struct { /* NDPI_PROTOCOL_LOLWILDRIFT */ u_int32_t lolwildrift_stage:1; + /* NDPI_PROTOCOL_ZOOM */ + u_int32_t zoom_p2p:1; + /* NDPI_PROTOCOL_EPICGAMES */ u_int32_t epicgames_stage:1; u_int32_t epicgames_word; diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index 30411df9e..8f70c8985 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -11172,6 +11172,8 @@ static const struct cfg_param { { "ookla", "dpi.aggressiveness", "0x01", "0", "1", CFG_PARAM_INT, __OFF(ookla_aggressiveness), NULL }, + { "zoom", "max_packets_extra_dissection", "4", "0", "255", CFG_PARAM_INT, __OFF(zoom_max_packets_extra_dissection), NULL }, + { "$PROTO_NAME_OR_ID", "log", "disable", NULL, NULL, CFG_PARAM_PROTOCOL_ENABLE_DISABLE, __OFF(debug_bitmask), NULL }, { "$PROTO_NAME_OR_ID", "ip_list.load", "1", NULL, NULL, CFG_PARAM_PROTOCOL_ENABLE_DISABLE, __OFF(ip_list_bitmask), NULL }, diff --git a/src/lib/protocols/zoom.c b/src/lib/protocols/zoom.c index a908e56bf..4ffad391a 100644 --- a/src/lib/protocols/zoom.c +++ b/src/lib/protocols/zoom.c @@ -55,8 +55,9 @@ static void ndpi_int_zoom_add_connection(struct ndpi_detection_module_struct *nd ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_ZOOM, master, NDPI_CONFIDENCE_DPI); /* Keep looking for RTP. It is similar to the STUN logic... */ - if(master == NDPI_PROTOCOL_UNKNOWN) { - flow->max_extra_packets_to_check = 4; + if(master == NDPI_PROTOCOL_UNKNOWN && + ndpi_struct->cfg.zoom_max_packets_extra_dissection > 0) { + flow->max_extra_packets_to_check = ndpi_struct->cfg.zoom_max_packets_extra_dissection; flow->extra_packets_func = zoom_search_again; } } @@ -70,35 +71,30 @@ static int is_zoom_port(struct ndpi_flow_struct *flow) return 0; } -static int is_sfu_5(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow) +static int is_zme(struct ndpi_flow_struct *flow, + const u_char *payload, u_int16_t payload_len) { - struct ndpi_packet_struct *packet = &ndpi_struct->packet; - - /* SFU types 5 */ - if(packet->payload[0] == 0x05 && - packet->payload_packet_len > sizeof(struct zoom_sfu_enc) + - sizeof(struct zoom_media_enc)) { - struct zoom_media_enc *enc = (struct zoom_media_enc *)&packet->payload[sizeof(struct zoom_sfu_enc)]; + if(payload_len > sizeof(struct zoom_media_enc)) { + struct zoom_media_enc *enc = (struct zoom_media_enc *)payload; switch(enc->enc_type) { case 13: /* Screen Share */ case 30: /* Screen Share */ - if(packet->payload_packet_len >= 27) { + if(payload_len >= 27) { flow->flow_multimedia_type = ndpi_multimedia_screen_sharing_flow; return 1; } break; case 15: /* RTP Audio */ - if(packet->payload_packet_len >= 27) { + if(payload_len >= 27) { flow->flow_multimedia_type = ndpi_multimedia_audio_flow; return 1; } break; case 16: /* RTP Video */ - if(packet->payload_packet_len >= 32) { + if(payload_len >= 32) { flow->flow_multimedia_type = ndpi_multimedia_video_flow; return 1; } @@ -107,25 +103,47 @@ static int is_sfu_5(struct ndpi_detection_module_struct *ndpi_struct, case 33: /* RTCP */ case 34: /* RTCP */ case 35: /* RTCP */ - if(packet->payload_packet_len >= 36) { + if(payload_len >= 36) { return 1; } break; default: - return 1; + return 0; } } return 0; } +static int is_sfu_5(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) +{ + struct ndpi_packet_struct *packet = &ndpi_struct->packet; + + /* SFU types 5 */ + if(packet->payload[0] == 0x05 && + packet->payload_packet_len > sizeof(struct zoom_sfu_enc) + + sizeof(struct zoom_media_enc)) { + return is_zme(flow, &packet->payload[sizeof(struct zoom_sfu_enc)], + packet->payload_packet_len - sizeof(struct zoom_sfu_enc)); + } + return 0; +} + static int zoom_search_again(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { + struct ndpi_packet_struct *packet = &ndpi_struct->packet; + if(is_sfu_5(ndpi_struct, flow)) { ndpi_int_zoom_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SRTP); return 0; /* Stop */ } + if(flow->l4.udp.zoom_p2p && + is_zme(flow, packet->payload, packet->payload_packet_len)) { + ndpi_int_zoom_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SRTP); + return 0; /* Stop */ + } return 1; /* Keep looking */ } @@ -136,6 +154,7 @@ static void ndpi_search_zoom(struct ndpi_detection_module_struct *ndpi_struct, u_int8_t tomatch_a[] = { 0x01, 0x00, 0x02 }; /* Other first pkt from the client */ u_int8_t tomatch2[] = { 0x02, 0x00, 0x03 }; /* Usually first pkt from the server: useful with asymmetric traffic */ u_int8_t tomatch2_a[] = { 0x02, 0x00, 0x02 }; /* Other first pkt from the server */ + u_int8_t tomatch_p2p[] = { 0x1f, 0x02, 0x01 }; /* Usually first pkt for P2P connections */ NDPI_LOG_DBG(ndpi_struct, "search Zoom\n"); @@ -162,6 +181,39 @@ static void ndpi_search_zoom(struct ndpi_detection_module_struct *ndpi_struct, ndpi_int_zoom_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_SRTP); return; } + } else if(packet->payload_packet_len > 36 && + memcmp(packet->payload, tomatch_p2p, 3) == 0 && + *(u_int32_t *)&packet->payload[packet->payload_packet_len - 4] == 0) { + u_int32_t ip_len, uuid_len; + + /* Check if it is a Peer-To-Peer call. + We have been identifing such flows using the "stun_zoom" LRU cache; let's + see if we are able to detect them properly via DPI. + According to the paper, P2P calls should use "Zoom Media Encapsulation" + header without any "Zoom SFU Encapsulation". + Looking at the traces, it seems that the packet structure is something like: + * ZME type 0x1F + * initial header 24 byte long, without any obvious sequence number field + * a Length-Value list of attributes (4 bytes length field) + * an ip address (as string) + * some kind of UUID + * 4 bytes as 0x00 at the end + + TODO: if everything will work as expected, we can remove stun_zoom cache + */ + + ip_len = ntohl(*(u_int32_t *)&packet->payload[24]); + + if(24 + 4 + ip_len + 4 < packet->payload_packet_len) { + uuid_len = ntohl(*(u_int32_t *)&packet->payload[24 + 4 + ip_len]); + + if(packet->payload_packet_len == 24 + 4 + ip_len + 4 + uuid_len + 4) { + NDPI_LOG_DBG(ndpi_struct, "found P2P Zoom\n"); + flow->l4.udp.zoom_p2p = 1; + ndpi_int_zoom_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_UNKNOWN); + return; + } + } } NDPI_EXCLUDE_PROTO(ndpi_struct, flow); |