From d7d78655bb6014c18e07a779b5c7d75b20a98a20 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Fri, 20 Sep 2024 23:07:50 +0800 Subject: [PATCH] verify the :authority pseudo-header when parsing request (#68) --- request.go | 16 +++++++++++++++- request_test.go | 7 +++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/request.go b/request.go index 71a9b85..07aef39 100644 --- a/request.go +++ b/request.go @@ -3,6 +3,7 @@ package masque import ( "fmt" "net/http" + "net/url" "reflect" "strconv" "strings" @@ -46,6 +47,14 @@ func (e *RequestParseError) Unwrap() error { return e.Err } // ParseRequest parses a CONNECT-UDP request. // The template is the URI template that clients will use to configure this UDP proxy. func ParseRequest(r *http.Request, template *uritemplate.Template) (*Request, error) { + u, err := url.Parse(template.Raw()) + if err != nil { + return nil, &RequestParseError{ + HTTPStatus: http.StatusInternalServerError, + Err: fmt.Errorf("failed to parse template: %w", err), + } + } + if r.Method != http.MethodConnect { return nil, &RequestParseError{ HTTPStatus: http.StatusMethodNotAllowed, @@ -58,7 +67,12 @@ func ParseRequest(r *http.Request, template *uritemplate.Template) (*Request, er Err: fmt.Errorf("unexpected protocol: %s", r.Proto), } } - // TODO: check :authority + if r.Host != u.Host { + return nil, &RequestParseError{ + HTTPStatus: http.StatusBadRequest, + Err: fmt.Errorf("host in :authority (%s) does not match template host (%s)", r.Host, u.Host), + } + } capsuleHeaderValues, ok := r.Header[capsuleHeader] if !ok { return nil, &RequestParseError{ diff --git a/request_test.go b/request_test.go index a09fe13..0a8afa8 100644 --- a/request_test.go +++ b/request_test.go @@ -50,6 +50,13 @@ func TestRequestParsing(t *testing.T) { require.Equal(t, http.StatusNotImplemented, err.(*RequestParseError).HTTPStatus) }) + t.Run("wrong :authority", func(t *testing.T) { + req := newRequest("https://quic-go.net:1234/masque") + _, err := ParseRequest(req, template) + require.EqualError(t, err, "host in :authority (quic-go.net:1234) does not match template host (localhost:1234)") + require.Equal(t, http.StatusBadRequest, err.(*RequestParseError).HTTPStatus) + }) + t.Run("missing Capsule-Protocol header", func(t *testing.T) { req := newRequest("https://localhost:1234/masque") req.Header.Del("Capsule-Protocol")