diff --git a/core/cmd/nekobox_core/core_box.go b/core/cmd/nekobox_core/core_box.go index bfe5099..1a69527 100644 --- a/core/cmd/nekobox_core/core_box.go +++ b/core/cmd/nekobox_core/core_box.go @@ -15,6 +15,7 @@ import ( ) var instance *boxbox.Box +var needUnsetDNS bool var systemProxyController settings.SystemProxy var systemProxyAddr metadata.Socksaddr var instance_cancel context.CancelFunc diff --git a/core/cmd/nekobox_core/grpc_box.go b/core/cmd/nekobox_core/grpc_box.go index 171996c..4b522df 100644 --- a/core/cmd/nekobox_core/grpc_box.go +++ b/core/cmd/nekobox_core/grpc_box.go @@ -8,9 +8,11 @@ import ( "github.com/sagernet/sing-box/experimental/clashapi" "github.com/sagernet/sing/common/metadata" "nekobox_core/internal/boxbox" + "nekobox_core/internal/sys" grpc_server "nekobox_core/server" "nekobox_core/server/gen" "os" + "runtime" "strings" "time" @@ -48,6 +50,13 @@ func (s *server) Start(ctx context.Context, in *gen.LoadConfigReq) (out *gen.Err } instance, instance_cancel, err = boxmain.Create([]byte(in.CoreConfig)) + if runtime.GOOS == "darwin" && strings.Contains(in.CoreConfig, "utun") && err == nil { + err := sys.SetSystemDNS("192.18.0.2", instance.Router().InterfaceMonitor()) + if err != nil { + log.Println("Failed to set system DNS:", err) + } + needUnsetDNS = true + } if instance != nil { // Logger @@ -78,6 +87,13 @@ func (s *server) Stop(ctx context.Context, in *gen.EmptyReq) (out *gen.ErrorResp return } + if needUnsetDNS { + needUnsetDNS = false + err := sys.SetSystemDNS("Empty", instance.Router().InterfaceMonitor()) + if err != nil { + log.Println("Failed to unset system DNS:", err) + } + } instance.CloseWithTimeout(instance_cancel, time.Second*2, log.Println) instance = nil diff --git a/core/cmd/nekobox_core/internal/sys/set_dns_darwin.go b/core/cmd/nekobox_core/internal/sys/set_dns_darwin.go new file mode 100644 index 0000000..cf7a813 --- /dev/null +++ b/core/cmd/nekobox_core/internal/sys/set_dns_darwin.go @@ -0,0 +1,40 @@ +package sys + +import ( + tun "github.com/sagernet/sing-tun" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/shell" + "net/netip" + "strings" +) + +func SetSystemDNS(addr string, interfaceMonitor tun.DefaultInterfaceMonitor) error { + interfaceName := interfaceMonitor.DefaultInterfaceName(netip.IPv4Unspecified()) + interfaceDisplayName, err := getInterfaceDisplayName(interfaceName) + if err != nil { + return err + } + + err = shell.Exec("networksetup", "-setdnsservers", interfaceDisplayName, addr).Attach().Run() + if err != nil { + return err + } + + return nil +} + +func getInterfaceDisplayName(name string) (string, error) { + content, err := shell.Exec("networksetup", "-listallhardwareports").ReadOutput() + if err != nil { + return "", err + } + for _, deviceSpan := range strings.Split(string(content), "Ethernet Address") { + if strings.Contains(deviceSpan, "Device: "+name) { + substr := "Hardware Port: " + deviceSpan = deviceSpan[strings.Index(deviceSpan, substr)+len(substr):] + deviceSpan = deviceSpan[:strings.Index(deviceSpan, "\n")] + return deviceSpan, nil + } + } + return "", E.New(name, " not found in networksetup -listallhardwareports") +} diff --git a/core/cmd/nekobox_core/internal/sys/set_dns_stub.go b/core/cmd/nekobox_core/internal/sys/set_dns_stub.go new file mode 100644 index 0000000..e493b29 --- /dev/null +++ b/core/cmd/nekobox_core/internal/sys/set_dns_stub.go @@ -0,0 +1,10 @@ +package sys + +import ( + "errors" + tun "github.com/sagernet/sing-tun" +) + +func SetSystemDNS(addr string, interfaceMonitor tun.DefaultInterfaceMonitor) error { + return errors.New("not implemented for this OS") +}