github.com/fjballest/golang@v0.0.0-20151209143359-e4c5fe594ca8/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  	if len(lines) == 0 {
   105  		return 0, UnknownNetworkError(name)
   106  	}
   107  	f := getFields(lines[0])
   108  	if len(f) < 2 {
   109  		return 0, UnknownNetworkError(name)
   110  	}
   111  	s := f[1]
   112  	if n, _, ok := dtoi(s, byteIndex(s, '=')+1); ok {
   113  		return n, nil
   114  	}
   115  	return 0, UnknownNetworkError(name)
   116  }
   117  
   118  func lookupHost(host string) (addrs []string, err error) {
   119  	// Use netdir/cs instead of netdir/dns because cs knows about
   120  	// host names in local network (e.g. from /lib/ndb/local)
   121  	lines, err := queryCS("net", host, "1")
   122  	if err != nil {
   123  		return
   124  	}
   125  loop:
   126  	for _, line := range lines {
   127  		f := getFields(line)
   128  		if len(f) < 2 {
   129  			continue
   130  		}
   131  		addr := f[1]
   132  		if i := byteIndex(addr, '!'); i >= 0 {
   133  			addr = addr[:i] // remove port
   134  		}
   135  		if ParseIP(addr) == nil {
   136  			continue
   137  		}
   138  		// only return unique addresses
   139  		for _, a := range addrs {
   140  			if a == addr {
   141  				continue loop
   142  			}
   143  		}
   144  		addrs = append(addrs, addr)
   145  	}
   146  	return
   147  }
   148  
   149  func lookupIP(host string) (addrs []IPAddr, err error) {
   150  	lits, err := LookupHost(host)
   151  	if err != nil {
   152  		return
   153  	}
   154  	for _, lit := range lits {
   155  		host, zone := splitHostZone(lit)
   156  		if ip := ParseIP(host); ip != nil {
   157  			addr := IPAddr{IP: ip, Zone: zone}
   158  			addrs = append(addrs, addr)
   159  		}
   160  	}
   161  	return
   162  }
   163  
   164  func lookupPort(network, service string) (port int, err error) {
   165  	switch network {
   166  	case "tcp4", "tcp6":
   167  		network = "tcp"
   168  	case "udp4", "udp6":
   169  		network = "udp"
   170  	}
   171  	lines, err := queryCS(network, "127.0.0.1", service)
   172  	if err != nil {
   173  		return
   174  	}
   175  	unknownPortError := &AddrError{Err: "unknown port", Addr: network + "/" + service}
   176  	if len(lines) == 0 {
   177  		return 0, unknownPortError
   178  	}
   179  	f := getFields(lines[0])
   180  	if len(f) < 2 {
   181  		return 0, unknownPortError
   182  	}
   183  	s := f[1]
   184  	if i := byteIndex(s, '!'); i >= 0 {
   185  		s = s[i+1:] // remove address
   186  	}
   187  	if n, _, ok := dtoi(s, 0); ok {
   188  		return n, nil
   189  	}
   190  	return 0, unknownPortError
   191  }
   192  
   193  // ensureEndDot adds '.' at the end of name unless it is already there.
   194  func ensureEndDot(name string) string {
   195  	if name == "" {
   196  		return "."
   197  	}
   198  	if name[len(name)-1] == '.' {
   199  		return name
   200  	}
   201  	return name + "."
   202  }
   203  
   204  func lookupCNAME(name string) (cname string, err error) {
   205  	lines, err := queryDNS(name, "cname")
   206  	if err != nil {
   207  		return
   208  	}
   209  	if len(lines) > 0 {
   210  		if f := getFields(lines[0]); len(f) >= 3 {
   211  			return f[2] + ".", nil
   212  		}
   213  	}
   214  	return "", errors.New("bad response from ndb/dns")
   215  }
   216  
   217  func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
   218  	var target string
   219  	if service == "" && proto == "" {
   220  		target = name
   221  	} else {
   222  		target = "_" + service + "._" + proto + "." + name
   223  	}
   224  	lines, err := queryDNS(target, "srv")
   225  	if err != nil {
   226  		return
   227  	}
   228  	for _, line := range lines {
   229  		f := getFields(line)
   230  		if len(f) < 6 {
   231  			continue
   232  		}
   233  		port, _, portOk := dtoi(f[4], 0)
   234  		priority, _, priorityOk := dtoi(f[3], 0)
   235  		weight, _, weightOk := dtoi(f[2], 0)
   236  		if !(portOk && priorityOk && weightOk) {
   237  			continue
   238  		}
   239  		addrs = append(addrs, &SRV{ensureEndDot(f[5]), uint16(port), uint16(priority), uint16(weight)})
   240  		cname = ensureEndDot(f[0])
   241  	}
   242  	byPriorityWeight(addrs).sort()
   243  	return
   244  }
   245  
   246  func lookupMX(name string) (mx []*MX, err error) {
   247  	lines, err := queryDNS(name, "mx")
   248  	if err != nil {
   249  		return
   250  	}
   251  	for _, line := range lines {
   252  		f := getFields(line)
   253  		if len(f) < 4 {
   254  			continue
   255  		}
   256  		if pref, _, ok := dtoi(f[2], 0); ok {
   257  			mx = append(mx, &MX{ensureEndDot(f[3]), uint16(pref)})
   258  		}
   259  	}
   260  	byPref(mx).sort()
   261  	return
   262  }
   263  
   264  func lookupNS(name string) (ns []*NS, err error) {
   265  	lines, err := queryDNS(name, "ns")
   266  	if err != nil {
   267  		return
   268  	}
   269  	for _, line := range lines {
   270  		f := getFields(line)
   271  		if len(f) < 3 {
   272  			continue
   273  		}
   274  		ns = append(ns, &NS{ensureEndDot(f[2])})
   275  	}
   276  	return
   277  }
   278  
   279  func lookupTXT(name string) (txt []string, err error) {
   280  	lines, err := queryDNS(name, "txt")
   281  	if err != nil {
   282  		return
   283  	}
   284  	for _, line := range lines {
   285  		if i := byteIndex(line, '\t'); i >= 0 {
   286  			txt = append(txt, ensureEndDot(line[i+1:]))
   287  		}
   288  	}
   289  	return
   290  }
   291  
   292  func lookupAddr(addr string) (name []string, err error) {
   293  	arpa, err := reverseaddr(addr)
   294  	if err != nil {
   295  		return
   296  	}
   297  	lines, err := queryDNS(arpa, "ptr")
   298  	if err != nil {
   299  		return
   300  	}
   301  	for _, line := range lines {
   302  		f := getFields(line)
   303  		if len(f) < 3 {
   304  			continue
   305  		}
   306  		name = append(name, ensureEndDot(f[2]))
   307  	}
   308  	return
   309  }