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 if byte(v
) < 6 { // major version of Windows Vista is 6
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
37 func adapterAddresses() ([]*windows
.IpAdapterAddresses
, error
) {
39 l
:= uint32(15000) // recommended initial size
42 err
:= windows
.GetAdaptersAddresses(syscall
.AF_UNSPEC
, windows
.GAA_FLAG_INCLUDE_PREFIX
, 0, (*windows
.IpAdapterAddresses
)(unsafe
.Pointer(&b
[0])), &l
)
49 if err
.(syscall
.Errno
) != syscall
.ERROR_BUFFER_OVERFLOW
{
50 return nil, os
.NewSyscallError("getadaptersaddresses", err
)
52 if l
<= uint32(len(b
)) {
53 return nil, os
.NewSyscallError("getadaptersaddresses", err
)
56 var aas
[]*windows
.IpAdapterAddresses
57 for aa
:= (*windows
.IpAdapterAddresses
)(unsafe
.Pointer(&b
[0])); aa
!= nil; aa
= aa
.Next
{
63 // If the ifindex is zero, interfaceTable returns mappings of all
64 // network interfaces. Otherwise it returns a mapping of a specific
66 func interfaceTable(ifindex
int) ([]Interface
, error
) {
67 aas
, err
:= adapterAddresses()
72 for _
, aa
:= range aas
{
74 if index
== 0 { // ipv6IfIndex is a substitute for ifIndex
75 index
= aa
.Ipv6IfIndex
77 if ifindex
== 0 || ifindex
== int(index
) {
80 Name
: syscall
.UTF16ToString((*(*[10000]uint16)(unsafe
.Pointer(aa
.FriendlyName
)))[:]),
82 if aa
.OperStatus
== windows
.IfOperStatusUp
{
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
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
100 if aa
.Mtu
== 0xffffffff {
103 ifi
.MTU
= int(aa
.Mtu
)
105 if aa
.PhysicalAddressLength
> 0 {
106 ifi
.HardwareAddr
= make(HardwareAddr
, aa
.PhysicalAddressLength
)
107 copy(ifi
.HardwareAddr
, aa
.PhysicalAddress
[:])
109 ift
= append(ift
, ifi
)
110 if ifindex
== ifi
.Index
{
118 // If the ifi is nil, interfaceAddrTable returns addresses for all
119 // network interfaces. Otherwise it returns addresses for a specific
121 func interfaceAddrTable(ifi
*Interface
) ([]Addr
, error
) {
122 aas
, err
:= adapterAddresses()
127 for _
, aa
:= range aas
{
129 if index
== 0 { // ipv6IfIndex is a substitute for ifIndex
130 index
= aa
.Ipv6IfIndex
132 var pfx4
, pfx6
[]IPNet
133 if !supportsVistaIP
{
134 pfx4
, pfx6
, err
= addrPrefixTable(aa
)
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()
143 return nil, os
.NewSyscallError("sockaddr", err
)
146 switch sa
:= sa
.(type) {
147 case *syscall
.SockaddrInet4
:
149 l
= int(puni
.OnLinkPrefixLength
)
151 l
= addrPrefixLen(pfx4
, IP(sa
.Addr
[:]))
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
:
156 l
= int(puni
.OnLinkPrefixLength
)
158 l
= addrPrefixLen(pfx6
, IP(sa
.Addr
[:]))
160 ifa
:= &IPNet
{IP
: make(IP
, IPv6len
), Mask
: CIDRMask(l
, 8*IPv6len
)}
161 copy(ifa
.IP
, sa
.Addr
[:])
162 ifat
= append(ifat
, ifa
)
165 for pany
:= aa
.FirstAnycastAddress
; pany
!= nil; pany
= pany
.Next
{
166 sa
, err
:= pany
.Address
.Sockaddr
.Sockaddr()
168 return nil, os
.NewSyscallError("sockaddr", err
)
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
)
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()
188 return nil, nil, os
.NewSyscallError("sockaddr", err
)
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
)
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
206 // NOTE: This is pretty naive implementation that contains many
207 // allocations and non-effective linear search, and should not be used
209 func addrPrefixLen(pfxs
[]IPNet
, ip IP
) int {
212 for i
:= range pfxs
{
213 if !pfxs
[i
].Contains(ip
) {
217 l
, _
= pfxs
[i
].Mask
.Size()
221 m
, _
:= pfxs
[i
].Mask
.Size()
237 // interfaceMulticastAddrTable returns addresses for a specific
239 func interfaceMulticastAddrTable(ifi
*Interface
) ([]Addr
, error
) {
240 aas
, err
:= adapterAddresses()
245 for _
, aa
:= range aas
{
247 if index
== 0 { // ipv6IfIndex is a substitute for ifIndex
248 index
= aa
.Ipv6IfIndex
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()
254 return nil, os
.NewSyscallError("sockaddr", err
)
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
)