[client] Scope the iOS file drop dial to the tunnel interface

A Network Extension's own unscoped sockets bypass its tunnel and leave on
the physical interface, so the file drop dial to a peer address died on
the local network. Bind the socket to the overlay address and the tunnel
interface index, the same way the iOS DNS upstream client dials. Other
platforms keep the plain dialer: Android and the desktops route the
client's own traffic into the tunnel already.
This commit is contained in:
Zoltán Papp
2026-08-27 16:10:25 +02:00
parent 951e5d3e28
commit 898539381c
2 changed files with 71 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
//go:build !ios
package internal
import (
"net"
"github.com/netbirdio/netbird/client/internal/filedrop"
)
func fileDropOSDial(WGIface) filedrop.DialFunc {
dialer := &net.Dialer{}
return dialer.DialContext
}
@@ -0,0 +1,57 @@
//go:build ios
package internal
import (
"context"
"fmt"
"net"
"net/netip"
"syscall"
"golang.org/x/sys/unix"
"github.com/netbirdio/netbird/client/internal/filedrop"
)
// fileDropOSDial scopes the dial to the tunnel interface, since a Network
// Extension's own unscoped sockets bypass its tunnel and leave on the
// physical interface.
func fileDropOSDial(wgIface WGIface) filedrop.DialFunc {
return func(ctx context.Context, network, addr string) (net.Conn, error) {
addrPort, err := netip.ParseAddrPort(addr)
if err != nil {
return nil, err
}
osIface, err := net.InterfaceByName(wgIface.Name())
if err != nil {
return nil, fmt.Errorf("lookup interface %q: %w", wgIface.Name(), err)
}
wgAddr := wgIface.Address()
bindIP := wgAddr.IP
proto, opt := unix.IPPROTO_IP, unix.IP_BOUND_IF
if addrPort.Addr().Is6() {
if !wgAddr.HasIPv6() {
return nil, fmt.Errorf("no IPv6 address on %s", wgIface.Name())
}
bindIP = wgAddr.IPv6
proto, opt = unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF
}
dialer := &net.Dialer{
LocalAddr: net.TCPAddrFromAddrPort(netip.AddrPortFrom(bindIP, 0)),
Control: func(_, _ string, c syscall.RawConn) error {
var operr error
if err := c.Control(func(s uintptr) {
operr = unix.SetsockoptInt(int(s), proto, opt, osIface.Index)
}); err != nil {
return err
}
return operr
},
}
return dialer.DialContext(ctx, network, addr)
}
}