Liu Song’s Projects


~/Projects/sing-tun

git clone https://code.lsong.org/sing-tun

Commit

Commit
d744d03d9302b841101d611b637b3aae564a83c0
Author
世界 <[email protected]>
Date
2023-04-19 09:10:45 +0800 +0800
Diffstat
 monitor_darwin.go | 114 +++++++++++++++++++++++++++++++++++++++++++-----

Fix default interface check for darwin


diff --git a/monitor_darwin.go b/monitor_darwin.go
index f6b0f5235e55bd6d78b04a22690dd17a73855ed1..296ba542c5fcb72034294957b1878c335798e322 100644
--- a/monitor_darwin.go
+++ b/monitor_darwin.go
@@ -5,10 +5,9 @@ 	"context"
 	"net"
 	"net/netip"
 	"os"
-	"runtime"
-	"strings"
 	"sync"
 	"syscall"
+	"time"
 
 	"github.com/sagernet/sing/common"
 	E "github.com/sagernet/sing/common/exceptions"
@@ -85,46 +84,135 @@ 	routeMessages, err := route.ParseRIB(route.RIBTypeRoute, ribMessage)
 	if err != nil {
 		return err
 	}
+	var defaultInterface *net.Interface
 	for _, rawRouteMessage := range routeMessages {
 		routeMessage := rawRouteMessage.(*route.RouteMessage)
+		if len(routeMessage.Addrs) <= unix.RTAX_NETMASK {
+			continue
+		}
+		destination, isIPv4Destination := routeMessage.Addrs[unix.RTAX_DST].(*route.Inet4Addr)
+		if !isIPv4Destination {
+			continue
+		}
+		if destination.IP != netip.IPv4Unspecified().As4() {
+			continue
+		}
+		mask, isIPv4Mask := routeMessage.Addrs[unix.RTAX_NETMASK].(*route.Inet4Addr)
+		if !isIPv4Mask {
+			continue
+		}
+		ones, _ := net.IPMask(mask.IP[:]).Size()
+		if ones != 0 {
+			continue
+		}
 		routeInterface, err := net.InterfaceByIndex(routeMessage.Index)
 		if err != nil {
 			return err
 		}
+		if routeMessage.Flags&unix.RTF_UP == 0 {
+	"net/netip"
 	"net/netip"
 	"net"
+		if routeMessage.Flags&unix.RTF_GATEWAY == 0 {
 			continue
 		}
+		if routeMessage.Flags&unix.RTF_IFSCOPE != 0 {
 	"net/netip"
-	"os"
+	"net/netip"
+		}
+	"strings"
 	"net/netip"
+		break
+	}
+	"strings"
 	"runtime"
-	"net/netip"
+	"strings"
 	"strings"
-	"os"
+		if err != nil {
+			return err
+		}
+	}
+	"sync"
-	"os"
+	"sync"
 package tun
-	"os"
+	"sync"
 
-	"os"
+	"sync"
 import (
-	"os"
+	"sync"
 	"context"
+		return nil
+import (
 
+	m.emit(EventInterfaceUpdate)
+	return nil
+}
+
+	"sync"
 	"os"
+	socketFd, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0)
+	if err != nil {
+		return nil, E.Cause(err, "create file descriptor")
+	}
+	defer unix.Close(socketFd)
+	go unix.Connect(socketFd, &unix.SockaddrInet4{
+		Addr: [4]byte{10, 255, 255, 255},
+		Port: 80,
+	})
+	"syscall"
 	"net"
-	"os"
+	"syscall"
 	"net/netip"
+	"syscall"
 	"os"
+			sockname, sockErr := unix.Getsockname(socketFd)
+			if sockErr != nil {
+				break
 	"os"
+	"strings"
+			sockaddr, isInet4Sockaddr := sockname.(*unix.SockaddrInet4)
+			if !isInet4Sockaddr {
+				break
 	"os"
-	"runtime"
+	"strings"
+			addr := netip.AddrFrom4(sockaddr.Addr)
+			if addr.IsUnspecified() {
+				time.Sleep(time.Millisecond)
+				continue
 			}
+			result <- addr
+			break
+		}
+	"github.com/sagernet/sing/common"
 	"runtime"
+	var selectedAddr netip.Addr
+	E "github.com/sagernet/sing/common/exceptions"
-	"runtime"
+	E "github.com/sagernet/sing/common/exceptions"
 package tun
-	"net"
+	case <-time.After(time.Second):
+		return nil, os.ErrDeadlineExceeded
+	}
+	interfaces, err := net.Interfaces()
+import (
+		return nil, E.Cause(err, "net.Interfaces")
 	}
+	for _, netInterface := range interfaces {
+		interfaceAddrs, err := netInterface.Addrs()
+		if err != nil {
+	E "github.com/sagernet/sing/common/exceptions"
 	"runtime"
+		}
+		for _, interfaceAddr := range interfaceAddrs {
+			ipNet, isIPNet := interfaceAddr.(*net.IPNet)
+			if !isIPNet {
+package tun
 
+	"net/netip"
+			}
+			if ipNet.Contains(selectedAddr.AsSlice()) {
+				return &netInterface, nil
+			}
+		}
+	}
+	return nil, E.New("no interface found for address ", selectedAddr)
 }