diff --git a/src/net/interface_android.go b/src/net/interface_android.go deleted file mode 100644 index 7946e0ca00..0000000000 --- a/src/net/interface_android.go +++ /dev/null @@ -1,154 +0,0 @@ -// 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 ( - "bytes" - "os" - "syscall" - "unsafe" -) - -type ifReq [40]byte - -// 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 ifReq - *(*uint32)(unsafe.Pointer(&ifr[syscall.IFNAMSIZ])) = index - err = ioctl(fd, syscall.SIOCGIFNAME, unsafe.Pointer(&ifr[0])) - if err != nil { - return "", err - } - - return string(bytes.Trim(ifr[:syscall.IFNAMSIZ], "\x00")), 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 ifReq - 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 ifReq - 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 -} diff --git a/src/net/interface_linux.go b/src/net/interface_linux.go index c81bd0af25..9bd7115a8a 100644 --- a/src/net/interface_linux.go +++ b/src/net/interface_linux.go @@ -12,12 +12,12 @@ import ( ) // 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. func interfaceTable(ifindex int) ([]Interface, error) { tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC) if err != nil { - if os.IsPermission(err) && runtime.GOOS == "android" { + if runtime.GOOS == "android" && os.IsPermission(err) { return interfaceTableAndroid(ifindex) } return nil, os.NewSyscallError("netlinkrib", err) @@ -274,3 +274,157 @@ func parseProcNetIGMP6(path string, ifi *Interface) []Addr { } 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 +} diff --git a/src/syscall/netlink_linux.go b/src/syscall/netlink_linux.go index ba39cdbd8d..fe9aa57443 100644 --- a/src/syscall/netlink_linux.go +++ b/src/syscall/netlink_linux.go @@ -7,8 +7,7 @@ package syscall import ( - err2 "errors" - "io/fs" + "internal/oserror" "runtime" "sync" "unsafe" @@ -69,7 +68,11 @@ func NetlinkRIB(proto, family int) ([]byte, error) { sa := &SockaddrNetlink{Family: AF_NETLINK} if err := Bind(s, sa); err != nil { // Bind operation of Netlink socket is prohibited in Android11 and later versions - if !(runtime.GOOS == "android" && err2.Is(err, fs.ErrPermission)) { + if runtime.GOOS != "android" { + return nil, err + } + + if e, ok := err.(Errno); !ok && !e.Is(oserror.ErrPermission) { return nil, err } }