Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cloudflare DNS support #41

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
A DNS client (stub resolver) implemented in Go for the [Google
DNS-over-HTTPS](https://developers.google.com/speed/public-dns/docs/dns-over-https).
It effectively encrypts all your DNS traffic. It also supports
[OpenResolve](https://www.openresolve.com/) by OpenDNS.
[OpenResolve](https://www.openresolve.com/) by OpenDNS and
[CloudFlare](https://developers.cloudflare.com/1.1.1.1/dns-over-https/request-structure/).

The ultimate goal for the project is to provide a secure, caching DNS client that
communicates with recursive DNS resolvers over encrypted channels only. For now,
Expand Down
101 changes: 101 additions & 0 deletions cfdns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/**
* dingo: a DNS caching proxy written in Go
* This file implements a Cloudflare DNS-over-HTTPS client
*
* Copyright (C) 2016 Pawel Foremski <[email protected]>
* Licensed under GNU GPL v3
*/

package main

import "fmt"
import "net/url"
import "time"
import "encoding/json"
import "math/rand"
import "strings"
import "flag"

/* API Docs https://developers.cloudflare.com/1.1.1.1/dns-over-https/request-structure/ */

type Cfdns struct {
workers *int
server *string
auto *bool
sni *string
host *string
edns *string
nopad *bool
}

/* command-line arguments */
func (r *Cfdns) Init() {
r.workers = flag.Int("cfdns:workers", 10,
"Cloudflare DNS: number of independent workers")
r.server = flag.String("cfdns:server", "1.1.1.1", /* or 1.0.0.1 */
"Cloudflare DNS: server address")
r.auto = flag.Bool("cfdns:auto", false,
"Cloudflare DNS: try to lookup the closest IPv4 server")
r.sni = flag.String("cfdns:sni", "dns.cloudflare.com",
"Cloudflare DNS: SNI string to send (should match server certificate)")
r.host = flag.String("cfdns:host", "dns.cloudflare.com",
"Cloudflare DNS: HTTP 'Host' header (real FQDN, encrypted in TLS)")
r.edns = flag.String("cfdns:edns", "",
"Cloudflare DNS: EDNS client subnet (set 0.0.0.0/0 to disable)")
r.nopad = flag.Bool("cfdns:nopad", false,
"Cloudflare DNS: disable random padding")
}

/**********************************************************************/

func (R *Cfdns) Start() {
if *R.workers <= 0 { return }

if *R.auto {
dbg(1, "resolving dns.cloudflare.com...")
r4 := R.resolve(NewHttps(*R.sni, false), *R.server, "dns.cloudflare.com", 1)
if r4.Status == 0 && len(r4.Answer) > 0 {
R.server = &r4.Answer[0].Data
}
}

dbg(1, "starting %d Cloudflare Public DNS client(s) querying server %s",
*R.workers, *R.server)
for i := 0; i < *R.workers; i++ { go R.worker(*R.server) }
}

func (R *Cfdns) worker(server string) {
var https = NewHttps(*R.sni, false)
for q := range qchan {
*q.rchan <- *R.resolve(https, server, q.Name, q.Type)
}
}

func (R *Cfdns) resolve(https *Https, server string, qname string, qtype int) *Reply {
r := Reply{ Status: -1 }
v := url.Values{}

/* prepare */
v.Set("ct", "application/dns-json") /* cfdns special: must set content type here */
v.Set("name", qname)
v.Set("type", fmt.Sprintf("%d", qtype))
if len(*R.edns) > 0 {
v.Set("edns_client_subnet", *R.edns)
}
if !*R.nopad {
v.Set("random_padding", strings.Repeat(string(65+rand.Intn(26)), rand.Intn(500)))
}

/* query */
buf, err := https.Get(server, *R.host, "/dns-query?" + v.Encode())
if err != nil { return &r }

/* parse */
r.Now = time.Now()
json.Unmarshal(buf, &r)

return &r
}

/* register module */
var _ = register("cfdns", new(Cfdns))
2 changes: 1 addition & 1 deletion gdns.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type Gdns struct {

/* command-line arguments */
func (r *Gdns) Init() {
r.workers = flag.Int("gdns:workers", 10,
r.workers = flag.Int("gdns:workers", 0,
"Google DNS: number of independent workers")
r.server = flag.String("gdns:server", "216.58.195.78",
"Google DNS: server address")
Expand Down