1
0
Эх сурвалжийг харах

Fix default dialer on legacy xiaomi systems

世界 10 сар өмнө
parent
commit
1ed8f3a8d3

+ 58 - 36
common/dialer/default.go

@@ -2,8 +2,10 @@ package dialer
 
 import (
 	"context"
+	"errors"
 	"net"
 	"net/netip"
+	"syscall"
 	"time"
 
 	"github.com/sagernet/sing-box/adapter"
@@ -26,20 +28,21 @@ var (
 )
 
 type DefaultDialer struct {
-	dialer4              tcpDialer
-	dialer6              tcpDialer
-	udpDialer4           net.Dialer
-	udpDialer6           net.Dialer
-	udpListener          net.ListenConfig
-	udpAddr4             string
-	udpAddr6             string
-	isWireGuardListener  bool
-	networkManager       adapter.NetworkManager
-	networkStrategy      *C.NetworkStrategy
-	networkType          []C.InterfaceType
-	fallbackNetworkType  []C.InterfaceType
-	networkFallbackDelay time.Duration
-	networkLastFallback  atomic.TypedValue[time.Time]
+	dialer4                tcpDialer
+	dialer6                tcpDialer
+	udpDialer4             net.Dialer
+	udpDialer6             net.Dialer
+	udpListener            net.ListenConfig
+	udpAddr4               string
+	udpAddr6               string
+	isWireGuardListener    bool
+	networkManager         adapter.NetworkManager
+	networkStrategy        *C.NetworkStrategy
+	defaultNetworkStrategy bool
+	networkType            []C.InterfaceType
+	fallbackNetworkType    []C.InterfaceType
+	networkFallbackDelay   time.Duration
+	networkLastFallback    atomic.TypedValue[time.Time]
 }
 
 func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDialer, error) {
@@ -47,13 +50,14 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
 	platformInterface := service.FromContext[platform.Interface](ctx)
 
 	var (
-		dialer               net.Dialer
-		listener             net.ListenConfig
-		interfaceFinder      control.InterfaceFinder
-		networkStrategy      *C.NetworkStrategy
-		networkType          []C.InterfaceType
-		fallbackNetworkType  []C.InterfaceType
-		networkFallbackDelay time.Duration
+		dialer                 net.Dialer
+		listener               net.ListenConfig
+		interfaceFinder        control.InterfaceFinder
+		networkStrategy        *C.NetworkStrategy
+		defaultNetworkStrategy bool
+		networkType            []C.InterfaceType
+		fallbackNetworkType    []C.InterfaceType
+		networkFallbackDelay   time.Duration
 	)
 	if networkManager != nil {
 		interfaceFinder = networkManager.InterfaceFinder()
@@ -98,6 +102,7 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
 					networkStrategy = (*C.NetworkStrategy)(options.NetworkStrategy)
 					if networkStrategy == nil {
 						networkStrategy = common.Ptr(C.NetworkStrategyDefault)
+						defaultNetworkStrategy = true
 					}
 					networkType = common.Map(options.NetworkType, option.InterfaceType.Build)
 					fallbackNetworkType = common.Map(options.FallbackNetworkType, option.InterfaceType.Build)
@@ -192,19 +197,20 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
 		return nil, err
 	}
 	return &DefaultDialer{
-		dialer4:              tcpDialer4,
-		dialer6:              tcpDialer6,
-		udpDialer4:           udpDialer4,
-		udpDialer6:           udpDialer6,
-		udpListener:          listener,
-		udpAddr4:             udpAddr4,
-		udpAddr6:             udpAddr6,
-		isWireGuardListener:  options.IsWireGuardListener,
-		networkManager:       networkManager,
-		networkStrategy:      networkStrategy,
-		networkType:          networkType,
-		fallbackNetworkType:  fallbackNetworkType,
-		networkFallbackDelay: networkFallbackDelay,
+		dialer4:                tcpDialer4,
+		dialer6:                tcpDialer6,
+		udpDialer4:             udpDialer4,
+		udpDialer6:             udpDialer6,
+		udpListener:            listener,
+		udpAddr4:               udpAddr4,
+		udpAddr6:               udpAddr6,
+		isWireGuardListener:    options.IsWireGuardListener,
+		networkManager:         networkManager,
+		networkStrategy:        networkStrategy,
+		defaultNetworkStrategy: defaultNetworkStrategy,
+		networkType:            networkType,
+		fallbackNetworkType:    fallbackNetworkType,
+		networkFallbackDelay:   networkFallbackDelay,
 	}, nil
 }
 
@@ -265,7 +271,13 @@ func (d *DefaultDialer) DialParallelInterface(ctx context.Context, network strin
 		conn, isPrimary, err = d.dialParallelInterfaceFastFallback(ctx, dialer, network, address.String(), *strategy, interfaceType, fallbackInterfaceType, fallbackDelay, d.networkLastFallback.Store)
 	}
 	if err != nil {
-		return nil, err
+		// bind interface failed on legacy xiaomi systems
+		if d.defaultNetworkStrategy && errors.Is(err, syscall.EPERM) {
+			d.networkStrategy = nil
+			return d.DialContext(ctx, network, address)
+		} else {
+			return nil, err
+		}
 	}
 	if !fastFallback && !isPrimary {
 		d.networkLastFallback.Store(time.Now())
@@ -307,7 +319,17 @@ func (d *DefaultDialer) ListenSerialInterfacePacket(ctx context.Context, destina
 	if destination.IsIPv4() && !destination.Addr.IsUnspecified() {
 		network += "4"
 	}
-	return trackPacketConn(d.listenSerialInterfacePacket(ctx, d.udpListener, network, "", *strategy, interfaceType, fallbackInterfaceType, fallbackDelay))
+	packetConn, err := d.listenSerialInterfacePacket(ctx, d.udpListener, network, "", *strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
+	if err != nil {
+		// bind interface failed on legacy xiaomi systems
+		if d.defaultNetworkStrategy && errors.Is(err, syscall.EPERM) {
+			d.networkStrategy = nil
+			return d.ListenPacket(ctx, destination)
+		} else {
+			return nil, err
+		}
+	}
+	return trackPacketConn(packetConn, nil)
 }
 
 func (d *DefaultDialer) ListenPacketCompat(network, address string) (net.PacketConn, error) {

+ 4 - 4
common/dialer/default_parallel_interface.go

@@ -35,7 +35,7 @@ func (d *DefaultDialer) dialParallelInterface(ctx context.Context, dialer net.Di
 		conn, err := perNetDialer.DialContext(ctx, network, addr)
 		if err != nil {
 			select {
-			case results <- dialResult{error: E.Cause(err, "dial ", iif.Name, " (", iif.Name, ")"), primary: primary}:
+			case results <- dialResult{error: E.Cause(err, "dial ", iif.Name, " (", iif.Index, ")"), primary: primary}:
 			case <-returned:
 			}
 		} else {
@@ -107,7 +107,7 @@ func (d *DefaultDialer) dialParallelInterfaceFastFallback(ctx context.Context, d
 		conn, err := perNetDialer.DialContext(ctx, network, addr)
 		if err != nil {
 			select {
-			case results <- dialResult{error: E.Cause(err, "dial ", iif.Name, " (", iif.Name, ")"), primary: primary}:
+			case results <- dialResult{error: E.Cause(err, "dial ", iif.Name, " (", iif.Index, ")"), primary: primary}:
 			case <-returned:
 			}
 		} else {
@@ -157,7 +157,7 @@ func (d *DefaultDialer) listenSerialInterfacePacket(ctx context.Context, listene
 		if err == nil {
 			return conn, nil
 		}
-		errors = append(errors, E.Cause(err, "listen ", primaryInterface.Name, " (", primaryInterface.Name, ")"))
+		errors = append(errors, E.Cause(err, "listen ", primaryInterface.Name, " (", primaryInterface.Index, ")"))
 	}
 	for _, fallbackInterface := range fallbackInterfaces {
 		perNetListener := listener
@@ -166,7 +166,7 @@ func (d *DefaultDialer) listenSerialInterfacePacket(ctx context.Context, listene
 		if err == nil {
 			return conn, nil
 		}
-		errors = append(errors, E.Cause(err, "listen ", fallbackInterface.Name, " (", fallbackInterface.Name, ")"))
+		errors = append(errors, E.Cause(err, "listen ", fallbackInterface.Name, " (", fallbackInterface.Index, ")"))
 	}
 	return nil, E.Errors(errors...)
 }