Home | History | Annotate | Download | only in 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 	"math/rand"
      9 	"sort"
     10 )
     11 
     12 // reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
     13 // address addr suitable for rDNS (PTR) record lookup or an error if it fails
     14 // to parse the IP address.
     15 func reverseaddr(addr string) (arpa string, err error) {
     16 	ip := ParseIP(addr)
     17 	if ip == nil {
     18 		return "", &DNSError{Err: "unrecognized address", Name: addr}
     19 	}
     20 	if ip.To4() != nil {
     21 		return uitoa(uint(ip[15])) + "." + uitoa(uint(ip[14])) + "." + uitoa(uint(ip[13])) + "." + uitoa(uint(ip[12])) + ".in-addr.arpa.", nil
     22 	}
     23 	// Must be IPv6
     24 	buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
     25 	// Add it, in reverse, to the buffer
     26 	for i := len(ip) - 1; i >= 0; i-- {
     27 		v := ip[i]
     28 		buf = append(buf, hexDigit[v&0xF])
     29 		buf = append(buf, '.')
     30 		buf = append(buf, hexDigit[v>>4])
     31 		buf = append(buf, '.')
     32 	}
     33 	// Append "ip6.arpa." and return (buf already has the final .)
     34 	buf = append(buf, "ip6.arpa."...)
     35 	return string(buf), nil
     36 }
     37 
     38 // Find answer for name in dns message.
     39 // On return, if err == nil, addrs != nil.
     40 func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs []dnsRR, err error) {
     41 	addrs = make([]dnsRR, 0, len(dns.answer))
     42 
     43 	if dns.rcode == dnsRcodeNameError {
     44 		return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server}
     45 	}
     46 	if dns.rcode != dnsRcodeSuccess {
     47 		// None of the error codes make sense
     48 		// for the query we sent. If we didn't get
     49 		// a name error and we didn't get success,
     50 		// the server is behaving incorrectly or
     51 		// having temporary trouble.
     52 		err := &DNSError{Err: "server misbehaving", Name: name, Server: server}
     53 		if dns.rcode == dnsRcodeServerFailure {
     54 			err.IsTemporary = true
     55 		}
     56 		return "", nil, err
     57 	}
     58 
     59 	// Look for the name.
     60 	// Presotto says it's okay to assume that servers listed in
     61 	// /etc/resolv.conf are recursive resolvers.
     62 	// We asked for recursion, so it should have included
     63 	// all the answers we need in this one packet.
     64 Cname:
     65 	for cnameloop := 0; cnameloop < 10; cnameloop++ {
     66 		addrs = addrs[0:0]
     67 		for _, rr := range dns.answer {
     68 			if _, justHeader := rr.(*dnsRR_Header); justHeader {
     69 				// Corrupt record: we only have a
     70 				// header. That header might say it's
     71 				// of type qtype, but we don't
     72 				// actually have it. Skip.
     73 				continue
     74 			}
     75 			h := rr.Header()
     76 			if h.Class == dnsClassINET && equalASCIILabel(h.Name, name) {
     77 				switch h.Rrtype {
     78 				case qtype:
     79 					addrs = append(addrs, rr)
     80 				case dnsTypeCNAME:
     81 					// redirect to cname
     82 					name = rr.(*dnsRR_CNAME).Cname
     83 					continue Cname
     84 				}
     85 			}
     86 		}
     87 		if len(addrs) == 0 {
     88 			return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server}
     89 		}
     90 		return name, addrs, nil
     91 	}
     92 
     93 	return "", nil, &DNSError{Err: "too many redirects", Name: name, Server: server}
     94 }
     95 
     96 func equalASCIILabel(x, y string) bool {
     97 	if len(x) != len(y) {
     98 		return false
     99 	}
    100 	for i := 0; i < len(x); i++ {
    101 		a := x[i]
    102 		b := y[i]
    103 		if 'A' <= a && a <= 'Z' {
    104 			a += 0x20
    105 		}
    106 		if 'A' <= b && b <= 'Z' {
    107 			b += 0x20
    108 		}
    109 		if a != b {
    110 			return false
    111 		}
    112 	}
    113 	return true
    114 }
    115 
    116 // isDomainName checks if a string is a presentation-format domain name
    117 // (currently restricted to hostname-compatible "preferred name" LDH labels and
    118 // SRV-like "underscore labels"; see golang.org/issue/12421).
    119 func isDomainName(s string) bool {
    120 	// See RFC 1035, RFC 3696.
    121 	// Presentation format has dots before every label except the first, and the
    122 	// terminal empty label is optional here because we assume fully-qualified
    123 	// (absolute) input. We must therefore reserve space for the first and last
    124 	// labels' length octets in wire format, where they are necessary and the
    125 	// maximum total length is 255.
    126 	// So our _effective_ maximum is 253, but 254 is not rejected if the last
    127 	// character is a dot.
    128 	l := len(s)
    129 	if l == 0 || l > 254 || l == 254 && s[l-1] != '.' {
    130 		return false
    131 	}
    132 
    133 	last := byte('.')
    134 	ok := false // Ok once we've seen a letter.
    135 	partlen := 0
    136 	for i := 0; i < len(s); i++ {
    137 		c := s[i]
    138 		switch {
    139 		default:
    140 			return false
    141 		case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_':
    142 			ok = true
    143 			partlen++
    144 		case '0' <= c && c <= '9':
    145 			// fine
    146 			partlen++
    147 		case c == '-':
    148 			// Byte before dash cannot be dot.
    149 			if last == '.' {
    150 				return false
    151 			}
    152 			partlen++
    153 		case c == '.':
    154 			// Byte before dot cannot be dot, dash.
    155 			if last == '.' || last == '-' {
    156 				return false
    157 			}
    158 			if partlen > 63 || partlen == 0 {
    159 				return false
    160 			}
    161 			partlen = 0
    162 		}
    163 		last = c
    164 	}
    165 	if last == '-' || partlen > 63 {
    166 		return false
    167 	}
    168 
    169 	return ok
    170 }
    171 
    172 // absDomainName returns an absolute domain name which ends with a
    173 // trailing dot to match pure Go reverse resolver and all other lookup
    174 // routines.
    175 // See golang.org/issue/12189.
    176 // But we don't want to add dots for local names from /etc/hosts.
    177 // It's hard to tell so we settle on the heuristic that names without dots
    178 // (like "localhost" or "myhost") do not get trailing dots, but any other
    179 // names do.
    180 func absDomainName(b []byte) string {
    181 	hasDots := false
    182 	for _, x := range b {
    183 		if x == '.' {
    184 			hasDots = true
    185 			break
    186 		}
    187 	}
    188 	if hasDots && b[len(b)-1] != '.' {
    189 		b = append(b, '.')
    190 	}
    191 	return string(b)
    192 }
    193 
    194 // An SRV represents a single DNS SRV record.
    195 type SRV struct {
    196 	Target   string
    197 	Port     uint16
    198 	Priority uint16
    199 	Weight   uint16
    200 }
    201 
    202 // byPriorityWeight sorts SRV records by ascending priority and weight.
    203 type byPriorityWeight []*SRV
    204 
    205 func (s byPriorityWeight) Len() int { return len(s) }
    206 func (s byPriorityWeight) Less(i, j int) bool {
    207 	return s[i].Priority < s[j].Priority || (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight)
    208 }
    209 func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
    210 
    211 // shuffleByWeight shuffles SRV records by weight using the algorithm
    212 // described in RFC 2782.
    213 func (addrs byPriorityWeight) shuffleByWeight() {
    214 	sum := 0
    215 	for _, addr := range addrs {
    216 		sum += int(addr.Weight)
    217 	}
    218 	for sum > 0 && len(addrs) > 1 {
    219 		s := 0
    220 		n := rand.Intn(sum)
    221 		for i := range addrs {
    222 			s += int(addrs[i].Weight)
    223 			if s > n {
    224 				if i > 0 {
    225 					addrs[0], addrs[i] = addrs[i], addrs[0]
    226 				}
    227 				break
    228 			}
    229 		}
    230 		sum -= int(addrs[0].Weight)
    231 		addrs = addrs[1:]
    232 	}
    233 }
    234 
    235 // sort reorders SRV records as specified in RFC 2782.
    236 func (addrs byPriorityWeight) sort() {
    237 	sort.Sort(addrs)
    238 	i := 0
    239 	for j := 1; j < len(addrs); j++ {
    240 		if addrs[i].Priority != addrs[j].Priority {
    241 			addrs[i:j].shuffleByWeight()
    242 			i = j
    243 		}
    244 	}
    245 	addrs[i:].shuffleByWeight()
    246 }
    247 
    248 // An MX represents a single DNS MX record.
    249 type MX struct {
    250 	Host string
    251 	Pref uint16
    252 }
    253 
    254 // byPref implements sort.Interface to sort MX records by preference
    255 type byPref []*MX
    256 
    257 func (s byPref) Len() int           { return len(s) }
    258 func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref }
    259 func (s byPref) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
    260 
    261 // sort reorders MX records as specified in RFC 5321.
    262 func (s byPref) sort() {
    263 	for i := range s {
    264 		j := rand.Intn(i + 1)
    265 		s[i], s[j] = s[j], s[i]
    266 	}
    267 	sort.Sort(s)
    268 }
    269 
    270 // An NS represents a single DNS NS record.
    271 type NS struct {
    272 	Host string
    273 }
    274