core: Reject oversized GET dns query parameter of DoH (#7926)

* core: Reject oversized GET dns query parameter of DoH

The DoH POST path limits request size using http.MaxBytesReader(..., 65536), but the GET path passes the dns query value directly to base64ToMsg() with no equivalent bound.

This PR adds length check.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

* Fix

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

---------

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
This commit is contained in:
Yong Tang
2026-03-18 00:38:44 -07:00
committed by GitHub
parent ece6a68b04
commit f67994442a
2 changed files with 30 additions and 1 deletions

View File

@@ -95,6 +95,9 @@ func requestToMsgPost(req *http.Request) (*dns.Msg, error) {
return toMsg(req.Body) return toMsg(req.Body)
} }
const maxDNSQuerySize = 65536
const maxBase64Len = (maxDNSQuerySize*8 + 5) / 6
// requestToMsgGet extract the dns message from the GET request. // requestToMsgGet extract the dns message from the GET request.
func requestToMsgGet(req *http.Request) (*dns.Msg, error) { func requestToMsgGet(req *http.Request) (*dns.Msg, error) {
values := req.URL.Query() values := req.URL.Query()
@@ -105,11 +108,14 @@ func requestToMsgGet(req *http.Request) (*dns.Msg, error) {
if len(b64) != 1 { if len(b64) != 1 {
return nil, fmt.Errorf("multiple 'dns' query values found") return nil, fmt.Errorf("multiple 'dns' query values found")
} }
if len(b64[0]) > maxBase64Len {
return nil, fmt.Errorf("dns query too large")
}
return base64ToMsg(b64[0]) return base64ToMsg(b64[0])
} }
func toMsg(r io.ReadCloser) (*dns.Msg, error) { func toMsg(r io.ReadCloser) (*dns.Msg, error) {
buf, err := io.ReadAll(http.MaxBytesReader(nil, r, 65536)) buf, err := io.ReadAll(http.MaxBytesReader(nil, r, maxDNSQuerySize))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -44,3 +44,26 @@ func TestDoH(t *testing.T) {
}) })
} }
} }
func TestDoHGETRejectsOversizedDNSQuery(t *testing.T) {
// Exceeding max size 65536
raw := make([]byte, 65536+1)
b64 := b64Enc.EncodeToString(raw)
req, err := http.NewRequest(
http.MethodGet,
"https://example.org"+Path+"?dns="+b64,
nil,
)
if err != nil {
t.Fatalf("failed to build request: %v", err)
}
_, err = RequestToMsg(req)
if err == nil {
t.Fatalf("expected oversized GET dns query to be rejected")
}
if err.Error() != "dns query too large" {
t.Fatalf("expected %q, got %v", "dns query too large", err)
}
}