Check incoming RTCP SDES

This commit is contained in:
Filip Klembara
2021-01-05 09:58:00 +01:00
parent 01085e4492
commit c43e82b8cb
2 changed files with 74 additions and 0 deletions

View File

@ -326,6 +326,9 @@ public:
inline SSRC ssrc() const { return ntohl(_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) {
auto base = &_items;
while (num-- > 0) {
@ -335,6 +338,39 @@ public:
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) {
unsigned int itemsSize = 0;
for (auto length: textLengths) {
@ -345,6 +381,8 @@ public:
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() {
std::vector<uint8_t> textLengths{};
unsigned int i = 0;
@ -374,8 +412,37 @@ public:
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() {
if (!isValid()) {
return 0;
}
uint16_t chunksSize = 4 * (header.length() + 1) - sizeof(header);
unsigned int size = 0;
unsigned int i = 0;
@ -385,6 +452,9 @@ public:
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) {
auto base = &_chunks;
while (num-- > 0) {