github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/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 // 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 } 66 // For now we need to infer link-layer service 67 // capabilities from media types. 68 // TODO: use MIB_IF_ROW2.AccessType now that we no longer support 69 // Windows XP. 70 switch aa.IfType { 71 case windows.IF_TYPE_ETHERNET_CSMACD, windows.IF_TYPE_ISO88025_TOKENRING, windows.IF_TYPE_IEEE80211, windows.IF_TYPE_IEEE1394: 72 ifi.Flags |= FlagBroadcast | FlagMulticast 73 case windows.IF_TYPE_PPP, windows.IF_TYPE_TUNNEL: 74 ifi.Flags |= FlagPointToPoint | FlagMulticast 75 case windows.IF_TYPE_SOFTWARE_LOOPBACK: 76 ifi.Flags |= FlagLoopback | FlagMulticast 77 case windows.IF_TYPE_ATM: 78 ifi.Flags |= FlagBroadcast | FlagPointToPoint | FlagMulticast // assume all services available; LANE, point-to-point and point-to-multipoint 79 } 80 if aa.Mtu == 0xffffffff { 81 ifi.MTU = -1 82 } else { 83 ifi.MTU = int(aa.Mtu) 84 } 85 if aa.PhysicalAddressLength > 0 { 86 ifi.HardwareAddr = make(HardwareAddr, aa.PhysicalAddressLength) 87 copy(ifi.HardwareAddr, aa.PhysicalAddress[:]) 88 } 89 ift = append(ift, ifi) 90 if ifindex == ifi.Index { 91 break 92 } 93 } 94 } 95 return ift, nil 96 } 97 98 // If the ifi is nil, interfaceAddrTable returns addresses for all 99 // network interfaces. Otherwise it returns addresses for a specific 100 // interface. 101 func interfaceAddrTable(ifi *Interface) ([]Addr, error) { 102 aas, err := adapterAddresses() 103 if err != nil { 104 return nil, err 105 } 106 var ifat []Addr 107 for _, aa := range aas { 108 index := aa.IfIndex 109 if index == 0 { // ipv6IfIndex is a substitute for ifIndex 110 index = aa.Ipv6IfIndex 111 } 112 if ifi == nil || ifi.Index == int(index) { 113 for puni := aa.FirstUnicastAddress; puni != nil; puni = puni.Next { 114 sa, err := puni.Address.Sockaddr.Sockaddr() 115 if err != nil { 116 return nil, os.NewSyscallError("sockaddr", err) 117 } 118 switch sa := sa.(type) { 119 case *syscall.SockaddrInet4: 120 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)}) 121 case *syscall.SockaddrInet6: 122 ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(puni.OnLinkPrefixLength), 8*IPv6len)} 123 copy(ifa.IP, sa.Addr[:]) 124 ifat = append(ifat, ifa) 125 } 126 } 127 for pany := aa.FirstAnycastAddress; pany != nil; pany = pany.Next { 128 sa, err := pany.Address.Sockaddr.Sockaddr() 129 if err != nil { 130 return nil, os.NewSyscallError("sockaddr", err) 131 } 132 switch sa := sa.(type) { 133 case *syscall.SockaddrInet4: 134 ifat = append(ifat, &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}) 135 case *syscall.SockaddrInet6: 136 ifa := &IPAddr{IP: make(IP, IPv6len)} 137 copy(ifa.IP, sa.Addr[:]) 138 ifat = append(ifat, ifa) 139 } 140 } 141 } 142 } 143 return ifat, nil 144 } 145 146 // interfaceMulticastAddrTable returns addresses for a specific 147 // interface. 148 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { 149 aas, err := adapterAddresses() 150 if err != nil { 151 return nil, err 152 } 153 var ifat []Addr 154 for _, aa := range aas { 155 index := aa.IfIndex 156 if index == 0 { // ipv6IfIndex is a substitute for ifIndex 157 index = aa.Ipv6IfIndex 158 } 159 if ifi == nil || ifi.Index == int(index) { 160 for pmul := aa.FirstMulticastAddress; pmul != nil; pmul = pmul.Next { 161 sa, err := pmul.Address.Sockaddr.Sockaddr() 162 if err != nil { 163 return nil, os.NewSyscallError("sockaddr", err) 164 } 165 switch sa := sa.(type) { 166 case *syscall.SockaddrInet4: 167 ifat = append(ifat, &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}) 168 case *syscall.SockaddrInet6: 169 ifa := &IPAddr{IP: make(IP, IPv6len)} 170 copy(ifa.IP, sa.Addr[:]) 171 ifat = append(ifat, ifa) 172 } 173 } 174 } 175 } 176 return ifat, nil 177 }