Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

x/mobile: Calling net.Listen fails on Android 11+ #68082

Open
wlynxg opened this issue Jun 20, 2024 · 9 comments
Open

x/mobile: Calling net.Listen fails on Android 11+ #68082

wlynxg opened this issue Jun 20, 2024 · 9 comments
Labels
mobile Android, iOS, and x/mobile NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@wlynxg
Copy link

wlynxg commented Jun 20, 2024

Go version

go version go1.20.11 darwin/arm64

Output of go env in your module/workspace:

GO111MODULE="on"
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/xxxx/Library/Caches/go-build"
GOENV="/Users/xxxx/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/xxxx/go/pkg/mod"
GONOPROXY="sum.golang.google.cn"
GONOSUMDB="sum.golang.google.cn"
GOOS="darwin"
GOPATH="/Users/xxxx/go"
GOPRIVATE=""
GOPROXY="https://goproxy.cn,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.20.11"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/xxxx/Desktop/xxxx/gomobile/go.mod"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/tl/pjq29cdd6s53760n3zjwwr3c0000gn/T/go-build3441012208=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

package mobile

import (
	"fmt"
	"log"
	"net"
	"net/netip"
	"syscall"

	"github.com/wlynxg/anet"
)

func Greetings(name string) string {
	anet.SetAndroidVersion(14)
	allifaces, err := anet.Interfaces()
	if err != nil {
		return fmt.Sprintf("Error: %s!", err)
	}
	s := ""

	for _, iface := range allifaces {
		s += iface.Name
		addrs, err := anet.InterfaceAddrsByInterface(&iface)
		if err != nil {
			s += fmt.Sprintf("Error: %s", err) + "\n"
		} else {
			s += fmt.Sprintf("%s \n", addrs)
		}

		for _, addr := range addrs {
			parseAddr, err := netip.ParsePrefix(addr.String())
			if err != nil {
				continue
			}

			if parseAddr.Addr().Is4() || parseAddr.Addr().IsMulticast() {
				continue
			}

			addr := fmt.Sprintf("[%s%%%s]:0", parseAddr.Addr().String(), iface.Name)

			_, err = net.Listen("tcp", addr)
			if err != nil {
				log.Printf("listen %s error: %s", addr, err)
			}
		}
	}
	return fmt.Sprintf("Hello, %s!", s)
}

What did you see happen?

listen [fe80::d461:24ff:fe95:d487%wlan0]:0 error: listen tcp [fe80::d461:24ff:fe95:d487%wlan0]:0: bind: invalid argument
listen [fe80::b6ee:d454:7f5b:6fe%rmnet_data1]:0 error: listen tcp [fe80::b6ee:d454:7f5b:6fe%rmnet_data1]:0: bind: invalid argument
listen [fe80::64bd:d9ff:fe5b:92a6%dummy0]:0 error: listen tcp [fe80::64bd:d9ff:fe5b:92a6%dummy0]:0: bind: invalid argument
listen [fe80::e0f1:31ff:fe88:8eb%ifb0]:0 error: listen tcp [fe80::e0f1:31ff:fe88:8eb%ifb0]:0: bind: invalid argument
listen [fe80::6cbb:96ff:fe13:ff68%ifb1]:0 error: listen tcp [fe80::6cbb:96ff:fe13:ff68%ifb1]:0: bind: invalid argument
listen [fe80::b0a1:c3ff:fe6d:c67%ifb2]:0 error: listen tcp [fe80::b0a1:c3ff:fe6d:c67%ifb2]:0: bind: invalid argument
listen [fe80::d41b:7750:b2d1:8fc6%rmnet_data0]:0 error: listen tcp [fe80::d41b:7750:b2d1:8fc6%rmnet_data0]:0: bind: invalid argument
listen [fe80::84bb:a6ff:cd2d:2ff1%rmnet_data3]:0 error: listen tcp [fe80::84bb:a6ff:cd2d:2ff1%rmnet_data3]:0: bind: invalid argument
listen [fe80::5bec:aaaf:e221:d681%rmnet_data4]:0 error: listen tcp [fe80::5bec:aaaf:e221:d681%rmnet_data4]:0: bind: invalid argument

What did you expect to see?

listen success

@gopherbot gopherbot added the mobile Android, iOS, and x/mobile label Jun 20, 2024
@gopherbot gopherbot added this to the Unreleased milestone Jun 20, 2024
@wlynxg wlynxg reopened this Jun 20, 2024
@wlynxg wlynxg closed this as completed Jun 20, 2024
@wlynxg wlynxg reopened this Jun 20, 2024
@wlynxg
Copy link
Author

wlynxg commented Jun 20, 2024

The error comes from https://github.com/torvalds/linux/blob/e5b3efbe1ab1793bb49ae07d56d0973267e65112/net/ipv6/af_inet6.c#L364

In my code, I specified the zone name, and go needs to obtain the corresponding relationship between zone name and zone index from zoneCache when parsing.
The data in zoneCache comes from

if ift, err = interfaceTable(0); err != nil {
,
but because there is a problem when go calls interfaceTable on the Android side #40569,
go fails when doing zone name -> zone index mapping, so in order to pass a valid zone id to the socket

I fixed this problem in anet: wlynxg/anet@a8525cb

@Zxilly
Copy link
Contributor

Zxilly commented Jun 20, 2024

It might be possible to commit these changes to the standard library.

@wlynxg
Copy link
Author

wlynxg commented Jun 20, 2024

It might be possible to commit these changes to the standard library.

This is difficult in some ways because the changes are tied to the Android version.

@vikulin
Copy link

vikulin commented Jun 20, 2024

The error comes from https://github.com/torvalds/linux/blob/e5b3efbe1ab1793bb49ae07d56d0973267e65112/net/ipv6/af_inet6.c#L364

In my code, I specified the zone name, and go needs to obtain the corresponding relationship between zone name and zone index from zoneCache when parsing. The data in zoneCache comes from

if ift, err = interfaceTable(0); err != nil {

,
but because there is a problem when go calls interfaceTable on the Android side #40569,
go fails when doing zone name -> zone index mapping, so in order to pass a valid zone id to the socket

I fixed this problem in anet: wlynxg/anet@a8525cb

How to get zone id ? I noticed that Android works with scope id for link local addresses not with zone name:
https://developer.android.com/reference/java/net/Inet6Address

@wlynxg
Copy link
Author

wlynxg commented Jun 21, 2024

@vikulin The zone id is actually the index of the interface

Index int // positive integer that starts at one, zero is never used
.
In fact, when passing the zone id, you can choose the name
index, ok = zoneCache.toIndex[name]
or directly pass the index
index, _, _ = dtoi(name)

@vikulin
Copy link

vikulin commented Jun 21, 2024

@wlynxg I'm not sure that zone id is what I'm looking for. Obviously zone id = 46 is not the index since the Android device never had so many interfaces. Linux devices return interface names - this is where the difference. Code is expecting interface name but getting scope id.

nBytes, rcm, fromAddr, err := m.sock.ReadFrom(bs)
from := fromAddr.(*net.UDPAddr)
log.Infoln(from.String())

returns

[fe80::33d6:4970:9c23:5f7c%46]:9001

@wlynxg
Copy link
Author

wlynxg commented Jun 21, 2024

@vikulin The network card index numbers do not necessarily need to be in order, as long as they are unique. You can make your own rules. You can directly output iface.Index to view their ids.
When using c for ipv6 socket, the zone id passed is the index of the network.

@dr2chase
Copy link
Contributor

@hyangah @ianlancetaylor

@joedian joedian added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Jun 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mobile Android, iOS, and x/mobile NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

7 participants