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