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