diff options
Diffstat (limited to 'libgo/go/net/interface_windows.go')
-rw-r--r-- | libgo/go/net/interface_windows.go | 250 |
1 files changed, 162 insertions, 88 deletions
diff --git a/libgo/go/net/interface_windows.go b/libgo/go/net/interface_windows.go index 0759dc255d4..e25c1ed560b 100644 --- a/libgo/go/net/interface_windows.go +++ b/libgo/go/net/interface_windows.go @@ -5,123 +5,139 @@ package net import ( + "internal/syscall/windows" "os" "syscall" "unsafe" ) -func bytePtrToString(p *uint8) string { - a := (*[10000]uint8)(unsafe.Pointer(p)) - i := 0 - for a[i] != 0 { - i++ - } - return string(a[:i]) -} +func getAdapters() (*windows.IpAdapterAddresses, error) { + block := uint32(unsafe.Sizeof(windows.IpAdapterAddresses{})) -func getAdapterList() (*syscall.IpAdapterInfo, error) { - b := make([]byte, 1000) - l := uint32(len(b)) - a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0])) - // TODO(mikio): GetAdaptersInfo returns IP_ADAPTER_INFO that - // contains IPv4 address list only. We should use another API - // for fetching IPv6 stuff from the kernel. - err := syscall.GetAdaptersInfo(a, &l) - if err == syscall.ERROR_BUFFER_OVERFLOW { - b = make([]byte, l) - a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0])) - err = syscall.GetAdaptersInfo(a, &l) - } - if err != nil { - return nil, os.NewSyscallError("GetAdaptersInfo", err) + // 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, os.NewSyscallError("getadaptersaddresses", err) + } } - return a, nil + return &addrs[0], nil } -func getInterfaceList() ([]syscall.InterfaceInfo, error) { +func getInterfaceInfos() ([]syscall.InterfaceInfo, error) { s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) if err != nil { - return nil, os.NewSyscallError("Socket", err) + return nil, err } - defer syscall.Closesocket(s) + defer closeFunc(s) - ii := [20]syscall.InterfaceInfo{} + iia := [20]syscall.InterfaceInfo{} ret := uint32(0) - size := uint32(unsafe.Sizeof(ii)) - err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 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, os.NewSyscallError("WSAIoctl", err) + return nil, os.NewSyscallError("wsaioctl", err) } - c := ret / uint32(unsafe.Sizeof(ii[0])) - return ii[:c-1], nil + 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) { - ai, err := getAdapterList() + paddr, err := getAdapters() if err != nil { return nil, err } - ii, err := getInterfaceList() + iis, err := getInterfaceInfos() if err != nil { return nil, err } var ift []Interface - for ; ai != nil; ai = ai.Next { - index := ai.Index + 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 - - row := syscall.MibIfRow{Index: index} - e := syscall.GetIfEntry(&row) - if e != nil { - return nil, os.NewSyscallError("GetIfEntry", e) + if paddr.Flags&windows.IfOperStatusUp != 0 { + flags |= FlagUp } - - for _, ii := range ii { - ip := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr - ipv4 := IPv4(ip[0], ip[1], ip[2], ip[3]) - ipl := &ai.IpAddressList - for ipl != nil { - ips := bytePtrToString(&ipl.IpAddress.String[0]) - if ipv4.Equal(parseIPv4(ips)) { - break - } - ipl = ipl.Next - } - if ipl == nil { - continue - } - if ii.Flags&syscall.IFF_UP != 0 { - flags |= FlagUp - } - if ii.Flags&syscall.IFF_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 - } + 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 } - - name := bytePtrToString(&ai.AdapterName[0]) - ifi := Interface{ Index: int(index), - MTU: int(row.Mtu), - Name: name, - HardwareAddr: HardwareAddr(row.PhysAddr[:row.PhysAddrLen]), - Flags: flags} + 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 @@ -131,28 +147,86 @@ func interfaceTable(ifindex int) ([]Interface, error) { // network interfaces. Otherwise it returns addresses for a specific // interface. func interfaceAddrTable(ifi *Interface) ([]Addr, error) { - ai, err := getAdapterList() + paddr, err := getAdapters() if err != nil { return nil, err } var ifat []Addr - for ; ai != nil; ai = ai.Next { - index := ai.Index + for ; paddr != nil; paddr = paddr.Next { + index := paddr.IfIndex + if paddr.Ipv6IfIndex != 0 { + index = paddr.Ipv6IfIndex + } if ifi == nil || ifi.Index == int(index) { - ipl := &ai.IpAddressList - for ; ipl != nil; ipl = ipl.Next { - ifa := IPAddr{IP: parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))} - ifat = append(ifat, ifa.toAddr()) + 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) { - // TODO(mikio): Implement this like other platforms. - return nil, nil + 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 } |