implement HTTP/3 stream hijacking

This commit is contained in:
Marten Seemann 2022-03-22 17:40:10 +01:00
parent a54816867f
commit 48a2cce9df
10 changed files with 152 additions and 37 deletions

View file

@ -2,6 +2,7 @@ package http3
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
@ -10,15 +11,34 @@ import (
"github.com/lucas-clemente/quic-go/quicvarint"
)
// FrameType is the frame type of a HTTP/3 frame
type FrameType uint64
type unknownFrameHandlerFunc func(FrameType) (processed bool, err error)
type frame interface{}
func parseNextFrame(r io.Reader) (frame, error) {
var errHijacked = errors.New("hijacked")
func parseNextFrame(r io.Reader, unknownFrameHandler unknownFrameHandlerFunc) (frame, error) {
qr := quicvarint.NewReader(r)
for {
t, err := quicvarint.Read(qr)
if err != nil {
return nil, err
}
// Call the unknownFrameHandler for frames not defined in the HTTP/3 spec
if t > 0xd && unknownFrameHandler != nil {
hijacked, err := unknownFrameHandler(FrameType(t))
if err != nil {
return nil, err
}
// If the unknownFrameHandler didn't process the frame, it is our responsibility to skip it.
if hijacked {
return nil, errHijacked
}
continue
}
l, err := quicvarint.Read(qr)
if err != nil {
return nil, err
@ -32,18 +52,13 @@ func parseNextFrame(r io.Reader) (frame, error) {
case 0x4:
return parseSettingsFrame(r, l)
case 0x3: // CANCEL_PUSH
fallthrough
case 0x5: // PUSH_PROMISE
fallthrough
case 0x7: // GOAWAY
fallthrough
case 0xd: // MAX_PUSH_ID
fallthrough
default:
// skip over unknown frames
if _, err := io.CopyN(ioutil.Discard, qr, int64(l)); err != nil {
return nil, err
}
}
// skip over unknown frames
if _, err := io.CopyN(ioutil.Discard, qr, int64(l)); err != nil {
return nil, err
}
}
}