From a19ee5a6dc701a2ababf2d4c89ede0acf0683101 Mon Sep 17 00:00:00 2001 From: fangdingjun Date: Fri, 11 May 2018 14:43:31 +0800 Subject: [PATCH] add support for cloudflare https dns --- .gitignore | 1 + cf_httpdns_test.go | 19 ++++++++++++++ cloudflare_httpdns.go | 59 +++++++++++++++++++++++++++++++++++++++++++ conf.go | 3 ++- config_example.yaml | 30 +++++++++++++++------- google_httpdns.go | 3 ++- handler.go | 22 +++++++++++----- server.go | 3 ++- 8 files changed, 122 insertions(+), 18 deletions(-) create mode 100644 cf_httpdns_test.go create mode 100644 cloudflare_httpdns.go diff --git a/.gitignore b/.gitignore index 8bde6a6..aa730c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *~ dns* +gdns* diff --git a/cf_httpdns_test.go b/cf_httpdns_test.go new file mode 100644 index 0000000..9bedf61 --- /dev/null +++ b/cf_httpdns_test.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + "testing" + + "github.com/miekg/dns" +) + +func TestCFDns(t *testing.T) { + cf := &CloudflareHTTPDns{} + m := new(dns.Msg) + m.SetQuestion("www.google.com.", dns.TypeA) + m1, _, err := cf.Exchange(m, "1.1.1.1") + if err != nil { + t.Fatal(err) + } + fmt.Println(m1.String()) +} diff --git a/cloudflare_httpdns.go b/cloudflare_httpdns.go new file mode 100644 index 0000000..5148e2e --- /dev/null +++ b/cloudflare_httpdns.go @@ -0,0 +1,59 @@ +package main + +import ( + "bytes" + "crypto/tls" + "fmt" + "io/ioutil" + "net/http" + "time" + + "github.com/miekg/dns" +) + +var httpclientCF = &http.Client{ + Timeout: 8 * time.Second, + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ServerName: "cloudflare-dns.com"}, + TLSHandshakeTimeout: 5 * time.Second, + }, +} + +// CloudflareHTTPDns cloudflare http dns +type CloudflareHTTPDns struct { +} + +// Exchange send request to server and get result +func (cf *CloudflareHTTPDns) Exchange(m *dns.Msg, addr string) (m1 *dns.Msg, d time.Duration, err error) { + u := fmt.Sprintf("https://%s/dns-query", addr) + data, err := m.Pack() + if err != nil { + return + } + + body := bytes.NewBuffer(data) + + req, err := http.NewRequest("POST", u, body) + if err != nil { + return + } + + req.Header.Set("Content-Type", "application/dns-udpwireformat") + + resp, err := httpclientCF.Do(req) + if err != nil { + return + } + defer resp.Body.Close() + + data, err = ioutil.ReadAll(resp.Body) + if err != nil { + return + } + + m1 = new(dns.Msg) + if err = m1.Unpack(data); err != nil { + return + } + return +} diff --git a/conf.go b/conf.go index 37a62e8..a288cbd 100644 --- a/conf.go +++ b/conf.go @@ -2,10 +2,11 @@ package main import ( "bufio" - "github.com/go-yaml/yaml" "io/ioutil" "os" "strings" + + "github.com/go-yaml/yaml" ) type conf struct { diff --git a/config_example.yaml b/config_example.yaml index d26a2a1..2fc9eac 100644 --- a/config_example.yaml +++ b/config_example.yaml @@ -1,10 +1,12 @@ listen: - - network: tcp + - + network: tcp host: 0.0.0.0 port: 1053 - - network: udp + - + network: udp host: 0.0.0.0 port: 1053 @@ -19,23 +21,33 @@ defaultupstream: host: 8.8.8.8 port: 53 - - network:udp + network: udp host: 8.8.8.8 port: 53 forwardrules: - - domainfile: ./testdata/cn.dat + - + domainfile: ./testdata/cn.dat server: - - network: tcp + - + network: tcp host: 114.114.114.114 port: 53 - - domainfile: testdata/us.dat + - + domainfile: testdata/us.dat server: - - network: tcp + - + network: tcp host: 8.8.8.8 port: 53 - - network: https - host: 74.175.200.100 + - + network: https_google + host: 172.217.161.174 port: 443 + + - + network: https_cloudflare + host: 1.1.1.1 + port: 443 \ No newline at end of file diff --git a/google_httpdns.go b/google_httpdns.go index aa20da9..f91eacc 100644 --- a/google_httpdns.go +++ b/google_httpdns.go @@ -4,13 +4,14 @@ import ( "crypto/tls" "encoding/json" "fmt" - "github.com/miekg/dns" "io/ioutil" "net" "net/http" "net/url" "sync" "time" + + "github.com/miekg/dns" ) // ServerAddr is Google dns server ip diff --git a/handler.go b/handler.go index 24dcb71..e8fab4f 100644 --- a/handler.go +++ b/handler.go @@ -3,9 +3,10 @@ package main import ( "errors" "fmt" - "github.com/miekg/dns" "strings" "time" + + "github.com/miekg/dns" ) type dnsClient interface { @@ -16,7 +17,8 @@ type dnsHandler struct { cfg *conf tcpclient dnsClient udpclient dnsClient - httpsclient dnsClient + httpsgoogle dnsClient + httpscf dnsClient } func newDNSHandler(cfg *conf) *dnsHandler { @@ -24,7 +26,8 @@ func newDNSHandler(cfg *conf) *dnsHandler { cfg: cfg, tcpclient: &dns.Client{Net: "tcp", Timeout: 8 * time.Second, UDPSize: 4096}, udpclient: &dns.Client{Net: "udp", Timeout: 5 * time.Second, UDPSize: 4096}, - httpsclient: &GoogleHTTPDns{}, + httpsgoogle: &GoogleHTTPDns{}, + httpscf: &CloudflareHTTPDns{}, } } @@ -79,13 +82,20 @@ func (h *dnsHandler) queryUpstream(r *dns.Msg, srv addr, ch chan *dns.Msg) { srv.Host, srv.Port) m, _, err = h.udpclient.Exchange(r, fmt.Sprintf("%s:%d", srv.Host, srv.Port)) - case "https": - info("query %s IN %s, forward to %s:%d through https", + case "https_google": + info("query %s IN %s, forward to %s:%d through google https", + r.Question[0].Name, + dns.TypeToString[r.Question[0].Qtype], + srv.Host, + srv.Port) + m, _, err = h.httpsgoogle.Exchange(r, fmt.Sprintf("%s:%d", srv.Host, srv.Port)) + case "https_cloudflare": + info("query %s IN %s, forward to %s:%d through cloudflare https", r.Question[0].Name, dns.TypeToString[r.Question[0].Qtype], srv.Host, srv.Port) - m, _, err = h.httpsclient.Exchange(r, fmt.Sprintf("%s:%d", srv.Host, srv.Port)) + m, _, err = h.httpscf.Exchange(r, srv.Host) default: // ignore } diff --git a/server.go b/server.go index ddd4ca9..fe4ad24 100644 --- a/server.go +++ b/server.go @@ -3,8 +3,9 @@ package main import ( "flag" "fmt" - "github.com/miekg/dns" "log" + + "github.com/miekg/dns" ) func main() {