1
2
3
4
5 package net
6
7 import (
8 "bytes"
9 "fmt"
10 "os"
11 "rand"
12 "sort"
13 )
14
15
16 type DNSError struct {
17 Error string
18 Name string
19 Server string
20 IsTimeout bool
21 }
22
23 func (e *DNSError) String() string {
24 if e == nil {
25 return "<nil>"
26 }
27 s := "lookup " + e.Name
28 if e.Server != "" {
29 s += " on " + e.Server
30 }
31 s += ": " + e.Error
32 return s
33 }
34
35 func (e *DNSError) Timeout() bool { return e.IsTimeout }
36 func (e *DNSError) Temporary() bool { return e.IsTimeout }
37
38 const noSuchHost = "no such host"
39
40
41
42
43 func reverseaddr(addr string) (arpa string, err os.Error) {
44 ip := ParseIP(addr)
45 if ip == nil {
46 return "", &DNSError{Error: "unrecognized address", Name: addr}
47 }
48 if ip.To4() != nil {
49 return fmt.Sprintf("%d.%d.%d.%d.in-addr.arpa.", ip[15], ip[14], ip[13], ip[12]), nil
50 }
51
52 var buf bytes.Buffer
53
54 for i := len(ip) - 1; i >= 0; i-- {
55 s := fmt.Sprintf("%02x", ip[i])
56 buf.WriteByte(s[1])
57 buf.WriteByte('.')
58 buf.WriteByte(s[0])
59 buf.WriteByte('.')
60 }
61
62 return buf.String() + "ip6.arpa.", nil
63 }
64
65
66
67 func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
68 addrs = make([]dnsRR, 0, len(dns.answer))
69
70 if dns.rcode == dnsRcodeNameError && dns.recursion_available {
71 return "", nil, &DNSError{Error: noSuchHost, Name: name}
72 }
73 if dns.rcode != dnsRcodeSuccess {
74
75
76
77
78 return "", nil, &DNSError{Error: "server misbehaving", Name: name, Server: server}
79 }
80
81
82
83
84
85
86 Cname:
87 for cnameloop := 0; cnameloop < 10; cnameloop++ {
88 addrs = addrs[0:0]
89 for _, rr := range dns.answer {
90 if _, justHeader := rr.(*dnsRR_Header); justHeader {
91
92
93
94
95 continue
96 }
97 h := rr.Header()
98 if h.Class == dnsClassINET && h.Name == name {
99 switch h.Rrtype {
100 case qtype:
101 addrs = append(addrs, rr)
102 case dnsTypeCNAME:
103
104 name = rr.(*dnsRR_CNAME).Cname
105 continue Cname
106 }
107 }
108 }
109 if len(addrs) == 0 {
110 return "", nil, &DNSError{Error: noSuchHost, Name: name, Server: server}
111 }
112 return name, addrs, nil
113 }
114
115 return "", nil, &DNSError{Error: "too many redirects", Name: name, Server: server}
116 }
117
118 func isDomainName(s string) bool {
119
120 if len(s) == 0 {
121 return false
122 }
123 if len(s) > 255 {
124 return false
125 }
126 if s[len(s)-1] != '.' {
127 s += "."
128 }
129
130 last := byte('.')
131 ok := false
132 partlen := 0
133 for i := 0; i < len(s); i++ {
134 c := s[i]
135 switch {
136 default:
137 return false
138 case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_':
139 ok = true
140 partlen++
141 case '0' <= c && c <= '9':
142
143 partlen++
144 case c == '-':
145
146 if last == '.' {
147 return false
148 }
149 partlen++
150 case c == '.':
151
152 if last == '.' || last == '-' {
153 return false
154 }
155 if partlen > 63 || partlen == 0 {
156 return false
157 }
158 partlen = 0
159 }
160 last = c
161 }
162
163 return ok
164 }
165
166
167 type SRV struct {
168 Target string
169 Port uint16
170 Priority uint16
171 Weight uint16
172 }
173
174
175 type byPriorityWeight []*SRV
176
177 func (s byPriorityWeight) Len() int { return len(s) }
178
179 func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
180
181 func (s byPriorityWeight) Less(i, j int) bool {
182 return s[i].Priority < s[j].Priority ||
183 (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight)
184 }
185
186
187
188 func (addrs byPriorityWeight) shuffleByWeight() {
189 sum := 0
190 for _, addr := range addrs {
191 sum += int(addr.Weight)
192 }
193 for sum > 0 && len(addrs) > 1 {
194 s := 0
195 n := rand.Intn(sum + 1)
196 for i := range addrs {
197 s += int(addrs[i].Weight)
198 if s >= n {
199 if i > 0 {
200 t := addrs[i]
201 copy(addrs[1:i+1], addrs[0:i])
202 addrs[0] = t
203 }
204 break
205 }
206 }
207 sum -= int(addrs[0].Weight)
208 addrs = addrs[1:]
209 }
210 }
211
212
213 func (addrs byPriorityWeight) sort() {
214 sort.Sort(addrs)
215 i := 0
216 for j := 1; j < len(addrs); j++ {
217 if addrs[i].Priority != addrs[j].Priority {
218 addrs[i:j].shuffleByWeight()
219 i = j
220 }
221 }
222 addrs[i:].shuffleByWeight()
223 }
224
225
226 type MX struct {
227 Host string
228 Pref uint16
229 }
230
231
232 type byPref []*MX
233
234 func (s byPref) Len() int { return len(s) }
235
236 func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref }
237
238 func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
239
240
241 func (s byPref) sort() {
242 for i := range s {
243 j := rand.Intn(i + 1)
244 s[i], s[j] = s[j], s[i]
245 }
246 sort.Sort(s)
247 }