aboutsummaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorMaatuq <mahmoudmatook.mm@gmail.com>2024-05-29 00:01:08 +0400
committerGitHub <noreply@github.com>2024-05-28 22:01:08 +0200
commit6127e04900d14682f524cca5b5720b2fb9f0e283 (patch)
tree649485a95b93e12b16ef1d902a805ebeeb431792 /src/lib
parent80171dbcf3865e8b02f136b0dc4b088033fd9054 (diff)
support rtp/rtcp over tcp (#2422) (#2457)
Support rtp/rtcp over tcp as per rfc4571. Signed-off-by: mmaatuq <mahmoudmatook.mm@gmail.com>
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/protocols/protobuf.c2
-rw-r--r--src/lib/protocols/raknet.c4
-rw-r--r--src/lib/protocols/rtp.c126
-rw-r--r--src/lib/protocols/viber.c2
4 files changed, 90 insertions, 44 deletions
diff --git a/src/lib/protocols/protobuf.c b/src/lib/protocols/protobuf.c
index 9f50e5c31..4306e81ad 100644
--- a/src/lib/protocols/protobuf.c
+++ b/src/lib/protocols/protobuf.c
@@ -228,7 +228,7 @@ static void ndpi_search_protobuf(struct ndpi_detection_module_struct *ndpi_struc
#endif
if ((protobuf_elements >= PROTOBUF_REQUIRED_ELEMENTS && protobuf_len_elements > 0 &&
/* (On UDP) this packet might be also a RTP/RTCP one. Wait for the next one */
- (flow->packet_counter > 1 || flow->l4_proto == IPPROTO_TCP || flow->l4.udp.rtp_stage == 0))
+ (flow->packet_counter > 1 || flow->l4_proto == IPPROTO_TCP || flow->rtp_stage == 0))
|| (flow->packet_counter >= PROTOBUF_MIN_PACKETS && protobuf_elements >= PROTOBUF_MIN_ELEMENTS))
{
#ifdef DEBUG_PROTOBUF
diff --git a/src/lib/protocols/raknet.c b/src/lib/protocols/raknet.c
index b11107ec3..3e3200e1a 100644
--- a/src/lib/protocols/raknet.c
+++ b/src/lib/protocols/raknet.c
@@ -295,7 +295,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct,
if (frame_offset == packet->payload_packet_len)
{
/* This packet might also be a RTP/RTCP one: give precedence to RTP/RTCP dissector */
- if(flow->l4.udp.rtp_stage == 0 && flow->l4.udp.rtcp_stage == 0)
+ if(flow->rtp_stage == 0 && flow->rtcp_stage == 0)
ndpi_int_raknet_add_connection(ndpi_struct, flow);
} else {
exclude_proto(ndpi_struct, flow);
@@ -366,7 +366,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct,
if (record_index == record_count && record_offset == packet->payload_packet_len)
{
/* This packet might also be a RTP/RTCP one: give precedence to RTP/RTCP dissector */
- if(flow->l4.udp.rtp_stage == 0 && flow->l4.udp.rtcp_stage == 0)
+ if(flow->rtp_stage == 0 && flow->rtcp_stage == 0)
ndpi_int_raknet_add_connection(ndpi_struct, flow);
} else {
exclude_proto(ndpi_struct, flow);
diff --git a/src/lib/protocols/rtp.c b/src/lib/protocols/rtp.c
index e549a910f..b543e8b99 100644
--- a/src/lib/protocols/rtp.c
+++ b/src/lib/protocols/rtp.c
@@ -90,10 +90,15 @@ int is_rtp_or_rtcp(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t *
u_int16_t ext_len;
u_int32_t min_len;
const u_int8_t *payload = packet->payload;
- const u_int16_t payload_len = packet->payload_packet_len;
+ u_int16_t payload_len = packet->payload_packet_len;
if(payload_len < 2)
return NO_RTP_RTCP;
+
+ if(packet->tcp != NULL) {
+ payload_len -= 2;
+ payload += 2; /* Skip the length field */
+ }
if((payload[0] & 0xC0) != 0x80) { /* Version 2 */
NDPI_LOG_DBG(ndpi_struct, "Not version 2\n");
@@ -142,20 +147,14 @@ int is_rtp_or_rtcp(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t *
static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
u_int8_t is_rtp;
- u_int16_t d_port = ntohs(ndpi_struct->packet.udp->dest);
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
const u_int8_t *payload = packet->payload;
u_int16_t seq;
- NDPI_LOG_DBG(ndpi_struct, "search RTP (stage %d/%d)\n", flow->l4.udp.rtp_stage, flow->l4.udp.rtcp_stage);
-
- if(d_port == 5355 || /* LLMNR_PORT */
- d_port == 5353 || /* MDNS_PORT */
- d_port == 9600 /* FINS_PORT */) {
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
- NDPI_EXCLUDE_PROTO_EXT(ndpi_struct, flow, NDPI_PROTOCOL_RTCP);
- return;
+ if(packet->tcp != NULL) {
+ payload += 2; /* Skip the length field */
}
+ 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.
@@ -163,8 +162,8 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
* RTCP packets in the flow or if RTP/RTCP are multiplexed together */
if(flow->packet_counter > 3 &&
- flow->l4.udp.rtp_stage == 0 &&
- flow->l4.udp.rtcp_stage == 0) {
+ flow->rtp_stage == 0 &&
+ flow->rtcp_stage == 0) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
NDPI_EXCLUDE_PROTO_EXT(ndpi_struct, flow, NDPI_PROTOCOL_RTCP);
return;
@@ -173,19 +172,19 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
is_rtp = is_rtp_or_rtcp(ndpi_struct, &seq);
if(is_rtp == IS_RTP) {
- if(flow->l4.udp.rtp_stage == 2) {
+ if(flow->rtp_stage == 2) {
if(flow->l4.udp.line_pkts[0] >= 2 && flow->l4.udp.line_pkts[1] >= 2) {
/* It seems that it is a LINE stuff; let its dissector to evaluate */
} else if(flow->l4.udp.epicgames_stage > 0) {
/* It seems that it is a EpicGames stuff; let its dissector to evaluate */
- } else if(flow->l4.udp.rtp_seq_set[packet->packet_direction] &&
- flow->l4.udp.rtp_seq[packet->packet_direction] == seq) {
+ } 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 */
NDPI_LOG_DBG(ndpi_struct, "Same seq on consecutive pkts\n");
- flow->l4.udp.rtp_stage = 0;
- flow->l4.udp.rtcp_stage = 0;
+ 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 {
@@ -198,32 +197,32 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
}
return;
}
- if(flow->l4.udp.rtp_stage == 0) {
- flow->l4.udp.rtp_seq[packet->packet_direction] = seq;
- flow->l4.udp.rtp_seq_set[packet->packet_direction] = 1;
+ if(flow->rtp_stage == 0) {
+ flow->rtp_seq[packet->packet_direction] = seq;
+ flow->rtp_seq_set[packet->packet_direction] = 1;
}
- flow->l4.udp.rtp_stage += 1;
- } else if(is_rtp == IS_RTCP && flow->l4.udp.rtp_stage > 0) {
+ flow->rtp_stage += 1;
+ } else if(is_rtp == IS_RTCP && flow->rtp_stage > 0) {
/* RTCP after (some) RTP. Keep looking for RTP */
- } else if(is_rtp == IS_RTCP && flow->l4.udp.rtp_stage == 0) {
- if(flow->l4.udp.rtcp_stage == 3) {
+ } else if(is_rtp == IS_RTCP && flow->rtp_stage == 0) {
+ if(flow->rtcp_stage == 3) {
NDPI_LOG_INFO(ndpi_struct, "Found RTCP\n");
ndpi_set_detected_protocol(ndpi_struct, flow,
NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_RTCP,
NDPI_CONFIDENCE_DPI);
return;
}
- flow->l4.udp.rtcp_stage += 1;
+ flow->rtcp_stage += 1;
} else {
- if(flow->l4.udp.rtp_stage || flow->l4.udp.rtcp_stage) {
+ if(flow->rtp_stage || flow->rtcp_stage) {
u_int16_t app_proto; /* unused */
u_int32_t unused;
/* TODO: we should switch to the demultiplexing-code in stun dissector */
if(is_stun(ndpi_struct, flow, &app_proto) != 0 &&
!is_dtls(packet->payload, packet->payload_packet_len, &unused)) {
- flow->l4.udp.rtp_stage = 0;
- flow->l4.udp.rtcp_stage = 0;
+ flow->rtp_stage = 0;
+ flow->rtcp_stage = 0;
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
NDPI_EXCLUDE_PROTO_EXT(ndpi_struct, flow, NDPI_PROTOCOL_RTCP);
}
@@ -235,21 +234,68 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
}
/* *************************************************************** */
+/* https://datatracker.ietf.org/doc/html/rfc4571
+ * message format for RTP/RTCP over TCP:
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * ---------------------------------------------------------------
+ * | LENGTH | RTP or RTCP packet ... |
+ * ---------------------------------------------------------------
+ */
+static void ndpi_search_rtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
+ 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);
+ return;
+ }
-static void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
+ u_int16_t len = ntohs(get_u_int16_t(payload, 0));
+ if(len + sizeof(len) != packet->payload_packet_len) { /*fragmented packets are not handled*/
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ NDPI_EXCLUDE_PROTO_EXT(ndpi_struct, flow, NDPI_PROTOCOL_RTCP);
+ } else {
+ ndpi_rtp_search(ndpi_struct, flow);
+ }
+
+}
+
+/* *************************************************************** */
+static void ndpi_search_rtp_udp(struct ndpi_detection_module_struct *ndpi_struct,
+ 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);
-
- if((source != 30303) && (dest != 30303 /* Avoid to mix it with Ethereum that looks alike */)
- && (dest > 1023)
- )
- ndpi_rtp_search(ndpi_struct, flow);
- else {
+ /*
+ * 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.
+ */
+ if((source == 30303) || (dest == 30303 /* Avoid to mix it with Ethereum that looks alike */)
+ || (dest == 5355 /* LLMNR_PORT */)
+ || (dest == 5353 /* MDNS_PORT */)
+ || (dest == 9600 /* FINS_PORT */)
+ || (dest <= 1023)){
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
NDPI_EXCLUDE_PROTO_EXT(ndpi_struct, flow, NDPI_PROTOCOL_RTCP);
+ return;
}
+ ndpi_rtp_search(ndpi_struct, flow);
+}
+
+/* *************************************************************** */
+static void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
+{
+ 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);
+ }
}
/* *************************************************************** */
@@ -257,11 +303,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_UDP_WITH_PAYLOAD,
- 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/viber.c b/src/lib/protocols/viber.c
index 3a1a57792..00cfae96a 100644
--- a/src/lib/protocols/viber.c
+++ b/src/lib/protocols/viber.c
@@ -70,7 +70,7 @@ static void ndpi_search_viber(struct ndpi_detection_module_struct *ndpi_struct,
if((packet->udp != NULL) && (packet->payload_packet_len > 5)) {
NDPI_LOG_DBG2(ndpi_struct, "calculating dport over udp\n");
- if((flow->l4.udp.rtp_stage == 0) && (flow->l4.udp.rtcp_stage == 0) /* Avoid collisions with RTP/RTCP */ &&
+ if((flow->rtp_stage == 0) && (flow->rtcp_stage == 0) /* Avoid collisions with RTP/RTCP */ &&
((packet->payload[2] == 0x03 && packet->payload[3] == 0x00)
|| (packet->payload_packet_len == 20 && packet->payload[2] == 0x09 && packet->payload[3] == 0x00)
|| (packet->payload[2] == 0x01 && packet->payload[3] == 0x00 && packet->payload[4] == 0x05 && packet->payload[5] == 0x00)