DoH: fallback to GET on servers that don't support POST

This commit is contained in:
Frank Denis 2018-02-05 11:30:10 +01:00
parent 8a7569555c
commit 43f3e64bd9
5 changed files with 29 additions and 8 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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)
}