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  }