| // Copyright 2011 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package net | |
| import ( | |
| "internal/syscall/windows" | |
| "os" | |
| "syscall" | |
| "unsafe" | |
| ) | |
| // adapterAddresses returns a list of IP adapter and address | |
| // structures. The structure contains an IP adapter and flattened | |
| // multiple IP addresses including unicast, anycast and multicast | |
| // addresses. | |
| func adapterAddresses() ([]*windows.IpAdapterAddresses, error) { | |
| var b []byte | |
| l := uint32(15000) // recommended initial size | |
| for { | |
| b = make([]byte, l) | |
| err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l) | |
| if err == nil { | |
| if l == 0 { | |
| return nil, nil | |
| } | |
| break | |
| } | |
| if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW { | |
| return nil, os.NewSyscallError("getadaptersaddresses", err) | |
| } | |
| if l <= uint32(len(b)) { | |
| return nil, os.NewSyscallError("getadaptersaddresses", err) | |
| } | |
| } | |
| var aas []*windows.IpAdapterAddresses | |
| for aa := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); aa != nil; aa = aa.Next { | |
| aas = append(aas, aa) | |
| } | |
| return aas, nil | |
| } | |
| // If the ifindex is zero, interfaceTable returns mappings of all | |
| // network interfaces. Otherwise it returns a mapping of a specific | |
| // interface. | |
| func interfaceTable(ifindex int) ([]Interface, error) { | |
| aas, err := adapterAddresses() | |
| if err != nil { | |
| return nil, err | |
| } | |
| var ift []Interface | |
| for _, aa := range aas { | |
| index := aa.IfIndex | |
| if index == 0 { // ipv6IfIndex is a substitute for ifIndex | |
| index = aa.Ipv6IfIndex | |
| } | |
| if ifindex == 0 || ifindex == int(index) { | |
| ifi := Interface{ | |
| Index: int(index), | |
| Name: windows.UTF16PtrToString(aa.FriendlyName), | |
| } | |
| if aa.OperStatus == windows.IfOperStatusUp { | |
| ifi.Flags |= FlagUp | |
| } | |
| // For now we need to infer link-layer service | |
| // capabilities from media types. | |
| // TODO: use MIB_IF_ROW2.AccessType now that we no longer support | |
| // Windows XP. | |
| switch aa.IfType { | |
| case windows.IF_TYPE_ETHERNET_CSMACD, windows.IF_TYPE_ISO88025_TOKENRING, windows.IF_TYPE_IEEE80211, windows.IF_TYPE_IEEE1394: | |
| ifi.Flags |= FlagBroadcast | FlagMulticast | |
| case windows.IF_TYPE_PPP, windows.IF_TYPE_TUNNEL: | |
| ifi.Flags |= FlagPointToPoint | FlagMulticast | |
| case windows.IF_TYPE_SOFTWARE_LOOPBACK: | |
| ifi.Flags |= FlagLoopback | FlagMulticast | |
| case windows.IF_TYPE_ATM: | |
| ifi.Flags |= FlagBroadcast | FlagPointToPoint | FlagMulticast // assume all services available; LANE, point-to-point and point-to-multipoint | |
| } | |
| if aa.Mtu == 0xffffffff { | |
| ifi.MTU = -1 | |
| } else { | |
| ifi.MTU = int(aa.Mtu) | |
| } | |
| if aa.PhysicalAddressLength > 0 { | |
| ifi.HardwareAddr = make(HardwareAddr, aa.PhysicalAddressLength) | |
| copy(ifi.HardwareAddr, aa.PhysicalAddress[:]) | |
| } | |
| ift = append(ift, ifi) | |
| if ifindex == ifi.Index { | |
| break | |
| } | |
| } | |
| } | |
| return ift, nil | |
| } | |
| // If the ifi is nil, interfaceAddrTable returns addresses for all | |
| // network interfaces. Otherwise it returns addresses for a specific | |
| // interface. | |
| func interfaceAddrTable(ifi *Interface) ([]Addr, error) { | |
| aas, err := adapterAddresses() | |
| if err != nil { | |
| return nil, err | |
| } | |
| var ifat []Addr | |
| for _, aa := range aas { | |
| index := aa.IfIndex | |
| if index == 0 { // ipv6IfIndex is a substitute for ifIndex | |
| index = aa.Ipv6IfIndex | |
| } | |
| if ifi == nil || ifi.Index == int(index) { | |
| for puni := aa.FirstUnicastAddress; puni != nil; puni = puni.Next { | |
| sa, err := puni.Address.Sockaddr.Sockaddr() | |
| if err != nil { | |
| return nil, os.NewSyscallError("sockaddr", err) | |
| } | |
| switch sa := sa.(type) { | |
| case *syscall.SockaddrInet4: | |
| 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)}) | |
| case *syscall.SockaddrInet6: | |
| ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(puni.OnLinkPrefixLength), 8*IPv6len)} | |
| copy(ifa.IP, sa.Addr[:]) | |
| ifat = append(ifat, ifa) | |
| } | |
| } | |
| for pany := aa.FirstAnycastAddress; pany != nil; pany = pany.Next { | |
| sa, err := pany.Address.Sockaddr.Sockaddr() | |
| if err != nil { | |
| return nil, os.NewSyscallError("sockaddr", err) | |
| } | |
| switch sa := sa.(type) { | |
| case *syscall.SockaddrInet4: | |
| ifat = append(ifat, &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}) | |
| case *syscall.SockaddrInet6: | |
| ifa := &IPAddr{IP: make(IP, IPv6len)} | |
| copy(ifa.IP, sa.Addr[:]) | |
| ifat = append(ifat, ifa) | |
| } | |
| } | |
| } | |
| } | |
| return ifat, nil | |
| } | |
| // interfaceMulticastAddrTable returns addresses for a specific | |
| // interface. | |
| func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { | |
| aas, err := adapterAddresses() | |
| if err != nil { | |
| return nil, err | |
| } | |
| var ifat []Addr | |
| for _, aa := range aas { | |
| index := aa.IfIndex | |
| if index == 0 { // ipv6IfIndex is a substitute for ifIndex | |
| index = aa.Ipv6IfIndex | |
| } | |
| if ifi == nil || ifi.Index == int(index) { | |
| for pmul := aa.FirstMulticastAddress; pmul != nil; pmul = pmul.Next { | |
| sa, err := pmul.Address.Sockaddr.Sockaddr() | |
| if err != nil { | |
| return nil, os.NewSyscallError("sockaddr", err) | |
| } | |
| switch sa := sa.(type) { | |
| case *syscall.SockaddrInet4: | |
| ifat = append(ifat, &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}) | |
| case *syscall.SockaddrInet6: | |
| ifa := &IPAddr{IP: make(IP, IPv6len)} | |
| copy(ifa.IP, sa.Addr[:]) | |
| ifat = append(ifat, ifa) | |
| } | |
| } | |
| } | |
| } | |
| return ifat, nil | |
| } |