-
-
Notifications
You must be signed in to change notification settings - Fork 18
/
dns_resolver.go
133 lines (110 loc) · 3.94 KB
/
dns_resolver.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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package truemail
import (
"context"
"net"
"sort"
"strings"
"time"
)
type gateway interface {
LookupHost(context.Context, string) ([]string, error)
LookupCNAME(context.Context, string) (string, error)
LookupMX(context.Context, string) ([]*net.MX, error)
LookupAddr(context.Context, string) ([]string, error)
}
// dnsResolver structure. Provides possibility to send DNS requests
// via system or custom DNS gateway
type dnsResolver struct {
connectionTimeout int
dnsServer string
gateway
}
// dnsResolver builder. Creates custom resolver with
// connection timeout and DNS gateway from configuration
func newDnsResolver(configuration *Configuration) *dnsResolver {
connectionTimeout, dnsServer := configuration.ConnectionTimeout, configuration.Dns
return &dnsResolver{
connectionTimeout: connectionTimeout,
dnsServer: dnsServer,
gateway: &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, networkProtocol, customDnsIpAddress string) (net.Conn, error) {
dialer := net.Dialer{Timeout: time.Duration(connectionTimeout) * time.Second}
if dnsServer != emptyString {
customDnsIpAddress = dnsServer
}
return dialer.DialContext(ctx, networkProtocol, customDnsIpAddress)
},
},
}
}
// dnsResolver methods
// Helper method. Removes last dot from dns hostname representation, example.com. => example.com
func (dnsResolver *dnsResolver) dnsNameToHostName(dnsName string) string {
return strings.TrimSuffix(dnsName, ".")
}
// Helper method. Filter out ipv6 ip addresses from mixed collection
func (dnsResolver *dnsResolver) rejectIp6Addresses(ipAddresses []string) (ip4Addresses []string) {
for _, ipAddress := range ipAddresses {
if matchRegex(ipAddress, regexIpAddressPattern) && ipAddress != "0.0.0.0" { // ipv6 can be converted to 0.0.0.0
ip4Addresses = append(ip4Addresses, ipAddress)
}
continue
}
return ip4Addresses
}
// Returns all A records by hostname
func (dnsResolver *dnsResolver) aRecords(hostName string) ([]string, error) {
ipAddresses, err := dnsResolver.gateway.LookupHost(context.Background(), hostName)
if err != nil {
return []string{}, wrapDnsError(err)
}
return dnsResolver.rejectIp6Addresses(ipAddresses), nil
}
// Returns first A record by hostname
func (dnsResolver *dnsResolver) aRecord(hostName string) (string, error) {
ipAddresses, err := dnsResolver.aRecords(hostName)
if err != nil {
return emptyString, err
}
return ipAddresses[0], nil
}
// Returns CNAME record by hostname for case when CNAME is different as hostname only
func (dnsResolver *dnsResolver) cnameRecord(hostName string) (resolvedHostName string, err error) {
cName, err := dnsResolver.gateway.LookupCNAME(context.Background(), hostName)
if err != nil {
return resolvedHostName, wrapDnsError(err)
}
cName = dnsResolver.dnsNameToHostName(cName)
if cName != hostName {
resolvedHostName = cName
}
return resolvedHostName, nil
}
// Returns MX records priorities and hostnames sorted by record priority
func (dnsResolver *dnsResolver) mxRecords(hostName string) (priorities []uint16, hostNames []string, err error) {
mxRecords, err := dnsResolver.gateway.LookupMX(context.Background(), hostName)
if err != nil {
return priorities, hostNames, wrapDnsError(err)
}
// sorting MX records by priority
sort.SliceStable(mxRecords, func(i, j int) bool {
return mxRecords[i].Pref < mxRecords[j].Pref
})
for _, mxRecord := range mxRecords {
priorities = append(priorities, mxRecord.Pref)
hostNames = append(hostNames, dnsResolver.dnsNameToHostName(mxRecord.Host))
}
return priorities, hostNames, nil
}
// Returns PTR records by host address
func (dnsResolver *dnsResolver) ptrRecords(hostAddress string) (hostNames []string, err error) {
hostNames, err = dnsResolver.gateway.LookupAddr(context.Background(), hostAddress)
if err != nil {
return hostNames, wrapDnsError(err)
}
for index, hostName := range hostNames {
hostNames[index] = dnsResolver.dnsNameToHostName(hostName)
}
return hostNames, nil
}