From 32a913c0ff41c91cf097a4f3eb40621a55e7b491 Mon Sep 17 00:00:00 2001 From: Marcus B Spencer Date: Tue, 8 Jul 2025 06:18:51 +0000 Subject: [PATCH] refactor(beacon, osutil, upnp, netutil): only use anet on Android (#10211) Add a wrapper that uses anet on Android, but net on other platforms. ### Purpose Fixes https://forum.syncthing.net/t/workaround-for-android-local-discovery/20403/12 ### Testing Run two Syncthing instances with Global Discovery disabled. Pair them with each other, don't hardcode their addresses, and verify they connect. --- lib/beacon/broadcast.go | 6 +++--- lib/beacon/multicast.go | 6 +++--- lib/netutil/interfaces_android.go | 21 +++++++++++++++++++++ lib/netutil/interfaces_other.go | 19 +++++++++++++++++++ lib/osutil/net.go | 6 +++--- lib/upnp/igd_service.go | 4 ++-- lib/upnp/upnp.go | 8 ++++---- 7 files changed, 55 insertions(+), 15 deletions(-) create mode 100644 lib/netutil/interfaces_android.go create mode 100644 lib/netutil/interfaces_other.go diff --git a/lib/beacon/broadcast.go b/lib/beacon/broadcast.go index 0c06b38fa..0c96684b8 100644 --- a/lib/beacon/broadcast.go +++ b/lib/beacon/broadcast.go @@ -11,7 +11,7 @@ import ( "net" "time" - "github.com/wlynxg/anet" + "github.com/syncthing/syncthing/lib/netutil" ) func NewBroadcast(port int) Interface { @@ -46,7 +46,7 @@ func writeBroadcasts(ctx context.Context, inbox <-chan []byte, port int) error { return doneCtx.Err() } - intfs, err := anet.Interfaces() + intfs, err := netutil.Interfaces() if err != nil { l.Debugln("Failed to list interfaces:", err) // net.Interfaces() is broken on Android. see https://github.com/golang/go/issues/40569 @@ -61,7 +61,7 @@ func writeBroadcasts(ctx context.Context, inbox <-chan []byte, port int) error { continue } - addrs, err := anet.InterfaceAddrsByInterface(&intf) + addrs, err := netutil.InterfaceAddrsByInterface(&intf) if err != nil { l.Debugln("Failed to list interface addresses:", err) // Interface discovery might work while retrieving the addresses doesn't. So log the error and carry on. diff --git a/lib/beacon/multicast.go b/lib/beacon/multicast.go index 28367ab6c..7e7f3f03f 100644 --- a/lib/beacon/multicast.go +++ b/lib/beacon/multicast.go @@ -12,7 +12,7 @@ import ( "net" "time" - "github.com/wlynxg/anet" + "github.com/syncthing/syncthing/lib/netutil" "golang.org/x/net/ipv6" ) @@ -61,7 +61,7 @@ func writeMulticasts(ctx context.Context, inbox <-chan []byte, addr string) erro return doneCtx.Err() } - intfs, err := anet.Interfaces() + intfs, err := netutil.Interfaces() if err != nil { l.Debugln(err) return err @@ -119,7 +119,7 @@ func readMulticasts(ctx context.Context, outbox chan<- recv, addr string) error conn.Close() }() - intfs, err := anet.Interfaces() + intfs, err := netutil.Interfaces() if err != nil { l.Debugln(err) return err diff --git a/lib/netutil/interfaces_android.go b/lib/netutil/interfaces_android.go new file mode 100644 index 000000000..b3f3be0e5 --- /dev/null +++ b/lib/netutil/interfaces_android.go @@ -0,0 +1,21 @@ +// Copyright (C) 2025 The Syncthing Authors. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +package netutil + +import ( + "net" + + "github.com/wlynxg/anet" +) + +func Interfaces() ([]net.Interface, error) { + return anet.Interfaces() +} + +func InterfaceAddrsByInterface(intf *net.Interface) ([]net.Addr, error) { + return anet.InterfaceAddrsByInterface(intf) +} diff --git a/lib/netutil/interfaces_other.go b/lib/netutil/interfaces_other.go new file mode 100644 index 000000000..f9be3a666 --- /dev/null +++ b/lib/netutil/interfaces_other.go @@ -0,0 +1,19 @@ +// Copyright (C) 2025 The Syncthing Authors. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. + +//go:build !android + +package netutil + +import "net" + +func Interfaces() ([]net.Interface, error) { + return net.Interfaces() +} + +func InterfaceAddrsByInterface(intf *net.Interface) ([]net.Addr, error) { + return intf.Addrs() +} diff --git a/lib/osutil/net.go b/lib/osutil/net.go index 42336599b..e936b692f 100644 --- a/lib/osutil/net.go +++ b/lib/osutil/net.go @@ -10,13 +10,13 @@ import ( "net" "strings" - "github.com/wlynxg/anet" + "github.com/syncthing/syncthing/lib/netutil" ) // GetInterfaceAddrs returns the IP networks of all interfaces that are up. // Point-to-point interfaces are exluded unless includePtP is true. func GetInterfaceAddrs(includePtP bool) ([]*net.IPNet, error) { - intfs, err := anet.Interfaces() + intfs, err := netutil.Interfaces() if err != nil { return nil, err } @@ -33,7 +33,7 @@ func GetInterfaceAddrs(includePtP bool) ([]*net.IPNet, error) { // which, for our purposes, do not qualify as LANs. continue } - intfAddrs, err := anet.InterfaceAddrsByInterface(&intf) + intfAddrs, err := netutil.InterfaceAddrsByInterface(&intf) if err != nil { return nil, err } diff --git a/lib/upnp/igd_service.go b/lib/upnp/igd_service.go index accefe174..a89474fb0 100644 --- a/lib/upnp/igd_service.go +++ b/lib/upnp/igd_service.go @@ -40,7 +40,7 @@ import ( "net" "time" - "github.com/wlynxg/anet" + "github.com/syncthing/syncthing/lib/netutil" "github.com/syncthing/syncthing/lib/nat" ) @@ -67,7 +67,7 @@ func (s *IGDService) AddPinhole(ctx context.Context, protocol nat.Protocol, intA return nil, errors.New("no interface") } - addrs, err := anet.InterfaceAddrsByInterface(s.Interface) + addrs, err := netutil.InterfaceAddrsByInterface(s.Interface) if err != nil { return nil, err } diff --git a/lib/upnp/upnp.go b/lib/upnp/upnp.go index d42555f11..cc49c2539 100644 --- a/lib/upnp/upnp.go +++ b/lib/upnp/upnp.go @@ -48,7 +48,7 @@ import ( "sync" "time" - "github.com/wlynxg/anet" + "github.com/syncthing/syncthing/lib/netutil" "github.com/syncthing/syncthing/lib/build" "github.com/syncthing/syncthing/lib/dialer" @@ -106,7 +106,7 @@ const ( func Discover(ctx context.Context, _, timeout time.Duration) []nat.Device { var results []nat.Device - interfaces, err := anet.Interfaces() + interfaces, err := netutil.Interfaces() if err != nil { l.Infoln("Listing network interfaces:", err) return results @@ -388,7 +388,7 @@ func parseResponse(ctx context.Context, deviceType string, addr *net.UDPAddr, re } func localIPv4(netInterface *net.Interface) (net.IP, error) { - addrs, err := anet.InterfaceAddrsByInterface(netInterface) + addrs, err := netutil.InterfaceAddrsByInterface(netInterface) if err != nil { return nil, err } @@ -631,7 +631,7 @@ func soapRequestWithIP(ctx context.Context, url, service, function, message stri } func interfaceHasGUAIPv6(intf net.Interface) (bool, error) { - addrs, err := anet.InterfaceAddrsByInterface(&intf) + addrs, err := netutil.InterfaceAddrsByInterface(&intf) if err != nil { return false, err }