143 lines
4.5 KiB
Go
143 lines
4.5 KiB
Go
package edns
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"testing"
|
|
|
|
"golang.org/x/net/dns/dnsmessage"
|
|
)
|
|
|
|
func TestExchangeDoHGETAndPOST(t *testing.T) {
|
|
server := httptest.NewTLSServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
|
var payload []byte
|
|
var err error
|
|
if request.Method == http.MethodGet {
|
|
payload, err = decodeGETQuery(request.URL.Query().Get("dns"))
|
|
} else {
|
|
payload, err = io.ReadAll(request.Body)
|
|
}
|
|
if err != nil {
|
|
http.Error(writer, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
if request.Header.Get("Accept") != "application/dns-message" {
|
|
http.Error(writer, "missing accept", http.StatusNotAcceptable)
|
|
return
|
|
}
|
|
|
|
var query dnsmessage.Message
|
|
if err := query.Unpack(payload); err != nil {
|
|
http.Error(writer, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
response := dnsmessage.Message{
|
|
Header: dnsmessage.Header{ID: query.Header.ID, Response: true, RecursionAvailable: true},
|
|
Questions: query.Questions,
|
|
}
|
|
responseWire, err := response.Pack()
|
|
if err != nil {
|
|
http.Error(writer, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
writer.Header().Set("Content-Type", "application/dns-message")
|
|
writer.Header().Set("Age", "10")
|
|
_, _ = writer.Write(responseWire)
|
|
}))
|
|
defer server.Close()
|
|
|
|
wire, _, _, err := BuildQuery("example.com", "A")
|
|
if err != nil {
|
|
t.Fatalf("build query: %v", err)
|
|
}
|
|
for _, method := range []string{"get", "post"} {
|
|
t.Run(method, func(t *testing.T) {
|
|
response, info, err := exchangeDoHWithClient(t.Context(), server.Client(), server.URL, wire, method)
|
|
if err != nil {
|
|
t.Fatalf("exchange DoH: %v", err)
|
|
}
|
|
if len(response) == 0 || !info.Encrypted || !info.ServerAuthenticated || info.HTTPAgeSeconds != 10 {
|
|
t.Fatalf("unexpected result: response=%d info=%#v", len(response), info)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestExchangeDoHThroughHTTPConnectProxy(t *testing.T) {
|
|
server := httptest.NewTLSServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
|
payload, err := io.ReadAll(request.Body)
|
|
if err != nil {
|
|
http.Error(writer, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
var query dnsmessage.Message
|
|
if err := query.Unpack(payload); err != nil {
|
|
http.Error(writer, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
response := dnsmessage.Message{
|
|
Header: dnsmessage.Header{ID: query.Header.ID, Response: true},
|
|
Questions: query.Questions,
|
|
}
|
|
responseWire, err := response.Pack()
|
|
if err != nil {
|
|
http.Error(writer, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
writer.Header().Set("Content-Type", "application/dns-message")
|
|
_, _ = writer.Write(responseWire)
|
|
}))
|
|
defer server.Close()
|
|
|
|
endpoint, err := url.Parse(server.URL)
|
|
if err != nil {
|
|
t.Fatalf("parse test endpoint: %v", err)
|
|
}
|
|
proxyURL, proxyError := startConnectProxy(t, endpoint.Host, "Basic dXNlcjpzZWNyZXQ=")
|
|
testTransport := server.Client().Transport.(*http.Transport)
|
|
client, proxyLabel, err := newDoHClientWithTLSConfig(server.URL, proxyURL, testTransport.TLSClientConfig)
|
|
if err != nil {
|
|
t.Fatalf("create proxied DoH client: %v", err)
|
|
}
|
|
if proxyLabel == "" || proxyLabel == proxyURL {
|
|
t.Fatalf("proxy label = %q, want sanitized URL", proxyLabel)
|
|
}
|
|
wire, _, _, err := BuildQuery("example.com", "A")
|
|
if err != nil {
|
|
t.Fatalf("build query: %v", err)
|
|
}
|
|
if _, _, err := exchangeDoHWithClient(t.Context(), client, server.URL, wire, "post"); err != nil {
|
|
t.Fatalf("exchange DoH through proxy: %v", err)
|
|
}
|
|
client.CloseIdleConnections()
|
|
if err := <-proxyError; err != nil {
|
|
t.Fatalf("serve CONNECT proxy: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestExchangeDoHRejectsInvalidAge(t *testing.T) {
|
|
server := httptest.NewTLSServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {
|
|
writer.Header().Set("Content-Type", "application/dns-message")
|
|
writer.Header().Set("Age", "invalid")
|
|
_, _ = writer.Write([]byte{1})
|
|
}))
|
|
defer server.Close()
|
|
|
|
if _, _, err := exchangeDoHWithClient(t.Context(), server.Client(), server.URL, []byte{1}, "post"); err == nil {
|
|
t.Fatal("invalid HTTP Age was accepted")
|
|
}
|
|
}
|
|
|
|
func TestExchangeDoHRejectsHTTPError(t *testing.T) {
|
|
server := httptest.NewTLSServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {
|
|
http.Error(writer, "unavailable", http.StatusServiceUnavailable)
|
|
}))
|
|
defer server.Close()
|
|
|
|
if _, _, err := exchangeDoHWithClient(t.Context(), server.Client(), server.URL, []byte{1}, "post"); err == nil {
|
|
t.Fatal("HTTP error was accepted")
|
|
}
|
|
}
|