Gerrit Bot has uploaded this change for review.
fix: get network card interface in Android 11 environment
For https://github.com/golang/go/issues/40569
Fix: In response to the modifications made to the permissions for accessing system MAC addresses in Android 11, ordinary applications encounter several main issues when using NETLINK sockets:
- Not allowing bind operations on `NETLINK` sockets.
- Not permitting the use of the `RTM_GETLINK` functionality.
For detailed information, please refer to: https://developer.android.com/training/articles/user-data-ids#mac-11-plus
As a result of the aforementioned reasons, using `net.Interfaces()` and `net.InterfaceAddrs()` from the Go net package in the Android environment leads to the `route ip+net: netlinkrib: permission denied` error.
You can find specific issue details here: https://github.com/golang/go/issues/40569
To address the issue of using the Go net package in the Android environment, we have made partial modifications to its source code to ensure proper functionality on Android.
I have fully resolved the issues with `net.InterfaceAddrs()`.
However, for `net.Interfaces()`, we have only addressed some problems, as the following issues still remain:
- It can only return interfaces with IP addresses.
- It cannot return hardware MAC addresses.
Nevertheless, the fixed `net.Interfaces()` function now aligns with the Android API's `NetworkInterface.getNetworkInterfaces()` and can be used normally in most scenarios.
The specific fix logic includes:
Removing the `Bind()` operation on `Netlink` sockets in the `NetlinkRIB()` function.
Using `ioctl` based on the Index number returned by `RTM_GETADDR` to retrieve the network card's name, MTU, and flags.
Change-Id: Idf2fcd3cf88f1fc4d5c4a983717e1c601a63db74
GitHub-Last-Rev: 1012c07e4003e36475d32175a95c01821097a4bb
GitHub-Pull-Request: golang/go#61089
---
A src/net/interface_android.go
M src/net/interface_linux.go
M src/syscall/netlink_linux.go
3 files changed, 162 insertions(+), 1 deletion(-)
diff --git a/src/net/interface_android.go b/src/net/interface_android.go
new file mode 100644
index 0000000..cdae0fb
--- /dev/null
+++ b/src/net/interface_android.go
@@ -0,0 +1,152 @@
+// 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
+ }
+
+ 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 9112ecc..c81bd0a 100644
--- a/src/net/interface_linux.go
+++ b/src/net/interface_linux.go
@@ -6,6 +6,7 @@
import (
"os"
+ "runtime"
"syscall"
"unsafe"
)
@@ -16,6 +17,9 @@
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" {
+ return interfaceTableAndroid(ifindex)
+ }
return nil, os.NewSyscallError("netlinkrib", err)
}
msgs, err := syscall.ParseNetlinkMessage(tab)
diff --git a/src/syscall/netlink_linux.go b/src/syscall/netlink_linux.go
index a503a07..a74caa8 100644
--- a/src/syscall/netlink_linux.go
+++ b/src/syscall/netlink_linux.go
@@ -7,6 +7,8 @@
package syscall
import (
+ "os"
+ "runtime"
"sync"
"unsafe"
)
@@ -65,7 +67,10 @@
defer Close(s)
sa := &SockaddrNetlink{Family: AF_NETLINK}
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" && os.IsPermission(err)) {
+ return nil, err
+ }
}
wb := newNetlinkRouteRequest(proto, 1, family)
if err := Sendto(s, wb, 0, sa); err != nil {
To view, visit change 507415. To unsubscribe, or for help writing mail filters, visit settings.
Congratulations on opening your first change. Thank you for your contribution!
Next steps:
A maintainer will review your change and provide feedback. See
https://go.dev/doc/contribute#review for more info and tips to get your
patch through code review.
Most changes in the Go project go through a few rounds of revision. This can be
surprising to people new to the project. The careful, iterative review process
is our way of helping mentor contributors and ensuring that their contributions
have a lasting impact.
During May-July and Nov-Jan the Go project is in a code freeze, during which
little code gets reviewed or merged. If a reviewer responds with a comment like
R=go1.11 or adds a tag like "wait-release", it means that this CL will be
reviewed as part of the next development cycle. See https://go.dev/s/release
for more details.
Attention is currently required from: Brad Fitzpatrick, Damien Neil, Ian Lance Taylor.
Gerrit Bot uploaded patch set #2 to this change.
x/mobile: fix net.Interface() and net.InterfaceAddrs() in Android11 version
For https://github.com/golang/go/issues/40569
Fix: In response to the modifications made to the permissions for accessing system MAC addresses in Android 11, ordinary applications encounter several main issues when using NETLINK sockets:
- Not allowing bind operations on `NETLINK` sockets.
- Not permitting the use of the `RTM_GETLINK` functionality.
For detailed information, please refer to: https://developer.android.com/training/articles/user-data-ids#mac-11-plus
As a result of the aforementioned reasons, using `net.Interfaces()` and `net.InterfaceAddrs()` from the Go net package in the Android environment leads to the `route ip+net: netlinkrib: permission denied` error.
You can find specific issue details here: https://github.com/golang/go/issues/40569
To address the issue of using the Go net package in the Android environment, we have made partial modifications to its source code to ensure proper functionality on Android.
I have fully resolved the issues with `net.InterfaceAddrs()`.
However, for `net.Interfaces()`, we have only addressed some problems, as the following issues still remain:
- It can only return interfaces with IP addresses.
- It cannot return hardware MAC addresses.
Nevertheless, the fixed `net.Interfaces()` function now aligns with the Android API's `NetworkInterface.getNetworkInterfaces()` and can be used normally in most scenarios.
The specific fix logic includes:
Removing the `Bind()` operation on `Netlink` sockets in the `NetlinkRIB()` function.
Using `ioctl` based on the Index number returned by `RTM_GETADDR` to retrieve the network card's name, MTU, and flags.
Change-Id: Idf2fcd3cf88f1fc4d5c4a983717e1c601a63db74
GitHub-Last-Rev: a64399c21a42214129aa3aaf7c28f42906b9ee5d
GitHub-Pull-Request: golang/go#61089
---
A src/net/interface_android.go
M src/net/interface_linux.go
M src/syscall/netlink_linux.go
3 files changed, 164 insertions(+), 1 deletion(-)
To view, visit change 507415. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Brad Fitzpatrick, Damien Neil, Ian Lance Taylor.
Gerrit Bot uploaded patch set #3 to this change.
x/mobile: fix net.Interface() and net.InterfaceAddrs() in Android11 version
For https://github.com/golang/go/issues/40569
Fix: In response to the modifications made to the permissions for accessing system MAC addresses in Android 11, ordinary applications encounter several main issues when using NETLINK sockets:
- Not allowing bind operations on `NETLINK` sockets.
- Not permitting the use of the `RTM_GETLINK` functionality.
For detailed information, please refer to: https://developer.android.com/training/articles/user-data-ids#mac-11-plus
As a result of the aforementioned reasons, using `net.Interfaces()` and `net.InterfaceAddrs()` from the Go net package in the Android environment leads to the `route ip+net: netlinkrib: permission denied` error.
You can find specific issue details here: https://github.com/golang/go/issues/40569
To address the issue of using the Go net package in the Android environment, we have made partial modifications to its source code to ensure proper functionality on Android.
I have fully resolved the issues with `net.InterfaceAddrs()`.
However, for `net.Interfaces()`, we have only addressed some problems, as the following issues still remain:
- It can only return interfaces with IP addresses.
- It cannot return hardware MAC addresses.
Nevertheless, the fixed `net.Interfaces()` function now aligns with the Android API's `NetworkInterface.getNetworkInterfaces()` and can be used normally in most scenarios.
The specific fix logic includes:
Removing the `Bind()` operation on `Netlink` sockets in the `NetlinkRIB()` function.
Using `ioctl` based on the Index number returned by `RTM_GETADDR` to retrieve the network card's name, MTU, and flags.
## Test Code
This part of the test code must be compiled into a jar and aar package that can be used under the Android 11 platform using gomobile
use `net.InterfaceAddrs()` :
```go
func NetInterfaceAddrs() {
addrs, err := net.InterfaceAddrs()
if err != nil {
panic(err)
}
for _, addr := range addrs {
log.Println(addr)
}
}
```
result:
```
127.0.0.1/8
::1/128
...
192.168.6.143/24
fe80::7e4f:4446:eb3:1eb8/64
```
use `net.Interfaces()` :
```go
func NetInterface() {
interfaces, err := net.Interfaces()
if err != nil {
panic(err)
}
for _, i := range interfaces {
log.Println(i)
}
}
```
result:
```
{1 65536 lo up|loopback|running}
{15 1400 rmnet_data1 up|running}
{24 1500 wlan0 up|broadcast|multicast|running}
{3 1500 dummy0 up|broadcast|running}
{4 1500 ifb0 up|broadcast|running}
{5 1500 ifb1 up|broadcast|running}
{12 1500 ifb2 up|broadcast|running}
{14 1500 rmnet_data0 up|running}
{16 1400 rmnet_data2 up|running}
{17 1400 rmnet_data3 up|running}
```
Change-Id: Idf2fcd3cf88f1fc4d5c4a983717e1c601a63db74
GitHub-Last-Rev: a64399c21a42214129aa3aaf7c28f42906b9ee5d
GitHub-Pull-Request: golang/go#61089
---
A src/net/interface_android.go
M src/net/interface_linux.go
M src/syscall/netlink_linux.go
3 files changed, 164 insertions(+), 1 deletion(-)
To view, visit change 507415. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Brad Fitzpatrick, Damien Neil, Ian Lance Taylor.
wei liu removed a vote from this change.
To view, visit change 507415. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Brad Fitzpatrick, Damien Neil, Ian Lance Taylor.
Patch set 3:Code-Review +1
Attention is currently required from: Brad Fitzpatrick, Damien Neil, Hyang-Ah Hana Kim, Ian Lance Taylor.
1 comment:
File src/net/interface_linux.go:
Patch Set #3, Line 20: if os.IsPermission(err) && runtime.GOOS == "android" {
Maybe better if you put the if runtime.GOOS == "android" condition to the beginning of this function. With it you can avoid an unnecessary syscall on Android. Your approach fit better for the deprecated Android versions.
To view, visit change 507415. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Brad Fitzpatrick, Damien Neil, Hyang-Ah Hana Kim, Ian Lance Taylor, Zoltan Papp.
1 comment:
File src/net/interface_linux.go:
Patch Set #3, Line 20: if os.IsPermission(err) && runtime.GOOS == "android" {
Maybe better if you put the if runtime. […]
Keeping RTM_GETLINK may be also useful for privileged Android applications (ex: those running as root).
To view, visit change 507415. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Brad Fitzpatrick, Damien Neil, Hyang-Ah Hana Kim, Ian Lance Taylor, Zoltan Papp.
Gerrit Bot uploaded patch set #4 to this change.
GitHub-Last-Rev: ad4f8ff11f4fe68c5b06bf600ab683ef7f3fbec4
GitHub-Pull-Request: golang/go#61089
---
A src/net/interface_android.go
M src/net/interface_linux.go
M src/syscall/netlink_linux.go
3 files changed, 165 insertions(+), 1 deletion(-)
To view, visit change 507415. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Brad Fitzpatrick, Damien Neil, Hyang-Ah Hana Kim, Ian Lance Taylor, Zoltan Papp.
1 comment:
File src/syscall/netlink_linux.go:
Patch Set #3, Line 71: if !(runtime.GOOS == "android" && os.IsPermission(err)) {
Including `os` package for this check here results in a cyclic dependency.
Removing the `os.IsPermission(err)` check would remove the need to import `os` package. This check was not done before this patch and any error of `Bind` resulted in an error returned for `NetlinRIB` so it won't change the behavior for the other platforms if removed
To view, visit change 507415. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Brad Fitzpatrick, Damien Neil, Hyang-Ah Hana Kim, Ian Lance Taylor, Zoltan Papp.
1 comment:
Patchset:
The build is getting stuck at building bootstrap
mamazur@pc:~/go-source/src$ ./all.bash
Building Go cmd/dist using /snap/go/10389. (go1.21.3 linux/amd64)
Building Go toolchain1 using /snap/go/10389.
Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.
It's been like that over 22 hours.
To view, visit change 507415. To unsubscribe, or for help writing mail filters, visit settings.
Attention is currently required from: Brad Fitzpatrick, Damien Neil, Hyang-Ah Hana Kim, Ian Lance Taylor, Zoltan Papp.
Gerrit Bot uploaded patch set #5 to this change.
GitHub-Last-Rev: bff8d409ebfb8d4c8488325f13cb212b07cf6bb4
GitHub-Pull-Request: golang/go#61089
---
M src/net/interface_linux.go
M src/syscall/netlink_linux.go
2 files changed, 169 insertions(+), 2 deletions(-)
To view, visit change 507415. To unsubscribe, or for help writing mail filters, visit settings.