Fix default dialer on legacy xiaomi systems

This commit is contained in:
世界 2024-12-21 21:26:42 +08:00
parent f72118135e
commit 339e3e6c15
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
2 changed files with 62 additions and 40 deletions

View File

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

View File

@ -35,7 +35,7 @@ func (d *DefaultDialer) dialParallelInterface(ctx context.Context, dialer net.Di
conn, err := perNetDialer.DialContext(ctx, network, addr) conn, err := perNetDialer.DialContext(ctx, network, addr)
if err != nil { if err != nil {
select { 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: case <-returned:
} }
} else { } else {
@ -107,7 +107,7 @@ func (d *DefaultDialer) dialParallelInterfaceFastFallback(ctx context.Context, d
conn, err := perNetDialer.DialContext(ctx, network, addr) conn, err := perNetDialer.DialContext(ctx, network, addr)
if err != nil { if err != nil {
select { 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: case <-returned:
} }
} else { } else {
@ -157,7 +157,7 @@ func (d *DefaultDialer) listenSerialInterfacePacket(ctx context.Context, listene
if err == nil { if err == nil {
return conn, 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 { for _, fallbackInterface := range fallbackInterfaces {
perNetListener := listener perNetListener := listener
@ -166,7 +166,7 @@ func (d *DefaultDialer) listenSerialInterfacePacket(ctx context.Context, listene
if err == nil { if err == nil {
return conn, 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...) return nil, E.Errors(errors...)
} }