sing-box/test/clash_darwin_test.go

72 lines
1.4 KiB
Go

package main
import (
"errors"
"fmt"
"net"
"net/netip"
"syscall"
"golang.org/x/net/route"
)
func defaultRouteIP() (netip.Addr, error) {
idx, err := defaultRouteInterfaceIndex()
if err != nil {
return netip.Addr{}, err
}
iface, err := net.InterfaceByIndex(idx)
if err != nil {
return netip.Addr{}, err
}
addrs, err := iface.Addrs()
if err != nil {
return netip.Addr{}, err
}
for _, addr := range addrs {
ip := addr.(*net.IPNet).IP
if ip.To4() != nil {
return netip.AddrFrom4(*(*[4]byte)(ip)), nil
}
}
return netip.Addr{}, errors.New("no ipv4 addr")
}
func defaultRouteInterfaceIndex() (int, error) {
rib, err := route.FetchRIB(syscall.AF_UNSPEC, syscall.NET_RT_DUMP2, 0)
if err != nil {
return 0, fmt.Errorf("route.FetchRIB: %w", err)
}
msgs, err := route.ParseRIB(syscall.NET_RT_IFLIST2, rib)
if err != nil {
return 0, fmt.Errorf("route.ParseRIB: %w", err)
}
for _, message := range msgs {
routeMessage := message.(*route.RouteMessage)
if routeMessage.Flags&(syscall.RTF_UP|syscall.RTF_GATEWAY|syscall.RTF_STATIC) == 0 {
continue
}
addresses := routeMessage.Addrs
destination, ok := addresses[0].(*route.Inet4Addr)
if !ok {
continue
}
if destination.IP != [4]byte{0, 0, 0, 0} {
continue
}
switch addresses[1].(type) {
case *route.Inet4Addr:
return routeMessage.Index, nil
default:
continue
}
}
return 0, fmt.Errorf("ambiguous gateway interfaces found")
}