github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/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 // supportsVistaIP reports whether the platform implements new IP 15 // stack and ABIs supported on Windows Vista and above. 16 var supportsVistaIP bool 17 18 func init() { 19 supportsVistaIP = probeWindowsIPStack() 20 } 21 22 func probeWindowsIPStack() (supportsVistaIP bool) { 23 v, err := syscall.GetVersion() 24 if err != nil { 25 return true // Windows 10 and above will deprecate this API 26 } 27 if byte(v) < 6 { // major version of Windows Vista is 6 28 return false 29 } 30 return true 31 } 32 33 // adapterAddresses returns a list of IP adapter and address 34 // structures. The structure contains an IP adapter and flattened 35 // multiple IP addresses including unicast, anycast and multicast 36 // addresses. 37 func adapterAddresses() ([]*windows.IpAdapterAddresses, error) { 38 var b []byte 39 l := uint32(15000) // recommended initial size 40 for { 41 b = make([]byte, l) 42 err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l) 43 if err == nil { 44 if l == 0 { 45 return nil, nil 46 } 47 break 48 } 49 if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW { 50 return nil, os.NewSyscallError("getadaptersaddresses", err) 51 } 52 if l <= uint32(len(b)) { 53 return nil, os.NewSyscallError("getadaptersaddresses", err) 54 } 55 } 56 var aas []*windows.IpAdapterAddresses 57 for aa := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); aa != nil; aa = aa.Next { 58 aas = append(aas, aa) 59 } 60 return aas, nil 61 } 62 63 // If the ifindex is zero, interfaceTable returns mappings of all 64 // network interfaces. Otherwise it returns a mapping of a specific 65 // interface. 66 func interfaceTable(ifindex int) ([]Interface, error) { 67 aas, err := adapterAddresses() 68 if err != nil { 69 return nil, err 70 } 71 var ift []Interface 72 for _, aa := range aas { 73 index := aa.IfIndex 74 if index == 0 { // ipv6IfIndex is a substitute for ifIndex 75 index = aa.Ipv6IfIndex 76 } 77 if ifindex == 0 || ifindex == int(index) { 78 ifi := Interface{ 79 Index: int(index), 80 Name: syscall.UTF16ToString((*(*[10000]uint16)(unsafe.Pointer(aa.FriendlyName)))[:]), 81 } 82 if aa.OperStatus == windows.IfOperStatusUp { 83 ifi.Flags |= FlagUp 84 } 85 // For now we need to infer link-layer service 86 // capabilities from media types. 87 // We will be able to use 88 // MIB_IF_ROW2.AccessType once we drop support 89 // for Windows XP. 90 switch aa.IfType { 91 case windows.IF_TYPE_ETHERNET_CSMACD, windows.IF_TYPE_ISO88025_TOKENRING, windows.IF_TYPE_IEEE80211, windows.IF_TYPE_IEEE1394: 92 ifi.Flags |= FlagBroadcast | FlagMulticast 93 case windows.IF_TYPE_PPP, windows.IF_TYPE_TUNNEL: 94 ifi.Flags |= FlagPointToPoint | FlagMulticast 95 case windows.IF_TYPE_SOFTWARE_LOOPBACK: 96 ifi.Flags |= FlagLoopback | FlagMulticast 97 case windows.IF_TYPE_ATM: 98 ifi.Flags |= FlagBroadcast | FlagPointToPoint | FlagMulticast // assume all services available; LANE, point-to-point and point-to-multipoint 99 } 100 if aa.Mtu == 0xffffffff { 101 ifi.MTU = -1 102 } else { 103 ifi.MTU = int(aa.Mtu) 104 } 105 if aa.PhysicalAddressLength > 0 { 106 ifi.HardwareAddr = make(HardwareAddr, aa.PhysicalAddressLength) 107 copy(ifi.HardwareAddr, aa.PhysicalAddress[:]) 108 } 109 ift = append(ift, ifi) 110 if ifindex == ifi.Index { 111 break 112 } 113 } 114 } 115 return ift, nil 116 } 117 118 // If the ifi is nil, interfaceAddrTable returns addresses for all 119 // network interfaces. Otherwise it returns addresses for a specific 120 // interface. 121 func interfaceAddrTable(ifi *Interface) ([]Addr, error) { 122 aas, err := adapterAddresses() 123 if err != nil { 124 return nil, err 125 } 126 var ifat []Addr 127 for _, aa := range aas { 128 index := aa.IfIndex 129 if index == 0 { // ipv6IfIndex is a substitute for ifIndex 130 index = aa.Ipv6IfIndex 131 } 132 var pfx4, pfx6 []IPNet 133 if !supportsVistaIP { 134 pfx4, pfx6, err = addrPrefixTable(aa) 135 if err != nil { 136 return nil, err 137 } 138 } 139 if ifi == nil || ifi.Index == int(index) { 140 for puni := aa.FirstUnicastAddress; puni != nil; puni = puni.Next { 141 sa, err := puni.Address.Sockaddr.Sockaddr() 142 if err != nil { 143 return nil, os.NewSyscallError("sockaddr", err) 144 } 145 var l int 146 switch sa := sa.(type) { 147 case *syscall.SockaddrInet4: 148 if supportsVistaIP { 149 l = int(puni.OnLinkPrefixLength) 150 } else { 151 l = addrPrefixLen(pfx4, IP(sa.Addr[:])) 152 } 153 ifat = append(ifat, &IPNet{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]), Mask: CIDRMask(l, 8*IPv4len)}) 154 case *syscall.SockaddrInet6: 155 if supportsVistaIP { 156 l = int(puni.OnLinkPrefixLength) 157 } else { 158 l = addrPrefixLen(pfx6, IP(sa.Addr[:])) 159 } 160 ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(l, 8*IPv6len)} 161 copy(ifa.IP, sa.Addr[:]) 162 ifat = append(ifat, ifa) 163 } 164 } 165 for pany := aa.FirstAnycastAddress; pany != nil; pany = pany.Next { 166 sa, err := pany.Address.Sockaddr.Sockaddr() 167 if err != nil { 168 return nil, os.NewSyscallError("sockaddr", err) 169 } 170 switch sa := sa.(type) { 171 case *syscall.SockaddrInet4: 172 ifat = append(ifat, &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}) 173 case *syscall.SockaddrInet6: 174 ifa := &IPAddr{IP: make(IP, IPv6len)} 175 copy(ifa.IP, sa.Addr[:]) 176 ifat = append(ifat, ifa) 177 } 178 } 179 } 180 } 181 return ifat, nil 182 } 183 184 func addrPrefixTable(aa *windows.IpAdapterAddresses) (pfx4, pfx6 []IPNet, err error) { 185 for p := aa.FirstPrefix; p != nil; p = p.Next { 186 sa, err := p.Address.Sockaddr.Sockaddr() 187 if err != nil { 188 return nil, nil, os.NewSyscallError("sockaddr", err) 189 } 190 switch sa := sa.(type) { 191 case *syscall.SockaddrInet4: 192 pfx := IPNet{IP: IP(sa.Addr[:]), Mask: CIDRMask(int(p.PrefixLength), 8*IPv4len)} 193 pfx4 = append(pfx4, pfx) 194 case *syscall.SockaddrInet6: 195 pfx := IPNet{IP: IP(sa.Addr[:]), Mask: CIDRMask(int(p.PrefixLength), 8*IPv6len)} 196 pfx6 = append(pfx6, pfx) 197 } 198 } 199 return 200 } 201 202 // addrPrefixLen returns an appropriate prefix length in bits for ip 203 // from pfxs. It returns 32 or 128 when no appropriate on-link address 204 // prefix found. 205 // 206 // NOTE: This is pretty naive implementation that contains many 207 // allocations and non-effective linear search, and should not be used 208 // freely. 209 func addrPrefixLen(pfxs []IPNet, ip IP) int { 210 var l int 211 var cand *IPNet 212 for i := range pfxs { 213 if !pfxs[i].Contains(ip) { 214 continue 215 } 216 if cand == nil { 217 l, _ = pfxs[i].Mask.Size() 218 cand = &pfxs[i] 219 continue 220 } 221 m, _ := pfxs[i].Mask.Size() 222 if m > l { 223 l = m 224 cand = &pfxs[i] 225 continue 226 } 227 } 228 if l > 0 { 229 return l 230 } 231 if ip.To4() != nil { 232 return 8 * IPv4len 233 } 234 return 8 * IPv6len 235 } 236 237 // interfaceMulticastAddrTable returns addresses for a specific 238 // interface. 239 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { 240 aas, err := adapterAddresses() 241 if err != nil { 242 return nil, err 243 } 244 var ifat []Addr 245 for _, aa := range aas { 246 index := aa.IfIndex 247 if index == 0 { // ipv6IfIndex is a substitute for ifIndex 248 index = aa.Ipv6IfIndex 249 } 250 if ifi == nil || ifi.Index == int(index) { 251 for pmul := aa.FirstMulticastAddress; pmul != nil; pmul = pmul.Next { 252 sa, err := pmul.Address.Sockaddr.Sockaddr() 253 if err != nil { 254 return nil, os.NewSyscallError("sockaddr", err) 255 } 256 switch sa := sa.(type) { 257 case *syscall.SockaddrInet4: 258 ifat = append(ifat, &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}) 259 case *syscall.SockaddrInet6: 260 ifa := &IPAddr{IP: make(IP, IPv6len)} 261 copy(ifa.IP, sa.Addr[:]) 262 ifat = append(ifat, ifa) 263 } 264 } 265 } 266 } 267 return ifat, nil 268 }