1 package dns
2
3 import (
4 "errors"
5 "net"
6 "strconv"
7 "strings"
8 )
9
10 const hexDigit = "0123456789abcdef"
11
12
13
14
15 func (dns *Msg) SetReply(request *Msg) *Msg {
16 dns.Id = request.Id
17 dns.Response = true
18 dns.Opcode = request.Opcode
19 if dns.Opcode == OpcodeQuery {
20 dns.RecursionDesired = request.RecursionDesired
21 dns.CheckingDisabled = request.CheckingDisabled
22 }
23 dns.Rcode = RcodeSuccess
24 if len(request.Question) > 0 {
25 dns.Question = []Question{request.Question[0]}
26 }
27 return dns
28 }
29
30
31
32
33 func (dns *Msg) SetQuestion(z string, t uint16) *Msg {
34 dns.Id = Id()
35 dns.RecursionDesired = true
36 dns.Question = make([]Question, 1)
37 dns.Question[0] = Question{z, t, ClassINET}
38 return dns
39 }
40
41
42
43
44 func (dns *Msg) SetNotify(z string) *Msg {
45 dns.Opcode = OpcodeNotify
46 dns.Authoritative = true
47 dns.Id = Id()
48 dns.Question = make([]Question, 1)
49 dns.Question[0] = Question{z, TypeSOA, ClassINET}
50 return dns
51 }
52
53
54 func (dns *Msg) SetRcode(request *Msg, rcode int) *Msg {
55 dns.SetReply(request)
56 dns.Rcode = rcode
57 return dns
58 }
59
60
61 func (dns *Msg) SetRcodeFormatError(request *Msg) *Msg {
62 dns.Rcode = RcodeFormatError
63 dns.Opcode = OpcodeQuery
64 dns.Response = true
65 dns.Authoritative = false
66 dns.Id = request.Id
67 return dns
68 }
69
70
71
72 func (dns *Msg) SetUpdate(z string) *Msg {
73 dns.Id = Id()
74 dns.Response = false
75 dns.Opcode = OpcodeUpdate
76 dns.Compress = false
77 dns.Question = make([]Question, 1)
78 dns.Question[0] = Question{z, TypeSOA, ClassINET}
79 return dns
80 }
81
82
83 func (dns *Msg) SetIxfr(z string, serial uint32, ns, mbox string) *Msg {
84 dns.Id = Id()
85 dns.Question = make([]Question, 1)
86 dns.Ns = make([]RR, 1)
87 s := new(SOA)
88 s.Hdr = RR_Header{z, TypeSOA, ClassINET, defaultTtl, 0}
89 s.Serial = serial
90 s.Ns = ns
91 s.Mbox = mbox
92 dns.Question[0] = Question{z, TypeIXFR, ClassINET}
93 dns.Ns[0] = s
94 return dns
95 }
96
97
98 func (dns *Msg) SetAxfr(z string) *Msg {
99 dns.Id = Id()
100 dns.Question = make([]Question, 1)
101 dns.Question[0] = Question{z, TypeAXFR, ClassINET}
102 return dns
103 }
104
105
106
107
108 func (dns *Msg) SetTsig(z, algo string, fudge uint16, timesigned int64) *Msg {
109 t := new(TSIG)
110 t.Hdr = RR_Header{z, TypeTSIG, ClassANY, 0, 0}
111 t.Algorithm = algo
112 t.Fudge = fudge
113 t.TimeSigned = uint64(timesigned)
114 t.OrigId = dns.Id
115 dns.Extra = append(dns.Extra, t)
116 return dns
117 }
118
119
120
121 func (dns *Msg) SetEdns0(udpsize uint16, do bool) *Msg {
122 e := new(OPT)
123 e.Hdr.Name = "."
124 e.Hdr.Rrtype = TypeOPT
125 e.SetUDPSize(udpsize)
126 if do {
127 e.SetDo()
128 }
129 dns.Extra = append(dns.Extra, e)
130 return dns
131 }
132
133
134
135 func (dns *Msg) IsTsig() *TSIG {
136 if len(dns.Extra) > 0 {
137 if dns.Extra[len(dns.Extra)-1].Header().Rrtype == TypeTSIG {
138 return dns.Extra[len(dns.Extra)-1].(*TSIG)
139 }
140 }
141 return nil
142 }
143
144
145
146
147 func (dns *Msg) IsEdns0() *OPT {
148
149
150
151 for i := len(dns.Extra) - 1; i >= 0; i-- {
152 if dns.Extra[i].Header().Rrtype == TypeOPT {
153 return dns.Extra[i].(*OPT)
154 }
155 }
156 return nil
157 }
158
159
160 func (dns *Msg) popEdns0() *OPT {
161
162
163
164 for i := len(dns.Extra) - 1; i >= 0; i-- {
165 if dns.Extra[i].Header().Rrtype == TypeOPT {
166 opt := dns.Extra[i].(*OPT)
167 dns.Extra = append(dns.Extra[:i], dns.Extra[i+1:]...)
168 return opt
169 }
170 }
171 return nil
172 }
173
174
175
176
177
178
179
180
181
182 func IsDomainName(s string) (labels int, ok bool) {
183
184
185
186 const lenmsg = 256
187
188 if len(s) == 0 {
189 return 0, false
190 }
191
192 s = Fqdn(s)
193
194
195
196
197 var (
198 off int
199 begin int
200 wasDot bool
201 )
202 for i := 0; i < len(s); i++ {
203 switch s[i] {
204 case '\\':
205 if off+1 > lenmsg {
206 return labels, false
207 }
208
209
210 if isDDD(s[i+1:]) {
211 i += 3
212 begin += 3
213 } else {
214 i++
215 begin++
216 }
217
218 wasDot = false
219 case '.':
220 if i == 0 && len(s) > 1 {
221
222 return labels, false
223 }
224
225 if wasDot {
226
227 return labels, false
228 }
229 wasDot = true
230
231 labelLen := i - begin
232 if labelLen >= 1<<6 {
233 return labels, false
234 }
235
236
237
238 off += 1 + labelLen
239 if off > lenmsg {
240 return labels, false
241 }
242
243 labels++
244 begin = i + 1
245 default:
246 wasDot = false
247 }
248 }
249
250 return labels, true
251 }
252
253
254
255 func IsSubDomain(parent, child string) bool {
256
257 return CompareDomainName(parent, child) == CountLabel(parent)
258 }
259
260
261
262 func IsMsg(buf []byte) error {
263
264 if len(buf) < headerSize {
265 return errors.New("dns: bad message header")
266 }
267
268
269 return nil
270 }
271
272
273 func IsFqdn(s string) bool {
274
275 if s == "" || s[len(s)-1] != '.' {
276 return false
277 }
278 s = s[:len(s)-1]
279
280
281
282 if s == "" || s[len(s)-1] != '\\' {
283 return true
284 }
285
286
287
288 i := strings.LastIndexFunc(s, func(r rune) bool {
289 return r != '\\'
290 })
291 return (len(s)-i)%2 != 0
292 }
293
294
295
296 func IsRRset(rrset []RR) bool {
297 if len(rrset) == 0 {
298 return false
299 }
300
301 baseH := rrset[0].Header()
302 for _, rr := range rrset[1:] {
303 curH := rr.Header()
304 if curH.Rrtype != baseH.Rrtype || curH.Class != baseH.Class || curH.Name != baseH.Name {
305
306
307 return false
308 }
309 }
310
311 return true
312 }
313
314
315
316 func Fqdn(s string) string {
317 if IsFqdn(s) {
318 return s
319 }
320 return s + "."
321 }
322
323
324
325
326 func CanonicalName(s string) string {
327 return strings.Map(func(r rune) rune {
328 if r >= 'A' && r <= 'Z' {
329 r += 'a' - 'A'
330 }
331 return r
332 }, Fqdn(s))
333 }
334
335
336
337
338
339
340 func ReverseAddr(addr string) (arpa string, err error) {
341 ip := net.ParseIP(addr)
342 if ip == nil {
343 return "", &Error{err: "unrecognized address: " + addr}
344 }
345 if v4 := ip.To4(); v4 != nil {
346 buf := make([]byte, 0, net.IPv4len*4+len("in-addr.arpa."))
347
348 for i := len(v4) - 1; i >= 0; i-- {
349 buf = strconv.AppendInt(buf, int64(v4[i]), 10)
350 buf = append(buf, '.')
351 }
352
353 buf = append(buf, "in-addr.arpa."...)
354 return string(buf), nil
355 }
356
357 buf := make([]byte, 0, net.IPv6len*4+len("ip6.arpa."))
358
359 for i := len(ip) - 1; i >= 0; i-- {
360 v := ip[i]
361 buf = append(buf, hexDigit[v&0xF], '.', hexDigit[v>>4], '.')
362 }
363
364 buf = append(buf, "ip6.arpa."...)
365 return string(buf), nil
366 }
367
368
369 func (t Type) String() string {
370 if t1, ok := TypeToString[uint16(t)]; ok {
371 return t1
372 }
373 return "TYPE" + strconv.Itoa(int(t))
374 }
375
376
377 func (c Class) String() string {
378 if s, ok := ClassToString[uint16(c)]; ok {
379
380 if _, ok := StringToType[s]; !ok {
381 return s
382 }
383 }
384 return "CLASS" + strconv.Itoa(int(c))
385 }
386
387
388 func (n Name) String() string {
389 return sprintName(string(n))
390 }
391
View as plain text