github.com/spotify/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/pkg/net/lookup_windows.go (about)

     1  // Copyright 2009 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  	"os"
     9  	"runtime"
    10  	"syscall"
    11  	"unsafe"
    12  )
    13  
    14  var (
    15  	lookupPort = oldLookupPort
    16  	lookupIP   = oldLookupIP
    17  )
    18  
    19  func getprotobyname(name string) (proto int, err error) {
    20  	p, err := syscall.GetProtoByName(name)
    21  	if err != nil {
    22  		return 0, os.NewSyscallError("GetProtoByName", err)
    23  	}
    24  	return int(p.Proto), nil
    25  }
    26  
    27  // lookupProtocol looks up IP protocol name and returns correspondent protocol number.
    28  func lookupProtocol(name string) (proto int, err error) {
    29  	// GetProtoByName return value is stored in thread local storage.
    30  	// Start new os thread before the call to prevent races.
    31  	type result struct {
    32  		proto int
    33  		err   error
    34  	}
    35  	ch := make(chan result)
    36  	go func() {
    37  		acquireThread()
    38  		defer releaseThread()
    39  		runtime.LockOSThread()
    40  		defer runtime.UnlockOSThread()
    41  		proto, err := getprotobyname(name)
    42  		ch <- result{proto: proto, err: err}
    43  	}()
    44  	r := <-ch
    45  	if r.err != nil {
    46  		if proto, ok := protocols[name]; ok {
    47  			return proto, nil
    48  		}
    49  	}
    50  	return r.proto, r.err
    51  }
    52  
    53  func lookupHost(name string) (addrs []string, err error) {
    54  	ips, err := LookupIP(name)
    55  	if err != nil {
    56  		return
    57  	}
    58  	addrs = make([]string, 0, len(ips))
    59  	for _, ip := range ips {
    60  		addrs = append(addrs, ip.String())
    61  	}
    62  	return
    63  }
    64  
    65  func gethostbyname(name string) (addrs []IP, err error) {
    66  	// caller already acquired thread
    67  	h, err := syscall.GetHostByName(name)
    68  	if err != nil {
    69  		return nil, os.NewSyscallError("GetHostByName", err)
    70  	}
    71  	switch h.AddrType {
    72  	case syscall.AF_INET:
    73  		i := 0
    74  		addrs = make([]IP, 100) // plenty of room to grow
    75  		for p := (*[100](*[4]byte))(unsafe.Pointer(h.AddrList)); i < cap(addrs) && p[i] != nil; i++ {
    76  			addrs[i] = IPv4(p[i][0], p[i][1], p[i][2], p[i][3])
    77  		}
    78  		addrs = addrs[0:i]
    79  	default: // TODO(vcc): Implement non IPv4 address lookups.
    80  		return nil, os.NewSyscallError("LookupIP", syscall.EWINDOWS)
    81  	}
    82  	return addrs, nil
    83  }
    84  
    85  func oldLookupIP(name string) (addrs []IP, err error) {
    86  	// GetHostByName return value is stored in thread local storage.
    87  	// Start new os thread before the call to prevent races.
    88  	type result struct {
    89  		addrs []IP
    90  		err   error
    91  	}
    92  	ch := make(chan result)
    93  	go func() {
    94  		acquireThread()
    95  		defer releaseThread()
    96  		runtime.LockOSThread()
    97  		defer runtime.UnlockOSThread()
    98  		addrs, err := gethostbyname(name)
    99  		ch <- result{addrs: addrs, err: err}
   100  	}()
   101  	r := <-ch
   102  	return r.addrs, r.err
   103  }
   104  
   105  func newLookupIP(name string) (addrs []IP, err error) {
   106  	acquireThread()
   107  	defer releaseThread()
   108  	hints := syscall.AddrinfoW{
   109  		Family:   syscall.AF_UNSPEC,
   110  		Socktype: syscall.SOCK_STREAM,
   111  		Protocol: syscall.IPPROTO_IP,
   112  	}
   113  	var result *syscall.AddrinfoW
   114  	e := syscall.GetAddrInfoW(syscall.StringToUTF16Ptr(name), nil, &hints, &result)
   115  	if e != nil {
   116  		return nil, os.NewSyscallError("GetAddrInfoW", e)
   117  	}
   118  	defer syscall.FreeAddrInfoW(result)
   119  	addrs = make([]IP, 0, 5)
   120  	for ; result != nil; result = result.Next {
   121  		addr := unsafe.Pointer(result.Addr)
   122  		switch result.Family {
   123  		case syscall.AF_INET:
   124  			a := (*syscall.RawSockaddrInet4)(addr).Addr
   125  			addrs = append(addrs, IPv4(a[0], a[1], a[2], a[3]))
   126  		case syscall.AF_INET6:
   127  			a := (*syscall.RawSockaddrInet6)(addr).Addr
   128  			addrs = append(addrs, IP{a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]})
   129  		default:
   130  			return nil, os.NewSyscallError("LookupIP", syscall.EWINDOWS)
   131  		}
   132  	}
   133  	return addrs, nil
   134  }
   135  
   136  func getservbyname(network, service string) (port int, err error) {
   137  	acquireThread()
   138  	defer releaseThread()
   139  	switch network {
   140  	case "tcp4", "tcp6":
   141  		network = "tcp"
   142  	case "udp4", "udp6":
   143  		network = "udp"
   144  	}
   145  	s, err := syscall.GetServByName(service, network)
   146  	if err != nil {
   147  		return 0, os.NewSyscallError("GetServByName", err)
   148  	}
   149  	return int(syscall.Ntohs(s.Port)), nil
   150  }
   151  
   152  func oldLookupPort(network, service string) (port int, err error) {
   153  	// GetServByName return value is stored in thread local storage.
   154  	// Start new os thread before the call to prevent races.
   155  	type result struct {
   156  		port int
   157  		err  error
   158  	}
   159  	ch := make(chan result)
   160  	go func() {
   161  		acquireThread()
   162  		defer releaseThread()
   163  		runtime.LockOSThread()
   164  		defer runtime.UnlockOSThread()
   165  		port, err := getservbyname(network, service)
   166  		ch <- result{port: port, err: err}
   167  	}()
   168  	r := <-ch
   169  	return r.port, r.err
   170  }
   171  
   172  func newLookupPort(network, service string) (port int, err error) {
   173  	acquireThread()
   174  	defer releaseThread()
   175  	var stype int32
   176  	switch network {
   177  	case "tcp4", "tcp6":
   178  		stype = syscall.SOCK_STREAM
   179  	case "udp4", "udp6":
   180  		stype = syscall.SOCK_DGRAM
   181  	}
   182  	hints := syscall.AddrinfoW{
   183  		Family:   syscall.AF_UNSPEC,
   184  		Socktype: stype,
   185  		Protocol: syscall.IPPROTO_IP,
   186  	}
   187  	var result *syscall.AddrinfoW
   188  	e := syscall.GetAddrInfoW(nil, syscall.StringToUTF16Ptr(service), &hints, &result)
   189  	if e != nil {
   190  		return 0, os.NewSyscallError("GetAddrInfoW", e)
   191  	}
   192  	defer syscall.FreeAddrInfoW(result)
   193  	if result == nil {
   194  		return 0, os.NewSyscallError("LookupPort", syscall.EINVAL)
   195  	}
   196  	addr := unsafe.Pointer(result.Addr)
   197  	switch result.Family {
   198  	case syscall.AF_INET:
   199  		a := (*syscall.RawSockaddrInet4)(addr)
   200  		return int(syscall.Ntohs(a.Port)), nil
   201  	case syscall.AF_INET6:
   202  		a := (*syscall.RawSockaddrInet6)(addr)
   203  		return int(syscall.Ntohs(a.Port)), nil
   204  	}
   205  	return 0, os.NewSyscallError("LookupPort", syscall.EINVAL)
   206  }
   207  
   208  func lookupCNAME(name string) (cname string, err error) {
   209  	acquireThread()
   210  	defer releaseThread()
   211  	var r *syscall.DNSRecord
   212  	e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &r, nil)
   213  	if e != nil {
   214  		return "", os.NewSyscallError("LookupCNAME", e)
   215  	}
   216  	defer syscall.DnsRecordListFree(r, 1)
   217  	if r != nil && r.Type == syscall.DNS_TYPE_CNAME {
   218  		v := (*syscall.DNSPTRData)(unsafe.Pointer(&r.Data[0]))
   219  		cname = syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."
   220  	}
   221  	return
   222  }
   223  
   224  func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
   225  	acquireThread()
   226  	defer releaseThread()
   227  	var target string
   228  	if service == "" && proto == "" {
   229  		target = name
   230  	} else {
   231  		target = "_" + service + "._" + proto + "." + name
   232  	}
   233  	var r *syscall.DNSRecord
   234  	e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &r, nil)
   235  	if e != nil {
   236  		return "", nil, os.NewSyscallError("LookupSRV", e)
   237  	}
   238  	defer syscall.DnsRecordListFree(r, 1)
   239  	addrs = make([]*SRV, 0, 10)
   240  	for p := r; p != nil && p.Type == syscall.DNS_TYPE_SRV; p = p.Next {
   241  		v := (*syscall.DNSSRVData)(unsafe.Pointer(&p.Data[0]))
   242  		addrs = append(addrs, &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight})
   243  	}
   244  	byPriorityWeight(addrs).sort()
   245  	return name, addrs, nil
   246  }
   247  
   248  func lookupMX(name string) (mx []*MX, err error) {
   249  	acquireThread()
   250  	defer releaseThread()
   251  	var r *syscall.DNSRecord
   252  	e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &r, nil)
   253  	if e != nil {
   254  		return nil, os.NewSyscallError("LookupMX", e)
   255  	}
   256  	defer syscall.DnsRecordListFree(r, 1)
   257  	mx = make([]*MX, 0, 10)
   258  	for p := r; p != nil && p.Type == syscall.DNS_TYPE_MX; p = p.Next {
   259  		v := (*syscall.DNSMXData)(unsafe.Pointer(&p.Data[0]))
   260  		mx = append(mx, &MX{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]) + ".", v.Preference})
   261  	}
   262  	byPref(mx).sort()
   263  	return mx, nil
   264  }
   265  
   266  func lookupNS(name string) (ns []*NS, err error) {
   267  	acquireThread()
   268  	defer releaseThread()
   269  	var r *syscall.DNSRecord
   270  	e := syscall.DnsQuery(name, syscall.DNS_TYPE_NS, 0, nil, &r, nil)
   271  	if e != nil {
   272  		return nil, os.NewSyscallError("LookupNS", e)
   273  	}
   274  	defer syscall.DnsRecordListFree(r, 1)
   275  	ns = make([]*NS, 0, 10)
   276  	for p := r; p != nil && p.Type == syscall.DNS_TYPE_NS; p = p.Next {
   277  		v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
   278  		ns = append(ns, &NS{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."})
   279  	}
   280  	return ns, nil
   281  }
   282  
   283  func lookupTXT(name string) (txt []string, err error) {
   284  	acquireThread()
   285  	defer releaseThread()
   286  	var r *syscall.DNSRecord
   287  	e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &r, nil)
   288  	if e != nil {
   289  		return nil, os.NewSyscallError("LookupTXT", e)
   290  	}
   291  	defer syscall.DnsRecordListFree(r, 1)
   292  	txt = make([]string, 0, 10)
   293  	if r != nil && r.Type == syscall.DNS_TYPE_TEXT {
   294  		d := (*syscall.DNSTXTData)(unsafe.Pointer(&r.Data[0]))
   295  		for _, v := range (*[1 << 10]*uint16)(unsafe.Pointer(&(d.StringArray[0])))[:d.StringCount] {
   296  			s := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(v))[:])
   297  			txt = append(txt, s)
   298  		}
   299  	}
   300  	return
   301  }
   302  
   303  func lookupAddr(addr string) (name []string, err error) {
   304  	acquireThread()
   305  	defer releaseThread()
   306  	arpa, err := reverseaddr(addr)
   307  	if err != nil {
   308  		return nil, err
   309  	}
   310  	var r *syscall.DNSRecord
   311  	e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &r, nil)
   312  	if e != nil {
   313  		return nil, os.NewSyscallError("LookupAddr", e)
   314  	}
   315  	defer syscall.DnsRecordListFree(r, 1)
   316  	name = make([]string, 0, 10)
   317  	for p := r; p != nil && p.Type == syscall.DNS_TYPE_PTR; p = p.Next {
   318  		v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
   319  		name = append(name, syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))
   320  	}
   321  	return name, nil
   322  }