mirror of
https://github.com/mii443/libdatachannel.git
synced 2025-08-27 01:19:31 +00:00
Check incoming RTCP SDES
This commit is contained in:
@ -326,6 +326,9 @@ public:
|
|||||||
inline SSRC ssrc() const { return ntohl(_ssrc); }
|
inline SSRC ssrc() const { return ntohl(_ssrc); }
|
||||||
inline void setSSRC(SSRC ssrc) { _ssrc = htonl(ssrc); }
|
inline void setSSRC(SSRC ssrc) { _ssrc = htonl(ssrc); }
|
||||||
|
|
||||||
|
/// Get item at given index
|
||||||
|
/// @note All items with index < `num` must be valid, otherwise this function has undefined behaviour (use `safelyCountChunkSize` to check if chunk is valid)
|
||||||
|
/// @param num Index of item to return
|
||||||
inline RTCP_SDES_ITEM *getItem(int num) {
|
inline RTCP_SDES_ITEM *getItem(int num) {
|
||||||
auto base = &_items;
|
auto base = &_items;
|
||||||
while (num-- > 0) {
|
while (num-- > 0) {
|
||||||
@ -335,6 +338,39 @@ public:
|
|||||||
return reinterpret_cast<RTCP_SDES_ITEM *>(base);
|
return reinterpret_cast<RTCP_SDES_ITEM *>(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long safelyCountChunkSize(unsigned int maxChunkSize) {
|
||||||
|
if (maxChunkSize < RTCP_SDES_CHUNK::size({})) {
|
||||||
|
// chunk is truncated
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
unsigned int size = sizeof(SSRC);
|
||||||
|
unsigned int i = 0;
|
||||||
|
// We can always access first 4 bytes of first item (in case of no items there will be 4 null bytes)
|
||||||
|
auto item = getItem(i);
|
||||||
|
std::vector<uint8_t> textsLength{};
|
||||||
|
while (item->type != 0) {
|
||||||
|
if (size + RTCP_SDES_ITEM::size(0) > maxChunkSize) {
|
||||||
|
// item is too short
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
auto itemLength = item->length();
|
||||||
|
if (size + RTCP_SDES_ITEM::size(itemLength) >= maxChunkSize) {
|
||||||
|
// item is too large (it can't be equal to chunk size because after item there must be 1-4 null bytes as padding)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
textsLength.push_back(itemLength);
|
||||||
|
// safely to access next item
|
||||||
|
item = getItem(++i);
|
||||||
|
}
|
||||||
|
auto realSize = RTCP_SDES_CHUNK::size(textsLength);
|
||||||
|
if (realSize > maxChunkSize) {
|
||||||
|
// Chunk is too large
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return realSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] static unsigned int size(std::vector<uint8_t> textLengths) {
|
[[nodiscard]] static unsigned int size(std::vector<uint8_t> textLengths) {
|
||||||
unsigned int itemsSize = 0;
|
unsigned int itemsSize = 0;
|
||||||
for (auto length: textLengths) {
|
for (auto length: textLengths) {
|
||||||
@ -345,6 +381,8 @@ public:
|
|||||||
return words * 4;
|
return words * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get size of chunk
|
||||||
|
/// @note All items must be valid, otherwise this function has undefined behaviour (use `safelyCountChunkSize` to check if chunk is valid)
|
||||||
[[nodiscard]] unsigned int getSize() {
|
[[nodiscard]] unsigned int getSize() {
|
||||||
std::vector<uint8_t> textLengths{};
|
std::vector<uint8_t> textLengths{};
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
@ -374,8 +412,37 @@ public:
|
|||||||
header.prepareHeader(202, chunkCount, length);
|
header.prepareHeader(202, chunkCount, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isValid() {
|
||||||
|
auto chunksSize = header.lengthInBytes() - sizeof(header);
|
||||||
|
if (chunksSize == 0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// there is at least one chunk
|
||||||
|
unsigned int i = 0;
|
||||||
|
unsigned int size = 0;
|
||||||
|
while (size < chunksSize) {
|
||||||
|
if (chunksSize < size + RTCP_SDES_CHUNK::size({})) {
|
||||||
|
// chunk is truncated
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto chunk = getChunk(i);
|
||||||
|
auto chunkSize = chunk->safelyCountChunkSize(chunksSize - size);
|
||||||
|
if (chunksSize < 0) {
|
||||||
|
// chunk is invalid
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
size += chunkSize;
|
||||||
|
}
|
||||||
|
return size == chunksSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns number of chunks in this packet
|
||||||
|
/// @note Returns 0 if packet is invalid
|
||||||
inline unsigned int chunksCount() {
|
inline unsigned int chunksCount() {
|
||||||
|
if (!isValid()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
uint16_t chunksSize = 4 * (header.length() + 1) - sizeof(header);
|
uint16_t chunksSize = 4 * (header.length() + 1) - sizeof(header);
|
||||||
unsigned int size = 0;
|
unsigned int size = 0;
|
||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
@ -385,6 +452,9 @@ public:
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get chunk at given index
|
||||||
|
/// @note All chunks (and their items) with index < `num` must be valid, otherwise this function has undefined behaviour (use `isValid` to check if chunk is valid)
|
||||||
|
/// @param num Index of chunk to return
|
||||||
inline RTCP_SDES_CHUNK *getChunk(int num) {
|
inline RTCP_SDES_CHUNK *getChunk(int num) {
|
||||||
auto base = &_chunks;
|
auto base = &_chunks;
|
||||||
while (num-- > 0) {
|
while (num-- > 0) {
|
||||||
|
@ -694,6 +694,10 @@ void PeerConnection::forwardMedia(message_ptr message) {
|
|||||||
ssrcs.insert(rtcpsr->getReportBlock(i)->getSSRC());
|
ssrcs.insert(rtcpsr->getReportBlock(i)->getSSRC());
|
||||||
} else if (header->payloadType() == 202) {
|
} else if (header->payloadType() == 202) {
|
||||||
auto sdes = reinterpret_cast<RTCP_SDES *>(header);
|
auto sdes = reinterpret_cast<RTCP_SDES *>(header);
|
||||||
|
if (!sdes->isValid()) {
|
||||||
|
PLOG_WARNING << "RTCP SDES packet is invalid";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (unsigned int i = 0; i < sdes->chunksCount(); i++) {
|
for (unsigned int i = 0; i < sdes->chunksCount(); i++) {
|
||||||
auto chunk = sdes->getChunk(i);
|
auto chunk = sdes->getChunk(i);
|
||||||
ssrcs.insert(chunk->ssrc());
|
ssrcs.insert(chunk->ssrc());
|
||||||
|
Reference in New Issue
Block a user