diff --git a/proxy/tun/tun_linux.go b/proxy/tun/tun_linux.go index b8eff0174..110809549 100644 --- a/proxy/tun/tun_linux.go +++ b/proxy/tun/tun_linux.go @@ -308,36 +308,37 @@ func findOutboundInterface(tunIndex int, fixedName string) (*net.Interface, erro return iface, nil } - probeIPs := []net.IP{ - net.ParseIP("8.8.8.8"), - net.ParseIP("2001:4860:4860::8888"), + for _, family := range []int{ + netlink.FAMILY_V4, + netlink.FAMILY_V6, + } { + iface, err := findDefaultInterface(family, tunIndex) + if err == nil { + return iface, nil + } } - for _, ip := range probeIPs { - routes, err := netlink.RouteGet(ip) - if err != nil || len(routes) == 0 { - continue - } - route := routes[0] - if route.LinkIndex == tunIndex { - continue + return nil, errors.New("no usable outbound interface found") +} + +func findDefaultInterface(family int, tunIndex int) (*net.Interface, error) { + routes, err := netlink.RouteList(nil, family) + if err != nil { + return nil, err + } + + var selected *net.Interface + selectedMetric := -1 + + for _, route := range routes { + if route.Dst != nil { + ones, _ := route.Dst.Mask.Size() + if ones != 0 { + continue + } } - link, err := netlink.LinkByIndex(route.LinkIndex) - if err != nil { - continue - } - attrs := link.Attrs() - - if attrs.Flags&net.FlagUp == 0 { - continue - } - operState := attrs.OperState - if operState != netlink.OperUp && operState != netlink.OperUnknown { - continue - } - - if route.Src == nil || route.Src.IsLoopback() || route.Src.IsLinkLocalUnicast() { + if route.LinkIndex == 0 || route.LinkIndex == tunIndex { continue } @@ -345,8 +346,21 @@ func findOutboundInterface(tunIndex int, fixedName string) (*net.Interface, erro if err != nil { continue } - return iface, nil + + if iface.Flags&net.FlagUp == 0 || + iface.Flags&net.FlagLoopback != 0 { + continue + } + + if selected == nil || route.Priority < selectedMetric { + selected = iface + selectedMetric = route.Priority + } } - return nil, errors.New("no usable outbound interface found") + if selected == nil { + return nil, errors.New("physical default route not found") + } + + return selected, nil }