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…