From 43f3e64bd9db491bd4c158a6136a8b3bc9762ad6 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Mon, 5 Feb 2018 11:30:10 +0100 Subject: [PATCH] DoH: fallback to GET on servers that don't support POST --- dnscrypt-proxy/proxy.go | 2 +- dnscrypt-proxy/serversInfo.go | 14 ++++++++++---- dnscrypt-proxy/sources.go | 2 +- dnscrypt-proxy/stamps.go | 4 +++- dnscrypt-proxy/xtransport.go | 15 ++++++++++++++- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/dnscrypt-proxy/proxy.go b/dnscrypt-proxy/proxy.go index 775043f7..d62a2776 100644 --- a/dnscrypt-proxy/proxy.go +++ b/dnscrypt-proxy/proxy.go @@ -284,7 +284,7 @@ func (proxy *Proxy) processIncomingQuery(serverInfo *ServerInfo, clientProto str } else if serverInfo.Proto == StampProtoTypeDoH { tid := TransactionID(query) SetTransactionID(query, 0) - resp, _, err := proxy.xTransport.Post(serverInfo.URL, "application/dns-udpwireformat", "application/dns-udpwireformat", query, proxy.timeout) + resp, _, err := proxy.xTransport.DoHQuery(serverInfo.useGet, serverInfo.URL, query, proxy.timeout) SetTransactionID(query, tid) if err != nil { return diff --git a/dnscrypt-proxy/serversInfo.go b/dnscrypt-proxy/serversInfo.go index 9db894a6..93d5cb54 100644 --- a/dnscrypt-proxy/serversInfo.go +++ b/dnscrypt-proxy/serversInfo.go @@ -54,6 +54,7 @@ type ServerInfo struct { lastActionTS time.Time rtt ewma.MovingAverage initialRtt int + useGet bool } type LBStrategy int @@ -243,11 +244,15 @@ func (serversInfo *ServersInfo) fetchDoHServerInfo(proxy *Proxy, name string, st body := []byte{ 0xca, 0xfe, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x29, 0x10, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, } - _, _, err := proxy.xTransport.Post(url, "application/dns-udpwireformat", "application/dns-udpwireformat", body, proxy.timeout) - if err != nil { - return ServerInfo{}, err + useGet := false + if _, _, err := proxy.xTransport.DoHQuery(useGet, url, body, proxy.timeout); err != nil { + useGet = true + if _, _, err := proxy.xTransport.DoHQuery(useGet, url, body, proxy.timeout); err != nil { + return ServerInfo{}, err + } + dlog.Debugf("Server [%s] doesn't appear to support POST; falling back to GET requests", name) } - resp, rtt, err := proxy.xTransport.Post(url, "application/dns-udpwireformat", "application/dns-udpwireformat", body, proxy.timeout) + resp, rtt, err := proxy.xTransport.DoHQuery(useGet, url, body, proxy.timeout) if err != nil { return ServerInfo{}, err } @@ -297,6 +302,7 @@ func (serversInfo *ServersInfo) fetchDoHServerInfo(proxy *Proxy, name string, st URL: url, HostName: stamp.providerName, initialRtt: int(rtt.Nanoseconds() / 1000000), + useGet: useGet, } return serverInfo, nil } diff --git a/dnscrypt-proxy/sources.go b/dnscrypt-proxy/sources.go index c95e280f..5ad4c38e 100644 --- a/dnscrypt-proxy/sources.go +++ b/dnscrypt-proxy/sources.go @@ -80,7 +80,7 @@ func fetchWithCache(xTransport *XTransport, urlStr string, cacheFile string) (in if err != nil { return } - resp, _, err = xTransport.Get(url, 30*time.Second) + resp, _, err = xTransport.Get(url, "", 30*time.Second) if err == nil && resp != nil && (resp.StatusCode < 200 || resp.StatusCode > 299) { err = fmt.Errorf("Webserver returned code %d", resp.StatusCode) return diff --git a/dnscrypt-proxy/stamps.go b/dnscrypt-proxy/stamps.go index 21c12af5..9392ea1f 100644 --- a/dnscrypt-proxy/stamps.go +++ b/dnscrypt-proxy/stamps.go @@ -154,7 +154,9 @@ func newDoHServerStamp(bin []byte) (ServerStamp, error) { return stamp, errors.New("Invalid stamp") } pos++ - stamp.hashes = append(stamp.hashes, bin[pos:pos+len]) + if len > 0 { + stamp.hashes = append(stamp.hashes, bin[pos:pos+len]) + } pos += len if vlen&0x80 != 0x80 { break diff --git a/dnscrypt-proxy/xtransport.go b/dnscrypt-proxy/xtransport.go index 733aa1e5..1fad6e07 100644 --- a/dnscrypt-proxy/xtransport.go +++ b/dnscrypt-proxy/xtransport.go @@ -3,6 +3,7 @@ package main import ( "bytes" "context" + "encoding/base64" "errors" "fmt" "io" @@ -152,7 +153,7 @@ func (xTransport *XTransport) Fetch(method string, url *url.URL, accept string, return resp, rtt, err } -func (xTransport *XTransport) Get(url *url.URL, timeout time.Duration) (*http.Response, time.Duration, error) { +func (xTransport *XTransport) Get(url *url.URL, accept string, timeout time.Duration) (*http.Response, time.Duration, error) { return xTransport.Fetch("GET", url, "", "", nil, timeout) } @@ -160,3 +161,15 @@ func (xTransport *XTransport) Post(url *url.URL, accept string, contentType stri bc := ioutil.NopCloser(bytes.NewReader(body)) return xTransport.Fetch("POST", url, accept, contentType, &bc, timeout) } +func (xTransport *XTransport) DoHQuery(useGet bool, url *url.URL, body []byte, timeout time.Duration) (*http.Response, time.Duration, error) { + dataType := "application/dns-udpwireformat" + if useGet { + qs := url.Query() + qs.Add("ct", "") + qs.Add("body", base64.RawURLEncoding.EncodeToString(body)) + url2 := *url + url2.RawQuery = qs.Encode() + return xTransport.Get(&url2, dataType, timeout) + } + return xTransport.Post(url, dataType, dataType, body, timeout) +}