...
Run Format

Source file src/net/lookup_plan9.go

Documentation: net

  // 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 (
  	"context"
  	"errors"
  	"io"
  	"os"
  )
  
  func query(ctx context.Context, filename, query string, bufSize int) (res []string, err error) {
  	file, err := os.OpenFile(filename, os.O_RDWR, 0)
  	if err != nil {
  		return
  	}
  	defer file.Close()
  
  	_, err = file.Seek(0, io.SeekStart)
  	if err != nil {
  		return
  	}
  	_, err = file.WriteString(query)
  	if err != nil {
  		return
  	}
  	_, err = file.Seek(0, io.SeekStart)
  	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(ctx context.Context, net, host, service string) (res []string, err error) {
  	switch net {
  	case "tcp4", "tcp6":
  		net = "tcp"
  	case "udp4", "udp6":
  		net = "udp"
  	}
  	if host == "" {
  		host = "*"
  	}
  	return query(ctx, netdir+"/cs", net+"!"+host+"!"+service, 128)
  }
  
  func queryCS1(ctx context.Context, net string, ip IP, port int) (clone, dest string, err error) {
  	ips := "*"
  	if len(ip) != 0 && !ip.IsUnspecified() {
  		ips = ip.String()
  	}
  	lines, err := queryCS(ctx, net, ips, itoa(port))
  	if err != nil {
  		return
  	}
  	f := getFields(lines[0])
  	if len(f) < 2 {
  		return "", "", errors.New("bad response from ndb/cs")
  	}
  	clone, dest = f[0], f[1]
  	return
  }
  
  func queryDNS(ctx context.Context, addr string, typ string) (res []string, err error) {
  	return query(ctx, netdir+"/dns", addr+" "+typ, 1024)
  }
  
  // toLower returns a lower-case version of in. Restricting us to
  // ASCII is sufficient to handle the IP protocol names and allow
  // us to not depend on the strings and unicode packages.
  func toLower(in string) string {
  	for _, c := range in {
  		if 'A' <= c && c <= 'Z' {
  			// Has upper case; need to fix.
  			out := []byte(in)
  			for i := 0; i < len(in); i++ {
  				c := in[i]
  				if 'A' <= c && c <= 'Z' {
  					c += 'a' - 'A'
  				}
  				out[i] = c
  			}
  			return string(out)
  		}
  	}
  	return in
  }
  
  // lookupProtocol looks up IP protocol name and returns
  // the corresponding protocol number.
  func lookupProtocol(ctx context.Context, name string) (proto int, err error) {
  	lines, err := query(ctx, netdir+"/cs", "!protocol="+toLower(name), 128)
  	if err != nil {
  		return 0, err
  	}
  	if len(lines) == 0 {
  		return 0, UnknownNetworkError(name)
  	}
  	f := getFields(lines[0])
  	if len(f) < 2 {
  		return 0, UnknownNetworkError(name)
  	}
  	s := f[1]
  	if n, _, ok := dtoi(s[byteIndex(s, '=')+1:]); ok {
  		return n, nil
  	}
  	return 0, UnknownNetworkError(name)
  }
  
  func (*Resolver) lookupHost(ctx context.Context, host string) (addrs []string, err error) {
  	// Use netdir/cs instead of netdir/dns because cs knows about
  	// host names in local network (e.g. from /lib/ndb/local)
  	lines, err := queryCS(ctx, "net", host, "1")
  	if err != nil {
  		if stringsHasSuffix(err.Error(), "dns failure") {
  			err = errNoSuchHost
  		}
  		return
  	}
  loop:
  	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
  		}
  		// only return unique addresses
  		for _, a := range addrs {
  			if a == addr {
  				continue loop
  			}
  		}
  		addrs = append(addrs, addr)
  	}
  	return
  }
  
  func (r *Resolver) lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
  	lits, err := r.lookupHost(ctx, host)
  	if err != nil {
  		return
  	}
  	for _, lit := range lits {
  		host, zone := splitHostZone(lit)
  		if ip := ParseIP(host); ip != nil {
  			addr := IPAddr{IP: ip, Zone: zone}
  			addrs = append(addrs, addr)
  		}
  	}
  	return
  }
  
  func (*Resolver) lookupPort(ctx context.Context, network, service string) (port int, err error) {
  	switch network {
  	case "tcp4", "tcp6":
  		network = "tcp"
  	case "udp4", "udp6":
  		network = "udp"
  	}
  	lines, err := queryCS(ctx, network, "127.0.0.1", toLower(service))
  	if err != nil {
  		return
  	}
  	unknownPortError := &AddrError{Err: "unknown port", Addr: 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); ok {
  		return n, nil
  	}
  	return 0, unknownPortError
  }
  
  func (*Resolver) lookupCNAME(ctx context.Context, name string) (cname string, err error) {
  	lines, err := queryDNS(ctx, name, "cname")
  	if err != nil {
  		if stringsHasSuffix(err.Error(), "dns failure") {
  			cname = name + "."
  			err = nil
  		}
  		return
  	}
  	if len(lines) > 0 {
  		if f := getFields(lines[0]); len(f) >= 3 {
  			return f[2] + ".", nil
  		}
  	}
  	return "", errors.New("bad response from ndb/dns")
  }
  
  func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
  	var target string
  	if service == "" && proto == "" {
  		target = name
  	} else {
  		target = "_" + service + "._" + proto + "." + name
  	}
  	lines, err := queryDNS(ctx, target, "srv")
  	if err != nil {
  		return
  	}
  	for _, line := range lines {
  		f := getFields(line)
  		if len(f) < 6 {
  			continue
  		}
  		port, _, portOk := dtoi(f[4])
  		priority, _, priorityOk := dtoi(f[3])
  		weight, _, weightOk := dtoi(f[2])
  		if !(portOk && priorityOk && weightOk) {
  			continue
  		}
  		addrs = append(addrs, &SRV{absDomainName([]byte(f[5])), uint16(port), uint16(priority), uint16(weight)})
  		cname = absDomainName([]byte(f[0]))
  	}
  	byPriorityWeight(addrs).sort()
  	return
  }
  
  func (*Resolver) lookupMX(ctx context.Context, name string) (mx []*MX, err error) {
  	lines, err := queryDNS(ctx, name, "mx")
  	if err != nil {
  		return
  	}
  	for _, line := range lines {
  		f := getFields(line)
  		if len(f) < 4 {
  			continue
  		}
  		if pref, _, ok := dtoi(f[2]); ok {
  			mx = append(mx, &MX{absDomainName([]byte(f[3])), uint16(pref)})
  		}
  	}
  	byPref(mx).sort()
  	return
  }
  
  func (*Resolver) lookupNS(ctx context.Context, name string) (ns []*NS, err error) {
  	lines, err := queryDNS(ctx, name, "ns")
  	if err != nil {
  		return
  	}
  	for _, line := range lines {
  		f := getFields(line)
  		if len(f) < 3 {
  			continue
  		}
  		ns = append(ns, &NS{absDomainName([]byte(f[2]))})
  	}
  	return
  }
  
  func (*Resolver) lookupTXT(ctx context.Context, name string) (txt []string, err error) {
  	lines, err := queryDNS(ctx, name, "txt")
  	if err != nil {
  		return
  	}
  	for _, line := range lines {
  		if i := byteIndex(line, '\t'); i >= 0 {
  			txt = append(txt, absDomainName([]byte(line[i+1:])))
  		}
  	}
  	return
  }
  
  func (*Resolver) lookupAddr(ctx context.Context, addr string) (name []string, err error) {
  	arpa, err := reverseaddr(addr)
  	if err != nil {
  		return
  	}
  	lines, err := queryDNS(ctx, arpa, "ptr")
  	if err != nil {
  		return
  	}
  	for _, line := range lines {
  		f := getFields(line)
  		if len(f) < 3 {
  			continue
  		}
  		name = append(name, absDomainName([]byte(f[2])))
  	}
  	return
  }
  

View as plain text