...

Source file src/net/dnsclient.go

Documentation: net

		 1  // Copyright 2009 The Go Authors. All rights reserved.
		 2  // Use of this source code is governed by a BSD-style
		 3  // license that can be found in the LICENSE file.
		 4  
		 5  package net
		 6  
		 7  import (
		 8  	"internal/itoa"
		 9  	"sort"
		10  
		11  	"golang.org/x/net/dns/dnsmessage"
		12  )
		13  
		14  // provided by runtime
		15  func fastrand() uint32
		16  
		17  func randInt() int {
		18  	x, y := fastrand(), fastrand()		// 32-bit halves
		19  	u := uint(x)<<31 ^ uint(int32(y)) // full uint, even on 64-bit systems; avoid 32-bit shift on 32-bit systems
		20  	i := int(u >> 1)									// clear sign bit, even on 32-bit systems
		21  	return i
		22  }
		23  
		24  func randIntn(n int) int {
		25  	return randInt() % n
		26  }
		27  
		28  // reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
		29  // address addr suitable for rDNS (PTR) record lookup or an error if it fails
		30  // to parse the IP address.
		31  func reverseaddr(addr string) (arpa string, err error) {
		32  	ip := ParseIP(addr)
		33  	if ip == nil {
		34  		return "", &DNSError{Err: "unrecognized address", Name: addr}
		35  	}
		36  	if ip.To4() != nil {
		37  		return itoa.Uitoa(uint(ip[15])) + "." + itoa.Uitoa(uint(ip[14])) + "." + itoa.Uitoa(uint(ip[13])) + "." + itoa.Uitoa(uint(ip[12])) + ".in-addr.arpa.", nil
		38  	}
		39  	// Must be IPv6
		40  	buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
		41  	// Add it, in reverse, to the buffer
		42  	for i := len(ip) - 1; i >= 0; i-- {
		43  		v := ip[i]
		44  		buf = append(buf, hexDigit[v&0xF],
		45  			'.',
		46  			hexDigit[v>>4],
		47  			'.')
		48  	}
		49  	// Append "ip6.arpa." and return (buf already has the final .)
		50  	buf = append(buf, "ip6.arpa."...)
		51  	return string(buf), nil
		52  }
		53  
		54  func equalASCIIName(x, y dnsmessage.Name) bool {
		55  	if x.Length != y.Length {
		56  		return false
		57  	}
		58  	for i := 0; i < int(x.Length); i++ {
		59  		a := x.Data[i]
		60  		b := y.Data[i]
		61  		if 'A' <= a && a <= 'Z' {
		62  			a += 0x20
		63  		}
		64  		if 'A' <= b && b <= 'Z' {
		65  			b += 0x20
		66  		}
		67  		if a != b {
		68  			return false
		69  		}
		70  	}
		71  	return true
		72  }
		73  
		74  // isDomainName checks if a string is a presentation-format domain name
		75  // (currently restricted to hostname-compatible "preferred name" LDH labels and
		76  // SRV-like "underscore labels"; see golang.org/issue/12421).
		77  func isDomainName(s string) bool {
		78  	// See RFC 1035, RFC 3696.
		79  	// Presentation format has dots before every label except the first, and the
		80  	// terminal empty label is optional here because we assume fully-qualified
		81  	// (absolute) input. We must therefore reserve space for the first and last
		82  	// labels' length octets in wire format, where they are necessary and the
		83  	// maximum total length is 255.
		84  	// So our _effective_ maximum is 253, but 254 is not rejected if the last
		85  	// character is a dot.
		86  	l := len(s)
		87  	if l == 0 || l > 254 || l == 254 && s[l-1] != '.' {
		88  		return false
		89  	}
		90  
		91  	last := byte('.')
		92  	nonNumeric := false // true once we've seen a letter or hyphen
		93  	partlen := 0
		94  	for i := 0; i < len(s); i++ {
		95  		c := s[i]
		96  		switch {
		97  		default:
		98  			return false
		99  		case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_':
	 100  			nonNumeric = true
	 101  			partlen++
	 102  		case '0' <= c && c <= '9':
	 103  			// fine
	 104  			partlen++
	 105  		case c == '-':
	 106  			// Byte before dash cannot be dot.
	 107  			if last == '.' {
	 108  				return false
	 109  			}
	 110  			partlen++
	 111  			nonNumeric = true
	 112  		case c == '.':
	 113  			// Byte before dot cannot be dot, dash.
	 114  			if last == '.' || last == '-' {
	 115  				return false
	 116  			}
	 117  			if partlen > 63 || partlen == 0 {
	 118  				return false
	 119  			}
	 120  			partlen = 0
	 121  		}
	 122  		last = c
	 123  	}
	 124  	if last == '-' || partlen > 63 {
	 125  		return false
	 126  	}
	 127  
	 128  	return nonNumeric
	 129  }
	 130  
	 131  // absDomainName returns an absolute domain name which ends with a
	 132  // trailing dot to match pure Go reverse resolver and all other lookup
	 133  // routines.
	 134  // See golang.org/issue/12189.
	 135  // But we don't want to add dots for local names from /etc/hosts.
	 136  // It's hard to tell so we settle on the heuristic that names without dots
	 137  // (like "localhost" or "myhost") do not get trailing dots, but any other
	 138  // names do.
	 139  func absDomainName(b []byte) string {
	 140  	hasDots := false
	 141  	for _, x := range b {
	 142  		if x == '.' {
	 143  			hasDots = true
	 144  			break
	 145  		}
	 146  	}
	 147  	if hasDots && b[len(b)-1] != '.' {
	 148  		b = append(b, '.')
	 149  	}
	 150  	return string(b)
	 151  }
	 152  
	 153  // An SRV represents a single DNS SRV record.
	 154  type SRV struct {
	 155  	Target	 string
	 156  	Port		 uint16
	 157  	Priority uint16
	 158  	Weight	 uint16
	 159  }
	 160  
	 161  // byPriorityWeight sorts SRV records by ascending priority and weight.
	 162  type byPriorityWeight []*SRV
	 163  
	 164  func (s byPriorityWeight) Len() int { return len(s) }
	 165  func (s byPriorityWeight) Less(i, j int) bool {
	 166  	return s[i].Priority < s[j].Priority || (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight)
	 167  }
	 168  func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
	 169  
	 170  // shuffleByWeight shuffles SRV records by weight using the algorithm
	 171  // described in RFC 2782.
	 172  func (addrs byPriorityWeight) shuffleByWeight() {
	 173  	sum := 0
	 174  	for _, addr := range addrs {
	 175  		sum += int(addr.Weight)
	 176  	}
	 177  	for sum > 0 && len(addrs) > 1 {
	 178  		s := 0
	 179  		n := randIntn(sum)
	 180  		for i := range addrs {
	 181  			s += int(addrs[i].Weight)
	 182  			if s > n {
	 183  				if i > 0 {
	 184  					addrs[0], addrs[i] = addrs[i], addrs[0]
	 185  				}
	 186  				break
	 187  			}
	 188  		}
	 189  		sum -= int(addrs[0].Weight)
	 190  		addrs = addrs[1:]
	 191  	}
	 192  }
	 193  
	 194  // sort reorders SRV records as specified in RFC 2782.
	 195  func (addrs byPriorityWeight) sort() {
	 196  	sort.Sort(addrs)
	 197  	i := 0
	 198  	for j := 1; j < len(addrs); j++ {
	 199  		if addrs[i].Priority != addrs[j].Priority {
	 200  			addrs[i:j].shuffleByWeight()
	 201  			i = j
	 202  		}
	 203  	}
	 204  	addrs[i:].shuffleByWeight()
	 205  }
	 206  
	 207  // An MX represents a single DNS MX record.
	 208  type MX struct {
	 209  	Host string
	 210  	Pref uint16
	 211  }
	 212  
	 213  // byPref implements sort.Interface to sort MX records by preference
	 214  type byPref []*MX
	 215  
	 216  func (s byPref) Len() int					 { return len(s) }
	 217  func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref }
	 218  func (s byPref) Swap(i, j int)			{ s[i], s[j] = s[j], s[i] }
	 219  
	 220  // sort reorders MX records as specified in RFC 5321.
	 221  func (s byPref) sort() {
	 222  	for i := range s {
	 223  		j := randIntn(i + 1)
	 224  		s[i], s[j] = s[j], s[i]
	 225  	}
	 226  	sort.Sort(s)
	 227  }
	 228  
	 229  // An NS represents a single DNS NS record.
	 230  type NS struct {
	 231  	Host string
	 232  }
	 233  

View as plain text