github.com/roboticscm/goman@v0.0.0-20210203095141-87c07b4a0a55/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) (ips []IP, err error) { 151 addrs, err := LookupHost(host) 152 if err != nil { 153 return 154 } 155 for _, addr := range addrs { 156 if ip := ParseIP(addr); ip != nil { 157 ips = append(ips, ip) 158 } 159 } 160 return 161 } 162 163 func lookupPort(network, service string) (port int, err error) { 164 switch network { 165 case "tcp4", "tcp6": 166 network = "tcp" 167 case "udp4", "udp6": 168 network = "udp" 169 } 170 lines, err := queryCS(network, "127.0.0.1", service) 171 if err != nil { 172 return 173 } 174 unknownPortError := &AddrError{"unknown port", network + "/" + service} 175 if len(lines) == 0 { 176 return 0, unknownPortError 177 } 178 f := getFields(lines[0]) 179 if len(f) < 2 { 180 return 0, unknownPortError 181 } 182 s := f[1] 183 if i := byteIndex(s, '!'); i >= 0 { 184 s = s[i+1:] // remove address 185 } 186 if n, _, ok := dtoi(s, 0); ok { 187 return n, nil 188 } 189 return 0, unknownPortError 190 } 191 192 func lookupCNAME(name string) (cname string, err error) { 193 lines, err := queryDNS(name, "cname") 194 if err != nil { 195 return 196 } 197 if len(lines) > 0 { 198 if f := getFields(lines[0]); len(f) >= 3 { 199 return f[2] + ".", nil 200 } 201 } 202 return "", errors.New("bad response from ndb/dns") 203 } 204 205 func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { 206 var target string 207 if service == "" && proto == "" { 208 target = name 209 } else { 210 target = "_" + service + "._" + proto + "." + name 211 } 212 lines, err := queryDNS(target, "srv") 213 if err != nil { 214 return 215 } 216 for _, line := range lines { 217 f := getFields(line) 218 if len(f) < 6 { 219 continue 220 } 221 port, _, portOk := dtoi(f[4], 0) 222 priority, _, priorityOk := dtoi(f[3], 0) 223 weight, _, weightOk := dtoi(f[2], 0) 224 if !(portOk && priorityOk && weightOk) { 225 continue 226 } 227 addrs = append(addrs, &SRV{f[5], uint16(port), uint16(priority), uint16(weight)}) 228 cname = f[0] 229 } 230 byPriorityWeight(addrs).sort() 231 return 232 } 233 234 func lookupMX(name string) (mx []*MX, err error) { 235 lines, err := queryDNS(name, "mx") 236 if err != nil { 237 return 238 } 239 for _, line := range lines { 240 f := getFields(line) 241 if len(f) < 4 { 242 continue 243 } 244 if pref, _, ok := dtoi(f[2], 0); ok { 245 mx = append(mx, &MX{f[3], uint16(pref)}) 246 } 247 } 248 byPref(mx).sort() 249 return 250 } 251 252 func lookupNS(name string) (ns []*NS, err error) { 253 lines, err := queryDNS(name, "ns") 254 if err != nil { 255 return 256 } 257 for _, line := range lines { 258 f := getFields(line) 259 if len(f) < 3 { 260 continue 261 } 262 ns = append(ns, &NS{f[2]}) 263 } 264 return 265 } 266 267 func lookupTXT(name string) (txt []string, err error) { 268 lines, err := queryDNS(name, "txt") 269 if err != nil { 270 return 271 } 272 for _, line := range lines { 273 if i := byteIndex(line, '\t'); i >= 0 { 274 txt = append(txt, line[i+1:]) 275 } 276 } 277 return 278 } 279 280 func lookupAddr(addr string) (name []string, err error) { 281 arpa, err := reverseaddr(addr) 282 if err != nil { 283 return 284 } 285 lines, err := queryDNS(arpa, "ptr") 286 if err != nil { 287 return 288 } 289 for _, line := range lines { 290 f := getFields(line) 291 if len(f) < 3 { 292 continue 293 } 294 name = append(name, f[2]) 295 } 296 return 297 }