author | Alberto Bertogli
<albertito@blitiri.com.ar> 2018-07-21 11:13:10 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2018-07-21 11:13:39 UTC |
parent | 3f473ebca2b022d79af6bd19fe12f4dff02ed368 |
dnss.go | +9 | -4 |
dnss_test.go | +9 | -2 |
internal/httpresolver/resolver.go | +40 | -8 |
tests/external.sh | +37 | -5 |
diff --git a/dnss.go b/dnss.go index 25d0e53..53f61dc 100644 --- a/dnss.go +++ b/dnss.go @@ -70,8 +70,8 @@ var ( insecureForTesting = flag.Bool("testing__insecure_http", false, "INSECURE, for testing only") - dohMode = flag.Bool("experimental__doh_mode", false, - "DoH mode (experimental)") + forceMode = flag.String("force_mode", "", + "Force HTTPS resolver mode ('JSON', 'DoH', 'autodetect' (default))") // Deprecated flags that no longer make sense; we keep them for backwards // compatibility but may be removed in the future. @@ -108,10 +108,15 @@ func main() { } var resolver dnsserver.Resolver - if *dohMode { + switch *forceMode { + case "DoH": resolver = httpresolver.NewDoH(upstream, *httpsClientCAFile) - } else { + case "JSON": resolver = httpresolver.NewJSON(upstream, *httpsClientCAFile) + case "", "autodetect": + resolver = httpresolver.New(upstream, *httpsClientCAFile) + default: + log.Fatalf("-force_mode=%q is not a valid mode", *forceMode) } if *enableCache { diff --git a/dnss_test.go b/dnss_test.go index d0cde94..38fcc51 100644 --- a/dnss_test.go +++ b/dnss_test.go @@ -52,11 +52,17 @@ func Setup(tb testing.TB, mode string) string { } var r dnsserver.Resolver - if mode == "DoH" { + switch mode { + case "DoH": r = httpresolver.NewDoH(HTTPSToDNSURL, "") - } else { + case "JSON": r = httpresolver.NewJSON(HTTPSToDNSURL, "") + case "autodetect": + r = httpresolver.New(HTTPSToDNSURL, "") + default: + tb.Fatalf("%q is not a valid mode", mode) } + dtoh := dnsserver.New(DNSToHTTPSAddr, r, "") go dtoh.ListenAndServe() @@ -144,6 +150,7 @@ func handleTestDNS(w dns.ResponseWriter, r *dns.Msg) { func TestEndToEnd(t *testing.T) { t.Run("mode=JSON", func(t *testing.T) { testEndToEnd(t, "JSON") }) t.Run("mode=DoH", func(t *testing.T) { testEndToEnd(t, "DoH") }) + t.Run("mode=autodetect", func(t *testing.T) { testEndToEnd(t, "autodetect") }) } func testEndToEnd(t *testing.T, mode string) { diff --git a/internal/httpresolver/resolver.go b/internal/httpresolver/resolver.go index 17c5fb2..8bc2090 100644 --- a/internal/httpresolver/resolver.go +++ b/internal/httpresolver/resolver.go @@ -47,6 +47,17 @@ func loadCertPool(caFile string) (*x509.CertPool, error) { return pool, nil } +// New creates a new HTTPS resolver, which uses the given upstream URL to +// resolve queries. It will auto-detect the mode (JSON or DoH) by doing a +// resolution at initialization time. +func New(upstream *url.URL, caFile string) *httpsResolver { + return &httpsResolver{ + Upstream: upstream, + CAFile: caFile, + mode: "autodetect", + } +} + // NewJSON creates a new JSON resolver which uses the given upstream URL to // resolve queries. func NewJSON(upstream *url.URL, caFile string) *httpsResolver { @@ -83,22 +94,43 @@ func (r *httpsResolver) Init() error { // If CAFile is empty, we're ok with the defaults (use the system default // CA database). - if r.CAFile == "" { - return nil - } + if r.CAFile != "" { + pool, err := loadCertPool(r.CAFile) + if err != nil { + return err + } - pool, err := loadCertPool(r.CAFile) - if err != nil { - return err + transport.TLSClientConfig = &tls.Config{ + ClientCAs: pool, + } } - transport.TLSClientConfig = &tls.Config{ - ClientCAs: pool, + if r.mode == "autodetect" { + if err := r.autodetect(); err != nil { + return err + } } return nil } +func (r *httpsResolver) autodetect() error { + tr := trace.New("httpsresolver", "Autodetect") + defer tr.Finish() + + m := &dns.Msg{} + m.SetQuestion("example.com.", dns.TypeA) + + for _, mode := range []string{"DoH", "JSON"} { + r.mode = mode + if _, err := r.Query(m, tr); err == nil { + return nil + } + } + + return fmt.Errorf("Failed to autodetect resolver mode") +} + func (r *httpsResolver) Maintain() { } diff --git a/tests/external.sh b/tests/external.sh index 178b6bb..5e0e23b 100755 --- a/tests/external.sh +++ b/tests/external.sh @@ -42,7 +42,6 @@ function dnss() { ./dnss $COVER_ARGS \ -v 3 -monitoring_listen_addr :1900 \ - -testing__insecure_http \ "$@" > .dnss.log 2>&1 & PID=$! } @@ -88,14 +87,25 @@ fi echo "## Launching HTTPS server" -dnss -enable_https_to_dns -https_server_addr "localhost:1999" +dnss -enable_https_to_dns \ + -testing__insecure_http -https_server_addr "localhost:1999" HTTP_PID=$PID mv .dnss.log .dnss.http.log wait_until_ready tcp 1999 +echo "## Autodetect against dnss" +dnss -enable_dns_to_https -dns_listen_addr "localhost:1053" \ + -testing__insecure_http \ + -https_upstream "http://localhost:1999/dns-query" + +resolve +kill $PID + echo "## JSON against dnss" dnss -enable_dns_to_https -dns_listen_addr "localhost:1053" \ + -testing__insecure_http \ + -force_mode="JSON" \ -https_upstream "http://localhost:1999/dns-query" resolve @@ -103,7 +113,8 @@ kill $PID echo "## DoH against dnss" dnss -enable_dns_to_https -dns_listen_addr "localhost:1053" \ - -experimental__doh_mode \ + -testing__insecure_http \ + -force_mode="DoH" \ -https_upstream "http://localhost:1999/dns-query" # Exercise DoH via GET (dnss always uses POST). @@ -125,16 +136,37 @@ kill $PID kill $HTTP_PID +echo "## Autodetect against 1.1.1.1" +dnss -enable_dns_to_https -dns_listen_addr "localhost:1053" \ + -https_upstream "https://1.1.1.1/dns-query" + +resolve +kill $PID + echo "## DoH against 1.1.1.1" dnss -enable_dns_to_https -dns_listen_addr "localhost:1053" \ - -experimental__doh_mode \ + -force_mode="DoH" \ -https_upstream "https://1.1.1.1/dns-query" resolve kill $PID +echo "## Autodetect against dns.google.com" +dnss -enable_dns_to_https -dns_listen_addr "localhost:1053" \ + -https_upstream "https://dns.google.com/resolve" + +resolve +kill $PID + +echo "## JSON against dns.google.com" +dnss -enable_dns_to_https -dns_listen_addr "localhost:1053" \ + -force_mode="JSON" \ + -https_upstream "https://dns.google.com/resolve" + +resolve +kill $PID -echo "## JSON against default (checks default works)" +echo "## Defaults" dnss -enable_dns_to_https -dns_listen_addr "localhost:1053" resolve