github.com/fjballest/golang@v0.0.0-20151209143359-e4c5fe594ca8/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 if len(lines) == 0 { 105 return 0, UnknownNetworkError(name) 106 } 107 f := getFields(lines[0]) 108 if len(f) < 2 { 109 return 0, UnknownNetworkError(name) 110 } 111 s := f[1] 112 if n, _, ok := dtoi(s, byteIndex(s, '=')+1); ok { 113 return n, nil 114 } 115 return 0, UnknownNetworkError(name) 116 } 117 118 func lookupHost(host string) (addrs []string, err error) { 119 // Use netdir/cs instead of netdir/dns because cs knows about 120 // host names in local network (e.g. from /lib/ndb/local) 121 lines, err := queryCS("net", host, "1") 122 if err != nil { 123 return 124 } 125 loop: 126 for _, line := range lines { 127 f := getFields(line) 128 if len(f) < 2 { 129 continue 130 } 131 addr := f[1] 132 if i := byteIndex(addr, '!'); i >= 0 { 133 addr = addr[:i] // remove port 134 } 135 if ParseIP(addr) == nil { 136 continue 137 } 138 // only return unique addresses 139 for _, a := range addrs { 140 if a == addr { 141 continue loop 142 } 143 } 144 addrs = append(addrs, addr) 145 } 146 return 147 } 148 149 func lookupIP(host string) (addrs []IPAddr, err error) { 150 lits, err := LookupHost(host) 151 if err != nil { 152 return 153 } 154 for _, lit := range lits { 155 host, zone := splitHostZone(lit) 156 if ip := ParseIP(host); ip != nil { 157 addr := IPAddr{IP: ip, Zone: zone} 158 addrs = append(addrs, addr) 159 } 160 } 161 return 162 } 163 164 func lookupPort(network, service string) (port int, err error) { 165 switch network { 166 case "tcp4", "tcp6": 167 network = "tcp" 168 case "udp4", "udp6": 169 network = "udp" 170 } 171 lines, err := queryCS(network, "127.0.0.1", service) 172 if err != nil { 173 return 174 } 175 unknownPortError := &AddrError{Err: "unknown port", Addr: network + "/" + service} 176 if len(lines) == 0 { 177 return 0, unknownPortError 178 } 179 f := getFields(lines[0]) 180 if len(f) < 2 { 181 return 0, unknownPortError 182 } 183 s := f[1] 184 if i := byteIndex(s, '!'); i >= 0 { 185 s = s[i+1:] // remove address 186 } 187 if n, _, ok := dtoi(s, 0); ok { 188 return n, nil 189 } 190 return 0, unknownPortError 191 } 192 193 // ensureEndDot adds '.' at the end of name unless it is already there. 194 func ensureEndDot(name string) string { 195 if name == "" { 196 return "." 197 } 198 if name[len(name)-1] == '.' { 199 return name 200 } 201 return name + "." 202 } 203 204 func lookupCNAME(name string) (cname string, err error) { 205 lines, err := queryDNS(name, "cname") 206 if err != nil { 207 return 208 } 209 if len(lines) > 0 { 210 if f := getFields(lines[0]); len(f) >= 3 { 211 return f[2] + ".", nil 212 } 213 } 214 return "", errors.New("bad response from ndb/dns") 215 } 216 217 func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { 218 var target string 219 if service == "" && proto == "" { 220 target = name 221 } else { 222 target = "_" + service + "._" + proto + "." + name 223 } 224 lines, err := queryDNS(target, "srv") 225 if err != nil { 226 return 227 } 228 for _, line := range lines { 229 f := getFields(line) 230 if len(f) < 6 { 231 continue 232 } 233 port, _, portOk := dtoi(f[4], 0) 234 priority, _, priorityOk := dtoi(f[3], 0) 235 weight, _, weightOk := dtoi(f[2], 0) 236 if !(portOk && priorityOk && weightOk) { 237 continue 238 } 239 addrs = append(addrs, &SRV{ensureEndDot(f[5]), uint16(port), uint16(priority), uint16(weight)}) 240 cname = ensureEndDot(f[0]) 241 } 242 byPriorityWeight(addrs).sort() 243 return 244 } 245 246 func lookupMX(name string) (mx []*MX, err error) { 247 lines, err := queryDNS(name, "mx") 248 if err != nil { 249 return 250 } 251 for _, line := range lines { 252 f := getFields(line) 253 if len(f) < 4 { 254 continue 255 } 256 if pref, _, ok := dtoi(f[2], 0); ok { 257 mx = append(mx, &MX{ensureEndDot(f[3]), uint16(pref)}) 258 } 259 } 260 byPref(mx).sort() 261 return 262 } 263 264 func lookupNS(name string) (ns []*NS, err error) { 265 lines, err := queryDNS(name, "ns") 266 if err != nil { 267 return 268 } 269 for _, line := range lines { 270 f := getFields(line) 271 if len(f) < 3 { 272 continue 273 } 274 ns = append(ns, &NS{ensureEndDot(f[2])}) 275 } 276 return 277 } 278 279 func lookupTXT(name string) (txt []string, err error) { 280 lines, err := queryDNS(name, "txt") 281 if err != nil { 282 return 283 } 284 for _, line := range lines { 285 if i := byteIndex(line, '\t'); i >= 0 { 286 txt = append(txt, ensureEndDot(line[i+1:])) 287 } 288 } 289 return 290 } 291 292 func lookupAddr(addr string) (name []string, err error) { 293 arpa, err := reverseaddr(addr) 294 if err != nil { 295 return 296 } 297 lines, err := queryDNS(arpa, "ptr") 298 if err != nil { 299 return 300 } 301 for _, line := range lines { 302 f := getFields(line) 303 if len(f) < 3 { 304 continue 305 } 306 name = append(name, ensureEndDot(f[2])) 307 } 308 return 309 }