mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-03 20:27:35 +03:00
http3: reject duplicate control streams opened by the client (#4344)
This commit is contained in:
parent
c5f7096f00
commit
d41c0b68cd
2 changed files with 38 additions and 1 deletions
|
@ -12,6 +12,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/quic-go/quic-go"
|
"github.com/quic-go/quic-go"
|
||||||
|
@ -498,6 +499,8 @@ func (s *Server) handleConn(conn quic.Connection) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleUnidirectionalStreams(conn quic.Connection) {
|
func (s *Server) handleUnidirectionalStreams(conn quic.Connection) {
|
||||||
|
var rcvdControlStream atomic.Bool
|
||||||
|
|
||||||
for {
|
for {
|
||||||
str, err := conn.AcceptUniStream(context.Background())
|
str, err := conn.AcceptUniStream(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -531,6 +534,11 @@ func (s *Server) handleUnidirectionalStreams(conn quic.Connection) {
|
||||||
str.CancelRead(quic.StreamErrorCode(ErrCodeStreamCreationError))
|
str.CancelRead(quic.StreamErrorCode(ErrCodeStreamCreationError))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Only a single control stream is allowed.
|
||||||
|
if isFirstControlStr := rcvdControlStream.CompareAndSwap(false, true); !isFirstControlStr {
|
||||||
|
conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "duplicate control stream")
|
||||||
|
return
|
||||||
|
}
|
||||||
f, err := parseNextFrame(str, nil)
|
f, err := parseNextFrame(str, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameError), "")
|
conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameError), "")
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/quic-go/quic-go"
|
"github.com/quic-go/quic-go"
|
||||||
mockquic "github.com/quic-go/quic-go/internal/mocks/quic"
|
mockquic "github.com/quic-go/quic-go/internal/mocks/quic"
|
||||||
"github.com/quic-go/quic-go/internal/protocol"
|
"github.com/quic-go/quic-go/internal/protocol"
|
||||||
|
"github.com/quic-go/quic-go/internal/qerr"
|
||||||
"github.com/quic-go/quic-go/internal/testdata"
|
"github.com/quic-go/quic-go/internal/testdata"
|
||||||
"github.com/quic-go/quic-go/internal/utils"
|
"github.com/quic-go/quic-go/internal/utils"
|
||||||
"github.com/quic-go/quic-go/quicvarint"
|
"github.com/quic-go/quic-go/quicvarint"
|
||||||
|
@ -497,7 +498,7 @@ var _ = Describe("Server", func() {
|
||||||
|
|
||||||
Context("control stream handling", func() {
|
Context("control stream handling", func() {
|
||||||
var conn *mockquic.MockEarlyConnection
|
var conn *mockquic.MockEarlyConnection
|
||||||
testDone := make(chan struct{})
|
testDone := make(chan struct{}, 1)
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
conn = mockquic.NewMockEarlyConnection(mockCtrl)
|
conn = mockquic.NewMockEarlyConnection(mockCtrl)
|
||||||
|
@ -528,6 +529,34 @@ var _ = Describe("Server", func() {
|
||||||
time.Sleep(scaleDuration(20 * time.Millisecond)) // don't EXPECT any calls to conn.CloseWithError
|
time.Sleep(scaleDuration(20 * time.Millisecond)) // don't EXPECT any calls to conn.CloseWithError
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("rejects duplicate control streams", func() {
|
||||||
|
b := quicvarint.Append(nil, streamTypeControlStream)
|
||||||
|
b = (&settingsFrame{}).Append(b)
|
||||||
|
r1 := bytes.NewReader(b)
|
||||||
|
controlStr1 := mockquic.NewMockStream(mockCtrl)
|
||||||
|
controlStr1.EXPECT().Read(gomock.Any()).DoAndReturn(r1.Read).AnyTimes()
|
||||||
|
r2 := bytes.NewReader(b)
|
||||||
|
controlStr2 := mockquic.NewMockStream(mockCtrl)
|
||||||
|
controlStr2.EXPECT().Read(gomock.Any()).DoAndReturn(r2.Read).AnyTimes()
|
||||||
|
done := make(chan struct{})
|
||||||
|
conn.EXPECT().CloseWithError(qerr.ApplicationErrorCode(ErrCodeStreamCreationError), "duplicate control stream").Do(func(qerr.ApplicationErrorCode, string) error {
|
||||||
|
close(done)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
conn.EXPECT().AcceptUniStream(gomock.Any()).DoAndReturn(func(context.Context) (quic.ReceiveStream, error) {
|
||||||
|
return controlStr1, nil
|
||||||
|
})
|
||||||
|
conn.EXPECT().AcceptUniStream(gomock.Any()).DoAndReturn(func(context.Context) (quic.ReceiveStream, error) {
|
||||||
|
return controlStr2, nil
|
||||||
|
})
|
||||||
|
conn.EXPECT().AcceptUniStream(gomock.Any()).DoAndReturn(func(context.Context) (quic.ReceiveStream, error) {
|
||||||
|
<-done
|
||||||
|
return nil, errors.New("test done")
|
||||||
|
})
|
||||||
|
s.handleConn(conn)
|
||||||
|
Eventually(done).Should(BeClosed())
|
||||||
|
})
|
||||||
|
|
||||||
for _, t := range []uint64{streamTypeQPACKEncoderStream, streamTypeQPACKDecoderStream} {
|
for _, t := range []uint64{streamTypeQPACKEncoderStream, streamTypeQPACKDecoderStream} {
|
||||||
streamType := t
|
streamType := t
|
||||||
name := "encoder"
|
name := "encoder"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue