bt90
(Bt90)
June 20, 2023, 5:46am
1
I fear the topic has seen quite its share of discussions already but hear me out.
The problem nowadays is that the discovery of interface IPs throws an error on Android. As far as I’m aware broadcast/multicast would still work, we’re just erroring out before we get to that point?
Would it be possible to catch that error and still send the broad- or multicast? The idea here would be that the other client can obtain the address from the packet it just received.
We’re doing something similar for global discovery if i’m not mistaken. The approach would work even more reliably for local networks, as we’re not dealing with NAT.
calmh
(Jakob Borg)
June 20, 2023, 5:58am
2
The code is in here if you want to experiment:
We list addresses on IPv4 in order to send directed broadcasts to each subnet, but there’s also a fallback to all-ones so that could work.
For IPv6 we don’t care about addresses, but we need to bind to each interface (hence list them) as the multicasts are link local.
bt90
(Bt90)
June 20, 2023, 6:06am
3
Not a go dev but it looks like we break out of the loop on the first interface discovery error?
var bs []byte
select {
case bs = <-inbox:
case <-doneCtx.Done():
return doneCtx.Err()
}
intfs, err := net.Interfaces()
if err != nil {
l.Debugln(err)
return err
}
var dsts []net.IP
for _, intf := range intfs {
if intf.Flags&net.FlagBroadcast == 0 {
continue
}
addrs, err := intf.Addrs()
if err != nil {
And also for the IPs
var dsts []net.IP
for _, intf := range intfs {
if intf.Flags&net.FlagBroadcast == 0 {
continue
}
addrs, err := intf.Addrs()
if err != nil {
l.Debugln(err)
return err
}
for _, addr := range addrs {
if iaddr, ok := addr.(*net.IPNet); ok && len(iaddr.IP) >= 4 && iaddr.IP.IsGlobalUnicast() && iaddr.IP.To4() != nil {
baddr := bcast(iaddr)
dsts = append(dsts, baddr.IP)
}
}
}
bt90
(Bt90)
June 20, 2023, 9:41am
5
Wouldn’t it be enough to capture and log the error thrown by intf.Addrs()
and carry on with an empty array of addresses?
The fallback provided by len(dsts) == 0
should be enough to send a broadcast.
The receiving party would need to generate an address based on the origin of the broadcast.
calmh
(Jakob Borg)
June 20, 2023, 9:59am
6
Maybe, if there’s a case where asking for interface addresses returns an error but it’s still possible to use the interface. Maybe android is that case, I don’t know.
bt90
(Bt90)
June 20, 2023, 10:44am
7
Exactly. That functionality is broken on Android.
opened 01:13PM - 04 Aug 20 UTC
NeedsInvestigation
mobile
<!--
Please answer these questions before submitting your issue. Thanks!
For q… uestions please use one of our forums: https://github.com/golang/go/wiki/Questions
-->
### What version of Go are you using (`go version`)?
<pre>
$ go version
go version go1.14.6 darwin/amd64
$gomobile version
gomobile version +973feb4 Sat Aug 1 11:21:45 2020 +0000 (android,ios); androidSDK=/sdk/platforms/android-30
</pre>
### Does this issue reproduce with the latest release?
Yes
### What operating system and processor architecture are you using (`go env`)?
<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GO111MODULE="on"
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/user/Library/Caches/go-build"
GOENV="/Users/user/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/user/golang"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/Cellar/go/1.14.6/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.14.6/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/user/golang/src/golang.org/x/mobile/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/kq/3436m_v11sg0l7zqtmv2r1gw0000gn/T/go-build713467523=/tmp/go-build -gno-record-gcc-switches -fno-common"
</pre></details>
### What did you do?
<!--
If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on play.golang.org is best.
-->
Calling `net.InterfaceAddrs()` fails on Android app targetting SDK version 30. With `build.gradle` looking like:
```
android {
compileSdkVersion 30
buildToolsVersion "30.0.0"
defaultConfig {
applicationId "com.example.testapp"
minSdkVersion 29
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
```
Building the exact same app targetting SDK 29 works, and returns no error:
```
android {
compileSdkVersion 30
buildToolsVersion "30.0.0"
defaultConfig {
applicationId "com.example.testapp"
minSdkVersion 29
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
```
### What did you expect to see?
Targetting SDK 30 would behave no differently.
### What did you see instead?
Calling `net.InterfaceAddrs()` results in error `route ip+net: netlinkrib: permission denied` when embedded in Android app targetting SDK 30 (R):
```
2020-08-04 15:10:21.386 15754-15754/? W/Thread-2: type=1400 audit(0.0:616): avc: denied { bind } for scontext=u:r:untrusted_app:s0:c158,c256,c512,c768 tcontext=u:r:untrusted_app:s0:c158,c256,c512,c768 tclass=netlink_route_socket permissive=0 b/155595000 app=com.example.testapp
```
The best case scenario would be to have the IP discovery a bit more resiliant and try to send a broadcast in any case. That would avoid Android specific hacks and still fix local discovery.
calmh
(Jakob Borg)
June 20, 2023, 11:27am
8
Someone should try it. That call failing doesn’t necessarily mean everything else will work if we just ignore the failure…
In meantime, a fix by a thin wrapper around go/net was discovered by the community. This addresses the android multicast issue and got part of other apps which had the same problem. The lib is called “anet”. Any chance we would get it in for Android builds too? It fixes the local discovery issue present since Android 11+ and would reinstate the “locally found devices” screen in the Android app.
develop
← bobrofon:android-multicast
opened 06:10PM - 06 Aug 24 UTC
This solution is bases on https://github.com/wlynxg/anet project. `github.com/wl… ynxg/anet` is a partial alternative implementation of the `golang.org/x/net` module. The goal of `anet` module is to provide workarounds of the issues https://github.com/golang/go/issues/40569 and https://github.com/golang/go/issues/68082 on Android 11+.
Tested on AOSP 13.
Resolves: #1149
bt90
(Bt90)
June 25, 2025, 8:59pm
11
Oh nice. That’s quite an improvement!
1 Like
tomasz86
(Tomasz Wilczyński)
July 6, 2025, 7:34pm
12
With this change implemented, Syncthing fails to compile for me with the error:
link: github.com/wlynxg/anet: invalid reference to net.zoneCache
This happens when cross-compiling for Android arm64 under Windows.
@Catfriend1 Have you got any ideas what the problem may be about?
@marbens Exactly this. We just need it for Android builds. Thanks for making a PR .
Marbens already found it.
marbens
(Marcus B Spencer)
July 6, 2025, 8:34pm
16
Indeed. Upstream recommends it in general though.
1 Like