diff --git a/fuzzers/rtcp_fuzzer.c b/fuzzers/rtcp_fuzzer.c index ff7a659f06..7fe297084d 100644 --- a/fuzzers/rtcp_fuzzer.c +++ b/fuzzers/rtcp_fuzzer.c @@ -30,11 +30,12 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { /* Do some copies of input data */ uint8_t copy_data0[size], copy_data1[size], copy_data2[size], copy_data3[size], - copy_data4[size]; - uint8_t *copy_data[5] = { copy_data0, copy_data1, - copy_data2, copy_data3, copy_data4}; + copy_data4[size], copy_data5[size]; + uint8_t *copy_data[6] = { copy_data0, copy_data1, + copy_data2, copy_data3, + copy_data4, copy_data5 }; int idx, newlen; - for (idx=0; idx < 5; idx++) { + for (idx=0; idx < 6; idx++) { memcpy(copy_data[idx], data, size); } idx = 0; @@ -53,8 +54,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { janus_rtcp_get_sender_ssrc((char *)data, size); /* Functions that alter input data */ janus_rtcp_cap_remb((char *)copy_data[idx++], size, 256000); - janus_rtcp_fix_report_data((char *)copy_data[idx++], size, 2000, 1000, 1234, 1234, 1234, TRUE); - janus_rtcp_fix_ssrc(&ctx0, (char *)copy_data[idx++], size, 1, 2, 3); + janus_rtcp_swap_report_blocks((char *)copy_data[idx++], size, 2); + janus_rtcp_fix_report_data((char *)copy_data[idx++], size, 2000, 1000, 2, 2, 2, TRUE); + janus_rtcp_fix_ssrc(&ctx0, (char *)copy_data[idx++], size, 1, 2, 2); janus_rtcp_parse(&ctx1, (char *)copy_data[idx++], size); janus_rtcp_remove_nacks((char *)copy_data[idx++], size); /* Functions that allocate new memory */ diff --git a/ice.c b/ice.c index 7e8f8a2434..a5c3d1de21 100644 --- a/ice.c +++ b/ice.c @@ -2779,6 +2779,9 @@ static void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint comp } /* Is this audio or video? */ int video = 0, vindex = 0; + if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RFC4588_RTX)) { + janus_rtcp_swap_report_blocks(buf, buflen, stream->video_ssrc_rtx); + } /* Bundled streams, should we check the SSRCs? */ if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_HAS_AUDIO)) { /* No audio has been negotiated, definitely video */ diff --git a/rtcp.c b/rtcp.c index 2e53f4778f..4a3561ea4c 100644 --- a/rtcp.c +++ b/rtcp.c @@ -154,6 +154,59 @@ guint32 janus_rtcp_get_receiver_ssrc(char *packet, int len) { return 0; } +void janus_rtcp_swap_report_blocks(char *packet, int len, uint32_t rtx_ssrc) { + if(packet == NULL || len == 0) + return; + janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; + int pno = 0, total = len; + while(rtcp) { + if (!janus_rtcp_check_len(rtcp, total)) + break; + if(rtcp->version != 2) + break; + pno++; + switch(rtcp->type) { + case RTCP_SR: { + /* SR, sender report */ + if (!janus_rtcp_check_sr(rtcp, total)) + break; + janus_rtcp_sr *sr = (janus_rtcp_sr *)rtcp; + if(sr->header.rc >= 2 && ntohl(sr->rb[0].ssrc) == rtx_ssrc) { + janus_report_block rb0_copy = sr->rb[0]; + sr->rb[0] = sr->rb[1]; + sr->rb[1] = rb0_copy; + } + break; + } + case RTCP_RR: { + /* RR, receiver report */ + if (!janus_rtcp_check_rr(rtcp, total)) + break; + janus_rtcp_rr *rr = (janus_rtcp_rr *)rtcp; + if(rr->header.rc >= 2 && ntohl(rr->rb[0].ssrc) == rtx_ssrc) { + janus_report_block rb0_copy = rr->rb[0]; + rr->rb[0] = rr->rb[1]; + rr->rb[1] = rb0_copy; + JANUS_LOG(LOG_HUGE, "Switched incoming RTCP Report Blocks %"SCNu32"(rtx) <--> %"SCNu32"\n", + rtx_ssrc, ntohl(rr->rb[0].ssrc)); + } + break; + } + default: + break; + } + /* Is this a compound packet? */ + int length = ntohs(rtcp->length); + if(length == 0) { + break; + } + total -= length*4+4; + if(total <= 0) + break; + rtcp = (janus_rtcp_header *)((uint32_t*)rtcp + length + 1); + } +} + /* Helper to handle an incoming SR: triggered by a call to janus_rtcp_fix_ssrc with a valid context pointer */ static void janus_rtcp_incoming_sr(janus_rtcp_context *ctx, janus_rtcp_sr *sr) { if(ctx == NULL) diff --git a/rtcp.h b/rtcp.h index 96ab8abb40..8c820a614f 100644 --- a/rtcp.h +++ b/rtcp.h @@ -322,6 +322,12 @@ uint32_t janus_rtcp_context_get_out_link_quality(janus_rtcp_context *ctx); * @param[in] ctx The RTCP context to query * @returns Outbound media link quality estimation */ uint32_t janus_rtcp_context_get_out_media_link_quality(janus_rtcp_context *ctx); +/*! \brief Method to swap Report Blocks and move media RB in first position in case rtx SSRC comes first + * @param[in] packet The message data + * @param[in] len The message data length in bytes + * @param[in] rtx_ssrc The rtx SSRC + * @returns The receiver SSRC, or 0 in case of error */ +void janus_rtcp_swap_report_blocks(char *packet, int len, uint32_t rtx_ssrc); /*! \brief Method to quickly retrieve the sender SSRC (needed for demuxing RTCP in BUNDLE) * @param[in] packet The message data * @param[in] len The message data length in bytes