OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / miekg / dns / defaults.go
1 package dns
2
3 import (
4         "errors"
5         "net"
6         "strconv"
7         "strings"
8 )
9
10 const hexDigit = "0123456789abcdef"
11
12 // Everything is assumed in ClassINET.
13
14 // SetReply creates a reply message from a request message.
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 // Copy rd bit
21                 dns.CheckingDisabled = request.CheckingDisabled // Copy cd bit
22         }
23         dns.Rcode = RcodeSuccess
24         if len(request.Question) > 0 {
25                 dns.Question = make([]Question, 1)
26                 dns.Question[0] = request.Question[0]
27         }
28         return dns
29 }
30
31 // SetQuestion creates a question message, it sets the Question
32 // section, generates an Id and sets the RecursionDesired (RD)
33 // bit to true.
34 func (dns *Msg) SetQuestion(z string, t uint16) *Msg {
35         dns.Id = Id()
36         dns.RecursionDesired = true
37         dns.Question = make([]Question, 1)
38         dns.Question[0] = Question{z, t, ClassINET}
39         return dns
40 }
41
42 // SetNotify creates a notify message, it sets the Question
43 // section, generates an Id and sets the Authoritative (AA)
44 // bit to true.
45 func (dns *Msg) SetNotify(z string) *Msg {
46         dns.Opcode = OpcodeNotify
47         dns.Authoritative = true
48         dns.Id = Id()
49         dns.Question = make([]Question, 1)
50         dns.Question[0] = Question{z, TypeSOA, ClassINET}
51         return dns
52 }
53
54 // SetRcode creates an error message suitable for the request.
55 func (dns *Msg) SetRcode(request *Msg, rcode int) *Msg {
56         dns.SetReply(request)
57         dns.Rcode = rcode
58         return dns
59 }
60
61 // SetRcodeFormatError creates a message with FormError set.
62 func (dns *Msg) SetRcodeFormatError(request *Msg) *Msg {
63         dns.Rcode = RcodeFormatError
64         dns.Opcode = OpcodeQuery
65         dns.Response = true
66         dns.Authoritative = false
67         dns.Id = request.Id
68         return dns
69 }
70
71 // SetUpdate makes the message a dynamic update message. It
72 // sets the ZONE section to: z, TypeSOA, ClassINET.
73 func (dns *Msg) SetUpdate(z string) *Msg {
74         dns.Id = Id()
75         dns.Response = false
76         dns.Opcode = OpcodeUpdate
77         dns.Compress = false // BIND9 cannot handle compression
78         dns.Question = make([]Question, 1)
79         dns.Question[0] = Question{z, TypeSOA, ClassINET}
80         return dns
81 }
82
83 // SetIxfr creates message for requesting an IXFR.
84 func (dns *Msg) SetIxfr(z string, serial uint32, ns, mbox string) *Msg {
85         dns.Id = Id()
86         dns.Question = make([]Question, 1)
87         dns.Ns = make([]RR, 1)
88         s := new(SOA)
89         s.Hdr = RR_Header{z, TypeSOA, ClassINET, defaultTtl, 0}
90         s.Serial = serial
91         s.Ns = ns
92         s.Mbox = mbox
93         dns.Question[0] = Question{z, TypeIXFR, ClassINET}
94         dns.Ns[0] = s
95         return dns
96 }
97
98 // SetAxfr creates message for requesting an AXFR.
99 func (dns *Msg) SetAxfr(z string) *Msg {
100         dns.Id = Id()
101         dns.Question = make([]Question, 1)
102         dns.Question[0] = Question{z, TypeAXFR, ClassINET}
103         return dns
104 }
105
106 // SetTsig appends a TSIG RR to the message.
107 // This is only a skeleton TSIG RR that is added as the last RR in the
108 // additional section. The Tsig is calculated when the message is being send.
109 func (dns *Msg) SetTsig(z, algo string, fudge uint16, timesigned int64) *Msg {
110         t := new(TSIG)
111         t.Hdr = RR_Header{z, TypeTSIG, ClassANY, 0, 0}
112         t.Algorithm = algo
113         t.Fudge = fudge
114         t.TimeSigned = uint64(timesigned)
115         t.OrigId = dns.Id
116         dns.Extra = append(dns.Extra, t)
117         return dns
118 }
119
120 // SetEdns0 appends a EDNS0 OPT RR to the message.
121 // TSIG should always the last RR in a message.
122 func (dns *Msg) SetEdns0(udpsize uint16, do bool) *Msg {
123         e := new(OPT)
124         e.Hdr.Name = "."
125         e.Hdr.Rrtype = TypeOPT
126         e.SetUDPSize(udpsize)
127         if do {
128                 e.SetDo()
129         }
130         dns.Extra = append(dns.Extra, e)
131         return dns
132 }
133
134 // IsTsig checks if the message has a TSIG record as the last record
135 // in the additional section. It returns the TSIG record found or nil.
136 func (dns *Msg) IsTsig() *TSIG {
137         if len(dns.Extra) > 0 {
138                 if dns.Extra[len(dns.Extra)-1].Header().Rrtype == TypeTSIG {
139                         return dns.Extra[len(dns.Extra)-1].(*TSIG)
140                 }
141         }
142         return nil
143 }
144
145 // IsEdns0 checks if the message has a EDNS0 (OPT) record, any EDNS0
146 // record in the additional section will do. It returns the OPT record
147 // found or nil.
148 func (dns *Msg) IsEdns0() *OPT {
149         // EDNS0 is at the end of the additional section, start there.
150         // We might want to change this to *only* look at the last two
151         // records. So we see TSIG and/or OPT - this a slightly bigger
152         // change though.
153         for i := len(dns.Extra) - 1; i >= 0; i-- {
154                 if dns.Extra[i].Header().Rrtype == TypeOPT {
155                         return dns.Extra[i].(*OPT)
156                 }
157         }
158         return nil
159 }
160
161 // IsDomainName checks if s is a valid domain name, it returns the number of
162 // labels and true, when a domain name is valid.  Note that non fully qualified
163 // domain name is considered valid, in this case the last label is counted in
164 // the number of labels.  When false is returned the number of labels is not
165 // defined.  Also note that this function is extremely liberal; almost any
166 // string is a valid domain name as the DNS is 8 bit protocol. It checks if each
167 // label fits in 63 characters and that the entire name will fit into the 255
168 // octet wire format limit.
169 func IsDomainName(s string) (labels int, ok bool) {
170         // XXX: The logic in this function was copied from packDomainName and
171         // should be kept in sync with that function.
172
173         const lenmsg = 256
174
175         if len(s) == 0 { // Ok, for instance when dealing with update RR without any rdata.
176                 return 0, false
177         }
178
179         s = Fqdn(s)
180
181         // Each dot ends a segment of the name. Except for escaped dots (\.), which
182         // are normal dots.
183
184         var (
185                 off    int
186                 begin  int
187                 wasDot bool
188         )
189         for i := 0; i < len(s); i++ {
190                 switch s[i] {
191                 case '\\':
192                         if off+1 > lenmsg {
193                                 return labels, false
194                         }
195
196                         // check for \DDD
197                         if i+3 < len(s) && isDigit(s[i+1]) && isDigit(s[i+2]) && isDigit(s[i+3]) {
198                                 i += 3
199                                 begin += 3
200                         } else {
201                                 i++
202                                 begin++
203                         }
204
205                         wasDot = false
206                 case '.':
207                         if wasDot {
208                                 // two dots back to back is not legal
209                                 return labels, false
210                         }
211                         wasDot = true
212
213                         labelLen := i - begin
214                         if labelLen >= 1<<6 { // top two bits of length must be clear
215                                 return labels, false
216                         }
217
218                         // off can already (we're in a loop) be bigger than lenmsg
219                         // this happens when a name isn't fully qualified
220                         off += 1 + labelLen
221                         if off > lenmsg {
222                                 return labels, false
223                         }
224
225                         labels++
226                         begin = i + 1
227                 default:
228                         wasDot = false
229                 }
230         }
231
232         return labels, true
233 }
234
235 // IsSubDomain checks if child is indeed a child of the parent. If child and parent
236 // are the same domain true is returned as well.
237 func IsSubDomain(parent, child string) bool {
238         // Entire child is contained in parent
239         return CompareDomainName(parent, child) == CountLabel(parent)
240 }
241
242 // IsMsg sanity checks buf and returns an error if it isn't a valid DNS packet.
243 // The checking is performed on the binary payload.
244 func IsMsg(buf []byte) error {
245         // Header
246         if len(buf) < headerSize {
247                 return errors.New("dns: bad message header")
248         }
249         // Header: Opcode
250         // TODO(miek): more checks here, e.g. check all header bits.
251         return nil
252 }
253
254 // IsFqdn checks if a domain name is fully qualified.
255 func IsFqdn(s string) bool {
256         s2 := strings.TrimSuffix(s, ".")
257         if s == s2 {
258                 return false
259         }
260
261         i := strings.LastIndexFunc(s2, func(r rune) bool {
262                 return r != '\\'
263         })
264
265         // Test whether we have an even number of escape sequences before
266         // the dot or none.
267         return (len(s2)-i)%2 != 0
268 }
269
270 // IsRRset checks if a set of RRs is a valid RRset as defined by RFC 2181.
271 // This means the RRs need to have the same type, name, and class. Returns true
272 // if the RR set is valid, otherwise false.
273 func IsRRset(rrset []RR) bool {
274         if len(rrset) == 0 {
275                 return false
276         }
277         if len(rrset) == 1 {
278                 return true
279         }
280         rrHeader := rrset[0].Header()
281         rrType := rrHeader.Rrtype
282         rrClass := rrHeader.Class
283         rrName := rrHeader.Name
284
285         for _, rr := range rrset[1:] {
286                 curRRHeader := rr.Header()
287                 if curRRHeader.Rrtype != rrType || curRRHeader.Class != rrClass || curRRHeader.Name != rrName {
288                         // Mismatch between the records, so this is not a valid rrset for
289                         //signing/verifying
290                         return false
291                 }
292         }
293
294         return true
295 }
296
297 // Fqdn return the fully qualified domain name from s.
298 // If s is already fully qualified, it behaves as the identity function.
299 func Fqdn(s string) string {
300         if IsFqdn(s) {
301                 return s
302         }
303         return s + "."
304 }
305
306 // Copied from the official Go code.
307
308 // ReverseAddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
309 // address suitable for reverse DNS (PTR) record lookups or an error if it fails
310 // to parse the IP address.
311 func ReverseAddr(addr string) (arpa string, err error) {
312         ip := net.ParseIP(addr)
313         if ip == nil {
314                 return "", &Error{err: "unrecognized address: " + addr}
315         }
316         if v4 := ip.To4(); v4 != nil {
317                 buf := make([]byte, 0, net.IPv4len*4+len("in-addr.arpa."))
318                 // Add it, in reverse, to the buffer
319                 for i := len(v4) - 1; i >= 0; i-- {
320                         buf = strconv.AppendInt(buf, int64(v4[i]), 10)
321                         buf = append(buf, '.')
322                 }
323                 // Append "in-addr.arpa." and return (buf already has the final .)
324                 buf = append(buf, "in-addr.arpa."...)
325                 return string(buf), nil
326         }
327         // Must be IPv6
328         buf := make([]byte, 0, net.IPv6len*4+len("ip6.arpa."))
329         // Add it, in reverse, to the buffer
330         for i := len(ip) - 1; i >= 0; i-- {
331                 v := ip[i]
332                 buf = append(buf, hexDigit[v&0xF])
333                 buf = append(buf, '.')
334                 buf = append(buf, hexDigit[v>>4])
335                 buf = append(buf, '.')
336         }
337         // Append "ip6.arpa." and return (buf already has the final .)
338         buf = append(buf, "ip6.arpa."...)
339         return string(buf), nil
340 }
341
342 // String returns the string representation for the type t.
343 func (t Type) String() string {
344         if t1, ok := TypeToString[uint16(t)]; ok {
345                 return t1
346         }
347         return "TYPE" + strconv.Itoa(int(t))
348 }
349
350 // String returns the string representation for the class c.
351 func (c Class) String() string {
352         if s, ok := ClassToString[uint16(c)]; ok {
353                 // Only emit mnemonics when they are unambiguous, specically ANY is in both.
354                 if _, ok := StringToType[s]; !ok {
355                         return s
356                 }
357         }
358         return "CLASS" + strconv.Itoa(int(c))
359 }
360
361 // String returns the string representation for the name n.
362 func (n Name) String() string {
363         return sprintName(string(n))
364 }