mirror of
https://github.com/golang/go
synced 2024-11-05 15:46:11 -07:00
net: re-implement Interfaces and InterfaceAddrs for IPNet, IPv6 on Windows
Fixes #5395 Change-Id: I4322bc8a974d04d9bae6b48c71c5d32d9252973c Reviewed-on: https://go-review.googlesource.com/3024 Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
This commit is contained in:
parent
e6fbce3596
commit
ea22a08fd4
@ -240,7 +240,7 @@ var pkgDeps = map[string][]string{
|
|||||||
// Basic networking.
|
// Basic networking.
|
||||||
// Because net must be used by any package that wants to
|
// Because net must be used by any package that wants to
|
||||||
// do networking portably, it must have a small dependency set: just L1+basic os.
|
// do networking portably, it must have a small dependency set: just L1+basic os.
|
||||||
"net": {"L1", "CGO", "os", "syscall", "time"},
|
"net": {"L1", "CGO", "os", "syscall", "time", "internal/syscall/windows"},
|
||||||
|
|
||||||
// NET enables use of basic network-related packages.
|
// NET enables use of basic network-related packages.
|
||||||
"NET": {
|
"NET": {
|
||||||
|
99
src/internal/syscall/windows/syscall_windows.go
Normal file
99
src/internal/syscall/windows/syscall_windows.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
// Copyright 2014 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 windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
|
||||||
|
|
||||||
|
const GAA_FLAG_INCLUDE_PREFIX = 0x00000010
|
||||||
|
|
||||||
|
const IF_TYPE_SOFTWARE_LOOPBACK = 24
|
||||||
|
|
||||||
|
type SocketAddress struct {
|
||||||
|
Sockaddr *syscall.RawSockaddrAny
|
||||||
|
SockaddrLength int32
|
||||||
|
}
|
||||||
|
|
||||||
|
type IpAdapterUnicastAddress struct {
|
||||||
|
Length uint32
|
||||||
|
Flags uint32
|
||||||
|
Next *IpAdapterUnicastAddress
|
||||||
|
Address SocketAddress
|
||||||
|
PrefixOrigin int32
|
||||||
|
SuffixOrigin int32
|
||||||
|
DadState int32
|
||||||
|
ValidLifetime uint32
|
||||||
|
PreferredLifetime uint32
|
||||||
|
LeaseLifetime uint32
|
||||||
|
OnLinkPrefixLength uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
type IpAdapterAnycastAddress struct {
|
||||||
|
Length uint32
|
||||||
|
Flags uint32
|
||||||
|
Next *IpAdapterAnycastAddress
|
||||||
|
Address SocketAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
type IpAdapterMulticastAddress struct {
|
||||||
|
Length uint32
|
||||||
|
Flags uint32
|
||||||
|
Next *IpAdapterMulticastAddress
|
||||||
|
Address SocketAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
type IpAdapterDnsServerAdapter struct {
|
||||||
|
Length uint32
|
||||||
|
Reserved uint32
|
||||||
|
Next *IpAdapterDnsServerAdapter
|
||||||
|
Address SocketAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
type IpAdapterPrefix struct {
|
||||||
|
Length uint32
|
||||||
|
Flags uint32
|
||||||
|
Next *IpAdapterPrefix
|
||||||
|
Address SocketAddress
|
||||||
|
PrefixLength uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type IpAdapterAddresses struct {
|
||||||
|
Length uint32
|
||||||
|
IfIndex uint32
|
||||||
|
Next *IpAdapterAddresses
|
||||||
|
AdapterName *byte
|
||||||
|
FirstUnicastAddress *IpAdapterUnicastAddress
|
||||||
|
FirstAnycastAddress *IpAdapterAnycastAddress
|
||||||
|
FirstMulticastAddress *IpAdapterMulticastAddress
|
||||||
|
FirstDnsServerAddress *IpAdapterDnsServerAdapter
|
||||||
|
DnsSuffix *uint16
|
||||||
|
Description *uint16
|
||||||
|
FriendlyName *uint16
|
||||||
|
PhysicalAddress [syscall.MAX_ADAPTER_ADDRESS_LENGTH]byte
|
||||||
|
PhysicalAddressLength uint32
|
||||||
|
Flags uint32
|
||||||
|
Mtu uint32
|
||||||
|
IfType uint32
|
||||||
|
OperStatus uint32
|
||||||
|
Ipv6IfIndex uint32
|
||||||
|
ZoneIndices [16]uint32
|
||||||
|
FirstPrefix *IpAdapterPrefix
|
||||||
|
/* more fields might be present here. */
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
IfOperStatusUp = 1
|
||||||
|
IfOperStatusDown = 2
|
||||||
|
IfOperStatusTesting = 3
|
||||||
|
IfOperStatusUnknown = 4
|
||||||
|
IfOperStatusDormant = 5
|
||||||
|
IfOperStatusNotPresent = 6
|
||||||
|
IfOperStatusLowerLayerDown = 7
|
||||||
|
)
|
||||||
|
|
||||||
|
//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizeOfPointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses
|
20
src/internal/syscall/windows/zsyscall_windows.go
Normal file
20
src/internal/syscall/windows/zsyscall_windows.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
var (
|
||||||
|
modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll")
|
||||||
|
|
||||||
|
procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizeOfPointer *uint32) (errcode error) {
|
||||||
|
r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizeOfPointer)), 0)
|
||||||
|
if r0 != 0 {
|
||||||
|
errcode = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
@ -38,8 +38,7 @@ func ipv6LinkLocalUnicastAddr(ifi *Interface) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
for _, ifa := range ifat {
|
for _, ifa := range ifat {
|
||||||
switch ifa := ifa.(type) {
|
if ifa, ok := ifa.(*IPNet); ok {
|
||||||
case *IPNet:
|
|
||||||
if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() {
|
if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() {
|
||||||
return ifa.IP.String()
|
return ifa.IP.String()
|
||||||
}
|
}
|
||||||
@ -49,10 +48,6 @@ func ipv6LinkLocalUnicastAddr(ifi *Interface) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInterfaces(t *testing.T) {
|
func TestInterfaces(t *testing.T) {
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
t.Skip("temporarily disabled until golang.org/issue/5395 is fixed")
|
|
||||||
}
|
|
||||||
|
|
||||||
ift, err := Interfaces()
|
ift, err := Interfaces()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -110,10 +105,6 @@ func TestInterfaces(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInterfaceAddrs(t *testing.T) {
|
func TestInterfaceAddrs(t *testing.T) {
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
t.Skip("temporarily disabled until golang.org/issue/5395 is fixed")
|
|
||||||
}
|
|
||||||
|
|
||||||
ift, err := Interfaces()
|
ift, err := Interfaces()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -5,123 +5,139 @@
|
|||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"internal/syscall/windows"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
func bytePtrToString(p *uint8) string {
|
func getAdapters() (*windows.IpAdapterAddresses, error) {
|
||||||
a := (*[10000]uint8)(unsafe.Pointer(p))
|
block := uint32(unsafe.Sizeof(windows.IpAdapterAddresses{}))
|
||||||
i := 0
|
|
||||||
for a[i] != 0 {
|
// pre-allocate a 15KB working buffer pointed to by the AdapterAddresses
|
||||||
i++
|
// 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 string(a[:i])
|
return &addrs[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAdapterList() (*syscall.IpAdapterInfo, error) {
|
func getInterfaceInfos() ([]syscall.InterfaceInfo, 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)
|
|
||||||
}
|
|
||||||
return a, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getInterfaceList() ([]syscall.InterfaceInfo, error) {
|
|
||||||
s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
|
s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, os.NewSyscallError("Socket", err)
|
return nil, os.NewSyscallError("Socket", err)
|
||||||
}
|
}
|
||||||
defer syscall.Closesocket(s)
|
defer syscall.Closesocket(s)
|
||||||
|
|
||||||
ii := [20]syscall.InterfaceInfo{}
|
iia := [20]syscall.InterfaceInfo{}
|
||||||
ret := uint32(0)
|
ret := uint32(0)
|
||||||
size := uint32(unsafe.Sizeof(ii))
|
size := uint32(unsafe.Sizeof(iia))
|
||||||
err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
|
err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&iia[0])), size, &ret, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, os.NewSyscallError("WSAIoctl", err)
|
return nil, os.NewSyscallError("WSAIoctl", err)
|
||||||
}
|
}
|
||||||
c := ret / uint32(unsafe.Sizeof(ii[0]))
|
iilen := ret / uint32(unsafe.Sizeof(iia[0]))
|
||||||
return ii[:c-1], nil
|
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
|
// If the ifindex is zero, interfaceTable returns mappings of all
|
||||||
// network interfaces. Otherwise it returns a mapping of a specific
|
// network interfaces. Otherwise it returns a mapping of a specific
|
||||||
// interface.
|
// interface.
|
||||||
func interfaceTable(ifindex int) ([]Interface, error) {
|
func interfaceTable(ifindex int) ([]Interface, error) {
|
||||||
ai, err := getAdapterList()
|
paddr, err := getAdapters()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ii, err := getInterfaceList()
|
iis, err := getInterfaceInfos()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var ift []Interface
|
var ift []Interface
|
||||||
for ; ai != nil; ai = ai.Next {
|
for ; paddr != nil; paddr = paddr.Next {
|
||||||
index := ai.Index
|
index := paddr.IfIndex
|
||||||
|
if paddr.Ipv6IfIndex != 0 {
|
||||||
|
index = paddr.Ipv6IfIndex
|
||||||
|
}
|
||||||
if ifindex == 0 || ifindex == int(index) {
|
if ifindex == 0 || ifindex == int(index) {
|
||||||
|
ii := findInterfaceInfo(iis, paddr)
|
||||||
|
if ii == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
var flags Flags
|
var flags Flags
|
||||||
|
if paddr.Flags&windows.IfOperStatusUp != 0 {
|
||||||
row := syscall.MibIfRow{Index: index}
|
flags |= FlagUp
|
||||||
e := syscall.GetIfEntry(&row)
|
|
||||||
if e != nil {
|
|
||||||
return nil, os.NewSyscallError("GetIfEntry", e)
|
|
||||||
}
|
}
|
||||||
|
if paddr.IfType&windows.IF_TYPE_SOFTWARE_LOOPBACK != 0 {
|
||||||
for _, ii := range ii {
|
flags |= FlagLoopback
|
||||||
ip := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr
|
}
|
||||||
ipv4 := IPv4(ip[0], ip[1], ip[2], ip[3])
|
if ii.Flags&syscall.IFF_BROADCAST != 0 {
|
||||||
ipl := &ai.IpAddressList
|
flags |= FlagBroadcast
|
||||||
for ipl != nil {
|
}
|
||||||
ips := bytePtrToString(&ipl.IpAddress.String[0])
|
if ii.Flags&syscall.IFF_POINTTOPOINT != 0 {
|
||||||
if ipv4.Equal(parseIPv4(ips)) {
|
flags |= FlagPointToPoint
|
||||||
break
|
}
|
||||||
}
|
if ii.Flags&syscall.IFF_MULTICAST != 0 {
|
||||||
ipl = ipl.Next
|
flags |= FlagMulticast
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
name := bytePtrToString(&ai.AdapterName[0])
|
|
||||||
|
|
||||||
ifi := Interface{
|
ifi := Interface{
|
||||||
Index: int(index),
|
Index: int(index),
|
||||||
MTU: int(row.Mtu),
|
MTU: int(paddr.Mtu),
|
||||||
Name: name,
|
Name: syscall.UTF16ToString((*(*[10000]uint16)(unsafe.Pointer(paddr.FriendlyName)))[:]),
|
||||||
HardwareAddr: HardwareAddr(row.PhysAddr[:row.PhysAddrLen]),
|
HardwareAddr: HardwareAddr(paddr.PhysicalAddress[:]),
|
||||||
Flags: flags}
|
Flags: flags,
|
||||||
|
}
|
||||||
ift = append(ift, ifi)
|
ift = append(ift, ifi)
|
||||||
|
if ifindex == int(ifi.Index) {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ift, nil
|
return ift, nil
|
||||||
@ -131,28 +147,86 @@ func interfaceTable(ifindex int) ([]Interface, error) {
|
|||||||
// network interfaces. Otherwise it returns addresses for a specific
|
// network interfaces. Otherwise it returns addresses for a specific
|
||||||
// interface.
|
// interface.
|
||||||
func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
|
func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
|
||||||
ai, err := getAdapterList()
|
paddr, err := getAdapters()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var ifat []Addr
|
var ifat []Addr
|
||||||
for ; ai != nil; ai = ai.Next {
|
for ; paddr != nil; paddr = paddr.Next {
|
||||||
index := ai.Index
|
index := paddr.IfIndex
|
||||||
|
if paddr.Ipv6IfIndex != 0 {
|
||||||
|
index = paddr.Ipv6IfIndex
|
||||||
|
}
|
||||||
if ifi == nil || ifi.Index == int(index) {
|
if ifi == nil || ifi.Index == int(index) {
|
||||||
ipl := &ai.IpAddressList
|
puni := paddr.FirstUnicastAddress
|
||||||
for ; ipl != nil; ipl = ipl.Next {
|
for ; puni != nil; puni = puni.Next {
|
||||||
ifa := IPAddr{IP: parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))}
|
if sa, err := puni.Address.Sockaddr.Sockaddr(); err == nil {
|
||||||
ifat = append(ifat, ifa.toAddr())
|
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
|
return ifat, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// interfaceMulticastAddrTable returns addresses for a specific
|
// interfaceMulticastAddrTable returns addresses for a specific
|
||||||
// interface.
|
// interface.
|
||||||
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
|
func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
|
||||||
// TODO(mikio): Implement this like other platforms.
|
paddr, err := getAdapters()
|
||||||
return nil, nil
|
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.toAddr())
|
||||||
|
case *syscall.SockaddrInet6:
|
||||||
|
ifa := &IPAddr{IP: make(IP, IPv6len)}
|
||||||
|
copy(ifa.IP, sav.Addr[:])
|
||||||
|
ifat = append(ifat, ifa.toAddr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ifat, nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user