/
dnsutil.go
152 lines (137 loc) · 3.38 KB
/
dnsutil.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
141
142
143
144
145
146
147
148
149
150
151
152
package dnsproxy
import (
"math/rand"
"strings"
"time"
"github.com/miekg/dns"
)
// IsSuccessfulResponse gets whether the msg is a successful response
func IsSuccessfulResponse(msg *dns.Msg) bool {
return msg.Rcode == dns.RcodeSuccess
}
// IsEmptyResponse gets whether the msg is an empty response
// which has no answer, no ns and no extra
func IsEmptyResponse(msg *dns.Msg) bool {
return len(msg.Answer) == 0 && len(msg.Ns) == 0 && len(msg.Extra) == 0
}
// GotAnswer gets whether do get the answer,
// whose RRtype is same as Qtype or
// the NS RR is a SOA
func GotAnswer(msg *dns.Msg) bool {
for _, an := range msg.Answer {
if an == nil {
continue
}
if an.Header().Rrtype == msg.Question[0].Qtype {
// answer type: A, AAAA, TXT, PTR
return true
}
}
if len(msg.Answer) == 0 && len(msg.Ns) == 1 && msg.Ns[0] != nil &&
msg.Ns[0].Header().Rrtype == dns.TypeSOA {
// SOA with no answer
return true
}
return false
}
// FindExtras gets a string array from msg's extra rr
func FindExtras(msg *dns.Msg) []string {
x := []string{}
for _, ad := range msg.Extra {
h := ad.Header()
if h.Rrtype == dns.TypeA {
if a, ok := ad.(*dns.A); ok { // assert *A instead of A
x = append(x, a.A.String())
}
}
}
return x
}
// FindNS gets a string array from msg's ns rr,
// which has no answer.
func FindNS(msg *dns.Msg) ([]string, bool) {
if len(msg.Answer) > 0 {
return nil, false
}
ns := make([]string, 0, len(msg.Ns))
for _, n := range msg.Ns {
if n.Header().Rrtype == dns.TypeNS {
if x, ok := n.(*dns.NS); ok {
ns = append(ns, x.Ns)
}
}
}
return ns, true
}
// FindNSExtras gets a copied message from msg,
// the copy's answer is msg's extra
func FindNSExtras(msg *dns.Msg) (*dns.Msg, bool) {
if msg.Authoritative && len(msg.Extra) > 0 {
_msg := msg.Copy()
_msg.Answer = make([]dns.RR, len(msg.Extra))
copy(_msg.Answer, msg.Extra)
return _msg, true
}
return nil, false
}
// FindCname gets the final cname in the msg.
func FindCname(msg *dns.Msg) (string, bool) {
// msg may has more than one CNAME
// NOTE: should return only one CNAME
x := make(map[string]string)
for _, an := range append(msg.Answer, msg.Ns...) {
if an == nil || an.Header().Rrtype != dns.TypeCNAME {
continue
}
if cname, ok := an.(*dns.CNAME); ok {
x[cname.Hdr.Name] = cname.Target
}
}
if len(x) == 0 {
return "", false
}
queryName := msg.Question[0].Name
for {
if _, ok := x[queryName]; ok {
queryName = x[queryName]
} else {
return queryName, true
}
}
}
// NewQuery creates a new dns query messge
func NewQuery(names []string) *dns.Msg {
qus := make([]dns.Question, len(names))
for i, name := range names {
if strings.HasSuffix(name, "in-addr.arpa.") {
qus[i] = dns.Question{
Name: name,
Qtype: dns.TypePTR,
Qclass: dns.ClassINET,
}
continue
}
qus[i] = dns.Question{
Name: name,
Qtype: dns.TypeA,
Qclass: dns.ClassINET,
}
}
msg := new(dns.Msg)
msg.Question = qus
msg.RecursionDesired = true
rand.Seed(time.Now().Unix())
msg.Id = uint16(rand.Uint32())
return msg
}
// NewResponse creates a new dns response message with the gived rcode
func NewResponse(rcode int) *dns.Msg {
msg := new(dns.Msg)
msg.Response = true
msg.RecursionDesired = true
msg.Rcode = rcode
return msg
}
func getQuetion(msg *dns.Msg) string {
return strings.ToLower(dns.TypeToString[msg.Question[0].Qtype]) + "." + msg.Question[0].Name
}