| // 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" |
| "syscall" |
| "unsafe" |
| ) |
| |
| func getAdapters() (*windows.IpAdapterAddresses, error) { |
| block := uint32(unsafe.Sizeof(windows.IpAdapterAddresses{})) |
| |
| // pre-allocate a 15KB working buffer pointed to by the AdapterAddresses |
| // parameter. |
| // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx |
| size := uint32(15000) |
| |
| var addrs []windows.IpAdapterAddresses |
| for { |
| addrs = make([]windows.IpAdapterAddresses, size/block+1) |
| err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, &addrs[0], &size) |
| if err == nil { |
| break |
| } |
| if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW { |
| return nil, err |
| } |
| } |
| return &addrs[0], nil |
| } |
| |
| func getInterfaceInfos() ([]syscall.InterfaceInfo, error) { |
| s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) |
| if err != nil { |
| return nil, err |
| } |
| defer closeFunc(s) |
| |
| iia := [20]syscall.InterfaceInfo{} |
| ret := uint32(0) |
| size := uint32(unsafe.Sizeof(iia)) |
| err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&iia[0])), size, &ret, nil, 0) |
| if err != nil { |
| return nil, err |
| } |
| iilen := ret / uint32(unsafe.Sizeof(iia[0])) |
| return iia[:iilen-1], nil |
| } |
| |
| func bytesEqualIP(a []byte, b []int8) bool { |
| for i := 0; i < len(a); i++ { |
| if a[i] != byte(b[i]) { |
| return false |
| } |
| } |
| return true |
| } |
| |
| func findInterfaceInfo(iis []syscall.InterfaceInfo, paddr *windows.IpAdapterAddresses) *syscall.InterfaceInfo { |
| for _, ii := range iis { |
| iaddr := (*syscall.RawSockaddr)(unsafe.Pointer(&ii.Address)) |
| puni := paddr.FirstUnicastAddress |
| for ; puni != nil; puni = puni.Next { |
| if iaddr.Family == puni.Address.Sockaddr.Addr.Family { |
| switch iaddr.Family { |
| case syscall.AF_INET: |
| a := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr |
| if bytesEqualIP(a[:], puni.Address.Sockaddr.Addr.Data[2:]) { |
| return &ii |
| } |
| case syscall.AF_INET6: |
| a := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&ii.Address)).Addr |
| if bytesEqualIP(a[:], puni.Address.Sockaddr.Addr.Data[2:]) { |
| return &ii |
| } |
| default: |
| continue |
| } |
| } |
| } |
| } |
| return 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) { |
| paddr, err := getAdapters() |
| if err != nil { |
| return nil, err |
| } |
| |
| iis, err := getInterfaceInfos() |
| if err != nil { |
| return nil, err |
| } |
| |
| var ift []Interface |
| for ; paddr != nil; paddr = paddr.Next { |
| index := paddr.IfIndex |
| if paddr.Ipv6IfIndex != 0 { |
| index = paddr.Ipv6IfIndex |
| } |
| if ifindex == 0 || ifindex == int(index) { |
| ii := findInterfaceInfo(iis, paddr) |
| if ii == nil { |
| continue |
| } |
| var flags Flags |
| if paddr.Flags&windows.IfOperStatusUp != 0 { |
| flags |= FlagUp |
| } |
| if paddr.IfType&windows.IF_TYPE_SOFTWARE_LOOPBACK != 0 { |
| flags |= FlagLoopback |
| } |
| if ii.Flags&syscall.IFF_BROADCAST != 0 { |
| flags |= FlagBroadcast |
| } |
| if ii.Flags&syscall.IFF_POINTTOPOINT != 0 { |
| flags |= FlagPointToPoint |
| } |
| if ii.Flags&syscall.IFF_MULTICAST != 0 { |
| flags |= FlagMulticast |
| } |
| ifi := Interface{ |
| Index: int(index), |
| MTU: int(paddr.Mtu), |
| Name: syscall.UTF16ToString((*(*[10000]uint16)(unsafe.Pointer(paddr.FriendlyName)))[:]), |
| HardwareAddr: HardwareAddr(paddr.PhysicalAddress[:]), |
| Flags: flags, |
| } |
| ift = append(ift, ifi) |
| if ifindex == int(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) { |
| paddr, err := getAdapters() |
| if err != nil { |
| return nil, err |
| } |
| |
| var ifat []Addr |
| for ; paddr != nil; paddr = paddr.Next { |
| index := paddr.IfIndex |
| if paddr.Ipv6IfIndex != 0 { |
| index = paddr.Ipv6IfIndex |
| } |
| if ifi == nil || ifi.Index == int(index) { |
| puni := paddr.FirstUnicastAddress |
| for ; puni != nil; puni = puni.Next { |
| if sa, err := puni.Address.Sockaddr.Sockaddr(); err == nil { |
| switch sav := sa.(type) { |
| case *syscall.SockaddrInet4: |
| ifa := &IPNet{IP: make(IP, IPv4len), Mask: CIDRMask(int(puni.Address.SockaddrLength), 8*IPv4len)} |
| copy(ifa.IP, sav.Addr[:]) |
| ifat = append(ifat, ifa) |
| case *syscall.SockaddrInet6: |
| ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(puni.Address.SockaddrLength), 8*IPv6len)} |
| copy(ifa.IP, sav.Addr[:]) |
| ifat = append(ifat, ifa) |
| } |
| } |
| } |
| pany := paddr.FirstAnycastAddress |
| for ; pany != nil; pany = pany.Next { |
| if sa, err := pany.Address.Sockaddr.Sockaddr(); err == nil { |
| switch sav := sa.(type) { |
| case *syscall.SockaddrInet4: |
| ifa := &IPNet{IP: make(IP, IPv4len), Mask: CIDRMask(int(pany.Address.SockaddrLength), 8*IPv4len)} |
| copy(ifa.IP, sav.Addr[:]) |
| ifat = append(ifat, ifa) |
| case *syscall.SockaddrInet6: |
| ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(pany.Address.SockaddrLength), 8*IPv6len)} |
| copy(ifa.IP, sav.Addr[:]) |
| ifat = append(ifat, ifa) |
| } |
| } |
| } |
| } |
| } |
| |
| return ifat, nil |
| } |
| |
| // interfaceMulticastAddrTable returns addresses for a specific |
| // interface. |
| func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { |
| paddr, err := getAdapters() |
| if err != nil { |
| return nil, err |
| } |
| |
| var ifat []Addr |
| for ; paddr != nil; paddr = paddr.Next { |
| index := paddr.IfIndex |
| if paddr.Ipv6IfIndex != 0 { |
| index = paddr.Ipv6IfIndex |
| } |
| if ifi == nil || ifi.Index == int(index) { |
| pmul := paddr.FirstMulticastAddress |
| for ; pmul != nil; pmul = pmul.Next { |
| if sa, err := pmul.Address.Sockaddr.Sockaddr(); err == nil { |
| switch sav := sa.(type) { |
| case *syscall.SockaddrInet4: |
| ifa := &IPAddr{IP: make(IP, IPv4len)} |
| copy(ifa.IP, sav.Addr[:]) |
| ifat = append(ifat, ifa) |
| case *syscall.SockaddrInet6: |
| ifa := &IPAddr{IP: make(IP, IPv6len)} |
| copy(ifa.IP, sav.Addr[:]) |
| ifat = append(ifat, ifa) |
| } |
| } |
| } |
| } |
| } |
| |
| return ifat, nil |
| } |