From 9184cd23e5df528d23b41ec1da5a2efca38f18b2 Mon Sep 17 00:00:00 2001 From: Andrei Tregubov Date: Sun, 18 Jan 2026 23:12:31 +0400 Subject: [PATCH] Fix outbound link-local connections on mobile (#1300) --- src/core/link_tcp.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/core/link_tcp.go b/src/core/link_tcp.go index 484e0164..7cbb1ba6 100644 --- a/src/core/link_tcp.go +++ b/src/core/link_tcp.go @@ -69,6 +69,13 @@ func (l *linkTCP) dialerFor(dst *net.TCPAddr, sintf string) (*net.Dialer, error) dialer.Control = l.getControl(sintf) ief, err := net.InterfaceByName(sintf) if err != nil { + // On mobile platforms (Android/iOS), InterfaceByName may fail due to + // permission restrictions (SELinux on Android), but for link-local + // addresses with zone identifiers, the zone is sufficient for routing + // and we can proceed without source binding + if dst.IP.IsLinkLocalUnicast() && dst.Zone != "" { + return dialer, nil + } return nil, fmt.Errorf("interface %q not found", sintf) } if ief.Flags&net.FlagUp == 0 { @@ -76,6 +83,10 @@ func (l *linkTCP) dialerFor(dst *net.TCPAddr, sintf string) (*net.Dialer, error) } addrs, err := ief.Addrs() if err != nil { + // Same mobile platform handling for address lookup failures + if dst.IP.IsLinkLocalUnicast() && dst.Zone != "" { + return dialer, nil + } return nil, fmt.Errorf("interface %q addresses not available: %w", sintf, err) } for addrindex, addr := range addrs { @@ -104,6 +115,10 @@ func (l *linkTCP) dialerFor(dst *net.TCPAddr, sintf string) (*net.Dialer, error) } } if dialer.LocalAddr == nil { + // Proceed without source binding if link-local + if dst.IP.IsLinkLocalUnicast() && dst.Zone != "" { + return dialer, nil + } return nil, fmt.Errorf("no suitable source address found on interface %q", sintf) } }