Initial support for DNS-over-HTTP2 -- Yes, it works with Google.
This commit is contained in:
parent
85f8aa1000
commit
50d0c0449f
|
@ -14,7 +14,7 @@
|
|||
## List of servers to use
|
||||
## If this line is commented, all registered servers will be used
|
||||
|
||||
# server_names = ['scaleway-fr']
|
||||
server_names = ['google']
|
||||
|
||||
|
||||
## List of local addresses and ports to listen to. Can be IPv4 and/or IPv6.
|
||||
|
@ -258,6 +258,6 @@ format = 'tsv'
|
|||
## Optional, local, static list of additional servers
|
||||
## Mostly useful for testing your own servers.
|
||||
|
||||
# [static]
|
||||
# [static.'example.com']
|
||||
# stamp = 'sdns://AQMAAAAAAAAAEjIxMi40Ny4yMjguMTM2OjQ0MyDoAbhOpga_sLrAzkNEW7FeumSwL6PEqjGuEGNqB5AyTR8yLmRuc2NyeXB0LWNlcnQuZnIuZG5zY3J5cHQub3Jn'
|
||||
[static]
|
||||
[static.'google']
|
||||
stamp = 'sdns://AgAAAAAAAAAADjIxNi41OC4yMDQuMTQyAA5kbnMuZ29vZ2xlLmNvbQ0vZXhwZXJpbWVudGFs'
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
@ -53,6 +56,7 @@ type Proxy struct {
|
|||
urlsToPrefetch []URLToPrefetch
|
||||
clientsCount uint32
|
||||
maxClients uint32
|
||||
httpTransport *http.Transport
|
||||
}
|
||||
|
||||
type App struct {
|
||||
|
@ -151,6 +155,15 @@ func (proxy *Proxy) StartProxy() {
|
|||
for _, registeredServer := range proxy.registeredServers {
|
||||
proxy.serversInfo.registerServer(proxy, registeredServer.name, registeredServer.stamp)
|
||||
}
|
||||
proxy.httpTransport = &http.Transport{
|
||||
DisableKeepAlives: false,
|
||||
DisableCompression: true,
|
||||
MaxIdleConns: 1,
|
||||
IdleConnTimeout: proxy.timeout,
|
||||
ResponseHeaderTimeout: proxy.timeout,
|
||||
ExpectContinueTimeout: proxy.timeout,
|
||||
MaxResponseHeaderBytes: 4096,
|
||||
}
|
||||
for _, listenAddrStr := range proxy.listenAddresses {
|
||||
listenUDPAddr, err := net.ResolveUDPAddr("udp", listenAddrStr)
|
||||
if err != nil {
|
||||
|
@ -353,6 +366,7 @@ func (proxy *Proxy) processIncomingQuery(serverInfo *ServerInfo, clientProto str
|
|||
}
|
||||
}
|
||||
if len(response) == 0 {
|
||||
if serverInfo.Proto == StampProtoTypeDNSCrypt {
|
||||
encryptedQuery, clientNonce, err := proxy.Encrypt(serverInfo, query, serverProto)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -367,8 +381,46 @@ func (proxy *Proxy) processIncomingQuery(serverInfo *ServerInfo, clientProto str
|
|||
serverInfo.noticeFailure(proxy)
|
||||
return
|
||||
}
|
||||
} else if serverInfo.Proto == StampProtoTypeDoH {
|
||||
req := &http.Request{
|
||||
Method: "POST",
|
||||
URL: serverInfo.URL,
|
||||
Host: serverInfo.HostName,
|
||||
Header: map[string][]string{
|
||||
"Accept": {"application/dns-udpwireformat"},
|
||||
"Content-Type": {"application/dns-udpwireformat"},
|
||||
"User-Agent": {"dnscrypt-proxy"},
|
||||
},
|
||||
Close: false,
|
||||
Body: ioutil.NopCloser(bytes.NewReader(query)),
|
||||
}
|
||||
client := http.Client{
|
||||
Transport: proxy.httpTransport,
|
||||
Timeout: proxy.timeout,
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err == nil && resp != nil && (resp.StatusCode < 200 || resp.StatusCode > 299) {
|
||||
return
|
||||
} else if err != nil || resp == nil {
|
||||
return
|
||||
}
|
||||
response, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
dlog.Fatal("Unsupported protocol")
|
||||
}
|
||||
if err != nil {
|
||||
serverInfo.noticeFailure(proxy)
|
||||
return
|
||||
}
|
||||
response, _ = pluginsState.ApplyResponsePlugins(&proxy.pluginsGlobals, response)
|
||||
}
|
||||
if len(response) < MinDNSPacketSize || len(response) > MaxDNSPacketSize {
|
||||
serverInfo.noticeFailure(proxy)
|
||||
return
|
||||
}
|
||||
if clientProto == "udp" {
|
||||
if len(response) > MaxDNSUDPPacketSize {
|
||||
response, err = TruncatedResponse(response)
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -32,12 +38,15 @@ type RegisteredServer struct {
|
|||
|
||||
type ServerInfo struct {
|
||||
sync.RWMutex
|
||||
Proto StampProtoType
|
||||
MagicQuery [8]byte
|
||||
ServerPk [32]byte
|
||||
SharedKey [32]byte
|
||||
CryptoConstruction CryptoConstruction
|
||||
Name string
|
||||
Timeout time.Duration
|
||||
URL *url.URL
|
||||
HostName string
|
||||
UDPAddr *net.UDPAddr
|
||||
TCPAddr *net.TCPAddr
|
||||
lastActionTS time.Time
|
||||
|
@ -142,6 +151,15 @@ func (serversInfo *ServersInfo) getOne() *ServerInfo {
|
|||
}
|
||||
|
||||
func (serversInfo *ServersInfo) fetchServerInfo(proxy *Proxy, name string, stamp ServerStamp) (ServerInfo, error) {
|
||||
if stamp.proto == StampProtoTypeDNSCrypt {
|
||||
return serversInfo.fetchDNSCryptServerInfo(proxy, name, stamp)
|
||||
} else if stamp.proto == StampProtoTypeDoH {
|
||||
return serversInfo.fetchDoHServerInfo(proxy, name, stamp)
|
||||
}
|
||||
return ServerInfo{}, errors.New("Unsupported protocol")
|
||||
}
|
||||
|
||||
func (serversInfo *ServersInfo) fetchDNSCryptServerInfo(proxy *Proxy, name string, stamp ServerStamp) (ServerInfo, error) {
|
||||
if len(stamp.serverPk) != ed25519.PublicKeySize {
|
||||
serverPk, err := hex.DecodeString(strings.Replace(string(stamp.serverPk), ":", "", -1))
|
||||
if err != nil || len(serverPk) != ed25519.PublicKeySize {
|
||||
|
@ -163,6 +181,7 @@ func (serversInfo *ServersInfo) fetchServerInfo(proxy *Proxy, name string, stamp
|
|||
return ServerInfo{}, err
|
||||
}
|
||||
serverInfo := ServerInfo{
|
||||
Proto: StampProtoTypeDNSCrypt,
|
||||
MagicQuery: certInfo.MagicQuery,
|
||||
ServerPk: certInfo.ServerPk,
|
||||
SharedKey: certInfo.SharedKey,
|
||||
|
@ -176,6 +195,59 @@ func (serversInfo *ServersInfo) fetchServerInfo(proxy *Proxy, name string, stamp
|
|||
return serverInfo, nil
|
||||
}
|
||||
|
||||
func (serversInfo *ServersInfo) fetchDoHServerInfo(proxy *Proxy, name string, stamp ServerStamp) (ServerInfo, error) {
|
||||
url := &url.URL{
|
||||
Scheme: "https",
|
||||
Host: stamp.providerName,
|
||||
Path: stamp.path,
|
||||
}
|
||||
body := ioutil.NopCloser(bytes.NewReader([]byte{
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
|
||||
}))
|
||||
req := &http.Request{
|
||||
Method: "POST",
|
||||
URL: url,
|
||||
Header: map[string][]string{
|
||||
"Accept": {"application/dns-udpwireformat"},
|
||||
"Content-Type": {"application/dns-udpwireformat"},
|
||||
"User-Agent": {"dnscrypt-proxy"},
|
||||
},
|
||||
Close: false,
|
||||
Host: stamp.providerName,
|
||||
Body: body,
|
||||
}
|
||||
client := http.Client{
|
||||
Transport: proxy.httpTransport,
|
||||
Timeout: proxy.timeout,
|
||||
}
|
||||
start := time.Now()
|
||||
resp, err := client.Do(req)
|
||||
elapsed := time.Since(start)
|
||||
if err == nil && resp != nil && (resp.StatusCode < 200 || resp.StatusCode > 299) {
|
||||
return ServerInfo{}, fmt.Errorf("Webserver returned code %d", resp.StatusCode)
|
||||
} else if err != nil {
|
||||
return ServerInfo{}, err
|
||||
} else if resp == nil {
|
||||
return ServerInfo{}, errors.New("Webserver returned an error")
|
||||
}
|
||||
respBody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return ServerInfo{}, err
|
||||
}
|
||||
if len(respBody) < MinDNSPacketSize || len(respBody) > MaxDNSPacketSize {
|
||||
return ServerInfo{}, errors.New("Webserver returned an unexpected response")
|
||||
}
|
||||
serverInfo := ServerInfo{
|
||||
Proto: StampProtoTypeDoH,
|
||||
Name: name,
|
||||
Timeout: proxy.timeout,
|
||||
URL: url,
|
||||
HostName: stamp.providerName,
|
||||
initialRtt: int(elapsed.Nanoseconds() / 1000000),
|
||||
}
|
||||
return serverInfo, nil
|
||||
}
|
||||
|
||||
func (serverInfo *ServerInfo) noticeFailure(proxy *Proxy) {
|
||||
serverInfo.Lock()
|
||||
serverInfo.rtt.Set(float64(proxy.timeout.Nanoseconds()))
|
||||
|
|
Loading…
Reference in New Issue