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 } 233