github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/net/interface_windows.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  	"internal/syscall/windows"
     9  	"os"
    10  	"syscall"
    11  	"unsafe"
    12  )
    13  
    14  func getAdapters() (*windows.IpAdapterAddresses, error) {
    15  	block := uint32(unsafe.Sizeof(windows.IpAdapterAddresses{}))
    16  
    17  	// pre-allocate a 15KB working buffer pointed to by the AdapterAddresses
    18  	// parameter.
    19  	// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx
    20  	size := uint32(15000)
    21  
    22  	var addrs []windows.IpAdapterAddresses
    23  	for {
    24  		addrs = make([]windows.IpAdapterAddresses, size/block+1)
    25  		err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, &addrs[0], &size)
    26  		if err == nil {
    27  			break
    28  		}
    29  		if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW {
    30  			return nil, os.NewSyscallError("getadaptersaddresses", err)
    31  		}
    32  	}
    33  	return &addrs[0], nil
    34  }
    35  
    36  func getInterfaceInfos() ([]syscall.InterfaceInfo, error) {
    37  	s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  	defer closeFunc(s)
    42  
    43  	iia := [20]syscall.InterfaceInfo{}
    44  	ret := uint32(0)
    45  	size := uint32(unsafe.Sizeof(iia))
    46  	err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&iia[0])), size, &ret, nil, 0)
    47  	if err != nil {
    48  		return nil, os.NewSyscallError("wsaioctl", err)
    49  	}
    50  	iilen := ret / uint32(unsafe.Sizeof(iia[0]))
    51  	return iia[:iilen-1], nil
    52  }
    53  
    54  func bytesEqualIP(a []byte, b []int8) bool {
    55  	for i := 0; i < len(a); i++ {
    56  		if a[i] != byte(b[i]) {
    57  			return false
    58  		}
    59  	}
    60  	return true
    61  }
    62  
    63  func findInterfaceInfo(iis []syscall.InterfaceInfo, paddr *windows.IpAdapterAddresses) *syscall.InterfaceInfo {
    64  	for _, ii := range iis {
    65  		iaddr := (*syscall.RawSockaddr)(unsafe.Pointer(&ii.Address))
    66  		puni := paddr.FirstUnicastAddress
    67  		for ; puni != nil; puni = puni.Next {
    68  			if iaddr.Family == puni.Address.Sockaddr.Addr.Family {
    69  				switch iaddr.Family {
    70  				case syscall.AF_INET:
    71  					a := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr
    72  					if bytesEqualIP(a[:], puni.Address.Sockaddr.Addr.Data[2:]) {
    73  						return &ii
    74  					}
    75  				case syscall.AF_INET6:
    76  					a := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&ii.Address)).Addr
    77  					if bytesEqualIP(a[:], puni.Address.Sockaddr.Addr.Data[2:]) {
    78  						return &ii
    79  					}
    80  				default:
    81  					continue
    82  				}
    83  			}
    84  		}
    85  	}
    86  	return nil
    87  }
    88  
    89  // If the ifindex is zero, interfaceTable returns mappings of all
    90  // network interfaces.  Otherwise it returns a mapping of a specific
    91  // interface.
    92  func interfaceTable(ifindex int) ([]Interface, error) {
    93  	paddr, err := getAdapters()
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	iis, err := getInterfaceInfos()
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	var ift []Interface
   104  	for ; paddr != nil; paddr = paddr.Next {
   105  		index := paddr.IfIndex
   106  		if paddr.Ipv6IfIndex != 0 {
   107  			index = paddr.Ipv6IfIndex
   108  		}
   109  		if ifindex == 0 || ifindex == int(index) {
   110  			ii := findInterfaceInfo(iis, paddr)
   111  			if ii == nil {
   112  				continue
   113  			}
   114  			var flags Flags
   115  			if paddr.Flags&windows.IfOperStatusUp != 0 {
   116  				flags |= FlagUp
   117  			}
   118  			if paddr.IfType&windows.IF_TYPE_SOFTWARE_LOOPBACK != 0 {
   119  				flags |= FlagLoopback
   120  			}
   121  			if ii.Flags&syscall.IFF_BROADCAST != 0 {
   122  				flags |= FlagBroadcast
   123  			}
   124  			if ii.Flags&syscall.IFF_POINTTOPOINT != 0 {
   125  				flags |= FlagPointToPoint
   126  			}
   127  			if ii.Flags&syscall.IFF_MULTICAST != 0 {
   128  				flags |= FlagMulticast
   129  			}
   130  			ifi := Interface{
   131  				Index:        int(index),
   132  				MTU:          int(paddr.Mtu),
   133  				Name:         syscall.UTF16ToString((*(*[10000]uint16)(unsafe.Pointer(paddr.FriendlyName)))[:]),
   134  				HardwareAddr: HardwareAddr(paddr.PhysicalAddress[:]),
   135  				Flags:        flags,
   136  			}
   137  			ift = append(ift, ifi)
   138  			if ifindex == int(ifi.Index) {
   139  				break
   140  			}
   141  		}
   142  	}
   143  	return ift, nil
   144  }
   145  
   146  // If the ifi is nil, interfaceAddrTable returns addresses for all
   147  // network interfaces.  Otherwise it returns addresses for a specific
   148  // interface.
   149  func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
   150  	paddr, err := getAdapters()
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  
   155  	var ifat []Addr
   156  	for ; paddr != nil; paddr = paddr.Next {
   157  		index := paddr.IfIndex
   158  		if paddr.Ipv6IfIndex != 0 {
   159  			index = paddr.Ipv6IfIndex
   160  		}
   161  		if ifi == nil || ifi.Index == int(index) {
   162  			puni := paddr.FirstUnicastAddress
   163  			for ; puni != nil; puni = puni.Next {
   164  				if sa, err := puni.Address.Sockaddr.Sockaddr(); err == nil {
   165  					switch sav := sa.(type) {
   166  					case *syscall.SockaddrInet4:
   167  						ifa := &IPNet{IP: make(IP, IPv4len), Mask: CIDRMask(int(puni.Address.SockaddrLength), 8*IPv4len)}
   168  						copy(ifa.IP, sav.Addr[:])
   169  						ifat = append(ifat, ifa)
   170  					case *syscall.SockaddrInet6:
   171  						ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(puni.Address.SockaddrLength), 8*IPv6len)}
   172  						copy(ifa.IP, sav.Addr[:])
   173  						ifat = append(ifat, ifa)
   174  					}
   175  				}
   176  			}
   177  			pany := paddr.FirstAnycastAddress
   178  			for ; pany != nil; pany = pany.Next {
   179  				if sa, err := pany.Address.Sockaddr.Sockaddr(); err == nil {
   180  					switch sav := sa.(type) {
   181  					case *syscall.SockaddrInet4:
   182  						ifa := &IPNet{IP: make(IP, IPv4len), Mask: CIDRMask(int(pany.Address.SockaddrLength), 8*IPv4len)}
   183  						copy(ifa.IP, sav.Addr[:])
   184  						ifat = append(ifat, ifa)
   185  					case *syscall.SockaddrInet6:
   186  						ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(pany.Address.SockaddrLength), 8*IPv6len)}
   187  						copy(ifa.IP, sav.Addr[:])
   188  						ifat = append(ifat, ifa)
   189  					}
   190  				}
   191  			}
   192  		}
   193  	}
   194  
   195  	return ifat, nil
   196  }
   197  
   198  // interfaceMulticastAddrTable returns addresses for a specific
   199  // interface.
   200  func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
   201  	paddr, err := getAdapters()
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  
   206  	var ifat []Addr
   207  	for ; paddr != nil; paddr = paddr.Next {
   208  		index := paddr.IfIndex
   209  		if paddr.Ipv6IfIndex != 0 {
   210  			index = paddr.Ipv6IfIndex
   211  		}
   212  		if ifi == nil || ifi.Index == int(index) {
   213  			pmul := paddr.FirstMulticastAddress
   214  			for ; pmul != nil; pmul = pmul.Next {
   215  				if sa, err := pmul.Address.Sockaddr.Sockaddr(); err == nil {
   216  					switch sav := sa.(type) {
   217  					case *syscall.SockaddrInet4:
   218  						ifa := &IPAddr{IP: make(IP, IPv4len)}
   219  						copy(ifa.IP, sav.Addr[:])
   220  						ifat = append(ifat, ifa)
   221  					case *syscall.SockaddrInet6:
   222  						ifa := &IPAddr{IP: make(IP, IPv6len)}
   223  						copy(ifa.IP, sav.Addr[:])
   224  						ifat = append(ifat, ifa)
   225  					}
   226  				}
   227  			}
   228  		}
   229  	}
   230  
   231  	return ifat, nil
   232  }