Skip to content

Commit a6397ff

Browse files
committedMay 10, 2022
Add limit to fragmentBuffer
Before we imposed no limit on the amount of data we would buffer during the handshake. This changes adds a 2 megabyte. When the limit is exceeded the Conn returns an error.
1 parent e0b2ce3 commit a6397ff

File tree

3 files changed

+36
-1
lines changed

3 files changed

+36
-1
lines changed
 

‎errors.go

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ var (
6262
errSequenceNumberOverflow = &InternalError{Err: errors.New("sequence number overflow")} //nolint:goerr113
6363
errInvalidFSMTransition = &InternalError{Err: errors.New("invalid state machine transition")} //nolint:goerr113
6464
errFailedToAccessPoolReadBuffer = &InternalError{Err: errors.New("failed to access pool read buffer")} //nolint:goerr113
65+
errFragmentBufferOverflow = &InternalError{Err: errors.New("fragment buffer overflow")} //nolint:goerr113
6566
)
6667

6768
// FatalError indicates that the DTLS connection is no longer available.

‎fragment_buffer.go

+18
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import (
66
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
77
)
88

9+
// 2 megabytes
10+
const fragmentBufferMaxSize = 2000000
11+
912
type fragment struct {
1013
recordLayerHeader recordlayer.Header
1114
handshakeHeader handshake.Header
@@ -23,10 +26,25 @@ func newFragmentBuffer() *fragmentBuffer {
2326
return &fragmentBuffer{cache: map[uint16][]*fragment{}}
2427
}
2528

29+
// current total size of buffer
30+
func (f *fragmentBuffer) size() int {
31+
size := 0
32+
for i := range f.cache {
33+
for j := range f.cache[i] {
34+
size += len(f.cache[i][j].data)
35+
}
36+
}
37+
return size
38+
}
39+
2640
// Attempts to push a DTLS packet to the fragmentBuffer
2741
// when it returns true it means the fragmentBuffer has inserted and the buffer shouldn't be handled
2842
// when an error returns it is fatal, and the DTLS connection should be stopped
2943
func (f *fragmentBuffer) push(buf []byte) (bool, error) {
44+
if f.size()+len(buf) >= fragmentBufferMaxSize {
45+
return false, errFragmentBufferOverflow
46+
}
47+
3048
frag := new(fragment)
3149
if err := frag.recordLayerHeader.Unmarshal(buf); err != nil {
3250
return false, err

‎fragment_buffer_test.go

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dtls
22

33
import (
4+
"errors"
45
"reflect"
56
"testing"
67
)
@@ -57,7 +58,7 @@ func TestFragmentBuffer(t *testing.T) {
5758
Epoch: 0,
5859
},
5960
{
60-
Name: "Multiple Handshakes in Signle Fragment",
61+
Name: "Multiple Handshakes in Single Fragment",
6162
In: [][]byte{
6263
{
6364
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x30, /* record header */
@@ -113,3 +114,18 @@ func TestFragmentBuffer(t *testing.T) {
113114
}
114115
}
115116
}
117+
118+
func TestFragmentBuffer_Overflow(t *testing.T) {
119+
fragmentBuffer := newFragmentBuffer()
120+
121+
// Push a buffer that doesn't exceed size limits
122+
if _, err := fragmentBuffer.push([]byte{0x16, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff, 0x00}); err != nil {
123+
t.Fatal(err)
124+
}
125+
126+
// Allocate a buffer that exceeds cache size
127+
largeBuffer := make([]byte, fragmentBufferMaxSize)
128+
if _, err := fragmentBuffer.push(largeBuffer); !errors.Is(err, errFragmentBufferOverflow) {
129+
t.Fatalf("Pushing a large buffer returned (%s) expected(%s)", err, errFragmentBufferOverflow)
130+
}
131+
}

0 commit comments

Comments
 (0)
Please sign in to comment.