mirror of https://github.com/golang/go.git
Merge bff8d409eb into 49cdf0c42e
This commit is contained in:
commit
5513d2118c
|
|
@ -6,16 +6,20 @@ package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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) {
|
||||||
tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
|
tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if runtime.GOOS == "android" && os.IsPermission(err) {
|
||||||
|
return interfaceTableAndroid(ifindex)
|
||||||
|
}
|
||||||
return nil, os.NewSyscallError("netlinkrib", err)
|
return nil, os.NewSyscallError("netlinkrib", err)
|
||||||
}
|
}
|
||||||
msgs, err := syscall.ParseNetlinkMessage(tab)
|
msgs, err := syscall.ParseNetlinkMessage(tab)
|
||||||
|
|
@ -255,3 +259,157 @@ func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
|
||||||
}
|
}
|
||||||
return ifmat
|
return ifmat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Starting from Android 11, it is no longer possible to retrieve network card information
|
||||||
|
// using the RTM_GETLINK method.
|
||||||
|
// As a result, alternative methods need to be employed.
|
||||||
|
// After considering the Android NetworkInterface.getNetworkInterfaces() method,
|
||||||
|
// I opted to utilize the RTM_GETADDR + ioctl approach to obtain network card information.
|
||||||
|
// However, it appears that retrieving the
|
||||||
|
// HWAddr (hardware address) of the network card is currently not achievable.
|
||||||
|
func interfaceTableAndroid(ifindex int) ([]Interface, error) {
|
||||||
|
tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
|
||||||
|
if err != nil {
|
||||||
|
return nil, os.NewSyscallError("netlinkrib", err)
|
||||||
|
}
|
||||||
|
msgs, err := syscall.ParseNetlinkMessage(tab)
|
||||||
|
if err != nil {
|
||||||
|
return nil, os.NewSyscallError("parsenetlinkmessage", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ift []Interface
|
||||||
|
im := make(map[uint32]struct{})
|
||||||
|
loop:
|
||||||
|
for _, m := range msgs {
|
||||||
|
switch m.Header.Type {
|
||||||
|
case syscall.NLMSG_DONE:
|
||||||
|
break loop
|
||||||
|
case syscall.RTM_NEWADDR:
|
||||||
|
ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
|
||||||
|
if _, ok := im[ifam.Index]; ok {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
im[ifam.Index] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ifindex == 0 || ifindex == int(ifam.Index) {
|
||||||
|
ifi := newLinkAndroid(ifam)
|
||||||
|
if ifi != nil {
|
||||||
|
ift = append(ift, *ifi)
|
||||||
|
}
|
||||||
|
if ifindex == int(ifam.Index) {
|
||||||
|
break loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ift, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// According to the network card Index, get the Name, MTU and Flags of the network card through ioctl
|
||||||
|
func newLinkAndroid(ifam *syscall.IfAddrmsg) *Interface {
|
||||||
|
ift := &Interface{Index: int(ifam.Index)}
|
||||||
|
|
||||||
|
name, err := indexToName(ifam.Index)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ift.Name = name
|
||||||
|
|
||||||
|
mtu, err := nameToMTU(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ift.MTU = mtu
|
||||||
|
|
||||||
|
flags, err := nameToFlags(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ift.Flags = flags
|
||||||
|
return ift
|
||||||
|
}
|
||||||
|
|
||||||
|
func ioctl(fd int, req uint, arg unsafe.Pointer) error {
|
||||||
|
_, _, e1 := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg))
|
||||||
|
if e1 != 0 {
|
||||||
|
return e1
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexToName(index uint32) (string, error) {
|
||||||
|
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM|syscall.SOCK_CLOEXEC, 0)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer syscall.Close(fd)
|
||||||
|
|
||||||
|
var ifr [40]byte
|
||||||
|
*(*uint32)(unsafe.Pointer(&ifr[syscall.IFNAMSIZ])) = index
|
||||||
|
err = ioctl(fd, syscall.SIOCGIFNAME, unsafe.Pointer(&ifr[0]))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(trim(ifr[:syscall.IFNAMSIZ])), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func nameToMTU(name string) (int, error) {
|
||||||
|
// Leave room for terminating NULL byte.
|
||||||
|
if len(name) >= syscall.IFNAMSIZ {
|
||||||
|
return 0, syscall.EINVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM|syscall.SOCK_CLOEXEC, 0)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer syscall.Close(fd)
|
||||||
|
|
||||||
|
var ifr [40]byte
|
||||||
|
copy(ifr[:], name)
|
||||||
|
err = ioctl(fd, syscall.SIOCGIFMTU, unsafe.Pointer(&ifr[0]))
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(*(*int32)(unsafe.Pointer(&ifr[syscall.IFNAMSIZ]))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func nameToFlags(name string) (Flags, error) {
|
||||||
|
// Leave room for terminating NULL byte.
|
||||||
|
if len(name) >= syscall.IFNAMSIZ {
|
||||||
|
return 0, syscall.EINVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM|syscall.SOCK_CLOEXEC, 0)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer syscall.Close(fd)
|
||||||
|
|
||||||
|
var ifr [40]byte
|
||||||
|
copy(ifr[:], name)
|
||||||
|
err = ioctl(fd, syscall.SIOCGIFFLAGS, unsafe.Pointer(&ifr[0]))
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return linkFlags(*(*uint32)(unsafe.Pointer(&ifr[syscall.IFNAMSIZ]))), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func trim(data []byte) []byte {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
index := len(data) - 1
|
||||||
|
|
||||||
|
for ; index > 0 && data[index] == 0; index-- {
|
||||||
|
}
|
||||||
|
result := make([]byte, index+1)
|
||||||
|
copy(result, data)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
package syscall
|
package syscall
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"internal/oserror"
|
||||||
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
@ -65,7 +67,14 @@ func NetlinkRIB(proto, family int) ([]byte, error) {
|
||||||
defer Close(s)
|
defer Close(s)
|
||||||
sa := &SockaddrNetlink{Family: AF_NETLINK}
|
sa := &SockaddrNetlink{Family: AF_NETLINK}
|
||||||
if err := Bind(s, sa); err != nil {
|
if err := Bind(s, sa); err != nil {
|
||||||
return nil, err
|
// Bind operation of Netlink socket is prohibited in Android11 and later versions
|
||||||
|
if runtime.GOOS != "android" {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if e, ok := err.(Errno); !ok && !e.Is(oserror.ErrPermission) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
wb := newNetlinkRouteRequest(proto, 1, family)
|
wb := newNetlinkRouteRequest(proto, 1, family)
|
||||||
if err := Sendto(s, wb, 0, sa); err != nil {
|
if err := Sendto(s, wb, 0, sa); err != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue