forked from folbricht/routedns
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dnsclient.go
72 lines (62 loc) · 1.68 KB
/
dnsclient.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package rdns
import (
"crypto/tls"
"net"
"github.com/miekg/dns"
"github.com/sirupsen/logrus"
)
// DNSClient represents a simple DNS resolver for UDP or TCP.
type DNSClient struct {
id string
endpoint string
net string
pipeline *Pipeline
// Pipeline also provides operation metrics.
}
type DNSClientOptions struct {
// Local IP to use for outbound connections. If nil, a local address is chosen.
LocalAddr net.IP
}
var _ Resolver = &DNSClient{}
// NewDNSClient returns a new instance of DNSClient which is a plain DNS resolver
// that supports pipelining over a single connection.
func NewDNSClient(id, endpoint, network string, opt DNSClientOptions) (*DNSClient, error) {
if err := validEndpoint(endpoint); err != nil {
return nil, err
}
// Use a custom dialer if a local address was provided
var dialer *net.Dialer
if opt.LocalAddr != nil {
switch network {
case "tcp":
dialer = &net.Dialer{LocalAddr: &net.TCPAddr{IP: opt.LocalAddr}}
case "udp":
dialer = &net.Dialer{LocalAddr: &net.UDPAddr{IP: opt.LocalAddr}}
}
}
client := &dns.Client{
Net: network,
Dialer: dialer,
TLSConfig: &tls.Config{},
UDPSize: 4096,
}
return &DNSClient{
id: id,
net: network,
endpoint: endpoint,
pipeline: NewPipeline(id, endpoint, client),
}, nil
}
// Resolve a DNS query.
func (d *DNSClient) Resolve(q *dns.Msg, ci ClientInfo) (*dns.Msg, error) {
logger(d.id, q, ci).WithFields(logrus.Fields{
"resolver": d.endpoint,
"protocol": d.net,
}).Debug("querying upstream resolver")
// Remove padding before sending over the wire in plain
stripPadding(q)
return d.pipeline.Resolve(q)
}
func (d *DNSClient) String() string {
return d.id
}