Files
rtnetmon/internal/monitor/dial_darwin.go
T
sneak ef3c373a12 Detect interfaces per platform; add macOS and single-interface support (closes #2)
Linux runs exactly as before when both bridge interfaces exist. When they do
not, the lone default-route interface is monitored, and a single interface now
draws a single UI pane instead of an empty second one.

macOS is newly supported: a running VPN tunnel (utun) is monitored as the
primary pane alongside the physical default-route interface, or the physical
interface alone when no VPN is up.

Detection lives in internal/netdetect: interface/route data types, pure
selection logic keyed on OS name, and route parsers, all unit-tested on Linux
for both platforms. Only the real route query and the per-platform TCP dial
binding (source address on Linux, IP_BOUND_IF on macOS) are build-tagged. Ping
argument construction is a pure, OS-keyed function. NewMonitor now takes a list
of interfaces.

Model: opus-4-8
2026-09-21 06:53:39 +00:00

37 lines
844 B
Go

//go:build darwin
package monitor
import (
"net"
"syscall"
"golang.org/x/sys/unix"
)
// bindControl returns a socket control hook that pins the connection to the
// given interface with IP_BOUND_IF. On macOS a bound source address is not
// enough: without this the kernel still routes the packets over the VPN's
// default route, so traffic would not leave the interface we are measuring.
func bindControl(iface string) func(network, address string, c syscall.RawConn) error {
ifi, err := net.InterfaceByName(iface)
if err != nil {
return nil
}
idx := ifi.Index
return func(_, _ string, c syscall.RawConn) error {
var setErr error
ctrlErr := c.Control(func(fd uintptr) {
setErr = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, idx)
})
if ctrlErr != nil {
return ctrlErr
}
return setErr
}
}