Check DoH servers with a query to a random name
The issue with benchmarking DoH servers is that some responses can be directly served by a CDN, while others require a round trip to the origin that can be significantly more expensive. Random padding was an attempt at mitigating this. Unfortunately, some servers (Tencent) ignore the padding. We end up with a query for the root zone served by the Tencent CDN very quickly, but anything else is orders of magnitude slower. So, measure a query within the reserved "test." zone instead. Caching resolvers should either know that "test." is undelegated, or have it in their negative cache already, so this is unlikely to trigger an actual query to authoritative servers. Take it as an opportunity to check that we don't get anything but a NXDOMAIN response for nonexistent domains.
This commit is contained in:
parent
60d4c98f31
commit
f3157b0a42
|
@ -390,6 +390,29 @@ func dohTestPacket(msgID uint16) []byte {
|
||||||
return body
|
return body
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func dohNXTestPacket(msgID uint16) []byte {
|
||||||
|
msg := dns.Msg{}
|
||||||
|
qName := make([]byte, 16)
|
||||||
|
charset := "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
for i := range qName {
|
||||||
|
qName[i] = charset[rand.Intn(len(charset))]
|
||||||
|
}
|
||||||
|
msg.SetQuestion(string(qName)+".dnscrypt.test.", dns.TypeNS)
|
||||||
|
msg.Id = msgID
|
||||||
|
msg.MsgHdr.RecursionDesired = true
|
||||||
|
msg.SetEdns0(uint16(MaxDNSPacketSize), false)
|
||||||
|
ext := new(dns.EDNS0_PADDING)
|
||||||
|
ext.Padding = make([]byte, 16)
|
||||||
|
crypto_rand.Read(ext.Padding)
|
||||||
|
edns0 := msg.IsEdns0()
|
||||||
|
edns0.Option = append(edns0.Option, ext)
|
||||||
|
body, err := msg.Pack()
|
||||||
|
if err != nil {
|
||||||
|
dlog.Fatal(err)
|
||||||
|
}
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
|
||||||
func fetchDoHServerInfo(proxy *Proxy, name string, stamp stamps.ServerStamp, isNew bool) (ServerInfo, error) {
|
func fetchDoHServerInfo(proxy *Proxy, name string, stamp stamps.ServerStamp, isNew bool) (ServerInfo, error) {
|
||||||
// If an IP has been provided, use it forever.
|
// If an IP has been provided, use it forever.
|
||||||
// Or else, if the fallback server and the DoH server are operated
|
// Or else, if the fallback server and the DoH server are operated
|
||||||
|
@ -424,6 +447,7 @@ func fetchDoHServerInfo(proxy *Proxy, name string, stamp stamps.ServerStamp, isN
|
||||||
}
|
}
|
||||||
dlog.Debugf("Server [%s] doesn't appear to support POST; falling back to GET requests", name)
|
dlog.Debugf("Server [%s] doesn't appear to support POST; falling back to GET requests", name)
|
||||||
}
|
}
|
||||||
|
body = dohNXTestPacket(0xcafe)
|
||||||
serverResponse, tls, rtt, err := proxy.xTransport.DoHQuery(useGet, url, body, proxy.timeout)
|
serverResponse, tls, rtt, err := proxy.xTransport.DoHQuery(useGet, url, body, proxy.timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ServerInfo{}, err
|
return ServerInfo{}, err
|
||||||
|
@ -431,6 +455,13 @@ func fetchDoHServerInfo(proxy *Proxy, name string, stamp stamps.ServerStamp, isN
|
||||||
if tls == nil || !tls.HandshakeComplete {
|
if tls == nil || !tls.HandshakeComplete {
|
||||||
return ServerInfo{}, errors.New("TLS handshake failed")
|
return ServerInfo{}, errors.New("TLS handshake failed")
|
||||||
}
|
}
|
||||||
|
msg := dns.Msg{}
|
||||||
|
if err := msg.Unpack(serverResponse); err != nil {
|
||||||
|
return ServerInfo{}, err
|
||||||
|
}
|
||||||
|
if msg.Rcode != dns.RcodeNameError {
|
||||||
|
dlog.Criticalf("[%s] may be a lying resolver", name)
|
||||||
|
}
|
||||||
protocol := tls.NegotiatedProtocol
|
protocol := tls.NegotiatedProtocol
|
||||||
if len(protocol) == 0 {
|
if len(protocol) == 0 {
|
||||||
protocol = "h1"
|
protocol = "h1"
|
||||||
|
|
Loading…
Reference in New Issue