rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/net/lookup_plan9.go (about) 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. 4 5 package net 6 7 import ( 8 "errors" 9 "os" 10 ) 11 12 func query(filename, query string, bufSize int) (res []string, err error) { 13 file, err := os.OpenFile(filename, os.O_RDWR, 0) 14 if err != nil { 15 return 16 } 17 defer file.Close() 18 19 _, err = file.Seek(0, 0) 20 if err != nil { 21 return 22 } 23 _, err = file.WriteString(query) 24 if err != nil { 25 return 26 } 27 _, err = file.Seek(0, 0) 28 if err != nil { 29 return 30 } 31 buf := make([]byte, bufSize) 32 for { 33 n, _ := file.Read(buf) 34 if n <= 0 { 35 break 36 } 37 res = append(res, string(buf[:n])) 38 } 39 return 40 } 41 42 func queryCS(net, host, service string) (res []string, err error) { 43 switch net { 44 case "tcp4", "tcp6": 45 net = "tcp" 46 case "udp4", "udp6": 47 net = "udp" 48 } 49 if host == "" { 50 host = "*" 51 } 52 return query(netdir+"/cs", net+"!"+host+"!"+service, 128) 53 } 54 55 func queryCS1(net string, ip IP, port int) (clone, dest string, err error) { 56 ips := "*" 57 if len(ip) != 0 && !ip.IsUnspecified() { 58 ips = ip.String() 59 } 60 lines, err := queryCS(net, ips, itoa(port)) 61 if err != nil { 62 return 63 } 64 f := getFields(lines[0]) 65 if len(f) < 2 { 66 return "", "", errors.New("bad response from ndb/cs") 67 } 68 clone, dest = f[0], f[1] 69 return 70 } 71 72 func queryDNS(addr string, typ string) (res []string, err error) { 73 return query(netdir+"/dns", addr+" "+typ, 1024) 74 } 75 76 // toLower returns a lower-case version of in. Restricting us to 77 // ASCII is sufficient to handle the IP protocol names and allow 78 // us to not depend on the strings and unicode packages. 79 func toLower(in string) string { 80 for _, c := range in { 81 if 'A' <= c && c <= 'Z' { 82 // Has upper case; need to fix. 83 out := []byte(in) 84 for i := 0; i < len(in); i++ { 85 c := in[i] 86 if 'A' <= c && c <= 'Z' { 87 c += 'a' - 'A' 88 } 89 out[i] = c 90 } 91 return string(out) 92 } 93 } 94 return in 95 } 96 97 // lookupProtocol looks up IP protocol name and returns 98 // the corresponding protocol number. 99 func lookupProtocol(name string) (proto int, err error) { 100 lines, err := query(netdir+"/cs", "!protocol="+toLower(name), 128) 101 if err != nil { 102 return 0, err 103 } 104 unknownProtoError := errors.New("unknown IP protocol specified: " + name) 105 if len(lines) == 0 { 106 return 0, unknownProtoError 107 } 108 f := getFields(lines[0]) 109 if len(f) < 2 { 110 return 0, unknownProtoError 111 } 112 s := f[1] 113 if n, _, ok := dtoi(s, byteIndex(s, '=')+1); ok { 114 return n, nil 115 } 116 return 0, unknownProtoError 117 } 118 119 func lookupHost(host string) (addrs []string, err error) { 120 // Use netdir/cs instead of netdir/dns because cs knows about 121 // host names in local network (e.g. from /lib/ndb/local) 122 lines, err := queryCS("net", host, "1") 123 if err != nil { 124 return 125 } 126 loop: 127 for _, line := range lines { 128 f := getFields(line) 129 if len(f) < 2 { 130 continue 131 } 132 addr := f[1] 133 if i := byteIndex(addr, '!'); i >= 0 { 134 addr = addr[:i] // remove port 135 } 136 if ParseIP(addr) == nil { 137 continue 138 } 139 // only return unique addresses 140 for _, a := range addrs { 141 if a == addr { 142 continue loop 143 } 144 } 145 addrs = append(addrs, addr) 146 } 147 return 148 } 149 150 func lookupIP(host string) (addrs []IPAddr, err error) { 151 lits, err := LookupHost(host) 152 if err != nil { 153 return 154 } 155 for _, lit := range lits { 156 host, zone := splitHostZone(lit) 157 if ip := ParseIP(host); ip != nil { 158 addr := IPAddr{IP: ip, Zone: zone} 159 addrs = append(addrs, addr) 160 } 161 } 162 return 163 } 164 165 func lookupPort(network, service string) (port int, err error) { 166 switch network { 167 case "tcp4", "tcp6": 168 network = "tcp" 169 case "udp4", "udp6": 170 network = "udp" 171 } 172 lines, err := queryCS(network, "127.0.0.1", service) 173 if err != nil { 174 return 175 } 176 unknownPortError := &AddrError{"unknown port", network + "/" + service} 177 if len(lines) == 0 { 178 return 0, unknownPortError 179 } 180 f := getFields(lines[0]) 181 if len(f) < 2 { 182 return 0, unknownPortError 183 } 184 s := f[1] 185 if i := byteIndex(s, '!'); i >= 0 { 186 s = s[i+1:] // remove address 187 } 188 if n, _, ok := dtoi(s, 0); ok { 189 return n, nil 190 } 191 return 0, unknownPortError 192 } 193 194 func lookupCNAME(name string) (cname string, err error) { 195 lines, err := queryDNS(name, "cname") 196 if err != nil { 197 return 198 } 199 if len(lines) > 0 { 200 if f := getFields(lines[0]); len(f) >= 3 { 201 return f[2] + ".", nil 202 } 203 } 204 return "", errors.New("bad response from ndb/dns") 205 } 206 207 func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { 208 var target string 209 if service == "" && proto == "" { 210 target = name 211 } else { 212 target = "_" + service + "._" + proto + "." + name 213 } 214 lines, err := queryDNS(target, "srv") 215 if err != nil { 216 return 217 } 218 for _, line := range lines { 219 f := getFields(line) 220 if len(f) < 6 { 221 continue 222 } 223 port, _, portOk := dtoi(f[4], 0) 224 priority, _, priorityOk := dtoi(f[3], 0) 225 weight, _, weightOk := dtoi(f[2], 0) 226 if !(portOk && priorityOk && weightOk) { 227 continue 228 } 229 addrs = append(addrs, &SRV{f[5], uint16(port), uint16(priority), uint16(weight)}) 230 cname = f[0] 231 } 232 byPriorityWeight(addrs).sort() 233 return 234 } 235 236 func lookupMX(name string) (mx []*MX, err error) { 237 lines, err := queryDNS(name, "mx") 238 if err != nil { 239 return 240 } 241 for _, line := range lines { 242 f := getFields(line) 243 if len(f) < 4 { 244 continue 245 } 246 if pref, _, ok := dtoi(f[2], 0); ok { 247 mx = append(mx, &MX{f[3], uint16(pref)}) 248 } 249 } 250 byPref(mx).sort() 251 return 252 } 253 254 func lookupNS(name string) (ns []*NS, err error) { 255 lines, err := queryDNS(name, "ns") 256 if err != nil { 257 return 258 } 259 for _, line := range lines { 260 f := getFields(line) 261 if len(f) < 3 { 262 continue 263 } 264 ns = append(ns, &NS{f[2]}) 265 } 266 return 267 } 268 269 func lookupTXT(name string) (txt []string, err error) { 270 lines, err := queryDNS(name, "txt") 271 if err != nil { 272 return 273 } 274 for _, line := range lines { 275 if i := byteIndex(line, '\t'); i >= 0 { 276 txt = append(txt, line[i+1:]) 277 } 278 } 279 return 280 } 281 282 func lookupAddr(addr string) (name []string, err error) { 283 arpa, err := reverseaddr(addr) 284 if err != nil { 285 return 286 } 287 lines, err := queryDNS(arpa, "ptr") 288 if err != nil { 289 return 290 } 291 for _, line := range lines { 292 f := getFields(line) 293 if len(f) < 3 { 294 continue 295 } 296 name = append(name, f[2]) 297 } 298 return 299 }