defaults.go raw

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