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.
8 "internal/syscall/windows"
14 // supportsVistaIP reports whether the platform implements new IP
15 // stack and ABIs supported on Windows Vista and above.
16 var supportsVistaIP
bool
19 supportsVistaIP
= probeWindowsIPStack()
22 func probeWindowsIPStack() (supportsVistaIP
bool) {
23 v
, err
:= syscall
.GetVersion()
25 return true // Windows 10 and above will deprecate this API
27 return byte(v
) >= 6 // major version of Windows Vista is 6
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
34 func adapterAddresses() ([]*windows
.IpAdapterAddresses
, error
) {
36 l
:= uint32(15000) // recommended initial size
39 err
:= windows
.GetAdaptersAddresses(syscall
.AF_UNSPEC
, windows
.GAA_FLAG_INCLUDE_PREFIX
, 0, (*windows
.IpAdapterAddresses
)(unsafe
.Pointer(&b
[0])), &l
)
46 if err
.(syscall
.Errno
) != syscall
.ERROR_BUFFER_OVERFLOW
{
47 return nil, os
.NewSyscallError("getadaptersaddresses", err
)
49 if l
<= uint32(len(b
)) {
50 return nil, os
.NewSyscallError("getadaptersaddresses", err
)
53 var aas
[]*windows
.IpAdapterAddresses
54 for aa
:= (*windows
.IpAdapterAddresses
)(unsafe
.Pointer(&b
[0])); aa
!= nil; aa
= aa
.Next
{
60 // If the ifindex is zero, interfaceTable returns mappings of all
61 // network interfaces. Otherwise it returns a mapping of a specific
63 func interfaceTable(ifindex
int) ([]Interface
, error
) {
64 aas
, err
:= adapterAddresses()
69 for _
, aa
:= range aas
{
71 if index
== 0 { // ipv6IfIndex is a substitute for ifIndex
72 index
= aa
.Ipv6IfIndex
74 if ifindex
== 0 || ifindex
== int(index
) {
77 Name
: syscall
.UTF16ToString((*(*[10000]uint16)(unsafe
.Pointer(aa
.FriendlyName
)))[:]),
79 if aa
.OperStatus
== windows
.IfOperStatusUp
{
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
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
97 if aa
.Mtu
== 0xffffffff {
100 ifi
.MTU
= int(aa
.Mtu
)
102 if aa
.PhysicalAddressLength
> 0 {
103 ifi
.HardwareAddr
= make(HardwareAddr
, aa
.PhysicalAddressLength
)
104 copy(ifi
.HardwareAddr
, aa
.PhysicalAddress
[:])
106 ift
= append(ift
, ifi
)
107 if ifindex
== ifi
.Index
{
115 // If the ifi is nil, interfaceAddrTable returns addresses for all
116 // network interfaces. Otherwise it returns addresses for a specific
118 func interfaceAddrTable(ifi
*Interface
) ([]Addr
, error
) {
119 aas
, err
:= adapterAddresses()
124 for _
, aa
:= range aas
{
126 if index
== 0 { // ipv6IfIndex is a substitute for ifIndex
127 index
= aa
.Ipv6IfIndex
129 var pfx4
, pfx6
[]IPNet
130 if !supportsVistaIP
{
131 pfx4
, pfx6
, err
= addrPrefixTable(aa
)
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()
140 return nil, os
.NewSyscallError("sockaddr", err
)
143 switch sa
:= sa
.(type) {
144 case *syscall
.SockaddrInet4
:
146 l
= int(puni
.OnLinkPrefixLength
)
148 l
= addrPrefixLen(pfx4
, IP(sa
.Addr
[:]))
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
:
153 l
= int(puni
.OnLinkPrefixLength
)
155 l
= addrPrefixLen(pfx6
, IP(sa
.Addr
[:]))
157 ifa
:= &IPNet
{IP
: make(IP
, IPv6len
), Mask
: CIDRMask(l
, 8*IPv6len
)}
158 copy(ifa
.IP
, sa
.Addr
[:])
159 ifat
= append(ifat
, ifa
)
162 for pany
:= aa
.FirstAnycastAddress
; pany
!= nil; pany
= pany
.Next
{
163 sa
, err
:= pany
.Address
.Sockaddr
.Sockaddr()
165 return nil, os
.NewSyscallError("sockaddr", err
)
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
)
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()
185 return nil, nil, os
.NewSyscallError("sockaddr", err
)
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
)
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
203 // NOTE: This is pretty naive implementation that contains many
204 // allocations and non-effective linear search, and should not be used
206 func addrPrefixLen(pfxs
[]IPNet
, ip IP
) int {
209 for i
:= range pfxs
{
210 if !pfxs
[i
].Contains(ip
) {
214 l
, _
= pfxs
[i
].Mask
.Size()
218 m
, _
:= pfxs
[i
].Mask
.Size()
234 // interfaceMulticastAddrTable returns addresses for a specific
236 func interfaceMulticastAddrTable(ifi
*Interface
) ([]Addr
, error
) {
237 aas
, err
:= adapterAddresses()
242 for _
, aa
:= range aas
{
244 if index
== 0 { // ipv6IfIndex is a substitute for ifIndex
245 index
= aa
.Ipv6IfIndex
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()
251 return nil, os
.NewSyscallError("sockaddr", err
)
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
)