Skip to content

Commit 68cc2ce

Browse files
aschmahmannlidel
andauthored
feat: allow localhost http endpoints (#28)
* feat: allow http endpoints * refactor: limit http:// to localhost --------- Co-authored-by: Marcin Rataj <[email protected]>
1 parent f2e2586 commit 68cc2ce

File tree

2 files changed

+39
-5
lines changed

2 files changed

+39
-5
lines changed

resolver.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package doh
22

33
import (
44
"context"
5+
"errors"
56
"math"
67
"net"
78
"strings"
@@ -52,7 +53,14 @@ func WithCacheDisabled() Option {
5253
}
5354

5455
func NewResolver(url string, opts ...Option) (*Resolver, error) {
55-
if !strings.HasPrefix(url, "https:") {
56+
if strings.HasPrefix(url, "http:") &&
57+
!strings.HasPrefix(url, "http://localhost") &&
58+
!strings.HasPrefix(url, "http://127.0.0.1") &&
59+
!strings.HasPrefix(url, "http://[::1]") {
60+
return nil, errors.New("insecure URL: non-local DoH resolvers must use HTTPS")
61+
}
62+
63+
if !strings.HasPrefix(url, "http:") && !strings.HasPrefix(url, "https:") {
5664
url = "https://" + url
5765
}
5866

resolver_test.go

+30-4
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,10 @@ func TestLookupTXT(t *testing.T) {
124124
})
125125
defer resolver.Close()
126126

127-
r, err := NewResolver("")
127+
r, err := NewResolver(resolver.URL)
128128
if err != nil {
129129
t.Fatal("resolver cannot be initialised")
130130
}
131-
r.url = resolver.URL
132131

133132
txt, err := r.LookupTXT(context.Background(), domain)
134133
if err != nil {
@@ -156,11 +155,10 @@ func TestLookupCache(t *testing.T) {
156155
defer resolver.Close()
157156

158157
const cacheTTL = time.Second
159-
r, err := NewResolver("", WithMaxCacheTTL(cacheTTL))
158+
r, err := NewResolver(resolver.URL, WithMaxCacheTTL(cacheTTL))
160159
if err != nil {
161160
t.Fatal("resolver cannot be initialised")
162161
}
163-
r.url = resolver.URL
164162

165163
txt, err := r.LookupTXT(context.Background(), domain)
166164
if err != nil {
@@ -190,6 +188,34 @@ func TestLookupCache(t *testing.T) {
190188
}
191189
}
192190

191+
func TestCleartextRemoteEndpoint(t *testing.T) {
192+
// use remote endpoint over http and not https
193+
_, err := NewResolver("http://cloudflare-dns.com/dns-query")
194+
if err == nil {
195+
t.Fatal("using remote DoH endpoint over unencrypted http:// expected should produce error, but expected error was not returned")
196+
}
197+
}
198+
199+
func TestCleartextLocalhostEndpoint(t *testing.T) {
200+
testCases := []struct{ hostname string }{
201+
{hostname: "localhost"},
202+
{hostname: "localhost:8080"},
203+
{hostname: "127.0.0.1"},
204+
{hostname: "127.0.0.1:8080"},
205+
{hostname: "[::1]"},
206+
{hostname: "[::1]:8080"},
207+
}
208+
for _, tc := range testCases {
209+
t.Run(tc.hostname, func(t *testing.T) {
210+
// use local endpoint over http and not https
211+
_, err := NewResolver("http://" + tc.hostname + "/dns-query")
212+
if err != nil {
213+
t.Fatalf("using %q DoH endpoint over unencrypted http:// expected to work, but unexpected error was returned instead", tc.hostname)
214+
}
215+
})
216+
}
217+
}
218+
193219
func sameIPs(a, b []net.IPAddr) bool {
194220
if len(a) != len(b) {
195221
return false

0 commit comments

Comments
 (0)