OLD | NEW |
1 // Copyright 2011 The Go Authors. All rights reserved. | 1 // Copyright 2011 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package net | 5 package net |
6 | 6 |
7 import ( | 7 import ( |
| 8 "errors" |
8 "os" | 9 "os" |
9 ) | 10 ) |
10 | 11 |
11 func query(filename, query string, bufSize int) (res []string, err os.Error) { | 12 func query(filename, query string, bufSize int) (res []string, err error) { |
12 file, err := os.OpenFile(filename, os.O_RDWR, 0) | 13 file, err := os.OpenFile(filename, os.O_RDWR, 0) |
13 if err != nil { | 14 if err != nil { |
14 return | 15 return |
15 } | 16 } |
16 defer file.Close() | 17 defer file.Close() |
17 | 18 |
18 _, err = file.WriteString(query) | 19 _, err = file.WriteString(query) |
19 if err != nil { | 20 if err != nil { |
20 return | 21 return |
21 } | 22 } |
22 _, err = file.Seek(0, 0) | 23 _, err = file.Seek(0, 0) |
23 if err != nil { | 24 if err != nil { |
24 return | 25 return |
25 } | 26 } |
26 buf := make([]byte, bufSize) | 27 buf := make([]byte, bufSize) |
27 for { | 28 for { |
28 n, _ := file.Read(buf) | 29 n, _ := file.Read(buf) |
29 if n <= 0 { | 30 if n <= 0 { |
30 break | 31 break |
31 } | 32 } |
32 res = append(res, string(buf[:n])) | 33 res = append(res, string(buf[:n])) |
33 } | 34 } |
34 return | 35 return |
35 } | 36 } |
36 | 37 |
37 func queryCS(net, host, service string) (res []string, err os.Error) { | 38 func queryCS(net, host, service string) (res []string, err error) { |
38 switch net { | 39 switch net { |
39 case "tcp4", "tcp6": | 40 case "tcp4", "tcp6": |
40 net = "tcp" | 41 net = "tcp" |
41 case "udp4", "udp6": | 42 case "udp4", "udp6": |
42 net = "udp" | 43 net = "udp" |
43 } | 44 } |
44 if host == "" { | 45 if host == "" { |
45 host = "*" | 46 host = "*" |
46 } | 47 } |
47 return query("/net/cs", net+"!"+host+"!"+service, 128) | 48 return query("/net/cs", net+"!"+host+"!"+service, 128) |
48 } | 49 } |
49 | 50 |
50 func queryCS1(net string, ip IP, port int) (clone, dest string, err os.Error) { | 51 func queryCS1(net string, ip IP, port int) (clone, dest string, err error) { |
51 ips := "*" | 52 ips := "*" |
52 if len(ip) != 0 && !ip.IsUnspecified() { | 53 if len(ip) != 0 && !ip.IsUnspecified() { |
53 ips = ip.String() | 54 ips = ip.String() |
54 } | 55 } |
55 lines, err := queryCS(net, ips, itoa(port)) | 56 lines, err := queryCS(net, ips, itoa(port)) |
56 if err != nil { | 57 if err != nil { |
57 return | 58 return |
58 } | 59 } |
59 f := getFields(lines[0]) | 60 f := getFields(lines[0]) |
60 if len(f) < 2 { | 61 if len(f) < 2 { |
61 » » return "", "", os.NewError("net: bad response from ndb/cs") | 62 » » return "", "", errors.New("net: bad response from ndb/cs") |
62 } | 63 } |
63 clone, dest = f[0], f[1] | 64 clone, dest = f[0], f[1] |
64 return | 65 return |
65 } | 66 } |
66 | 67 |
67 func queryDNS(addr string, typ string) (res []string, err os.Error) { | 68 func queryDNS(addr string, typ string) (res []string, err error) { |
68 return query("/net/dns", addr+" "+typ, 1024) | 69 return query("/net/dns", addr+" "+typ, 1024) |
69 } | 70 } |
70 | 71 |
71 // LookupHost looks up the given host using the local resolver. | 72 // LookupHost looks up the given host using the local resolver. |
72 // It returns an array of that host's addresses. | 73 // It returns an array of that host's addresses. |
73 func LookupHost(host string) (addrs []string, err os.Error) { | 74 func LookupHost(host string) (addrs []string, err error) { |
74 // Use /net/cs insead of /net/dns because cs knows about | 75 // Use /net/cs insead of /net/dns because cs knows about |
75 // host names in local network (e.g. from /lib/ndb/local) | 76 // host names in local network (e.g. from /lib/ndb/local) |
76 lines, err := queryCS("tcp", host, "1") | 77 lines, err := queryCS("tcp", host, "1") |
77 if err != nil { | 78 if err != nil { |
78 return | 79 return |
79 } | 80 } |
80 for _, line := range lines { | 81 for _, line := range lines { |
81 f := getFields(line) | 82 f := getFields(line) |
82 if len(f) < 2 { | 83 if len(f) < 2 { |
83 continue | 84 continue |
84 } | 85 } |
85 addr := f[1] | 86 addr := f[1] |
86 if i := byteIndex(addr, '!'); i >= 0 { | 87 if i := byteIndex(addr, '!'); i >= 0 { |
87 addr = addr[:i] // remove port | 88 addr = addr[:i] // remove port |
88 } | 89 } |
89 if ParseIP(addr) == nil { | 90 if ParseIP(addr) == nil { |
90 continue | 91 continue |
91 } | 92 } |
92 addrs = append(addrs, addr) | 93 addrs = append(addrs, addr) |
93 } | 94 } |
94 return | 95 return |
95 } | 96 } |
96 | 97 |
97 // LookupIP looks up host using the local resolver. | 98 // LookupIP looks up host using the local resolver. |
98 // It returns an array of that host's IPv4 and IPv6 addresses. | 99 // It returns an array of that host's IPv4 and IPv6 addresses. |
99 func LookupIP(host string) (ips []IP, err os.Error) { | 100 func LookupIP(host string) (ips []IP, err error) { |
100 addrs, err := LookupHost(host) | 101 addrs, err := LookupHost(host) |
101 if err != nil { | 102 if err != nil { |
102 return | 103 return |
103 } | 104 } |
104 for _, addr := range addrs { | 105 for _, addr := range addrs { |
105 if ip := ParseIP(addr); ip != nil { | 106 if ip := ParseIP(addr); ip != nil { |
106 ips = append(ips, ip) | 107 ips = append(ips, ip) |
107 } | 108 } |
108 } | 109 } |
109 return | 110 return |
110 } | 111 } |
111 | 112 |
112 // LookupPort looks up the port for the given network and service. | 113 // LookupPort looks up the port for the given network and service. |
113 func LookupPort(network, service string) (port int, err os.Error) { | 114 func LookupPort(network, service string) (port int, err error) { |
114 switch network { | 115 switch network { |
115 case "tcp4", "tcp6": | 116 case "tcp4", "tcp6": |
116 network = "tcp" | 117 network = "tcp" |
117 case "udp4", "udp6": | 118 case "udp4", "udp6": |
118 network = "udp" | 119 network = "udp" |
119 } | 120 } |
120 lines, err := queryCS(network, "127.0.0.1", service) | 121 lines, err := queryCS(network, "127.0.0.1", service) |
121 if err != nil { | 122 if err != nil { |
122 return | 123 return |
123 } | 124 } |
(...skipping 12 matching lines...) Expand all Loading... |
136 if n, _, ok := dtoi(s, 0); ok { | 137 if n, _, ok := dtoi(s, 0); ok { |
137 return n, nil | 138 return n, nil |
138 } | 139 } |
139 return 0, unknownPortError | 140 return 0, unknownPortError |
140 } | 141 } |
141 | 142 |
142 // LookupCNAME returns the canonical DNS host for the given name. | 143 // LookupCNAME returns the canonical DNS host for the given name. |
143 // Callers that do not care about the canonical name can call | 144 // Callers that do not care about the canonical name can call |
144 // LookupHost or LookupIP directly; both take care of resolving | 145 // LookupHost or LookupIP directly; both take care of resolving |
145 // the canonical name as part of the lookup. | 146 // the canonical name as part of the lookup. |
146 func LookupCNAME(name string) (cname string, err os.Error) { | 147 func LookupCNAME(name string) (cname string, err error) { |
147 lines, err := queryDNS(name, "cname") | 148 lines, err := queryDNS(name, "cname") |
148 if err != nil { | 149 if err != nil { |
149 return | 150 return |
150 } | 151 } |
151 if len(lines) > 0 { | 152 if len(lines) > 0 { |
152 if f := getFields(lines[0]); len(f) >= 3 { | 153 if f := getFields(lines[0]); len(f) >= 3 { |
153 return f[2] + ".", nil | 154 return f[2] + ".", nil |
154 } | 155 } |
155 } | 156 } |
156 » return "", os.NewError("net: bad response from ndb/dns") | 157 » return "", errors.New("net: bad response from ndb/dns") |
157 } | 158 } |
158 | 159 |
159 // LookupSRV tries to resolve an SRV query of the given service, | 160 // LookupSRV tries to resolve an SRV query of the given service, |
160 // protocol, and domain name. The proto is "tcp" or "udp". | 161 // protocol, and domain name. The proto is "tcp" or "udp". |
161 // The returned records are sorted by priority and randomized | 162 // The returned records are sorted by priority and randomized |
162 // by weight within a priority. | 163 // by weight within a priority. |
163 // | 164 // |
164 // LookupSRV constructs the DNS name to look up following RFC 2782. | 165 // LookupSRV constructs the DNS name to look up following RFC 2782. |
165 // That is, it looks up _service._proto.name. To accommodate services | 166 // That is, it looks up _service._proto.name. To accommodate services |
166 // publishing SRV records under non-standard names, if both service | 167 // publishing SRV records under non-standard names, if both service |
167 // and proto are empty strings, LookupSRV looks up name directly. | 168 // and proto are empty strings, LookupSRV looks up name directly. |
168 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.
Error) { | 169 func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
or) { |
169 var target string | 170 var target string |
170 if service == "" && proto == "" { | 171 if service == "" && proto == "" { |
171 target = name | 172 target = name |
172 } else { | 173 } else { |
173 target = "_" + service + "._" + proto + "." + name | 174 target = "_" + service + "._" + proto + "." + name |
174 } | 175 } |
175 lines, err := queryDNS(target, "srv") | 176 lines, err := queryDNS(target, "srv") |
176 if err != nil { | 177 if err != nil { |
177 return | 178 return |
178 } | 179 } |
179 for _, line := range lines { | 180 for _, line := range lines { |
180 f := getFields(line) | 181 f := getFields(line) |
181 if len(f) < 6 { | 182 if len(f) < 6 { |
182 continue | 183 continue |
183 } | 184 } |
184 port, _, portOk := dtoi(f[2], 0) | 185 port, _, portOk := dtoi(f[2], 0) |
185 priority, _, priorityOk := dtoi(f[3], 0) | 186 priority, _, priorityOk := dtoi(f[3], 0) |
186 weight, _, weightOk := dtoi(f[4], 0) | 187 weight, _, weightOk := dtoi(f[4], 0) |
187 if !(portOk && priorityOk && weightOk) { | 188 if !(portOk && priorityOk && weightOk) { |
188 continue | 189 continue |
189 } | 190 } |
190 addrs = append(addrs, &SRV{f[5], uint16(port), uint16(priority),
uint16(weight)}) | 191 addrs = append(addrs, &SRV{f[5], uint16(port), uint16(priority),
uint16(weight)}) |
191 cname = f[0] | 192 cname = f[0] |
192 } | 193 } |
193 byPriorityWeight(addrs).sort() | 194 byPriorityWeight(addrs).sort() |
194 return | 195 return |
195 } | 196 } |
196 | 197 |
197 // LookupMX returns the DNS MX records for the given domain name sorted by prefe
rence. | 198 // LookupMX returns the DNS MX records for the given domain name sorted by prefe
rence. |
198 func LookupMX(name string) (mx []*MX, err os.Error) { | 199 func LookupMX(name string) (mx []*MX, err error) { |
199 lines, err := queryDNS(name, "mx") | 200 lines, err := queryDNS(name, "mx") |
200 if err != nil { | 201 if err != nil { |
201 return | 202 return |
202 } | 203 } |
203 for _, line := range lines { | 204 for _, line := range lines { |
204 f := getFields(line) | 205 f := getFields(line) |
205 if len(f) < 4 { | 206 if len(f) < 4 { |
206 continue | 207 continue |
207 } | 208 } |
208 if pref, _, ok := dtoi(f[2], 0); ok { | 209 if pref, _, ok := dtoi(f[2], 0); ok { |
209 mx = append(mx, &MX{f[3], uint16(pref)}) | 210 mx = append(mx, &MX{f[3], uint16(pref)}) |
210 } | 211 } |
211 } | 212 } |
212 byPref(mx).sort() | 213 byPref(mx).sort() |
213 return | 214 return |
214 } | 215 } |
215 | 216 |
216 // LookupTXT returns the DNS TXT records for the given domain name. | 217 // LookupTXT returns the DNS TXT records for the given domain name. |
217 func LookupTXT(name string) (txt []string, err os.Error) { | 218 func LookupTXT(name string) (txt []string, err error) { |
218 lines, err := queryDNS(name, "txt") | 219 lines, err := queryDNS(name, "txt") |
219 if err != nil { | 220 if err != nil { |
220 return | 221 return |
221 } | 222 } |
222 for _, line := range lines { | 223 for _, line := range lines { |
223 if i := byteIndex(line, '\t'); i >= 0 { | 224 if i := byteIndex(line, '\t'); i >= 0 { |
224 txt = append(txt, line[i+1:]) | 225 txt = append(txt, line[i+1:]) |
225 } | 226 } |
226 } | 227 } |
227 return | 228 return |
228 } | 229 } |
229 | 230 |
230 // LookupAddr performs a reverse lookup for the given address, returning a list | 231 // LookupAddr performs a reverse lookup for the given address, returning a list |
231 // of names mapping to that address. | 232 // of names mapping to that address. |
232 func LookupAddr(addr string) (name []string, err os.Error) { | 233 func LookupAddr(addr string) (name []string, err error) { |
233 arpa, err := reverseaddr(addr) | 234 arpa, err := reverseaddr(addr) |
234 if err != nil { | 235 if err != nil { |
235 return | 236 return |
236 } | 237 } |
237 lines, err := queryDNS(arpa, "ptr") | 238 lines, err := queryDNS(arpa, "ptr") |
238 if err != nil { | 239 if err != nil { |
239 return | 240 return |
240 } | 241 } |
241 for _, line := range lines { | 242 for _, line := range lines { |
242 f := getFields(line) | 243 f := getFields(line) |
243 if len(f) < 3 { | 244 if len(f) < 3 { |
244 continue | 245 continue |
245 } | 246 } |
246 name = append(name, f[2]) | 247 name = append(name, f[2]) |
247 } | 248 } |
248 return | 249 return |
249 } | 250 } |
OLD | NEW |