Skip to content

Commit ece8be3

Browse files
committed
Few fixes for Header.Unmarshal
- Skip one-byte padding with non-zero length as specified in RFC; - Return proper header length when one-byte extension with ID=15 or one-byte padding with non-zero length was found; - fixed check for end of extended header payloads;
1 parent f6b0da1 commit ece8be3

File tree

2 files changed

+113
-17
lines changed

2 files changed

+113
-17
lines changed

packet.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ const (
7272
extensionShift = 4
7373
extensionMask = 0x1
7474
extensionIDReserved = 0xF
75+
extensionIDPadding = 0x0
7576
ccMask = 0xF
7677
markerShift = 7
7778
markerMask = 0x1
@@ -138,6 +139,7 @@ func (h *Header) Unmarshal(buf []byte) (n int, err error) { //nolint:gocognit,cy
138139
return n, fmt.Errorf("size %d < %d: %w", len(buf), n,
139140
errHeaderSizeInsufficient)
140141
}
142+
headerLength := n
141143

142144
h.Marker = (buf[1] >> markerShift & markerMask) > 0
143145
h.PayloadType = buf[1] & ptMask
@@ -168,6 +170,7 @@ func (h *Header) Unmarshal(buf []byte) (n int, err error) { //nolint:gocognit,cy
168170
extensionLength := int(binary.BigEndian.Uint16(buf[n:])) * 4
169171
n += 2
170172
extensionEnd := n + extensionLength
173+
headerLength = extensionEnd
171174

172175
if len(buf) < extensionEnd {
173176
return n, fmt.Errorf("size %d < %d: %w", len(buf), extensionEnd, errHeaderSizeInsufficientForExtension)
@@ -180,7 +183,7 @@ func (h *Header) Unmarshal(buf []byte) (n int, err error) { //nolint:gocognit,cy
180183
)
181184

182185
for n < extensionEnd {
183-
if buf[n] == 0x00 { // padding
186+
if buf[n] == extensionIDPadding { // padding
184187
n++
185188

186189
continue
@@ -191,23 +194,24 @@ func (h *Header) Unmarshal(buf []byte) (n int, err error) { //nolint:gocognit,cy
191194
payloadLen = int(buf[n]&^0xF0 + 1)
192195
n++
193196

194-
if extid == extensionIDReserved {
197+
// Stop parsing extensions if we reach the reserved ID or padding with non-zero length
198+
if extid == extensionIDReserved || extid == extensionIDPadding {
195199
break
196200
}
197201
} else {
198202
extid = buf[n]
199203
n++
200204

201-
if len(buf) <= n {
202-
return n, fmt.Errorf("size %d < %d: %w", len(buf), n, errHeaderSizeInsufficientForExtension)
205+
if extensionEnd <= n {
206+
return n, fmt.Errorf("size %d < %d: %w", extensionEnd, n, errHeaderSizeInsufficientForExtension)
203207
}
204208

205209
payloadLen = int(buf[n])
206210
n++
207211
}
208212

209-
if extensionPayloadEnd := n + payloadLen; len(buf) < extensionPayloadEnd {
210-
return n, fmt.Errorf("size %d < %d: %w", len(buf), extensionPayloadEnd, errHeaderSizeInsufficientForExtension)
213+
if extensionPayloadEnd := n + payloadLen; extensionEnd < extensionPayloadEnd {
214+
return n, fmt.Errorf("size %d < %d: %w", extensionEnd, extensionPayloadEnd, errHeaderSizeInsufficientForExtension)
211215
}
212216

213217
extension := Extension{id: extid, payload: buf[n : n+payloadLen]}
@@ -218,11 +222,10 @@ func (h *Header) Unmarshal(buf []byte) (n int, err error) { //nolint:gocognit,cy
218222
// RFC3550 Extension
219223
extension := Extension{id: 0, payload: buf[n:extensionEnd]}
220224
h.Extensions = append(h.Extensions, extension)
221-
n += len(h.Extensions[0].payload)
222225
}
223226
}
224227

225-
return n, nil
228+
return headerLength, nil
226229
}
227230

228231
// Unmarshal parses the passed byte slice and stores the result in the Packet.

packet_test.go

Lines changed: 102 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,29 @@ func TestRFC8285TwoByteMultipleExtensionsWithPadding(t *testing.T) {
573573
ext3 := packet.GetExtension(3)
574574
ext3Expect := []byte{0xCC, 0xCC, 0xCC, 0xCC}
575575
assert.Equal(t, ext3Expect, ext3, "Extension has incorrect data")
576+
577+
rawPktReMarshal := []byte{
578+
0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64,
579+
0x27, 0x82, 0x10, 0x00, 0x00, 0x03, 0x01, 0x00, 0x02, 0x01,
580+
0xBB, 0x03, 0x04, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, // padding is moved to the end by re-marshaling
581+
// Payload
582+
0x98, 0x36, 0xbe, 0x88, 0x9e,
583+
}
584+
dstBuf := map[string][]byte{
585+
"CleanBuffer": make([]byte, 1000),
586+
"DirtyBuffer": make([]byte, 1000),
587+
}
588+
for i := range dstBuf["DirtyBuffer"] {
589+
dstBuf["DirtyBuffer"][i] = 0xFF
590+
}
591+
for name, buf := range dstBuf {
592+
buf := buf
593+
t.Run(name, func(t *testing.T) {
594+
n, err := packet.MarshalTo(buf)
595+
assert.NoError(t, err)
596+
assert.Equal(t, rawPktReMarshal, buf[:n])
597+
})
598+
}
576599
}
577600

578601
func TestRFC8285TwoByteMultipleExtensionsWithLargeExtension(t *testing.T) {
@@ -884,7 +907,7 @@ func TestRFC8285OneByteSetExtensionShouldErrorWhenInvalidIDProvided(t *testing.T
884907
)
885908
}
886909

887-
func TestRFC8285OneByteExtensionTermianteProcessingWhenReservedIDEncountered(t *testing.T) {
910+
func TestRFC8285OneByteExtensionTerminateProcessingWhenReservedIDEncountered(t *testing.T) {
888911
packet := &Packet{}
889912

890913
reservedIDPkt := []byte{
@@ -897,7 +920,24 @@ func TestRFC8285OneByteExtensionTermianteProcessingWhenReservedIDEncountered(t *
897920
)
898921
assert.Len(t, packet.Extensions, 0, "Extensions should be empty for invalid id")
899922

900-
payload := reservedIDPkt[17:]
923+
payload := reservedIDPkt[20:]
924+
assert.Equal(t, payload, packet.Payload)
925+
}
926+
927+
func TestRFC8285OneByteExtensionTerminateProcessingWhenPaddingWithSizeEncountered(t *testing.T) {
928+
packet := &Packet{}
929+
930+
reservedIDPkt := []byte{
931+
0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64,
932+
0x27, 0x82, 0xBE, 0xDE, 0x00, 0x01, 0x01, 0xAA, 0x98, 0x36, 0xbe, 0x88, 0x9e,
933+
}
934+
assert.NoError(
935+
t, packet.Unmarshal(reservedIDPkt),
936+
"Unmarshal error on packet with non-zero padding size",
937+
)
938+
assert.Len(t, packet.Extensions, 0, "Extensions should be empty for non-zero padding size")
939+
940+
payload := reservedIDPkt[20:]
901941
assert.Equal(t, payload, packet.Payload)
902942
}
903943

@@ -1059,26 +1099,26 @@ func TestRFC8285TwoByteSetExtensionShouldErrorWhenPayloadTooLarge(t *testing.T)
10591099
func TestRFC8285Padding(t *testing.T) {
10601100
header := &Header{}
10611101

1062-
for _, payload := range [][]byte{
1102+
for n, payload := range [][]byte{
10631103
{
10641104
0b00010000, // header.Extension = true
10651105
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // SequenceNumber, Timestamp, SSRC
10661106
0xBE, 0xDE, // header.ExtensionProfile = extensionProfileOneByte
10671107
0, 1, // extensionLength
10681108
0, 0, 0, // padding
1069-
1, // extid
1109+
0x10, // extid and length
10701110
},
10711111
{
10721112
0b00010000, // header.Extension = true
10731113
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // SequenceNumber, Timestamp, SSRC
1074-
0x10, 0x00, // header.ExtensionProfile = extensionProfileOneByte
1114+
0x10, 0x00, // header.ExtensionProfile = extensionProfileTwoByte
10751115
0, 1, // extensionLength
1076-
0, 0, 0, // padding
1077-
1, // extid
1116+
0, 0, // padding
1117+
0x01, 0x01, // extid and length
10781118
},
10791119
} {
10801120
_, err := header.Unmarshal(payload)
1081-
assert.ErrorIs(t, err, errHeaderSizeInsufficientForExtension)
1121+
assert.ErrorIs(t, err, errHeaderSizeInsufficientForExtension, "case %d", n)
10821122
}
10831123
}
10841124

@@ -1198,7 +1238,7 @@ func TestUnmarshal_ErrorHandling(t *testing.T) {
11981238
}
11991239

12001240
// https://github.com/pion/rtp/issues/275
1201-
func TestUnmarshal_ExtensionWithoutRTPPayload(t *testing.T) {
1241+
func TestUnmarshal_OneByteExtensionWithoutRTPPayload(t *testing.T) {
12021242
rawPkt := []byte{
12031243
0x10, 0x64, 0x57, 0x49, 0x00, 0x00, 0x01, 0x90, 0x12, 0x34, 0xAB, 0xCD,
12041244
0xBE, 0xDE, 0x00, 0x01, // One-Byte extension header, 4 bytes
@@ -1210,6 +1250,59 @@ func TestUnmarshal_ExtensionWithoutRTPPayload(t *testing.T) {
12101250
assert.NoError(t, p.Unmarshal(rawPkt))
12111251
}
12121252

1253+
func TestUnmarshal_TwoByteExtensionWithoutRTPPayload(t *testing.T) {
1254+
rawPkt := []byte{
1255+
0x10, 0x64, 0x57, 0x49, 0x00, 0x00, 0x01, 0x90, 0x12, 0x34, 0xAB, 0xCD,
1256+
0x10, 0x00, 0x00, 0x01, // Two-Byte extension header, 4 bytes
1257+
0x02, 0x02, // ID=0, Len=2 (2 bytes data)
1258+
0x02, 0x03, // Extension data
1259+
}
1260+
1261+
p := &Packet{}
1262+
assert.NoError(t, p.Unmarshal(rawPkt))
1263+
}
1264+
1265+
func TestUnmarshal_NonStandardExtensionWithoutRTPPayload(t *testing.T) {
1266+
rawPkt := []byte{
1267+
0x10, 0x64, 0x57, 0x49, 0x00, 0x00, 0x01, 0x90, 0x12, 0x34, 0xAB, 0xCD,
1268+
0xAA, 0xAA, 0x00, 0x01, // Non-standard header extension 0xAAAA, 4 bytes
1269+
0x01, 0x02, 0x03, 0x04, // Extension data
1270+
}
1271+
1272+
p := &Packet{}
1273+
assert.NoError(t, p.Unmarshal(rawPkt))
1274+
}
1275+
1276+
func TestUnmarshal_EmptyOneByteExtensionWithoutRTPPayload(t *testing.T) {
1277+
rawPkt := []byte{
1278+
0x10, 0x64, 0x57, 0x49, 0x00, 0x00, 0x01, 0x90, 0x12, 0x34, 0xAB, 0xCD,
1279+
0xBE, 0xDE, 0x00, 0x00, // One-Byte extension header, 0 bytes
1280+
}
1281+
1282+
p := &Packet{}
1283+
assert.NoError(t, p.Unmarshal(rawPkt))
1284+
}
1285+
1286+
func TestUnmarshal_EmptyTwoByteExtensionWithoutRTPPayload(t *testing.T) {
1287+
rawPkt := []byte{
1288+
0x10, 0x64, 0x57, 0x49, 0x00, 0x00, 0x01, 0x90, 0x12, 0x34, 0xAB, 0xCD,
1289+
0x10, 0x00, 0x00, 0x00, // Two-Byte extension header, 0 bytes
1290+
}
1291+
1292+
p := &Packet{}
1293+
assert.NoError(t, p.Unmarshal(rawPkt))
1294+
}
1295+
1296+
func TestUnmarshal_EmptyNonStandardExtensionWithoutRTPPayload(t *testing.T) {
1297+
rawPkt := []byte{
1298+
0x10, 0x64, 0x57, 0x49, 0x00, 0x00, 0x01, 0x90, 0x12, 0x34, 0xAB, 0xCD,
1299+
0xAA, 0xAA, 0x00, 0x00, // Non-standard header extension 0xAAAA, 0 bytes
1300+
}
1301+
1302+
p := &Packet{}
1303+
assert.NoError(t, p.Unmarshal(rawPkt))
1304+
}
1305+
12131306
func TestRoundtrip(t *testing.T) {
12141307
rawPkt := []byte{
12151308
0x00, 0x10, 0x23, 0x45, 0x12, 0x34, 0x45, 0x67, 0xCC, 0xDD, 0xEE, 0xFF,

0 commit comments

Comments
 (0)