10 const hexDigit = "0123456789abcdef"
12 // Everything is assumed in ClassINET.
14 // SetReply creates a reply message from a request message.
15 func (dns *Msg) SetReply(request *Msg) *Msg {
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
23 dns.Rcode = RcodeSuccess
24 if len(request.Question) > 0 {
25 dns.Question = make([]Question, 1)
26 dns.Question[0] = request.Question[0]
31 // SetQuestion creates a question message, it sets the Question
32 // section, generates an Id and sets the RecursionDesired (RD)
34 func (dns *Msg) SetQuestion(z string, t uint16) *Msg {
36 dns.RecursionDesired = true
37 dns.Question = make([]Question, 1)
38 dns.Question[0] = Question{z, t, ClassINET}
42 // SetNotify creates a notify message, it sets the Question
43 // section, generates an Id and sets the Authoritative (AA)
45 func (dns *Msg) SetNotify(z string) *Msg {
46 dns.Opcode = OpcodeNotify
47 dns.Authoritative = true
49 dns.Question = make([]Question, 1)
50 dns.Question[0] = Question{z, TypeSOA, ClassINET}
54 // SetRcode creates an error message suitable for the request.
55 func (dns *Msg) SetRcode(request *Msg, rcode int) *Msg {
61 // SetRcodeFormatError creates a message with FormError set.
62 func (dns *Msg) SetRcodeFormatError(request *Msg) *Msg {
63 dns.Rcode = RcodeFormatError
64 dns.Opcode = OpcodeQuery
66 dns.Authoritative = false
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 {
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}
83 // SetIxfr creates message for requesting an IXFR.
84 func (dns *Msg) SetIxfr(z string, serial uint32, ns, mbox string) *Msg {
86 dns.Question = make([]Question, 1)
87 dns.Ns = make([]RR, 1)
89 s.Hdr = RR_Header{z, TypeSOA, ClassINET, defaultTtl, 0}
93 dns.Question[0] = Question{z, TypeIXFR, ClassINET}
98 // SetAxfr creates message for requesting an AXFR.
99 func (dns *Msg) SetAxfr(z string) *Msg {
101 dns.Question = make([]Question, 1)
102 dns.Question[0] = Question{z, TypeAXFR, ClassINET}
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 {
111 t.Hdr = RR_Header{z, TypeTSIG, ClassANY, 0, 0}
114 t.TimeSigned = uint64(timesigned)
116 dns.Extra = append(dns.Extra, t)
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 {
125 e.Hdr.Rrtype = TypeOPT
126 e.SetUDPSize(udpsize)
130 dns.Extra = append(dns.Extra, e)
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)
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
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
153 for i := len(dns.Extra) - 1; i >= 0; i-- {
154 if dns.Extra[i].Header().Rrtype == TypeOPT {
155 return dns.Extra[i].(*OPT)
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.
175 if len(s) == 0 { // Ok, for instance when dealing with update RR without any rdata.
181 // Each dot ends a segment of the name. Except for escaped dots (\.), which
189 for i := 0; i < len(s); i++ {
197 if i+3 < len(s) && isDigit(s[i+1]) && isDigit(s[i+2]) && isDigit(s[i+3]) {
208 // two dots back to back is not legal
213 labelLen := i - begin
214 if labelLen >= 1<<6 { // top two bits of length must be clear
218 // off can already (we're in a loop) be bigger than lenmsg
219 // this happens when a name isn't fully qualified
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)
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 {
246 if len(buf) < headerSize {
247 return errors.New("dns: bad message header")
250 // TODO(miek): more checks here, e.g. check all header bits.
254 // IsFqdn checks if a domain name is fully qualified.
255 func IsFqdn(s string) bool {
256 s2 := strings.TrimSuffix(s, ".")
261 i := strings.LastIndexFunc(s2, func(r rune) bool {
265 // Test whether we have an even number of escape sequences before
267 return (len(s2)-i)%2 != 0
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 {
280 rrHeader := rrset[0].Header()
281 rrType := rrHeader.Rrtype
282 rrClass := rrHeader.Class
283 rrName := rrHeader.Name
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
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 {
306 // Copied from the official Go code.
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)
314 return "", &Error{err: "unrecognized address: " + addr}
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, '.')
323 // Append "in-addr.arpa." and return (buf already has the final .)
324 buf = append(buf, "in-addr.arpa."...)
325 return string(buf), nil
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-- {
332 buf = append(buf, hexDigit[v&0xF])
333 buf = append(buf, '.')
334 buf = append(buf, hexDigit[v>>4])
335 buf = append(buf, '.')
337 // Append "ip6.arpa." and return (buf already has the final .)
338 buf = append(buf, "ip6.arpa."...)
339 return string(buf), nil
342 // String returns the string representation for the type t.
343 func (t Type) String() string {
344 if t1, ok := TypeToString[uint16(t)]; ok {
347 return "TYPE" + strconv.Itoa(int(t))
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 {
358 return "CLASS" + strconv.Itoa(int(c))
361 // String returns the string representation for the name n.
362 func (n Name) String() string {
363 return sprintName(string(n))