Add option in client to allow DNS over TLS

We should allow the client to send requests to a recursive DNS server using a
encrypted connection. This is proposed on the document
draft-ietf-dprive-dns-over-tls [1].

For now we didn't allow the API user to change the TLS configuration (using
defaults). We also need to add the intelligence to fallback to normal DNS when
the TLS connection fails (as described in the draft).

See #297

[1] http://tools.ietf.org/html/draft-ietf-dprive-dns-over-tls-02
This commit is contained in:
Rafael Dantas Justo 2016-01-04 10:05:29 -02:00
parent 1756430e42
commit 0d866c924c
1 changed files with 36 additions and 4 deletions

View File

@ -4,6 +4,7 @@ package dns
import (
"bytes"
"crypto/tls"
"io"
"net"
"time"
@ -26,6 +27,7 @@ type Conn struct {
type Client struct {
Net string // if "tcp" a TCP query will be initiated, otherwise an UDP one (default is "" for UDP)
UDPSize uint16 // minimum receive buffer for UDP messages
TLS bool // enables TLS connection (port 853)
DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds
@ -152,11 +154,18 @@ func (c *Client) writeTimeout() time.Duration {
func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
var co *Conn
if c.Net == "" {
co, err = DialTimeout("udp", a, c.dialTimeout())
} else {
co, err = DialTimeout(c.Net, a, c.dialTimeout())
network := "udp"
if c.Net != "" {
network = c.Net
}
if c.TLS {
co, err = DialTimeoutWithTLS(network, a, c.dialTimeout())
} else {
co, err = DialTimeout(network, a, c.dialTimeout())
}
if err != nil {
return nil, 0, err
}
@ -383,3 +392,26 @@ func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, er
}
return conn, nil
}
// DialWithTLS connects to the address on the named network with TLS.
func DialWithTLS(network, address string) (conn *Conn, err error) {
conn = new(Conn)
conn.Conn, err = tls.Dial(network, address, nil)
if err != nil {
return nil, err
}
return conn, nil
}
// DialTimeoutWithTLS acts like DialWithTLS but takes a timeout.
func DialTimeoutWithTLS(network, address string, timeout time.Duration) (conn *Conn, err error) {
var dialer net.Dialer
dialer.Timeout = timeout
conn = new(Conn)
conn.Conn, err = tls.DialWithDialer(&dialer, network, address, nil)
if err != nil {
return nil, err
}
return conn, nil
}