Skip to content

Commit a1810b3

Browse files
committed
support rtp/rtcp over tcp (ntop#2422)
* support rtp/rtcp over tcp as per rfc4571. Signed-off-by: mmaatuq <mahmoudmatook.mm@gmail.com>
1 parent 41050af commit a1810b3

File tree

5 files changed

+89
-49
lines changed

5 files changed

+89
-49
lines changed

src/include/ndpi_typedefs.h

+10-10
Original file line numberDiff line numberDiff line change
@@ -908,12 +908,6 @@ struct ndpi_flow_udp_struct {
908908
/* NDPI_PROTOCOL_XBOX */
909909
u_int32_t xbox_stage:1;
910910

911-
/* NDPI_PROTOCOL_RTP */
912-
u_int32_t rtp_stage:2;
913-
914-
/* NDPI_PROTOCOL_RTCP */
915-
u_int32_t rtcp_stage:2;
916-
917911
/* NDPI_PROTOCOL_QUIC */
918912
u_int32_t quic_0rtt_found:1;
919913
u_int32_t quic_vn_pair:1;
@@ -928,10 +922,6 @@ struct ndpi_flow_udp_struct {
928922
/* NDPI_PROTOCOL_RAKNET */
929923
u_int32_t raknet_custom:1;
930924

931-
/* NDPI_PROTOCOL_RTP */
932-
u_int16_t rtp_seq[2];
933-
u_int8_t rtp_seq_set[2];
934-
935925
/* NDPI_PROTOCOL_EAQ */
936926
u_int8_t eaq_pkt_id;
937927
u_int32_t eaq_sequence;
@@ -1440,6 +1430,16 @@ struct ndpi_flow_struct {
14401430
u_int8_t url_count;
14411431
char url[4][48];
14421432
} slp;
1433+
1434+
struct {
1435+
u_int32_t rtp_stage:2;
1436+
u_int16_t rtp_seq[2];
1437+
u_int8_t rtp_seq_set[2];
1438+
} rtp;
1439+
1440+
struct {
1441+
u_int32_t rtcp_stage:2;
1442+
} rtcp;
14431443
} protos;
14441444

14451445
/*** ALL protocol specific 64 bit variables here ***/

src/lib/protocols/protobuf.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ static void ndpi_search_protobuf(struct ndpi_detection_module_struct *ndpi_struc
228228
#endif
229229
if ((protobuf_elements >= PROTOBUF_REQUIRED_ELEMENTS && protobuf_len_elements > 0 &&
230230
/* (On UDP) this packet might be also a RTP/RTCP one. Wait for the next one */
231-
(flow->packet_counter > 1 || flow->l4_proto == IPPROTO_TCP || flow->l4.udp.rtp_stage == 0))
231+
(flow->packet_counter > 1 || flow->l4_proto == IPPROTO_TCP || flow->protos.rtp.rtp_stage == 0))
232232
|| (flow->packet_counter >= PROTOBUF_MIN_PACKETS && protobuf_elements >= PROTOBUF_MIN_ELEMENTS))
233233
{
234234
#ifdef DEBUG_PROTOBUF

src/lib/protocols/raknet.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct,
295295
if (frame_offset == packet->payload_packet_len)
296296
{
297297
/* This packet might also be a RTP/RTCP one: give precedence to RTP/RTCP dissector */
298-
if(flow->l4.udp.rtp_stage == 0 && flow->l4.udp.rtcp_stage == 0)
298+
if(flow->protos.rtp.rtp_stage == 0 && flow->protos.rtcp.rtcp_stage == 0)
299299
ndpi_int_raknet_add_connection(ndpi_struct, flow);
300300
} else {
301301
exclude_proto(ndpi_struct, flow);
@@ -366,7 +366,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct,
366366
if (record_index == record_count && record_offset == packet->payload_packet_len)
367367
{
368368
/* This packet might also be a RTP/RTCP one: give precedence to RTP/RTCP dissector */
369-
if(flow->l4.udp.rtp_stage == 0 && flow->l4.udp.rtcp_stage == 0)
369+
if(flow->protos.rtp.rtp_stage == 0 && flow->protos.rtcp.rtcp_stage == 0)
370370
ndpi_int_raknet_add_connection(ndpi_struct, flow);
371371
} else {
372372
exclude_proto(ndpi_struct, flow);

src/lib/protocols/rtp.c

+75-35
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ int is_rtp_or_rtcp(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t *
9494

9595
if(payload_len < 2)
9696
return NO_RTP_RTCP;
97+
98+
if(packet->tcp != NULL) {
99+
if(payload_len < 4)
100+
return NO_RTP_RTCP;
101+
payload += 2; /* Skip the length field */
102+
}
97103

98104
if((payload[0] & 0xC0) != 0x80) { /* Version 2 */
99105
NDPI_LOG_DBG(ndpi_struct, "Not version 2\n");
@@ -142,29 +148,23 @@ int is_rtp_or_rtcp(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t *
142148
static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
143149
struct ndpi_flow_struct *flow) {
144150
u_int8_t is_rtp;
145-
u_int16_t d_port = ntohs(ndpi_struct->packet.udp->dest);
146151
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
147152
const u_int8_t *payload = packet->payload;
148153
u_int16_t seq;
149154

150-
NDPI_LOG_DBG(ndpi_struct, "search RTP (stage %d/%d)\n", flow->l4.udp.rtp_stage, flow->l4.udp.rtcp_stage);
151-
152-
if(d_port == 5355 || /* LLMNR_PORT */
153-
d_port == 5353 || /* MDNS_PORT */
154-
d_port == 9600 /* FINS_PORT */) {
155-
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
156-
NDPI_EXCLUDE_PROTO_EXT(ndpi_struct, flow, NDPI_PROTOCOL_RTCP);
157-
return;
155+
if(packet->tcp != NULL) {
156+
payload += 2; /* Skip the length field */
158157
}
158+
NDPI_LOG_DBG(ndpi_struct, "search RTP (stage %d/%d)\n", flow->protos.rtp.rtp_stage, flow->protos.rtcp.rtcp_stage);
159159

160160
/* * Let some "unknown" packets at the beginning:
161161
* search for 3/4 consecutive RTP/RTCP packets.
162162
* Wait a little longer (4 vs 3 pkts) for RTCP to try to tell if there are only
163163
* RTCP packets in the flow or if RTP/RTCP are multiplexed together */
164164

165165
if(flow->packet_counter > 3 &&
166-
flow->l4.udp.rtp_stage == 0 &&
167-
flow->l4.udp.rtcp_stage == 0) {
166+
flow->protos.rtp.rtp_stage == 0 &&
167+
flow->protos.rtcp.rtcp_stage == 0) {
168168
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
169169
NDPI_EXCLUDE_PROTO_EXT(ndpi_struct, flow, NDPI_PROTOCOL_RTCP);
170170
return;
@@ -173,19 +173,19 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
173173
is_rtp = is_rtp_or_rtcp(ndpi_struct, &seq);
174174

175175
if(is_rtp == IS_RTP) {
176-
if(flow->l4.udp.rtp_stage == 2) {
176+
if(flow->protos.rtp.rtp_stage == 2) {
177177
if(flow->l4.udp.line_pkts[0] >= 2 && flow->l4.udp.line_pkts[1] >= 2) {
178178
/* It seems that it is a LINE stuff; let its dissector to evaluate */
179179
} else if(flow->l4.udp.epicgames_stage > 0) {
180180
/* It seems that it is a EpicGames stuff; let its dissector to evaluate */
181-
} else if(flow->l4.udp.rtp_seq_set[packet->packet_direction] &&
182-
flow->l4.udp.rtp_seq[packet->packet_direction] == seq) {
181+
} else if(flow->protos.rtp.rtp_seq_set[packet->packet_direction] &&
182+
flow->protos.rtp.rtp_seq[packet->packet_direction] == seq) {
183183
/* Simple heuristic to avoid false positives. tradeoff between:
184184
* consecutive RTP packets should have different sequence number
185185
* we should handle duplicated traffic */
186186
NDPI_LOG_DBG(ndpi_struct, "Same seq on consecutive pkts\n");
187-
flow->l4.udp.rtp_stage = 0;
188-
flow->l4.udp.rtcp_stage = 0;
187+
flow->protos.rtp.rtp_stage = 0;
188+
flow->protos.rtcp.rtcp_stage = 0;
189189
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
190190
NDPI_EXCLUDE_PROTO_EXT(ndpi_struct, flow, NDPI_PROTOCOL_RTCP);
191191
} else {
@@ -198,32 +198,32 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
198198
}
199199
return;
200200
}
201-
if(flow->l4.udp.rtp_stage == 0) {
202-
flow->l4.udp.rtp_seq[packet->packet_direction] = seq;
203-
flow->l4.udp.rtp_seq_set[packet->packet_direction] = 1;
201+
if(flow->protos.rtp.rtp_stage == 0) {
202+
flow->protos.rtp.rtp_seq[packet->packet_direction] = seq;
203+
flow->protos.rtp.rtp_seq_set[packet->packet_direction] = 1;
204204
}
205-
flow->l4.udp.rtp_stage += 1;
206-
} else if(is_rtp == IS_RTCP && flow->l4.udp.rtp_stage > 0) {
205+
flow->protos.rtp.rtp_stage += 1;
206+
} else if(is_rtp == IS_RTCP && flow->protos.rtp.rtp_stage > 0) {
207207
/* RTCP after (some) RTP. Keep looking for RTP */
208-
} else if(is_rtp == IS_RTCP && flow->l4.udp.rtp_stage == 0) {
209-
if(flow->l4.udp.rtcp_stage == 3) {
208+
} else if(is_rtp == IS_RTCP && flow->protos.rtp.rtp_stage == 0) {
209+
if(flow->protos.rtcp.rtcp_stage == 3) {
210210
NDPI_LOG_INFO(ndpi_struct, "Found RTCP\n");
211211
ndpi_set_detected_protocol(ndpi_struct, flow,
212212
NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_RTCP,
213213
NDPI_CONFIDENCE_DPI);
214214
return;
215215
}
216-
flow->l4.udp.rtcp_stage += 1;
216+
flow->protos.rtcp.rtcp_stage += 1;
217217
} else {
218-
if(flow->l4.udp.rtp_stage || flow->l4.udp.rtcp_stage) {
218+
if(flow->protos.rtp.rtp_stage || flow->protos.rtcp.rtcp_stage) {
219219
u_int16_t app_proto; /* unused */
220220
u_int32_t unused;
221221

222222
/* TODO: we should switch to the demultiplexing-code in stun dissector */
223223
if(is_stun(ndpi_struct, flow, &app_proto) != 0 &&
224224
!is_dtls(packet->payload, packet->payload_packet_len, &unused)) {
225-
flow->l4.udp.rtp_stage = 0;
226-
flow->l4.udp.rtcp_stage = 0;
225+
flow->protos.rtp.rtp_stage = 0;
226+
flow->protos.rtcp.rtcp_stage = 0;
227227
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
228228
NDPI_EXCLUDE_PROTO_EXT(ndpi_struct, flow, NDPI_PROTOCOL_RTCP);
229229
}
@@ -235,21 +235,61 @@ static void ndpi_rtp_search(struct ndpi_detection_module_struct *ndpi_struct,
235235
}
236236

237237
/* *************************************************************** */
238+
/* https://datatracker.ietf.org/doc/html/rfc4571
239+
* message format for RTP/RTCP over TCP:
240+
* 0 1 2 3
241+
* 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
242+
* ---------------------------------------------------------------
243+
* | LENGTH | RTP or RTCP packet ... |
244+
* ---------------------------------------------------------------
245+
*/
246+
static void ndpi_search_rtp_tcp(struct ndpi_detection_module_struct *ndpi_struct,
247+
struct ndpi_flow_struct *flow)
248+
{
249+
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
250+
const u_int8_t *payload = packet->payload;
251+
u_int16_t len = ntohs(get_u_int16_t(payload, 0));
252+
if(len + sizeof(len) != packet->payload_packet_len) { /*fragmented packets are not handled*/
253+
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
254+
NDPI_EXCLUDE_PROTO_EXT(ndpi_struct, flow, NDPI_PROTOCOL_RTCP);
255+
} else {
256+
ndpi_rtp_search(ndpi_struct, flow);
257+
}
238258

239-
static void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
259+
}
260+
261+
/* *************************************************************** */
262+
static void ndpi_search_rtp_udp(struct ndpi_detection_module_struct *ndpi_struct,
263+
struct ndpi_flow_struct *flow)
240264
{
241265
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
242266
u_int16_t source = ntohs(packet->udp->source);
243267
u_int16_t dest = ntohs(packet->udp->dest);
244-
245-
if((source != 30303) && (dest != 30303 /* Avoid to mix it with Ethereum that looks alike */)
246-
&& (dest > 1023)
247-
)
248-
ndpi_rtp_search(ndpi_struct, flow);
249-
else {
268+
/*
269+
* XXX: not sure if rtp/rtcp over tcp will also mix with Ethereum
270+
* for now, will not add it unitl we have a false positive.
271+
*/
272+
if((source == 30303) || (dest == 30303 /* Avoid to mix it with Ethereum that looks alike */)
273+
|| (dest == 5355 /* LLMNR_PORT */)
274+
|| (dest == 5353 /* MDNS_PORT */)
275+
|| (dest == 9600 /* FINS_PORT */)
276+
|| (dest <= 1023)){
250277
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
251278
NDPI_EXCLUDE_PROTO_EXT(ndpi_struct, flow, NDPI_PROTOCOL_RTCP);
279+
return;
252280
}
281+
ndpi_rtp_search(ndpi_struct, flow);
282+
}
283+
284+
/* *************************************************************** */
285+
static void ndpi_search_rtp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
286+
{
287+
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
288+
if(packet->tcp != NULL) {
289+
ndpi_search_rtp_tcp(ndpi_struct, flow);
290+
} else {
291+
ndpi_search_rtp_udp(ndpi_struct, flow);
292+
}
253293
}
254294

255295
/* *************************************************************** */
@@ -259,7 +299,7 @@ void init_rtp_dissector(struct ndpi_detection_module_struct *ndpi_struct,
259299
ndpi_set_bitmask_protocol_detection("RTP", ndpi_struct, *id,
260300
NDPI_PROTOCOL_RTP,
261301
ndpi_search_rtp,
262-
NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_UDP_WITH_PAYLOAD,
302+
NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION,
263303
SAVE_DETECTION_BITMASK_AS_UNKNOWN,
264304
ADD_TO_DETECTION_BITMASK);
265305

src/lib/protocols/viber.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ static void ndpi_search_viber(struct ndpi_detection_module_struct *ndpi_struct,
7070
if((packet->udp != NULL) && (packet->payload_packet_len > 5)) {
7171
NDPI_LOG_DBG2(ndpi_struct, "calculating dport over udp\n");
7272

73-
if((flow->l4.udp.rtp_stage == 0) && (flow->l4.udp.rtcp_stage == 0) /* Avoid collisions with RTP/RTCP */ &&
73+
if((flow->protos.rtp.rtp_stage == 0) && (flow->protos.rtcp.rtcp_stage == 0) /* Avoid collisions with RTP/RTCP */ &&
7474
((packet->payload[2] == 0x03 && packet->payload[3] == 0x00)
7575
|| (packet->payload_packet_len == 20 && packet->payload[2] == 0x09 && packet->payload[3] == 0x00)
7676
|| (packet->payload[2] == 0x01 && packet->payload[3] == 0x00 && packet->payload[4] == 0x05 && packet->payload[5] == 0x00)

0 commit comments

Comments
 (0)