Files
portmaster/service/splittun/proxy/bind_linux.go
T
Alexandr Stelnykovych f7e6ea0eb3 splittun/proxy: add LocalBinding with SO_BINDTODEVICE support
Introduces LocalBinding{IP, Interface} to carry both source-address
and device binding in a single DeciderFunc return value. On Linux,
SO_BINDTODEVICE is applied via net.Dialer.Control before connect(2),
forcing traffic through the specified interface regardless of the
routing table. Non-Linux platforms get a no-op stub.

Wires LocalBinding through TCPProxy, UDPProxy, and splittun's
proxyDecider/AwaitRequest so split-tunnelled connections are bound
to the correct physical interface.
2026-04-29 17:37:57 +03:00

39 lines
1006 B
Go

//go:build linux
package proxy
import (
"net"
"syscall"
)
// applyBindToDevice configures d to bind all outgoing connections to the named
// network interface via the SO_BINDTODEVICE socket option. The option is set
// in d.Control, which the net package invokes on the raw file descriptor
// immediately after socket creation and before connect(2), ensuring the kernel
// routes the connection through the specified device regardless of the routing
// table.
//
// If iface is empty, d is left unchanged and no binding is performed.
// d.Control is overwritten; any previously set hook is discarded.
func applyBindToDevice(d *net.Dialer, iface string) {
if iface == "" {
return
}
d.Control = func(network, address string, c syscall.RawConn) error {
var innerErr error
err := c.Control(func(fd uintptr) {
innerErr = syscall.SetsockoptString(
int(fd),
syscall.SOL_SOCKET,
syscall.SO_BINDTODEVICE,
iface,
)
})
if err != nil {
return err
}
return innerErr
}
}