Skip to content

Commit

Permalink
Merge pull request #135 from negbie/master
Browse files Browse the repository at this point in the history
Guard against malformed second ReportBlocks
  • Loading branch information
negbie authored Oct 22, 2019
2 parents 7ce167a + 878b781 commit d47b027
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 30 deletions.
57 changes: 29 additions & 28 deletions protos/rtcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,19 +192,20 @@ func (rp *RTCP_Packet) MarshalJSON() ([]byte, error) {
var enc = jingo.NewStructEncoder(RTCP_Packet{})

func ParseRTCP(data []byte) ([]byte, []byte, string) {
curLen := len(data)
dataLen := len(data)
if dataLen < 28 {
return nil, nil, fmt.Sprintf("Fishy RTCP dataLen=%d in packet:\n% X", dataLen, data)
if curLen < 28 {
return nil, nil, fmt.Sprintf("Fishy RTCP curLen=%d in packet:\n% X", curLen, data)
}

var ssrcBytes []byte
var infoMsg string
pkt := &RTCP_Packet{}
offset := 0

for dataLen > 0 {
if dataLen < 4 || dataLen > 768 || offset > len(data)-4 {
infoMsg = fmt.Sprintf("Fishy RTCP dataLen=%d, offset=%d in packet:\n% X", dataLen, offset, data)
for curLen > 0 {
if curLen < 4 || curLen > 768 || offset > dataLen-4 {
infoMsg = fmt.Sprintf("Fishy RTCP curLen=%d, offset=%d in packet:\n% X", curLen, offset, data)
break
}

Expand All @@ -215,9 +216,9 @@ func ParseRTCP(data []byte) ([]byte, []byte, string) {
RTCPLength := int(binary.BigEndian.Uint16(data[offset+2:]) * 4)
offset += 4

if RTCPVersion != 2 || RTCPPadding > 1 || RTCPReportCount < 0 || RTCPReportCount > 4 || RTCPType < 200 || RTCPType > 207 || RTCPLength > dataLen {
infoMsg = fmt.Sprintf("Fishy RTCP_Header RTCPVersion=%d, RTCPPadding=%d, RTCPReportCount=%d, RTCPType=%d, RTCPLength=%d, packetLen=%d, dataLen=%d, offset=%d in packet:\n% X",
RTCPVersion, RTCPPadding, RTCPReportCount, RTCPType, RTCPLength, len(data), dataLen, offset, data)
if RTCPVersion != 2 || RTCPPadding > 1 || RTCPReportCount < 0 || RTCPReportCount > 4 || RTCPType < 200 || RTCPType > 207 || RTCPLength > curLen {
infoMsg = fmt.Sprintf("Fishy RTCP_Header RTCPVersion=%d, RTCPPadding=%d, RTCPReportCount=%d, RTCPType=%d, RTCPLength=%d, dataLen=%d, curLen=%d, offset=%d in packet:\n% X",
RTCPVersion, RTCPPadding, RTCPReportCount, RTCPType, RTCPLength, dataLen, curLen, offset, data)
break
}

Expand All @@ -226,9 +227,9 @@ func ParseRTCP(data []byte) ([]byte, []byte, string) {

switch RTCPType {
case TYPE_RTCP_SR:
if RTCPLength < 24 || offset+24 > len(data) {
infoMsg = fmt.Sprintf("Fishy RTCP_SR RTCPVersion=%d, RTCPReportCount=%d, RTCPType=%d, RTCPLength=%d, dataLen=%d, offset=%d in packet:\n% X",
RTCPVersion, RTCPReportCount, RTCPType, RTCPLength, dataLen, offset, data)
if RTCPLength < 24 || offset+24 > dataLen {
infoMsg = fmt.Sprintf("Fishy RTCP_SR RTCPVersion=%d, RTCPReportCount=%d, RTCPType=%d, RTCPLength=%d, curLen=%d, offset=%d in packet:\n% X",
RTCPVersion, RTCPReportCount, RTCPType, RTCPLength, curLen, offset, data)
break
}

Expand All @@ -242,9 +243,9 @@ func ParseRTCP(data []byte) ([]byte, []byte, string) {
pkt.SenderInformation.Octet_count = binary.BigEndian.Uint32(data[offset+20:])
offset += 24

if RTCPReportCount > 0 && RTCPLength >= 24 && offset+24 <= len(data) {
tmpReportBlocks := make([]RTCP_report_block, RTCPReportCount)
for i := 0; i < RTCPReportCount; i++ {
tmpReportBlocks := make([]RTCP_report_block, RTCPReportCount)
for i := 0; i < RTCPReportCount; i++ {
if RTCPReportCount > 0 && RTCPLength >= 24 && offset+24 <= dataLen && len(data[offset:]) >= 4 {
tmpReportBlocks[i].SourceSsrc = binary.BigEndian.Uint32(data[offset:])
tmpReportBlocks[i].Fraction_lost = data[offset+4]
var cumBuf [4]byte
Expand All @@ -261,19 +262,19 @@ func ParseRTCP(data []byte) ([]byte, []byte, string) {
}

case TYPE_RTCP_RR:
if RTCPLength < 4 || offset+4 > len(data) {
infoMsg = fmt.Sprintf("Fishy RTCP_RR RTCPVersion=%d, RTCPReportCount=%d, RTCPType=%d, RTCPLength=%d, dataLen=%d, offset=%d in packet:\n% X",
RTCPVersion, RTCPReportCount, RTCPType, RTCPLength, dataLen, offset, data)
if RTCPLength < 4 || offset+4 > dataLen {
infoMsg = fmt.Sprintf("Fishy RTCP_RR RTCPVersion=%d, RTCPReportCount=%d, RTCPType=%d, RTCPLength=%d, curLen=%d, offset=%d in packet:\n% X",
RTCPVersion, RTCPReportCount, RTCPType, RTCPLength, curLen, offset, data)
break
}

ssrcBytes = data[offset : offset+4]
pkt.Ssrc = binary.BigEndian.Uint32(data[offset:])
offset += 4

if RTCPReportCount > 0 && RTCPLength >= 24 && offset+24 <= len(data) {
tmpReportBlocks := make([]RTCP_report_block, RTCPReportCount)
for i := 0; i < RTCPReportCount; i++ {
tmpReportBlocks := make([]RTCP_report_block, RTCPReportCount)
for i := 0; i < RTCPReportCount; i++ {
if RTCPReportCount > 0 && RTCPLength >= 24 && offset+24 <= dataLen && len(data[offset:]) >= 4 {
tmpReportBlocks[i].SourceSsrc = binary.BigEndian.Uint32(data[offset:])
tmpReportBlocks[i].Fraction_lost = data[offset+4]
var cumBuf [4]byte
Expand All @@ -290,9 +291,9 @@ func ParseRTCP(data []byte) ([]byte, []byte, string) {
}

case TYPE_RTCP_SDES:
if RTCPLength < 4 || offset+4 > len(data) {
infoMsg = fmt.Sprintf("Fishy RTCP_SDES RTCPVersion=%d, RTCPReportCount=%d, RTCPType=%d, RTCPLength=%d, dataLen=%d, offset=%d in packet:\n% X",
RTCPVersion, RTCPReportCount, RTCPType, RTCPLength, dataLen, offset, data)
if RTCPLength < 4 || offset+4 > dataLen {
infoMsg = fmt.Sprintf("Fishy RTCP_SDES RTCPVersion=%d, RTCPReportCount=%d, RTCPType=%d, RTCPLength=%d, curLen=%d, offset=%d in packet:\n% X",
RTCPVersion, RTCPReportCount, RTCPType, RTCPLength, curLen, offset, data)
break
}

Expand All @@ -307,17 +308,17 @@ func ParseRTCP(data []byte) ([]byte, []byte, string) {
infoMsg = fmt.Sprintf("Discard RTCP_BYE packet type=%d", RTCPType)
offset += RTCPLength
case TYPE_RTCP_XR:
if RTCPLength < 8 || offset+8 > len(data) {
infoMsg = fmt.Sprintf("Fishy RTCP_XR RTCPVersion=%d, RTCPReportCount=%d, RTCPType=%d, RTCPLength=%d, dataLen=%d, offset=%d in packet:\n% X",
RTCPVersion, RTCPReportCount, RTCPType, RTCPLength, dataLen, offset, data)
if RTCPLength < 8 || offset+8 > dataLen {
infoMsg = fmt.Sprintf("Fishy RTCP_XR RTCPVersion=%d, RTCPReportCount=%d, RTCPType=%d, RTCPLength=%d, curLen=%d, offset=%d in packet:\n% X",
RTCPVersion, RTCPReportCount, RTCPType, RTCPLength, curLen, offset, data)
break
}

ssrcBytes = data[offset : offset+4]
pkt.Ssrc = binary.BigEndian.Uint32(data[offset:])
pkt.ReportBlocksXr.Type = data[offset+4]

if pkt.ReportBlocksXr.Type == 7 && RTCPLength >= 24 && offset+24 <= len(data) {
if pkt.ReportBlocksXr.Type == 7 && RTCPLength >= 24 && offset+24 <= dataLen {
pkt.ReportBlocksXr.ID = binary.BigEndian.Uint32(data[offset+8:])
pkt.ReportBlocksXr.Fraction_lost = data[offset+12]
pkt.ReportBlocksXr.Fraction_discard = data[offset+13]
Expand All @@ -330,7 +331,7 @@ func ParseRTCP(data []byte) ([]byte, []byte, string) {
}
offset += RTCPLength
}
dataLen -= RTCPLength + 4
curLen -= RTCPLength + 4
}

b := jingo.NewBufferFromPool()
Expand Down
76 changes: 74 additions & 2 deletions protos/rtcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,84 @@ package protos

import (
"testing"

"github.com/stretchr/testify/assert"
)

var rtcpPacket = []byte{0x81, 0xc8, 0x0, 0xc, 0x58, 0xf3, 0x3d, 0xea, 0x0, 0x2, 0x4f, 0xfb, 0x82, 0x8f, 0x5b, 0x92, 0x11, 0x4a, 0xc, 0x42, 0x0, 0x0, 0x2, 0xed, 0x0, 0x1, 0xca, 0xcf, 0xd2, 0xbd, 0x4e, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x1, 0x0, 0x0, 0x0, 0x14, 0x86, 0xe9, 0xf, 0x9d, 0x0, 0x3, 0x44, 0xdd, 0x81, 0xca, 0x0, 0x8, 0x58, 0xf3, 0x3d, 0xea, 0x1, 0x16, 0x41, 0x43, 0x4c, 0x54, 0x50, 0x20, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x33, 0x30, 0x0, 0x0, 0x0, 0x0}
var testPacket = []byte{
// Receiver Report (offset=0)
// v=2, p=0, count=1, RR, len=7
0x81, 0xc9, 0x0, 0x7,
// ssrc=0x902f9e2e
0x90, 0x2f, 0x9e, 0x2e,
// ssrc=0xbc5e9a40
0xbc, 0x5e, 0x9a, 0x40,
// fracLost=0, totalLost=0
0x0, 0x0, 0x0, 0x0,
// lastSeq=0x46e1
0x0, 0x0, 0x46, 0xe1,
// jitter=273
0x0, 0x0, 0x1, 0x11,
// lsr=0x9f36432
0x9, 0xf3, 0x64, 0x32,
// delay=150137
0x0, 0x2, 0x4a, 0x79,

// Source Description (offset=32)
// v=2, p=0, count=1, SDES, len=12
0x81, 0xca, 0x0, 0xc,
// ssrc=0x902f9e2e
0x90, 0x2f, 0x9e, 0x2e,
// CNAME, len=38
0x1, 0x26,
// text="{9c00eb92-1afb-9d49-a47d-91f64eee69f5}"
0x7b, 0x39, 0x63, 0x30,
0x30, 0x65, 0x62, 0x39,
0x32, 0x2d, 0x31, 0x61,
0x66, 0x62, 0x2d, 0x39,
0x64, 0x34, 0x39, 0x2d,
0x61, 0x34, 0x37, 0x64,
0x2d, 0x39, 0x31, 0x66,
0x36, 0x34, 0x65, 0x65,
0x65, 0x36, 0x39, 0x66,
0x35, 0x7d,
// END + padding
0x0, 0x0, 0x0, 0x0,

// Goodbye (offset=84)
// v=2, p=0, count=1, BYE, len=1
0x81, 0xcb, 0x0, 0x1,
// source=0x902f9e2e
0x90, 0x2f, 0x9e, 0x2e,

// Picture Loss Indication (offset=92)
0x81, 0xce, 0x0, 0x2,
// sender=0x902f9e2e
0x90, 0x2f, 0x9e, 0x2e,
// media=0x902f9e2e
0x90, 0x2f, 0x9e, 0x2e,

// RapidResynchronizationRequest (offset=104)
0x85, 0xcd, 0x0, 0x2,
// sender=0x902f9e2e
0x90, 0x2f, 0x9e, 0x2e,
// media=0x902f9e2e
0x90, 0x2f, 0x9e, 0x2e,
}

func TestUnmarshal(t *testing.T) {
_, packet, _ := ParseRTCP(testPacket)
expected := `{"sender_information":{"ntp_timestamp_sec":0,"ntp_timestamp_usec":0,"rtp_timestamp":0,"packets":0,"octets":0},"ssrc":2419039790,"type":206,"report_count":1,"report_blocks":[{"source_ssrc":3160316480,"fraction_lost":0,"packets_lost":0,"highest_seq_no":18145,"ia_jitter":273,"lsr":166945842,"dlsr":150137}],"report_blocks_xr":{"type":0,"id":0,"fraction_lost":0,"fraction_discard":0,"burst_density":0,"gap_density":0,"burst_duration":0,"gap_duration":0,"round_trip_delay":0,"end_system_delay":0},"sdes_ssrc":2419039790}`
assert.Equal(t, expected, string(packet))
_, packet, _ = ParseRTCP(benchPacket)
expected = `{"sender_information":{"ntp_timestamp_sec":151547,"ntp_timestamp_usec":2190433170,"rtp_timestamp":290065474,"packets":749,"octets":117455},"ssrc":1492336106,"type":202,"report_count":1,"report_blocks":[{"source_ssrc":3535621694,"fraction_lost":0,"packets_lost":0,"highest_seq_no":513,"ia_jitter":20,"lsr":2263420829,"dlsr":214237}],"report_blocks_xr":{"type":0,"id":0,"fraction_lost":0,"fraction_discard":0,"burst_density":0,"gap_density":0,"burst_duration":0,"gap_duration":0,"round_trip_delay":0,"end_system_delay":0},"sdes_ssrc":1492336106}`
assert.Equal(t, expected, string(packet))
}

var benchPacket = []byte{0x81, 0xc8, 0x0, 0xc, 0x58, 0xf3, 0x3d, 0xea, 0x0, 0x2, 0x4f, 0xfb, 0x82, 0x8f, 0x5b, 0x92, 0x11, 0x4a, 0xc, 0x42, 0x0, 0x0, 0x2, 0xed, 0x0, 0x1, 0xca, 0xcf, 0xd2, 0xbd, 0x4e, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x1, 0x0, 0x0, 0x0, 0x14, 0x86, 0xe9, 0xf, 0x9d, 0x0, 0x3, 0x44, 0xdd, 0x81, 0xca, 0x0, 0x8, 0x58, 0xf3, 0x3d, 0xea, 0x1, 0x16, 0x41, 0x43, 0x4c, 0x54, 0x50, 0x20, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x20, 0x33, 0x30, 0x0, 0x0, 0x0, 0x0}

func BenchmarkParseRTCP(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseRTCP(rtcpPacket)
ParseRTCP(benchPacket)
}
}

0 comments on commit d47b027

Please sign in to comment.