Source file
src/net/lookup_plan9.go
1
2
3
4
5 package net
6
7 import (
8 "context"
9 "errors"
10 "internal/bytealg"
11 "internal/itoa"
12 "io"
13 "os"
14 )
15
16
17
18
19 const cgoAvailable = true
20
21 func query(ctx context.Context, filename, query string, bufSize int) (addrs []string, err error) {
22 queryAddrs := func() (addrs []string, err error) {
23 file, err := os.OpenFile(filename, os.O_RDWR, 0)
24 if err != nil {
25 return nil, err
26 }
27 defer file.Close()
28
29 _, err = file.Seek(0, io.SeekStart)
30 if err != nil {
31 return nil, err
32 }
33 _, err = file.WriteString(query)
34 if err != nil {
35 return nil, err
36 }
37 _, err = file.Seek(0, io.SeekStart)
38 if err != nil {
39 return nil, err
40 }
41 buf := make([]byte, bufSize)
42 for {
43 n, _ := file.Read(buf)
44 if n <= 0 {
45 break
46 }
47 addrs = append(addrs, string(buf[:n]))
48 }
49 return addrs, nil
50 }
51
52 type ret struct {
53 addrs []string
54 err error
55 }
56
57 ch := make(chan ret, 1)
58 go func() {
59 addrs, err := queryAddrs()
60 ch <- ret{addrs: addrs, err: err}
61 }()
62
63 select {
64 case r := <-ch:
65 return r.addrs, r.err
66 case <-ctx.Done():
67 return nil, &DNSError{
68 Name: query,
69 Err: ctx.Err().Error(),
70 IsTimeout: ctx.Err() == context.DeadlineExceeded,
71 }
72 }
73 }
74
75 func queryCS(ctx context.Context, net, host, service string) (res []string, err error) {
76 switch net {
77 case "tcp4", "tcp6":
78 net = "tcp"
79 case "udp4", "udp6":
80 net = "udp"
81 }
82 if host == "" {
83 host = "*"
84 }
85 return query(ctx, netdir+"/cs", net+"!"+host+"!"+service, 128)
86 }
87
88 func queryCS1(ctx context.Context, net string, ip IP, port int) (clone, dest string, err error) {
89 ips := "*"
90 if len(ip) != 0 && !ip.IsUnspecified() {
91 ips = ip.String()
92 }
93 lines, err := queryCS(ctx, net, ips, itoa.Itoa(port))
94 if err != nil {
95 return
96 }
97 f := getFields(lines[0])
98 if len(f) < 2 {
99 return "", "", errors.New("bad response from ndb/cs")
100 }
101 clone, dest = f[0], f[1]
102 return
103 }
104
105 func queryDNS(ctx context.Context, addr string, typ string) (res []string, err error) {
106 return query(ctx, netdir+"/dns", addr+" "+typ, 1024)
107 }
108
109
110
111
112 func toLower(in string) string {
113 for _, c := range in {
114 if 'A' <= c && c <= 'Z' {
115
116 out := []byte(in)
117 for i := 0; i < len(in); i++ {
118 c := in[i]
119 if 'A' <= c && c <= 'Z' {
120 c += 'a' - 'A'
121 }
122 out[i] = c
123 }
124 return string(out)
125 }
126 }
127 return in
128 }
129
130
131
132 func lookupProtocol(ctx context.Context, name string) (proto int, err error) {
133 lines, err := query(ctx, netdir+"/cs", "!protocol="+toLower(name), 128)
134 if err != nil {
135 return 0, err
136 }
137 if len(lines) == 0 {
138 return 0, UnknownNetworkError(name)
139 }
140 f := getFields(lines[0])
141 if len(f) < 2 {
142 return 0, UnknownNetworkError(name)
143 }
144 s := f[1]
145 if n, _, ok := dtoi(s[bytealg.IndexByteString(s, '=')+1:]); ok {
146 return n, nil
147 }
148 return 0, UnknownNetworkError(name)
149 }
150
151 func (*Resolver) lookupHost(ctx context.Context, host string) (addrs []string, err error) {
152
153
154 lines, err := queryCS(ctx, "net", host, "1")
155 if err != nil {
156 dnsError := &DNSError{Err: err.Error(), Name: host}
157 if stringsHasSuffix(err.Error(), "dns failure") {
158 dnsError.Err = errNoSuchHost.Error()
159 dnsError.IsNotFound = true
160 }
161 return nil, dnsError
162 }
163 loop:
164 for _, line := range lines {
165 f := getFields(line)
166 if len(f) < 2 {
167 continue
168 }
169 addr := f[1]
170 if i := bytealg.IndexByteString(addr, '!'); i >= 0 {
171 addr = addr[:i]
172 }
173 if ParseIP(addr) == nil {
174 continue
175 }
176
177 for _, a := range addrs {
178 if a == addr {
179 continue loop
180 }
181 }
182 addrs = append(addrs, addr)
183 }
184 return
185 }
186
187
188
189
190 func (r *Resolver) preferGoOverPlan9() bool {
191 _, _, res := r.preferGoOverPlan9WithOrderAndConf()
192 return res
193 }
194
195 func (r *Resolver) preferGoOverPlan9WithOrderAndConf() (hostLookupOrder, *dnsConfig, bool) {
196 order, conf := systemConf().hostLookupOrder(r, "")
197
198
199
200
201
202
203
204
205 return order, conf, order != hostLookupCgo && r != nil && r.Dial != nil
206 }
207
208 func (r *Resolver) lookupIP(ctx context.Context, network, host string) (addrs []IPAddr, err error) {
209 if r.preferGoOverPlan9() {
210 return r.goLookupIP(ctx, network, host)
211 }
212 lits, err := r.lookupHost(ctx, host)
213 if err != nil {
214 return
215 }
216 for _, lit := range lits {
217 host, zone := splitHostZone(lit)
218 if ip := ParseIP(host); ip != nil {
219 addr := IPAddr{IP: ip, Zone: zone}
220 addrs = append(addrs, addr)
221 }
222 }
223 return
224 }
225
226 func (*Resolver) lookupPort(ctx context.Context, network, service string) (port int, err error) {
227 switch network {
228 case "tcp4", "tcp6":
229 network = "tcp"
230 case "udp4", "udp6":
231 network = "udp"
232 }
233 lines, err := queryCS(ctx, network, "127.0.0.1", toLower(service))
234 if err != nil {
235 return
236 }
237 unknownPortError := &AddrError{Err: "unknown port", Addr: network + "/" + service}
238 if len(lines) == 0 {
239 return 0, unknownPortError
240 }
241 f := getFields(lines[0])
242 if len(f) < 2 {
243 return 0, unknownPortError
244 }
245 s := f[1]
246 if i := bytealg.IndexByteString(s, '!'); i >= 0 {
247 s = s[i+1:]
248 }
249 if n, _, ok := dtoi(s); ok {
250 return n, nil
251 }
252 return 0, unknownPortError
253 }
254
255 func (r *Resolver) lookupCNAME(ctx context.Context, name string) (cname string, err error) {
256 if order, conf, preferGo := r.preferGoOverPlan9WithOrderAndConf(); preferGo {
257 return r.goLookupCNAME(ctx, name, order, conf)
258 }
259
260 lines, err := queryDNS(ctx, name, "cname")
261 if err != nil {
262 if stringsHasSuffix(err.Error(), "dns failure") || stringsHasSuffix(err.Error(), "resource does not exist; negrcode 0") {
263 cname = name + "."
264 err = nil
265 }
266 return
267 }
268 if len(lines) > 0 {
269 if f := getFields(lines[0]); len(f) >= 3 {
270 return f[2] + ".", nil
271 }
272 }
273 return "", errors.New("bad response from ndb/dns")
274 }
275
276 func (r *Resolver) lookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
277 if r.preferGoOverPlan9() {
278 return r.goLookupSRV(ctx, service, proto, name)
279 }
280 var target string
281 if service == "" && proto == "" {
282 target = name
283 } else {
284 target = "_" + service + "._" + proto + "." + name
285 }
286 lines, err := queryDNS(ctx, target, "srv")
287 if err != nil {
288 return
289 }
290 for _, line := range lines {
291 f := getFields(line)
292 if len(f) < 6 {
293 continue
294 }
295 port, _, portOk := dtoi(f[4])
296 priority, _, priorityOk := dtoi(f[3])
297 weight, _, weightOk := dtoi(f[2])
298 if !(portOk && priorityOk && weightOk) {
299 continue
300 }
301 addrs = append(addrs, &SRV{absDomainName(f[5]), uint16(port), uint16(priority), uint16(weight)})
302 cname = absDomainName(f[0])
303 }
304 byPriorityWeight(addrs).sort()
305 return
306 }
307
308 func (r *Resolver) lookupMX(ctx context.Context, name string) (mx []*MX, err error) {
309 if r.preferGoOverPlan9() {
310 return r.goLookupMX(ctx, name)
311 }
312 lines, err := queryDNS(ctx, name, "mx")
313 if err != nil {
314 return
315 }
316 for _, line := range lines {
317 f := getFields(line)
318 if len(f) < 4 {
319 continue
320 }
321 if pref, _, ok := dtoi(f[2]); ok {
322 mx = append(mx, &MX{absDomainName(f[3]), uint16(pref)})
323 }
324 }
325 byPref(mx).sort()
326 return
327 }
328
329 func (r *Resolver) lookupNS(ctx context.Context, name string) (ns []*NS, err error) {
330 if r.preferGoOverPlan9() {
331 return r.goLookupNS(ctx, name)
332 }
333 lines, err := queryDNS(ctx, name, "ns")
334 if err != nil {
335 return
336 }
337 for _, line := range lines {
338 f := getFields(line)
339 if len(f) < 3 {
340 continue
341 }
342 ns = append(ns, &NS{absDomainName(f[2])})
343 }
344 return
345 }
346
347 func (r *Resolver) lookupTXT(ctx context.Context, name string) (txt []string, err error) {
348 if r.preferGoOverPlan9() {
349 return r.goLookupTXT(ctx, name)
350 }
351 lines, err := queryDNS(ctx, name, "txt")
352 if err != nil {
353 return
354 }
355 for _, line := range lines {
356 if i := bytealg.IndexByteString(line, '\t'); i >= 0 {
357 txt = append(txt, line[i+1:])
358 }
359 }
360 return
361 }
362
363 func (r *Resolver) lookupAddr(ctx context.Context, addr string) (name []string, err error) {
364 if order, conf, preferGo := r.preferGoOverPlan9WithOrderAndConf(); preferGo {
365 return r.goLookupPTR(ctx, addr, order, conf)
366 }
367 arpa, err := reverseaddr(addr)
368 if err != nil {
369 return
370 }
371 lines, err := queryDNS(ctx, arpa, "ptr")
372 if err != nil {
373 return
374 }
375 for _, line := range lines {
376 f := getFields(line)
377 if len(f) < 3 {
378 continue
379 }
380 name = append(name, absDomainName(f[2]))
381 }
382 return
383 }
384
385
386
387 func concurrentThreadsLimit() int {
388 return 500
389 }
390
View as plain text