diff options
Diffstat (limited to 'src/pkg/net/lookup_plan9.go')
-rw-r--r-- | src/pkg/net/lookup_plan9.go | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/src/pkg/net/lookup_plan9.go b/src/pkg/net/lookup_plan9.go new file mode 100644 index 0000000000..37d6b8e315 --- /dev/null +++ b/src/pkg/net/lookup_plan9.go @@ -0,0 +1,226 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "os" +) + +func query(filename, query string, bufSize int) (res []string, err os.Error) { + file, err := os.OpenFile(filename, os.O_RDWR, 0) + if err != nil { + return + } + defer file.Close() + + _, err = file.WriteString(query) + if err != nil { + return + } + _, err = file.Seek(0, 0) + if err != nil { + return + } + buf := make([]byte, bufSize) + for { + n, _ := file.Read(buf) + if n <= 0 { + break + } + res = append(res, string(buf[:n])) + } + return +} + +func queryCS(net, host, service string) (res []string, err os.Error) { + switch net { + case "tcp4", "tcp6": + net = "tcp" + case "udp4", "udp6": + net = "udp" + } + if host == "" { + host = "*" + } + return query("/net/cs", net+"!"+host+"!"+service, 128) +} + +func queryCS1(net string, ip IP, port int) (clone, dest string, err os.Error) { + ips := "*" + if !ip.IsUnspecified() { + ips = ip.String() + } + lines, err := queryCS(net, ips, itoa(port)) + if err != nil { + return + } + f := getFields(lines[0]) + if len(f) < 2 { + return "", "", os.NewError("net: bad response from ndb/cs") + } + clone, dest = f[0], f[1] + return +} + +func queryDNS(addr string, typ string) (res []string, err os.Error) { + return query("/net/dns", addr+" "+typ, 1024) +} + +// LookupHost looks up the given host using the local resolver. +// It returns an array of that host's addresses. +func LookupHost(host string) (addrs []string, err os.Error) { + // Use /net/cs insead of /net/dns because cs knows about + // host names in local network (e.g. from /lib/ndb/local) + lines, err := queryCS("tcp", host, "1") + if err != nil { + return + } + for _, line := range lines { + f := getFields(line) + if len(f) < 2 { + continue + } + addr := f[1] + if i := byteIndex(addr, '!'); i >= 0 { + addr = addr[:i] // remove port + } + if ParseIP(addr) == nil { + continue + } + addrs = append(addrs, addr) + } + return +} + +// LookupIP looks up host using the local resolver. +// It returns an array of that host's IPv4 and IPv6 addresses. +func LookupIP(host string) (ips []IP, err os.Error) { + addrs, err := LookupHost(host) + if err != nil { + return + } + for _, addr := range addrs { + if ip := ParseIP(addr); ip != nil { + ips = append(ips, ip) + } + } + return +} + +// LookupPort looks up the port for the given network and service. +func LookupPort(network, service string) (port int, err os.Error) { + switch network { + case "tcp4", "tcp6": + network = "tcp" + case "udp4", "udp6": + network = "udp" + } + lines, err := queryCS(network, "127.0.0.1", service) + if err != nil { + return + } + unknownPortError := &AddrError{"unknown port", network + "/" + service} + if len(lines) == 0 { + return 0, unknownPortError + } + f := getFields(lines[0]) + if len(f) < 2 { + return 0, unknownPortError + } + s := f[1] + if i := byteIndex(s, '!'); i >= 0 { + s = s[i+1:] // remove address + } + if n, _, ok := dtoi(s, 0); ok { + return n, nil + } + return 0, unknownPortError +} + +// LookupCNAME returns the canonical DNS host for the given name. +// Callers that do not care about the canonical name can call +// LookupHost or LookupIP directly; both take care of resolving +// the canonical name as part of the lookup. +func LookupCNAME(name string) (cname string, err os.Error) { + lines, err := queryDNS(name, "cname") + if err != nil { + return + } + if len(lines) > 0 { + if f := getFields(lines[0]); len(f) >= 3 { + return f[2] + ".", nil + } + } + return "", os.NewError("net: bad response from ndb/dns") +} + +// LookupSRV tries to resolve an SRV query of the given service, +// protocol, and domain name, as specified in RFC 2782. In most cases +// the proto argument can be the same as the corresponding +// Addr.Network(). The returned records are sorted by priority +// and randomized by weight within a priority. +func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) { + target := "_" + service + "._" + proto + "." + name + lines, err := queryDNS(target, "srv") + if err != nil { + return + } + for _, line := range lines { + f := getFields(line) + if len(f) < 6 { + continue + } + port, _, portOk := dtoi(f[2], 0) + priority, _, priorityOk := dtoi(f[3], 0) + weight, _, weightOk := dtoi(f[4], 0) + if !(portOk && priorityOk && weightOk) { + continue + } + addrs = append(addrs, &SRV{f[5], uint16(port), uint16(priority), uint16(weight)}) + cname = f[0] + } + byPriorityWeight(addrs).sort() + return +} + +// LookupMX returns the DNS MX records for the given domain name sorted by preference. +func LookupMX(name string) (mx []*MX, err os.Error) { + lines, err := queryDNS(name, "mx") + if err != nil { + return + } + for _, line := range lines { + f := getFields(line) + if len(f) < 4 { + continue + } + if pref, _, ok := dtoi(f[2], 0); ok { + mx = append(mx, &MX{f[3], uint16(pref)}) + } + } + byPref(mx).sort() + return +} + +// LookupAddr performs a reverse lookup for the given address, returning a list +// of names mapping to that address. +func LookupAddr(addr string) (name []string, err os.Error) { + arpa, err := reverseaddr(addr) + if err != nil { + return + } + lines, err := queryDNS(arpa, "ptr") + if err != nil { + return + } + for _, line := range lines { + f := getFields(line) + if len(f) < 3 { + continue + } + name = append(name, f[2]) + } + return +} |