1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
| // src/net/interface_android.go
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
}
|