mirror of
https://github.com/safing/portmaster.git
synced 2026-05-20 20:40:36 +00:00
f7e6ea0eb3
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.
39 lines
1006 B
Go
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
|
|
}
|
|
}
|