Skip to content

Commit

Permalink
HTTP/2 support thanks to @voidd (#19, #7)
Browse files Browse the repository at this point in the history
  • Loading branch information
pforemski committed Nov 16, 2016
1 parent 118eba9 commit 91bb369
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 23 deletions.
94 changes: 85 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,94 @@
# dingo

A caching DNS proxy for the [Google DNS-over-HTTPS](https://developers.google.com/speed/public-dns/docs/dns-over-https).
It effectively encrypts all your DNS traffic.
A DNS stub resolver 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.

For now, it resolves DNS queries over HTTPS/1.1, in a few independent threads (configurable).
Future plans include HTTP/2.0 and QUIC support, better caching, and support for other resolvers.
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,
it resolves DNS queries over HTTP/2 in independent threads. The plans for
future include better caching and support for QUIC.

You can start it as root using:
## Quick start

Download a pre-built binary for your platform from [the latest
release](https://github.com/pforemski/dingo/releases/latest) (or build your own binaries).

Run dingo as root on port 53. For example, on Linux:
```
$ sudo ./dingo-linux-amd64 -port=53
```

Update your DNS configuration. On Linux, edit your `/etc/resolv.conf` as root (remember to
make backup first), e.g.:
```
$ sudo sh -c "echo nameserver 127.0.0.1 > /etc/resolv.conf"
```

## Tuning dingo

You will probably want to change the default Google DNS-over-HTTPS server IP address, using the
`-gdns:server` option. First, resolve `dns.google.com` to IP address, which should give you the
server closest to you:
```
$ host dns.google.com
dns.google.com has address 216.58.209.174
dns.google.com has IPv6 address 2a00:1450:401b:800::200e
```

Next, pass it to dingo. If you prefer IPv6, enclose the address in brackets, e.g.:
```
$ sudo ./dingo-linux-amd64 -port=53 -gdns:server=[2a00:1450:401b:800::200e]
```

To see all options, run `dingo -h`:
```
Usage of dingo-linux-amd64:
-bind string
IP address to bind to (default "127.0.0.1")
-dbg int
debugging level (default 2)
-gdns:auto
Google DNS: try to lookup the closest IPv4 server
-gdns:edns string
Google DNS: EDNS client subnet (set 0.0.0.0/0 to disable)
-gdns:host string
Google DNS: HTTP 'Host' header (real FQDN, encrypted in TLS) (default "dns.google.com")
-gdns:nopad
Google DNS: disable random padding
-gdns:server string
Google DNS: server address (default "216.58.195.78")
-gdns:sni string
Google DNS: SNI string to send (should match server certificate) (default "www.google.com")
-gdns:workers int
Google DNS: number of independent workers (default 10)
-h1
use HTTP/1.1 transport
-odns:host string
OpenDNS: HTTP 'Host' header (real FQDN, encrypted in TLS) (default "api.openresolve.com")
-odns:server string
OpenDNS: web server address (default "67.215.70.81")
-odns:sni string
OpenDNS: TLS SNI string to send (unencrypted, must validate as server cert) (default "www.openresolve.com")
-odns:workers int
OpenDNS: number of independent workers
-port int
listen on port number (default 32000)
```

Finally, you will need to make dingo start in background each time you boot your machine. In Linux,
you might want to use the [GNU Screen](https://en.wikipedia.org/wiki/GNU_Screen), which can start
processes in background. For example, you might want to add the following line to your
`/etc/rc.local`:
```
root@localhost:~# go run ./dingo.go ./gdns.go -port=53
screen -dmS dingo /path/to/bin/dingo -port=53 -gdns:server=[2a00:1450:401b:800::200e]
```

Remember to prepare your Go environment and download all dependencies first.
## Author

Alternatively, use pre-built binaries in the `./release` sub-directory.
Pawel Foremski, [[email protected]](mailto:[email protected])

Note that you will need to update your `/etc/resolv.conf` file to use `dingo` as your system-wide resolver.
Find me on: [LinkedIn](https://www.linkedin.com/in/pforemski),
[Twitter](https://twitter.com/pforemski)
13 changes: 7 additions & 6 deletions dingo.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,16 @@ import "math/rand"

/* command-line arguments */
var (
bindip = flag.String("bind", "127.0.0.1", "IP address to bind to")
port = flag.Int("port", 32000, "listen on port number")
dbglvl = flag.Int("dbg", 2, "debugging level")
opt_bindip = flag.String("bind", "127.0.0.1", "IP address to bind to")
opt_port = flag.Int("port", 32000, "listen on port number")
opt_h1 = flag.Bool("h1", false, "use HTTPS/1.1 transport")
opt_dbglvl = flag.Int("dbg", 2, "debugging level")
)

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

/* logging stuff */
func dbg(lvl int, fmt string, v ...interface{}) { if (*dbglvl >= lvl) { dbglog.Printf(fmt, v...) } }
func dbg(lvl int, fmt string, v ...interface{}) { if (*opt_dbglvl >= lvl) { dbglog.Printf(fmt, v...) } }
func die(msg error) { dbglog.Fatalln("fatal error:", msg.Error()) }
var dbglog *log.Logger

Expand Down Expand Up @@ -165,15 +166,15 @@ func main() {
rcache = cache.New(24*time.Hour, 60*time.Second)

/* listen */
laddr := net.UDPAddr{ IP: net.ParseIP(*bindip), Port: *port }
laddr := net.UDPAddr{ IP: net.ParseIP(*opt_bindip), Port: *opt_port }
uc, err := net.ListenUDP("udp", &laddr)
if err != nil { die(err) }

/* start workers */
for _, mod := range Modules { mod.Start() }

/* accept new connections forever */
dbg(1, "dingo ver. 0.12 listening on %s UDP port %d", *bindip, laddr.Port)
dbg(1, "dingo ver. 0.13 listening on %s UDP port %d", *opt_bindip, laddr.Port)
var buf []byte
for {
buf = make([]byte, 1500)
Expand Down
4 changes: 3 additions & 1 deletion gdns.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ func (R *Gdns) Start() {

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

func (R *Gdns) resolve(https *Https, server string, qname string, qtype int) *Reply {
Expand Down
27 changes: 20 additions & 7 deletions https.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,34 @@ import "net/http"
import "io/ioutil"
import "crypto/tls"
import "errors"
import "golang.org/x/net/http2"

type Https struct {
client http.Client
transport http.Transport
tlscfg tls.Config
client http.Client
}

func NewHttps(sni string) *Https {
H := Https{}

/* basic setup */
/* TLS setup */
tlscfg := new(tls.Config)
tlscfg.ServerName = sni

/* HTTP transport */
var tr http.RoundTripper
if (*opt_h1) {
h1 := new(http.Transport)
h1.TLSClientConfig = tlscfg
tr = h1
} else {
h2 := new(http2.Transport)
h2.TLSClientConfig = tlscfg
tr = h2
}

/* HTTP client */
H.client.Timeout = time.Second * 10
H.client.Transport = &H.transport
H.transport.TLSClientConfig = &H.tlscfg
H.tlscfg.ServerName = sni
H.client.Transport = tr

return &H
}
Expand Down

0 comments on commit 91bb369

Please sign in to comment.