From 06dd8ee6d75e14a62b7da28b2eec33f2f5695fc8 Mon Sep 17 00:00:00 2001 From: Catfriend1 <16361913+Catfriend1@users.noreply.github.com> Date: Wed, 2 Jul 2025 20:40:38 +0200 Subject: [PATCH] fix(pmp, netutil): workaround native code denied to discover gateway ipv4 addr on Android 14+ (#10204) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Purpose As discussed on the forum: https://forum.syncthing.net/t/reviving-nat-pmp-in-v2-x-on-android-14/24554 TL;DR Android 14+ only lets java code get the gateway IPv4 address which is used in SyncthingNative’s NAT-PMP feature. So I’ve added the java code to the wrapper, got the router IP address and feeded it to SyncthingNative by setting the env var “FALLBACK_NET_GATEWAY_IPV4”. This revives the NAT feature: > [Z36WU] INFO: Detected 1 NAT service ### Testing Local build and test via Android emulator (AVD 15). --- lib/netutil/netutil.go | 28 +++++++++++++++++++++++++++- lib/pmp/pmp.go | 4 ++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/lib/netutil/netutil.go b/lib/netutil/netutil.go index d1b4a7f5b..ee042a5b3 100644 --- a/lib/netutil/netutil.go +++ b/lib/netutil/netutil.go @@ -6,7 +6,14 @@ package netutil -import "net/url" +import ( + "fmt" + "net" + "net/url" + "os" + + "github.com/jackpal/gateway" +) // Address constructs a URL from the given network and hostname. func AddressURL(network, host string) string { @@ -16,3 +23,22 @@ func AddressURL(network, host string) string { } return u.String() } + +// Gateway returns the IP address of the default network gateway. +func Gateway() (ip net.IP, err error) { + ip, err = gateway.DiscoverGateway() + if err != nil { + // Fails on Android 14+ due to permission denied error when reading + // /proc/net/route. The wrapper may give a hint then because it is + // able to discover the gateway from java code. + if v := os.Getenv("FALLBACK_NET_GATEWAY_IPV4"); v != "" { + ip = net.ParseIP(v) + if ip == nil { + return nil, fmt.Errorf("%q: invalid IP", v) + } + return ip, nil + } + return ip, err + } + return ip, nil +} diff --git a/lib/pmp/pmp.go b/lib/pmp/pmp.go index d6b71f669..e5acf1409 100644 --- a/lib/pmp/pmp.go +++ b/lib/pmp/pmp.go @@ -14,10 +14,10 @@ import ( "strings" "time" - "github.com/jackpal/gateway" natpmp "github.com/jackpal/go-nat-pmp" "github.com/syncthing/syncthing/lib/nat" + "github.com/syncthing/syncthing/lib/netutil" "github.com/syncthing/syncthing/lib/osutil" "github.com/syncthing/syncthing/lib/svcutil" ) @@ -30,7 +30,7 @@ func Discover(ctx context.Context, renewal, timeout time.Duration) []nat.Device var ip net.IP err := svcutil.CallWithContext(ctx, func() error { var err error - ip, err = gateway.DiscoverGateway() + ip, err = netutil.Gateway() return err }) if err != nil {