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