github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/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 // adapterAddresses returns a list of IP adapter and address 15 // structures. The structure contains an IP adapter and flattened 16 // multiple IP addresses including unicast, anycast and multicast 17 // addresses. 18 func adapterAddresses() ([]*windows.IpAdapterAddresses, error) { 19 var b []byte 20 l := uint32(15000) // recommended initial size 21 for { 22 b = make([]byte, l) 23 err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l) 24 if err == nil { 25 if l == 0 { 26 return nil, nil 27 } 28 break 29 } 30 if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW { 31 return nil, os.NewSyscallError("getadaptersaddresses", err) 32 } 33 if l <= uint32(len(b)) { 34 return nil, os.NewSyscallError("getadaptersaddresses", err) 35 } 36 } 37 var aas []*windows.IpAdapterAddresses 38 for aa := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); aa != nil; aa = aa.Next { 39 aas = append(aas, aa) 40 } 41 return aas, nil 42 } 43 44 // If the ifindex is zero, interfaceTable returns mappings of all 45 // network interfaces. Otherwise it returns a mapping of a specific 46 // interface. 47 func interfaceTable(ifindex int) ([]Interface, error) { 48 aas, err := adapterAddresses() 49 if err != nil { 50 return nil, err 51 } 52 var ift []Interface 53 for _, aa := range aas { 54 index := aa.IfIndex 55 if index == 0 { // ipv6IfIndex is a substitute for ifIndex 56 index = aa.Ipv6IfIndex 57 } 58 if ifindex == 0 || ifindex == int(index) { 59 ifi := Interface{ 60 Index: int(index), 61 Name: windows.UTF16PtrToString(aa.FriendlyName), 62 } 63 if aa.OperStatus == windows.IfOperStatusUp { 64 ifi.Flags |= FlagUp 65 ifi.Flags |= FlagRunning 66 } 67 // For now we need to infer link-layer service 68 // capabilities from media types. 69 // TODO: use MIB_IF_ROW2.AccessType now that we no longer support 70 // Windows XP. 71 switch aa.IfType { 72 case windows.IF_TYPE_ETHERNET_CSMACD, windows.IF_TYPE_ISO88025_TOKENRING, windows.IF_TYPE_IEEE80211, windows.IF_TYPE_IEEE1394: 73 ifi.Flags |= FlagBroadcast | FlagMulticast 74 case windows.IF_TYPE_PPP, windows.IF_TYPE_TUNNEL: 75 ifi.Flags |= FlagPointToPoint | FlagMulticast 76 case windows.IF_TYPE_SOFTWARE_LOOPBACK: 77 ifi.Flags |= FlagLoopback | FlagMulticast 78 case windows.IF_TYPE_ATM: 79 ifi.Flags |= FlagBroadcast | FlagPointToPoint | FlagMulticast // assume all services available; LANE, point-to-point and point-to-multipoint 80 } 81 if aa.Mtu == 0xffffffff { 82 ifi.MTU = -1 83 } else { 84 ifi.MTU = int(aa.Mtu) 85 } 86 if aa.PhysicalAddressLength > 0 { 87 ifi.HardwareAddr = make(HardwareAddr, aa.PhysicalAddressLength) 88 copy(ifi.HardwareAddr, aa.PhysicalAddress[:]) 89 } 90 ift = append(ift, ifi) 91 if ifindex == ifi.Index { 92 break 93 } 94 } 95 } 96 return ift, nil 97 } 98 99 // If the ifi is nil, interfaceAddrTable returns addresses for all 100 // network interfaces. Otherwise it returns addresses for a specific 101 // interface. 102 func interfaceAddrTable(ifi *Interface) ([]Addr, error) { 103 aas, err := adapterAddresses() 104 if err != nil { 105 return nil, err 106 } 107 var ifat []Addr 108 for _, aa := range aas { 109 index := aa.IfIndex 110 if index == 0 { // ipv6IfIndex is a substitute for ifIndex 111 index = aa.Ipv6IfIndex 112 } 113 if ifi == nil || ifi.Index == int(index) { 114 for puni := aa.FirstUnicastAddress; puni != nil; puni = puni.Next { 115 sa, err := puni.Address.Sockaddr.Sockaddr() 116 if err != nil { 117 return nil, os.NewSyscallError("sockaddr", err) 118 } 119 switch sa := sa.(type) { 120 case *syscall.SockaddrInet4: 121 ifat = append(ifat, &IPNet{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]), Mask: CIDRMask(int(puni.OnLinkPrefixLength), 8*IPv4len)}) 122 case *syscall.SockaddrInet6: 123 ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(puni.OnLinkPrefixLength), 8*IPv6len)} 124 copy(ifa.IP, sa.Addr[:]) 125 ifat = append(ifat, ifa) 126 } 127 } 128 for pany := aa.FirstAnycastAddress; pany != nil; pany = pany.Next { 129 sa, err := pany.Address.Sockaddr.Sockaddr() 130 if err != nil { 131 return nil, os.NewSyscallError("sockaddr", err) 132 } 133 switch sa := sa.(type) { 134 case *syscall.SockaddrInet4: 135 ifat = append(ifat, &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}) 136 case *syscall.SockaddrInet6: 137 ifa := &IPAddr{IP: make(IP, IPv6len)} 138 copy(ifa.IP, sa.Addr[:]) 139 ifat = append(ifat, ifa) 140 } 141 } 142 } 143 } 144 return ifat, nil 145 } 146 147 // interfaceMulticastAddrTable returns addresses for a specific 148 // interface. 149 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { 150 aas, err := adapterAddresses() 151 if err != nil { 152 return nil, err 153 } 154 var ifat []Addr 155 for _, aa := range aas { 156 index := aa.IfIndex 157 if index == 0 { // ipv6IfIndex is a substitute for ifIndex 158 index = aa.Ipv6IfIndex 159 } 160 if ifi == nil || ifi.Index == int(index) { 161 for pmul := aa.FirstMulticastAddress; pmul != nil; pmul = pmul.Next { 162 sa, err := pmul.Address.Sockaddr.Sockaddr() 163 if err != nil { 164 return nil, os.NewSyscallError("sockaddr", err) 165 } 166 switch sa := sa.(type) { 167 case *syscall.SockaddrInet4: 168 ifat = append(ifat, &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}) 169 case *syscall.SockaddrInet6: 170 ifa := &IPAddr{IP: make(IP, IPv6len)} 171 copy(ifa.IP, sa.Addr[:]) 172 ifat = append(ifat, ifa) 173 } 174 } 175 } 176 } 177 return ifat, nil 178 }