Skip to content

Commit

Permalink
fix: package reference causes compilation failure
Browse files Browse the repository at this point in the history
  • Loading branch information
wlynxg committed Nov 14, 2023
1 parent ad4f8ff commit bff8d40
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 159 deletions.
154 changes: 0 additions & 154 deletions src/net/interface_android.go

This file was deleted.

158 changes: 156 additions & 2 deletions src/net/interface_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
9 changes: 6 additions & 3 deletions src/syscall/netlink_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
package syscall

import (
err2 "errors"
"io/fs"
"internal/oserror"
"runtime"
"sync"
"unsafe"
Expand Down Expand Up @@ -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
}
}
Expand Down

0 comments on commit bff8d40

Please sign in to comment.