2017-07-18 François Dumont <fdumont@gcc.gnu.org>
[official-gcc.git] / libgo / go / net / lookup_plan9.go
blobf81e220fc8ce65ff4b262734c96f8cdfd4f3db43
1 // Copyright 2011 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.
5 package net
7 import (
8 "context"
9 "errors"
10 "io"
11 "os"
14 func query(ctx context.Context, filename, query string, bufSize int) (res []string, err error) {
15 file, err := os.OpenFile(filename, os.O_RDWR, 0)
16 if err != nil {
17 return
19 defer file.Close()
21 _, err = file.Seek(0, io.SeekStart)
22 if err != nil {
23 return
25 _, err = file.WriteString(query)
26 if err != nil {
27 return
29 _, err = file.Seek(0, io.SeekStart)
30 if err != nil {
31 return
33 buf := make([]byte, bufSize)
34 for {
35 n, _ := file.Read(buf)
36 if n <= 0 {
37 break
39 res = append(res, string(buf[:n]))
41 return
44 func queryCS(ctx context.Context, net, host, service string) (res []string, err error) {
45 switch net {
46 case "tcp4", "tcp6":
47 net = "tcp"
48 case "udp4", "udp6":
49 net = "udp"
51 if host == "" {
52 host = "*"
54 return query(ctx, netdir+"/cs", net+"!"+host+"!"+service, 128)
57 func queryCS1(ctx context.Context, net string, ip IP, port int) (clone, dest string, err error) {
58 ips := "*"
59 if len(ip) != 0 && !ip.IsUnspecified() {
60 ips = ip.String()
62 lines, err := queryCS(ctx, net, ips, itoa(port))
63 if err != nil {
64 return
66 f := getFields(lines[0])
67 if len(f) < 2 {
68 return "", "", errors.New("bad response from ndb/cs")
70 clone, dest = f[0], f[1]
71 return
74 func queryDNS(ctx context.Context, addr string, typ string) (res []string, err error) {
75 return query(ctx, netdir+"/dns", addr+" "+typ, 1024)
78 // toLower returns a lower-case version of in. Restricting us to
79 // ASCII is sufficient to handle the IP protocol names and allow
80 // us to not depend on the strings and unicode packages.
81 func toLower(in string) string {
82 for _, c := range in {
83 if 'A' <= c && c <= 'Z' {
84 // Has upper case; need to fix.
85 out := []byte(in)
86 for i := 0; i < len(in); i++ {
87 c := in[i]
88 if 'A' <= c && c <= 'Z' {
89 c += 'a' - 'A'
91 out[i] = c
93 return string(out)
96 return in
99 // lookupProtocol looks up IP protocol name and returns
100 // the corresponding protocol number.
101 func lookupProtocol(ctx context.Context, name string) (proto int, err error) {
102 lines, err := query(ctx, netdir+"/cs", "!protocol="+toLower(name), 128)
103 if err != nil {
104 return 0, err
106 if len(lines) == 0 {
107 return 0, UnknownNetworkError(name)
109 f := getFields(lines[0])
110 if len(f) < 2 {
111 return 0, UnknownNetworkError(name)
113 s := f[1]
114 if n, _, ok := dtoi(s[byteIndex(s, '=')+1:]); ok {
115 return n, nil
117 return 0, UnknownNetworkError(name)
120 func (*Resolver) lookupHost(ctx context.Context, host string) (addrs []string, err error) {
121 // Use netdir/cs instead of netdir/dns because cs knows about
122 // host names in local network (e.g. from /lib/ndb/local)
123 lines, err := queryCS(ctx, "net", host, "1")
124 if err != nil {
125 if stringsHasSuffix(err.Error(), "dns failure") {
126 err = errNoSuchHost
128 return
130 loop:
131 for _, line := range lines {
132 f := getFields(line)
133 if len(f) < 2 {
134 continue
136 addr := f[1]
137 if i := byteIndex(addr, '!'); i >= 0 {
138 addr = addr[:i] // remove port
140 if ParseIP(addr) == nil {
141 continue
143 // only return unique addresses
144 for _, a := range addrs {
145 if a == addr {
146 continue loop
149 addrs = append(addrs, addr)
151 return
154 func (r *Resolver) lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
155 lits, err := r.lookupHost(ctx, host)
156 if err != nil {
157 return
159 for _, lit := range lits {
160 host, zone := splitHostZone(lit)
161 if ip := ParseIP(host); ip != nil {
162 addr := IPAddr{IP: ip, Zone: zone}
163 addrs = append(addrs, addr)
166 return
169 func (*Resolver) lookupPort(ctx context.Context, network, service string) (port int, err error) {
170 switch network {
171 case "tcp4", "tcp6":
172 network = "tcp"
173 case "udp4", "udp6":
174 network = "udp"
176 lines, err := queryCS(ctx, network, "127.0.0.1", toLower(service))
177 if err != nil {
178 return
180 unknownPortError := &AddrError{Err: "unknown port", Addr: network + "/" + service}
181 if len(lines) == 0 {
182 return 0, unknownPortError
184 f := getFields(lines[0])
185 if len(f) < 2 {
186 return 0, unknownPortError
188 s := f[1]
189 if i := byteIndex(s, '!'); i >= 0 {
190 s = s[i+1:] // remove address
192 if n, _, ok := dtoi(s); ok {
193 return n, nil
195 return 0, unknownPortError
198 func (*Resolver) lookupCNAME(ctx context.Context, name string) (cname string, err error) {
199 lines, err := queryDNS(ctx, name, "cname")
200 if err != nil {
201 if stringsHasSuffix(err.Error(), "dns failure") {
202 cname = name + "."
203 err = nil
205 return
207 if len(lines) > 0 {
208 if f := getFields(lines[0]); len(f) >= 3 {
209 return f[2] + ".", nil
212 return "", errors.New("bad response from ndb/dns")
215 func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
216 var target string
217 if service == "" && proto == "" {
218 target = name
219 } else {
220 target = "_" + service + "._" + proto + "." + name
222 lines, err := queryDNS(ctx, target, "srv")
223 if err != nil {
224 return
226 for _, line := range lines {
227 f := getFields(line)
228 if len(f) < 6 {
229 continue
231 port, _, portOk := dtoi(f[4])
232 priority, _, priorityOk := dtoi(f[3])
233 weight, _, weightOk := dtoi(f[2])
234 if !(portOk && priorityOk && weightOk) {
235 continue
237 addrs = append(addrs, &SRV{absDomainName([]byte(f[5])), uint16(port), uint16(priority), uint16(weight)})
238 cname = absDomainName([]byte(f[0]))
240 byPriorityWeight(addrs).sort()
241 return
244 func (*Resolver) lookupMX(ctx context.Context, name string) (mx []*MX, err error) {
245 lines, err := queryDNS(ctx, name, "mx")
246 if err != nil {
247 return
249 for _, line := range lines {
250 f := getFields(line)
251 if len(f) < 4 {
252 continue
254 if pref, _, ok := dtoi(f[2]); ok {
255 mx = append(mx, &MX{absDomainName([]byte(f[3])), uint16(pref)})
258 byPref(mx).sort()
259 return
262 func (*Resolver) lookupNS(ctx context.Context, name string) (ns []*NS, err error) {
263 lines, err := queryDNS(ctx, name, "ns")
264 if err != nil {
265 return
267 for _, line := range lines {
268 f := getFields(line)
269 if len(f) < 3 {
270 continue
272 ns = append(ns, &NS{absDomainName([]byte(f[2]))})
274 return
277 func (*Resolver) lookupTXT(ctx context.Context, name string) (txt []string, err error) {
278 lines, err := queryDNS(ctx, name, "txt")
279 if err != nil {
280 return
282 for _, line := range lines {
283 if i := byteIndex(line, '\t'); i >= 0 {
284 txt = append(txt, absDomainName([]byte(line[i+1:])))
287 return
290 func (*Resolver) lookupAddr(ctx context.Context, addr string) (name []string, err error) {
291 arpa, err := reverseaddr(addr)
292 if err != nil {
293 return
295 lines, err := queryDNS(ctx, arpa, "ptr")
296 if err != nil {
297 return
299 for _, line := range lines {
300 f := getFields(line)
301 if len(f) < 3 {
302 continue
304 name = append(name, absDomainName([]byte(f[2])))
306 return