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  }