This repository has been archived by the owner on Nov 8, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
/
dns.go
140 lines (124 loc) · 3.09 KB
/
dns.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
134
135
136
137
138
139
140
//
// Perform a DNS query of a given name & type and return an array of
// maps with suitable results.
//
package main
import (
"errors"
"fmt"
"os"
"time"
"github.com/miekg/dns"
)
//
// StringToType is a map of DNS query-types, we only cover the few we
// care about.
//
var StringToType = map[string]uint16{
"A": dns.TypeA,
"AAAA": dns.TypeAAAA,
"CNAME": dns.TypeCNAME,
"MX": dns.TypeMX,
"NS": dns.TypeNS,
"PTR": dns.TypePTR,
"SOA": dns.TypeSOA,
"TXT": dns.TypeTXT,
}
var (
localm *dns.Msg
localc *dns.Client
conf *dns.ClientConfig
)
// lookup will perform a DNS query, using the nameservers in /etc/resolv.conf,
// and return an array of maps of the response
//
func lookup(name string, ltype string) ([]map[string]string, error) {
var results []map[string]string
var err error
conf, err = dns.ClientConfigFromFile("/etc/resolv.conf")
if err != nil || conf == nil {
fmt.Printf("Cannot initialize the local resolver: %s\n", err)
os.Exit(1)
}
localm = &dns.Msg{
MsgHdr: dns.MsgHdr{
RecursionDesired: true,
},
Question: make([]dns.Question, 1),
}
localc = &dns.Client{
ReadTimeout: 5 * time.Second,
}
r, err := localQuery(dns.Fqdn(name), ltype)
if err != nil || r == nil {
return nil, fmt.Errorf("Cannot retrieve the list of name servers for %s", name)
}
if r.Rcode == dns.RcodeNameError {
return nil, fmt.Errorf("no such domain %s", dns.Fqdn(name))
}
for _, ent := range r.Answer {
tmp := make(map[string]string)
tmp["name"] = ent.Header().Name
tmp["ttl"] = fmt.Sprintf("%d", ent.Header().Ttl)
//
// Lookup the value
//
switch ent.(type) {
case *dns.A:
a := ent.(*dns.A).A
tmp["type"] = "A"
tmp["value"] = fmt.Sprintf("%s", a)
case *dns.AAAA:
aaaa := ent.(*dns.AAAA).AAAA
tmp["type"] = "AAAA"
tmp["value"] = fmt.Sprintf("%s", aaaa)
case *dns.CNAME:
cname := ent.(*dns.CNAME).Target
tmp["type"] = "CNAME"
tmp["value"] = cname
case *dns.MX:
mxName := ent.(*dns.MX).Mx
mxPrio := ent.(*dns.MX).Preference
tmp["type"] = "MX"
tmp["value"] = fmt.Sprintf("%d\t%s", mxPrio, mxName)
case *dns.NS:
nameserver := ent.(*dns.NS).Ns
tmp["type"] = "NS"
tmp["value"] = nameserver
case *dns.PTR:
ptr := ent.(*dns.PTR).Ptr
tmp["type"] = "PTR"
tmp["value"] = ptr
case *dns.SOA:
serial := ent.(*dns.SOA).Serial
tmp["type"] = "SOA"
tmp["value"] = fmt.Sprintf("%d", serial)
case *dns.TXT:
txt := ent.(*dns.TXT).Txt
tmp["type"] = "TXT"
tmp["value"] = fmt.Sprintf("%s", txt[0])
}
results = append(results, tmp)
}
return results, nil
}
//
// Given a thing to lookup, and a type, do the necessary.
//
// e.g. "steve.fi" "txt"
//
func localQuery(qname string, lookupType string) (*dns.Msg, error) {
qtype := StringToType[lookupType]
localm.SetQuestion(qname, qtype)
for i := range conf.Servers {
server := conf.Servers[i]
r, _, err := localc.Exchange(localm, server+":"+conf.Port)
if err != nil {
return nil, err
}
if r == nil || r.Rcode == dns.RcodeNameError || r.Rcode == dns.RcodeSuccess {
return r, err
}
}
return nil, errors.New("No name server to answer the question")
}