defaults.go (10913B)
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 // RFC 6891, Section 6.1.1 allows the OPT record to appear 150 // anywhere in the additional record section, but it's usually at 151 // the end so start there. 152 for i := len(dns.Extra) - 1; i >= 0; i-- { 153 if dns.Extra[i].Header().Rrtype == TypeOPT { 154 return dns.Extra[i].(*OPT) 155 } 156 } 157 return nil 158 } 159 160 // popEdns0 is like IsEdns0, but it removes the record from the message. 161 func (dns *Msg) popEdns0() *OPT { 162 // RFC 6891, Section 6.1.1 allows the OPT record to appear 163 // anywhere in the additional record section, but it's usually at 164 // the end so start there. 165 for i := len(dns.Extra) - 1; i >= 0; i-- { 166 if dns.Extra[i].Header().Rrtype == TypeOPT { 167 opt := dns.Extra[i].(*OPT) 168 dns.Extra = append(dns.Extra[:i], dns.Extra[i+1:]...) 169 return opt 170 } 171 } 172 return nil 173 } 174 175 // IsDomainName checks if s is a valid domain name, it returns the number of 176 // labels and true, when a domain name is valid. Note that non fully qualified 177 // domain name is considered valid, in this case the last label is counted in 178 // the number of labels. When false is returned the number of labels is not 179 // defined. Also note that this function is extremely liberal; almost any 180 // string is a valid domain name as the DNS is 8 bit protocol. It checks if each 181 // label fits in 63 characters and that the entire name will fit into the 255 182 // octet wire format limit. 183 func IsDomainName(s string) (labels int, ok bool) { 184 // XXX: The logic in this function was copied from packDomainName and 185 // should be kept in sync with that function. 186 187 const lenmsg = 256 188 189 if len(s) == 0 { // Ok, for instance when dealing with update RR without any rdata. 190 return 0, false 191 } 192 193 s = Fqdn(s) 194 195 // Each dot ends a segment of the name. Except for escaped dots (\.), which 196 // are normal dots. 197 198 var ( 199 off int 200 begin int 201 wasDot bool 202 ) 203 for i := 0; i < len(s); i++ { 204 switch s[i] { 205 case '\\': 206 if off+1 > lenmsg { 207 return labels, false 208 } 209 210 // check for \DDD 211 if isDDD(s[i+1:]) { 212 i += 3 213 begin += 3 214 } else { 215 i++ 216 begin++ 217 } 218 219 wasDot = false 220 case '.': 221 if i == 0 && len(s) > 1 { 222 // leading dots are not legal except for the root zone 223 return labels, false 224 } 225 226 if wasDot { 227 // two dots back to back is not legal 228 return labels, false 229 } 230 wasDot = true 231 232 labelLen := i - begin 233 if labelLen >= 1<<6 { // top two bits of length must be clear 234 return labels, false 235 } 236 237 // off can already (we're in a loop) be bigger than lenmsg 238 // this happens when a name isn't fully qualified 239 off += 1 + labelLen 240 if off > lenmsg { 241 return labels, false 242 } 243 244 labels++ 245 begin = i + 1 246 default: 247 wasDot = false 248 } 249 } 250 251 return labels, true 252 } 253 254 // IsSubDomain checks if child is indeed a child of the parent. If child and parent 255 // are the same domain true is returned as well. 256 func IsSubDomain(parent, child string) bool { 257 // Entire child is contained in parent 258 return CompareDomainName(parent, child) == CountLabel(parent) 259 } 260 261 // IsMsg sanity checks buf and returns an error if it isn't a valid DNS packet. 262 // The checking is performed on the binary payload. 263 func IsMsg(buf []byte) error { 264 // Header 265 if len(buf) < headerSize { 266 return errors.New("dns: bad message header") 267 } 268 // Header: Opcode 269 // TODO(miek): more checks here, e.g. check all header bits. 270 return nil 271 } 272 273 // IsFqdn checks if a domain name is fully qualified. 274 func IsFqdn(s string) bool { 275 // Check for (and remove) a trailing dot, returning if there isn't one. 276 if s == "" || s[len(s)-1] != '.' { 277 return false 278 } 279 s = s[:len(s)-1] 280 281 // If we don't have an escape sequence before the final dot, we know it's 282 // fully qualified and can return here. 283 if s == "" || s[len(s)-1] != '\\' { 284 return true 285 } 286 287 // Otherwise we have to check if the dot is escaped or not by checking if 288 // there are an odd or even number of escape sequences before the dot. 289 i := strings.LastIndexFunc(s, func(r rune) bool { 290 return r != '\\' 291 }) 292 return (len(s)-i)%2 != 0 293 } 294 295 // IsRRset checks if a set of RRs is a valid RRset as defined by RFC 2181. 296 // This means the RRs need to have the same type, name, and class. Returns true 297 // if the RR set is valid, otherwise false. 298 func IsRRset(rrset []RR) bool { 299 if len(rrset) == 0 { 300 return false 301 } 302 if len(rrset) == 1 { 303 return true 304 } 305 rrHeader := rrset[0].Header() 306 rrType := rrHeader.Rrtype 307 rrClass := rrHeader.Class 308 rrName := rrHeader.Name 309 310 for _, rr := range rrset[1:] { 311 curRRHeader := rr.Header() 312 if curRRHeader.Rrtype != rrType || curRRHeader.Class != rrClass || curRRHeader.Name != rrName { 313 // Mismatch between the records, so this is not a valid rrset for 314 //signing/verifying 315 return false 316 } 317 } 318 319 return true 320 } 321 322 // Fqdn return the fully qualified domain name from s. 323 // If s is already fully qualified, it behaves as the identity function. 324 func Fqdn(s string) string { 325 if IsFqdn(s) { 326 return s 327 } 328 return s + "." 329 } 330 331 // CanonicalName returns the domain name in canonical form. A name in canonical 332 // form is lowercase and fully qualified. See Section 6.2 in RFC 4034. 333 func CanonicalName(s string) string { 334 return strings.ToLower(Fqdn(s)) 335 } 336 337 // Copied from the official Go code. 338 339 // ReverseAddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP 340 // address suitable for reverse DNS (PTR) record lookups or an error if it fails 341 // to parse the IP address. 342 func ReverseAddr(addr string) (arpa string, err error) { 343 ip := net.ParseIP(addr) 344 if ip == nil { 345 return "", &Error{err: "unrecognized address: " + addr} 346 } 347 if v4 := ip.To4(); v4 != nil { 348 buf := make([]byte, 0, net.IPv4len*4+len("in-addr.arpa.")) 349 // Add it, in reverse, to the buffer 350 for i := len(v4) - 1; i >= 0; i-- { 351 buf = strconv.AppendInt(buf, int64(v4[i]), 10) 352 buf = append(buf, '.') 353 } 354 // Append "in-addr.arpa." and return (buf already has the final .) 355 buf = append(buf, "in-addr.arpa."...) 356 return string(buf), nil 357 } 358 // Must be IPv6 359 buf := make([]byte, 0, net.IPv6len*4+len("ip6.arpa.")) 360 // Add it, in reverse, to the buffer 361 for i := len(ip) - 1; i >= 0; i-- { 362 v := ip[i] 363 buf = append(buf, hexDigit[v&0xF], '.', hexDigit[v>>4], '.') 364 } 365 // Append "ip6.arpa." and return (buf already has the final .) 366 buf = append(buf, "ip6.arpa."...) 367 return string(buf), nil 368 } 369 370 // String returns the string representation for the type t. 371 func (t Type) String() string { 372 if t1, ok := TypeToString[uint16(t)]; ok { 373 return t1 374 } 375 return "TYPE" + strconv.Itoa(int(t)) 376 } 377 378 // String returns the string representation for the class c. 379 func (c Class) String() string { 380 if s, ok := ClassToString[uint16(c)]; ok { 381 // Only emit mnemonics when they are unambiguous, specially ANY is in both. 382 if _, ok := StringToType[s]; !ok { 383 return s 384 } 385 } 386 return "CLASS" + strconv.Itoa(int(c)) 387 } 388 389 // String returns the string representation for the name n. 390 func (n Name) String() string { 391 return sprintName(string(n)) 392 }