Fix domain strategy

This commit is contained in:
世界 2024-12-15 00:45:41 +08:00
parent f08861185a
commit dda692e955
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
19 changed files with 195 additions and 136 deletions

View File

@ -72,7 +72,7 @@ type InboundContext struct {
UDPConnect bool UDPConnect bool
UDPTimeout time.Duration UDPTimeout time.Duration
NetworkStrategy C.NetworkStrategy NetworkStrategy *C.NetworkStrategy
NetworkType []C.InterfaceType NetworkType []C.InterfaceType
FallbackNetworkType []C.InterfaceType FallbackNetworkType []C.InterfaceType
FallbackDelay time.Duration FallbackDelay time.Duration

View File

@ -28,7 +28,7 @@ type NetworkManager interface {
} }
type NetworkOptions struct { type NetworkOptions struct {
NetworkStrategy C.NetworkStrategy NetworkStrategy *C.NetworkStrategy
NetworkType []C.InterfaceType NetworkType []C.InterfaceType
FallbackNetworkType []C.InterfaceType FallbackNetworkType []C.InterfaceType
FallbackDelay time.Duration FallbackDelay time.Duration

View File

@ -9,6 +9,7 @@ import (
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/conntrack" "github.com/sagernet/sing-box/common/conntrack"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/experimental/libbox/platform"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common" "github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic" "github.com/sagernet/sing/common/atomic"
@ -16,6 +17,7 @@ import (
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata" M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/service"
) )
var ( var (
@ -33,19 +35,22 @@ type DefaultDialer struct {
udpAddr6 string udpAddr6 string
isWireGuardListener bool isWireGuardListener bool
networkManager adapter.NetworkManager networkManager adapter.NetworkManager
networkStrategy C.NetworkStrategy networkStrategy *C.NetworkStrategy
networkType []C.InterfaceType networkType []C.InterfaceType
fallbackNetworkType []C.InterfaceType fallbackNetworkType []C.InterfaceType
networkFallbackDelay time.Duration networkFallbackDelay time.Duration
networkLastFallback atomic.TypedValue[time.Time] networkLastFallback atomic.TypedValue[time.Time]
} }
func NewDefault(networkManager adapter.NetworkManager, options option.DialerOptions) (*DefaultDialer, error) { func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDialer, error) {
networkManager := service.FromContext[adapter.NetworkManager](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 networkType []C.InterfaceType
fallbackNetworkType []C.InterfaceType fallbackNetworkType []C.InterfaceType
networkFallbackDelay time.Duration networkFallbackDelay time.Duration
@ -74,31 +79,37 @@ func NewDefault(networkManager adapter.NetworkManager, options option.DialerOpti
listener.Control = control.Append(listener.Control, control.RoutingMark(autoRedirectOutputMark)) listener.Control = control.Append(listener.Control, control.RoutingMark(autoRedirectOutputMark))
} }
} }
if C.NetworkStrategy(options.NetworkStrategy) != C.NetworkStrategyDefault { disableDefaultBind := options.BindInterface != "" || options.Inet4BindAddress != nil || options.Inet6BindAddress != nil
if options.BindInterface != "" || options.Inet4BindAddress != nil || options.Inet6BindAddress != nil { if disableDefaultBind || options.TCPFastOpen {
return nil, E.New("`network_strategy` is conflict with `bind_interface`, `inet4_bind_address` and `inet6_bind_address`") if options.NetworkStrategy != nil || len(options.NetworkType) > 0 && options.FallbackNetworkType == nil && options.FallbackDelay == 0 {
} return nil, E.New("`network_strategy` is conflict with `bind_interface`, `inet4_bind_address`, `inet6_bind_address` and `tcp_fast_open`")
networkStrategy = C.NetworkStrategy(options.NetworkStrategy)
networkType = common.Map(options.NetworkType, option.InterfaceType.Build)
fallbackNetworkType = common.Map(options.FallbackNetworkType, option.InterfaceType.Build)
networkFallbackDelay = time.Duration(options.NetworkFallbackDelay)
if networkManager == nil || !networkManager.AutoDetectInterface() {
return nil, E.New("`route.auto_detect_interface` is require by `network_strategy`")
} }
} }
if networkManager != nil && options.BindInterface == "" && options.Inet4BindAddress == nil && options.Inet6BindAddress == nil {
if networkManager != nil {
defaultOptions := networkManager.DefaultOptions() defaultOptions := networkManager.DefaultOptions()
if options.BindInterface == "" { if !disableDefaultBind {
if defaultOptions.BindInterface != "" { if defaultOptions.BindInterface != "" {
bindFunc := control.BindToInterface(networkManager.InterfaceFinder(), defaultOptions.BindInterface, -1) bindFunc := control.BindToInterface(networkManager.InterfaceFinder(), defaultOptions.BindInterface, -1)
dialer.Control = control.Append(dialer.Control, bindFunc) dialer.Control = control.Append(dialer.Control, bindFunc)
listener.Control = control.Append(listener.Control, bindFunc) listener.Control = control.Append(listener.Control, bindFunc)
} else if networkManager.AutoDetectInterface() { } else if networkManager.AutoDetectInterface() {
if defaultOptions.NetworkStrategy != C.NetworkStrategyDefault && C.NetworkStrategy(options.NetworkStrategy) == C.NetworkStrategyDefault { if platformInterface != nil {
networkStrategy = defaultOptions.NetworkStrategy networkStrategy = (*C.NetworkStrategy)(options.NetworkStrategy)
networkType = defaultOptions.NetworkType if networkStrategy == nil {
fallbackNetworkType = defaultOptions.FallbackNetworkType networkStrategy = common.Ptr(C.NetworkStrategyDefault)
networkFallbackDelay = defaultOptions.FallbackDelay }
networkType = common.Map(options.NetworkType, option.InterfaceType.Build)
fallbackNetworkType = common.Map(options.FallbackNetworkType, option.InterfaceType.Build)
if networkStrategy == nil && len(networkType) == 0 && len(fallbackNetworkType) == 0 {
networkStrategy = defaultOptions.NetworkStrategy
networkType = defaultOptions.NetworkType
fallbackNetworkType = defaultOptions.FallbackNetworkType
}
networkFallbackDelay = time.Duration(options.FallbackDelay)
if networkFallbackDelay == 0 && defaultOptions.FallbackDelay != 0 {
networkFallbackDelay = defaultOptions.FallbackDelay
}
bindFunc := networkManager.ProtectFunc() bindFunc := networkManager.ProtectFunc()
dialer.Control = control.Append(dialer.Control, bindFunc) dialer.Control = control.Append(dialer.Control, bindFunc)
listener.Control = control.Append(listener.Control, bindFunc) listener.Control = control.Append(listener.Control, bindFunc)
@ -172,9 +183,6 @@ func NewDefault(networkManager adapter.NetworkManager, options option.DialerOpti
listener.Control = control.Append(listener.Control, controlFn) listener.Control = control.Append(listener.Control, controlFn)
} }
} }
if networkStrategy != C.NetworkStrategyDefault && options.TCPFastOpen {
return nil, E.New("`tcp_fast_open` is conflict with `network_strategy` or `route.default_network_strategy`")
}
tcpDialer4, err := newTCPDialer(dialer4, options.TCPFastOpen) tcpDialer4, err := newTCPDialer(dialer4, options.TCPFastOpen)
if err != nil { if err != nil {
return nil, err return nil, err
@ -204,7 +212,7 @@ func (d *DefaultDialer) DialContext(ctx context.Context, network string, address
if !address.IsValid() { if !address.IsValid() {
return nil, E.New("invalid address") return nil, E.New("invalid address")
} }
if d.networkStrategy == C.NetworkStrategyDefault { if d.networkStrategy == nil {
switch N.NetworkName(network) { switch N.NetworkName(network) {
case N.NetworkUDP: case N.NetworkUDP:
if !address.IsIPv6() { if !address.IsIPv6() {
@ -223,12 +231,21 @@ func (d *DefaultDialer) DialContext(ctx context.Context, network string, address
} }
} }
func (d *DefaultDialer) DialParallelInterface(ctx context.Context, network string, address M.Socksaddr, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) { func (d *DefaultDialer) DialParallelInterface(ctx context.Context, network string, address M.Socksaddr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) {
if strategy == C.NetworkStrategyDefault { if strategy == nil {
strategy = d.networkStrategy
}
if strategy == nil {
return d.DialContext(ctx, network, address) return d.DialContext(ctx, network, address)
} }
if !d.networkManager.AutoDetectInterface() { if len(interfaceType) == 0 {
return nil, E.New("`route.auto_detect_interface` is require by `network_strategy`") interfaceType = d.networkType
}
if len(fallbackInterfaceType) == 0 {
fallbackInterfaceType = d.fallbackNetworkType
}
if fallbackDelay == 0 {
fallbackDelay = d.networkFallbackDelay
} }
var dialer net.Dialer var dialer net.Dialer
if N.NetworkName(network) == N.NetworkTCP { if N.NetworkName(network) == N.NetworkTCP {
@ -243,9 +260,9 @@ func (d *DefaultDialer) DialParallelInterface(ctx context.Context, network strin
err error err error
) )
if !fastFallback { if !fastFallback {
conn, isPrimary, err = d.dialParallelInterface(ctx, dialer, network, address.String(), strategy, interfaceType, fallbackInterfaceType, fallbackDelay) conn, isPrimary, err = d.dialParallelInterface(ctx, dialer, network, address.String(), *strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
} else { } else {
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 return nil, err
@ -257,7 +274,7 @@ func (d *DefaultDialer) DialParallelInterface(ctx context.Context, network strin
} }
func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
if d.networkStrategy == C.NetworkStrategyDefault { if d.networkStrategy == nil {
if destination.IsIPv6() { if destination.IsIPv6() {
return trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr6)) return trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr6))
} else if destination.IsIPv4() && !destination.Addr.IsUnspecified() { } else if destination.IsIPv4() && !destination.Addr.IsUnspecified() {
@ -270,18 +287,27 @@ func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksadd
} }
} }
func (d *DefaultDialer) ListenSerialInterfacePacket(ctx context.Context, destination M.Socksaddr, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, error) { func (d *DefaultDialer) ListenSerialInterfacePacket(ctx context.Context, destination M.Socksaddr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, error) {
if strategy == C.NetworkStrategyDefault { if strategy == nil {
strategy = d.networkStrategy
}
if strategy == nil {
return d.ListenPacket(ctx, destination) return d.ListenPacket(ctx, destination)
} }
if !d.networkManager.AutoDetectInterface() { if len(interfaceType) == 0 {
return nil, E.New("`route.auto_detect_interface` is require by `network_strategy`") interfaceType = d.networkType
}
if len(fallbackInterfaceType) == 0 {
fallbackInterfaceType = d.fallbackNetworkType
}
if fallbackDelay == 0 {
fallbackDelay = d.networkFallbackDelay
} }
network := N.NetworkUDP network := N.NetworkUDP
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)) return trackPacketConn(d.listenSerialInterfacePacket(ctx, d.udpListener, network, "", *strategy, interfaceType, fallbackInterfaceType, fallbackDelay))
} }
func (d *DefaultDialer) ListenPacketCompat(network, address string) (net.PacketConn, error) { func (d *DefaultDialer) ListenPacketCompat(network, address string) (net.PacketConn, error) {

View File

@ -40,7 +40,7 @@ func (d *DefaultDialer) dialParallelInterface(ctx context.Context, dialer net.Di
} }
} else { } else {
select { select {
case results <- dialResult{Conn: conn}: case results <- dialResult{Conn: conn, primary: primary}:
case <-returned: case <-returned:
conn.Close() conn.Close()
} }
@ -112,7 +112,7 @@ func (d *DefaultDialer) dialParallelInterfaceFastFallback(ctx context.Context, d
} }
} else { } else {
select { select {
case results <- dialResult{Conn: conn}: case results <- dialResult{Conn: conn, primary: primary}:
case <-returned: case <-returned:
if primary && time.Since(startAt) <= fallbackDelay { if primary && time.Since(startAt) <= fallbackDelay {
resetFastFallback(time.Time{}) resetFastFallback(time.Time{})
@ -177,44 +177,57 @@ func selectInterfaces(networkManager adapter.NetworkManager, strategy C.NetworkS
case C.NetworkStrategyDefault: case C.NetworkStrategyDefault:
if len(interfaceType) == 0 { if len(interfaceType) == 0 {
defaultIf := networkManager.InterfaceMonitor().DefaultInterface() defaultIf := networkManager.InterfaceMonitor().DefaultInterface()
for _, iif := range interfaces { if defaultIf != nil {
if iif.Index == defaultIf.Index { for _, iif := range interfaces {
primaryInterfaces = append(primaryInterfaces, iif) if iif.Index == defaultIf.Index {
} else { primaryInterfaces = append(primaryInterfaces, iif)
fallbackInterfaces = append(fallbackInterfaces, iif) }
} }
} else {
primaryInterfaces = interfaces
} }
} else { } else {
primaryInterfaces = common.Filter(interfaces, func(iif adapter.NetworkInterface) bool { primaryInterfaces = common.Filter(interfaces, func(it adapter.NetworkInterface) bool {
return common.Contains(interfaceType, iif.Type) return common.Contains(interfaceType, it.Type)
}) })
} }
case C.NetworkStrategyHybrid: case C.NetworkStrategyHybrid:
if len(interfaceType) == 0 { if len(interfaceType) == 0 {
primaryInterfaces = interfaces primaryInterfaces = interfaces
} else { } else {
primaryInterfaces = common.Filter(interfaces, func(iif adapter.NetworkInterface) bool { primaryInterfaces = common.Filter(interfaces, func(it adapter.NetworkInterface) bool {
return common.Contains(interfaceType, iif.Type) return common.Contains(interfaceType, it.Type)
}) })
} }
case C.NetworkStrategyFallback: case C.NetworkStrategyFallback:
if len(interfaceType) == 0 { if len(interfaceType) == 0 {
defaultIf := networkManager.InterfaceMonitor().DefaultInterface() defaultIf := networkManager.InterfaceMonitor().DefaultInterface()
for _, iif := range interfaces { if defaultIf != nil {
if iif.Index == defaultIf.Index { for _, iif := range interfaces {
primaryInterfaces = append(primaryInterfaces, iif) if iif.Index == defaultIf.Index {
} else { primaryInterfaces = append(primaryInterfaces, iif)
fallbackInterfaces = append(fallbackInterfaces, iif) break
}
} }
} else {
primaryInterfaces = interfaces
} }
} else { } else {
primaryInterfaces = common.Filter(interfaces, func(iif adapter.NetworkInterface) bool { primaryInterfaces = common.Filter(interfaces, func(it adapter.NetworkInterface) bool {
return common.Contains(interfaceType, iif.Type) return common.Contains(interfaceType, it.Type)
})
}
if len(fallbackInterfaceType) == 0 {
fallbackInterfaces = common.Filter(interfaces, func(it adapter.NetworkInterface) bool {
return !common.Any(primaryInterfaces, func(iif adapter.NetworkInterface) bool {
return it.Index == iif.Index
})
})
} else {
fallbackInterfaces = common.Filter(interfaces, func(iif adapter.NetworkInterface) bool {
return common.Contains(fallbackInterfaceType, iif.Type)
}) })
} }
fallbackInterfaces = common.Filter(interfaces, func(iif adapter.NetworkInterface) bool {
return common.Contains(fallbackInterfaceType, iif.Type)
})
} }
return primaryInterfaces, fallbackInterfaces return primaryInterfaces, fallbackInterfaces
} }

View File

@ -13,7 +13,13 @@ import (
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
) )
func DialSerialNetwork(ctx context.Context, dialer N.Dialer, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) { func DialSerialNetwork(ctx context.Context, dialer N.Dialer, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) {
if len(destinationAddresses) == 0 {
if !destination.IsIP() {
panic("invalid usage")
}
destinationAddresses = []netip.Addr{destination.Addr}
}
if parallelDialer, isParallel := dialer.(ParallelNetworkDialer); isParallel { if parallelDialer, isParallel := dialer.(ParallelNetworkDialer); isParallel {
return parallelDialer.DialParallelNetwork(ctx, network, destination, destinationAddresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay) return parallelDialer.DialParallelNetwork(ctx, network, destination, destinationAddresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
} }
@ -38,7 +44,14 @@ func DialSerialNetwork(ctx context.Context, dialer N.Dialer, network string, des
return nil, E.Errors(errors...) return nil, E.Errors(errors...)
} }
func DialParallelNetwork(ctx context.Context, dialer ParallelInterfaceDialer, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, preferIPv6 bool, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) { func DialParallelNetwork(ctx context.Context, dialer ParallelInterfaceDialer, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, preferIPv6 bool, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) {
if len(destinationAddresses) == 0 {
if !destination.IsIP() {
panic("invalid usage")
}
destinationAddresses = []netip.Addr{destination.Addr}
}
if fallbackDelay == 0 { if fallbackDelay == 0 {
fallbackDelay = N.DefaultFallbackDelay fallbackDelay = N.DefaultFallbackDelay
} }
@ -116,7 +129,13 @@ func DialParallelNetwork(ctx context.Context, dialer ParallelInterfaceDialer, ne
} }
} }
func ListenSerialNetworkPacket(ctx context.Context, dialer N.Dialer, destination M.Socksaddr, destinationAddresses []netip.Addr, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, netip.Addr, error) { func ListenSerialNetworkPacket(ctx context.Context, dialer N.Dialer, destination M.Socksaddr, destinationAddresses []netip.Addr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, netip.Addr, error) {
if len(destinationAddresses) == 0 {
if !destination.IsIP() {
panic("invalid usage")
}
destinationAddresses = []netip.Addr{destination.Addr}
}
if parallelDialer, isParallel := dialer.(ParallelNetworkDialer); isParallel { if parallelDialer, isParallel := dialer.(ParallelNetworkDialer); isParallel {
return parallelDialer.ListenSerialNetworkPacket(ctx, destination, destinationAddresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay) return parallelDialer.ListenSerialNetworkPacket(ctx, destination, destinationAddresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
} }

View File

@ -17,16 +17,15 @@ import (
) )
func New(ctx context.Context, options option.DialerOptions) (N.Dialer, error) { func New(ctx context.Context, options option.DialerOptions) (N.Dialer, error) {
networkManager := service.FromContext[adapter.NetworkManager](ctx)
if options.IsWireGuardListener { if options.IsWireGuardListener {
return NewDefault(networkManager, options) return NewDefault(ctx, options)
} }
var ( var (
dialer N.Dialer dialer N.Dialer
err error err error
) )
if options.Detour == "" { if options.Detour == "" {
dialer, err = NewDefault(networkManager, options) dialer, err = NewDefault(ctx, options)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -37,9 +36,6 @@ func New(ctx context.Context, options option.DialerOptions) (N.Dialer, error) {
} }
dialer = NewDetour(outboundManager, options.Detour) dialer = NewDetour(outboundManager, options.Detour)
} }
if networkManager == nil {
return NewDefault(networkManager, options)
}
if options.Detour == "" { if options.Detour == "" {
router := service.FromContext[adapter.Router](ctx) router := service.FromContext[adapter.Router](ctx)
if router != nil { if router != nil {
@ -58,11 +54,10 @@ func NewDirect(ctx context.Context, options option.DialerOptions) (ParallelInter
if options.Detour != "" { if options.Detour != "" {
return nil, E.New("`detour` is not supported in direct context") return nil, E.New("`detour` is not supported in direct context")
} }
networkManager := service.FromContext[adapter.NetworkManager](ctx)
if options.IsWireGuardListener { if options.IsWireGuardListener {
return NewDefault(networkManager, options) return NewDefault(ctx, options)
} }
dialer, err := NewDefault(networkManager, options) dialer, err := NewDefault(ctx, options)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -77,11 +72,11 @@ func NewDirect(ctx context.Context, options option.DialerOptions) (ParallelInter
type ParallelInterfaceDialer interface { type ParallelInterfaceDialer interface {
N.Dialer N.Dialer
DialParallelInterface(ctx context.Context, network string, destination M.Socksaddr, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) DialParallelInterface(ctx context.Context, network string, destination M.Socksaddr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error)
ListenSerialInterfacePacket(ctx context.Context, destination M.Socksaddr, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, error) ListenSerialInterfacePacket(ctx context.Context, destination M.Socksaddr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, error)
} }
type ParallelNetworkDialer interface { type ParallelNetworkDialer interface {
DialParallelNetwork(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) DialParallelNetwork(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error)
ListenSerialNetworkPacket(ctx context.Context, destination M.Socksaddr, destinationAddresses []netip.Addr, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, netip.Addr, error) ListenSerialNetworkPacket(ctx context.Context, destination M.Socksaddr, destinationAddresses []netip.Addr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, netip.Addr, error)
} }

View File

@ -106,7 +106,7 @@ func (d *resolveDialer) ListenPacket(ctx context.Context, destination M.Socksadd
return bufio.NewNATPacketConn(bufio.NewPacketConn(conn), M.SocksaddrFrom(destinationAddress, destination.Port), destination), nil return bufio.NewNATPacketConn(bufio.NewPacketConn(conn), M.SocksaddrFrom(destinationAddress, destination.Port), destination), nil
} }
func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context, network string, destination M.Socksaddr, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) { func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context, network string, destination M.Socksaddr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) {
if !destination.IsFqdn() { if !destination.IsFqdn() {
return d.dialer.DialContext(ctx, network, destination) return d.dialer.DialContext(ctx, network, destination)
} }
@ -134,7 +134,7 @@ func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context
} }
} }
func (d *resolveParallelNetworkDialer) ListenSerialInterfacePacket(ctx context.Context, destination M.Socksaddr, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, error) { func (d *resolveParallelNetworkDialer) ListenSerialInterfacePacket(ctx context.Context, destination M.Socksaddr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, error) {
if !destination.IsFqdn() { if !destination.IsFqdn() {
return d.dialer.ListenPacket(ctx, destination) return d.dialer.ListenPacket(ctx, destination)
} }

View File

@ -65,25 +65,24 @@ type DialerOptionsWrapper interface {
} }
type DialerOptions struct { type DialerOptions struct {
Detour string `json:"detour,omitempty"` Detour string `json:"detour,omitempty"`
BindInterface string `json:"bind_interface,omitempty"` BindInterface string `json:"bind_interface,omitempty"`
Inet4BindAddress *badoption.Addr `json:"inet4_bind_address,omitempty"` Inet4BindAddress *badoption.Addr `json:"inet4_bind_address,omitempty"`
Inet6BindAddress *badoption.Addr `json:"inet6_bind_address,omitempty"` Inet6BindAddress *badoption.Addr `json:"inet6_bind_address,omitempty"`
ProtectPath string `json:"protect_path,omitempty"` ProtectPath string `json:"protect_path,omitempty"`
RoutingMark FwMark `json:"routing_mark,omitempty"` RoutingMark FwMark `json:"routing_mark,omitempty"`
ReuseAddr bool `json:"reuse_addr,omitempty"` ReuseAddr bool `json:"reuse_addr,omitempty"`
ConnectTimeout badoption.Duration `json:"connect_timeout,omitempty"` ConnectTimeout badoption.Duration `json:"connect_timeout,omitempty"`
TCPFastOpen bool `json:"tcp_fast_open,omitempty"` TCPFastOpen bool `json:"tcp_fast_open,omitempty"`
TCPMultiPath bool `json:"tcp_multi_path,omitempty"` TCPMultiPath bool `json:"tcp_multi_path,omitempty"`
UDPFragment *bool `json:"udp_fragment,omitempty"` UDPFragment *bool `json:"udp_fragment,omitempty"`
UDPFragmentDefault bool `json:"-"` UDPFragmentDefault bool `json:"-"`
DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"` DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"`
NetworkStrategy NetworkStrategy `json:"network_strategy,omitempty"` NetworkStrategy *NetworkStrategy `json:"network_strategy,omitempty"`
NetworkType badoption.Listable[InterfaceType] `json:"network_type,omitempty"` NetworkType badoption.Listable[InterfaceType] `json:"network_type,omitempty"`
FallbackNetworkType badoption.Listable[InterfaceType] `json:"fallback_network_type,omitempty"` FallbackNetworkType badoption.Listable[InterfaceType] `json:"fallback_network_type,omitempty"`
FallbackDelay badoption.Duration `json:"fallback_delay,omitempty"` FallbackDelay badoption.Duration `json:"fallback_delay,omitempty"`
NetworkFallbackDelay badoption.Duration `json:"network_fallback_delay,omitempty"` IsWireGuardListener bool `json:"-"`
IsWireGuardListener bool `json:"-"`
} }
func (o *DialerOptions) TakeDialerOptions() DialerOptions { func (o *DialerOptions) TakeDialerOptions() DialerOptions {

View File

@ -13,7 +13,7 @@ type RouteOptions struct {
OverrideAndroidVPN bool `json:"override_android_vpn,omitempty"` OverrideAndroidVPN bool `json:"override_android_vpn,omitempty"`
DefaultInterface string `json:"default_interface,omitempty"` DefaultInterface string `json:"default_interface,omitempty"`
DefaultMark FwMark `json:"default_mark,omitempty"` DefaultMark FwMark `json:"default_mark,omitempty"`
DefaultNetworkStrategy NetworkStrategy `json:"default_network_strategy,omitempty"` DefaultNetworkStrategy *NetworkStrategy `json:"default_network_strategy,omitempty"`
DefaultNetworkType badoption.Listable[InterfaceType] `json:"default_network_type,omitempty"` DefaultNetworkType badoption.Listable[InterfaceType] `json:"default_network_type,omitempty"`
DefaultFallbackNetworkType badoption.Listable[InterfaceType] `json:"default_fallback_network_type,omitempty"` DefaultFallbackNetworkType badoption.Listable[InterfaceType] `json:"default_fallback_network_type,omitempty"`
DefaultFallbackDelay badoption.Duration `json:"default_fallback_delay,omitempty"` DefaultFallbackDelay badoption.Duration `json:"default_fallback_delay,omitempty"`

View File

@ -145,8 +145,8 @@ type RawRouteOptionsActionOptions struct {
OverrideAddress string `json:"override_address,omitempty"` OverrideAddress string `json:"override_address,omitempty"`
OverridePort uint16 `json:"override_port,omitempty"` OverridePort uint16 `json:"override_port,omitempty"`
NetworkStrategy NetworkStrategy `json:"network_strategy,omitempty"` NetworkStrategy *NetworkStrategy `json:"network_strategy,omitempty"`
FallbackDelay uint32 `json:"fallback_delay,omitempty"` FallbackDelay uint32 `json:"fallback_delay,omitempty"`
UDPDisableDomainUnmapping bool `json:"udp_disable_domain_unmapping,omitempty"` UDPDisableDomainUnmapping bool `json:"udp_disable_domain_unmapping,omitempty"`
UDPConnect bool `json:"udp_connect,omitempty"` UDPConnect bool `json:"udp_connect,omitempty"`

View File

@ -32,16 +32,12 @@ var (
type Outbound struct { type Outbound struct {
outbound.Adapter outbound.Adapter
logger logger.ContextLogger logger logger.ContextLogger
dialer dialer.ParallelInterfaceDialer dialer dialer.ParallelInterfaceDialer
domainStrategy dns.DomainStrategy domainStrategy dns.DomainStrategy
fallbackDelay time.Duration fallbackDelay time.Duration
networkStrategy C.NetworkStrategy overrideOption int
networkType []C.InterfaceType overrideDestination M.Socksaddr
fallbackNetworkType []C.InterfaceType
networkFallbackDelay time.Duration
overrideOption int
overrideDestination M.Socksaddr
// loopBack *loopBackDetector // loopBack *loopBackDetector
} }
@ -52,15 +48,11 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
return nil, err return nil, err
} }
outbound := &Outbound{ outbound := &Outbound{
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions), Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions),
logger: logger, logger: logger,
domainStrategy: dns.DomainStrategy(options.DomainStrategy), domainStrategy: dns.DomainStrategy(options.DomainStrategy),
fallbackDelay: time.Duration(options.FallbackDelay), fallbackDelay: time.Duration(options.FallbackDelay),
networkStrategy: C.NetworkStrategy(options.NetworkStrategy), dialer: outboundDialer,
networkType: common.Map(options.NetworkType, option.InterfaceType.Build),
fallbackNetworkType: common.Map(options.FallbackNetworkType, option.InterfaceType.Build),
networkFallbackDelay: time.Duration(options.NetworkFallbackDelay),
dialer: outboundDialer,
// loopBack: newLoopBackDetector(router), // loopBack: newLoopBackDetector(router),
} }
//nolint:staticcheck //nolint:staticcheck
@ -178,10 +170,10 @@ func (h *Outbound) DialParallel(ctx context.Context, network string, destination
return nil, E.New("no IPv6 address available for ", destination) return nil, E.New("no IPv6 address available for ", destination)
} }
} }
return dialer.DialParallelNetwork(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == dns.DomainStrategyPreferIPv6, h.networkStrategy, h.networkType, h.fallbackNetworkType, h.fallbackDelay) return dialer.DialParallelNetwork(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == dns.DomainStrategyPreferIPv6, nil, nil, nil, h.fallbackDelay)
} }
func (h *Outbound) DialParallelNetwork(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, networkStrategy C.NetworkStrategy, networkType []C.InterfaceType, fallbackNetworkType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) { func (h *Outbound) DialParallelNetwork(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, networkStrategy *C.NetworkStrategy, networkType []C.InterfaceType, fallbackNetworkType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) {
ctx, metadata := adapter.ExtendContext(ctx) ctx, metadata := adapter.ExtendContext(ctx)
metadata.Outbound = h.Tag() metadata.Outbound = h.Tag()
metadata.Destination = destination metadata.Destination = destination
@ -221,7 +213,7 @@ func (h *Outbound) DialParallelNetwork(ctx context.Context, network string, dest
return dialer.DialParallelNetwork(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == dns.DomainStrategyPreferIPv6, networkStrategy, networkType, fallbackNetworkType, fallbackDelay) return dialer.DialParallelNetwork(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == dns.DomainStrategyPreferIPv6, networkStrategy, networkType, fallbackNetworkType, fallbackDelay)
} }
func (h *Outbound) ListenSerialNetworkPacket(ctx context.Context, destination M.Socksaddr, destinationAddresses []netip.Addr, networkStrategy C.NetworkStrategy, networkType []C.InterfaceType, fallbackNetworkType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, netip.Addr, error) { func (h *Outbound) ListenSerialNetworkPacket(ctx context.Context, destination M.Socksaddr, destinationAddresses []netip.Addr, networkStrategy *C.NetworkStrategy, networkType []C.InterfaceType, fallbackNetworkType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, netip.Addr, error) {
ctx, metadata := adapter.ExtendContext(ctx) ctx, metadata := adapter.ExtendContext(ctx)
metadata.Outbound = h.Tag() metadata.Outbound = h.Tag()
metadata.Destination = destination metadata.Destination = destination

View File

@ -20,7 +20,6 @@ import (
"github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata" M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/service"
) )
func RegisterEndpoint(registry *endpoint.Registry) { func RegisterEndpoint(registry *endpoint.Registry) {
@ -70,7 +69,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
UDPTimeout: udpTimeout, UDPTimeout: udpTimeout,
Dialer: outboundDialer, Dialer: outboundDialer,
CreateDialer: func(interfaceName string) N.Dialer { CreateDialer: func(interfaceName string) N.Dialer {
return common.Must1(dialer.NewDefault(service.FromContext[adapter.NetworkManager](ctx), option.DialerOptions{ return common.Must1(dialer.NewDefault(ctx, option.DialerOptions{
BindInterface: interfaceName, BindInterface: interfaceName,
})) }))
}, },

View File

@ -19,7 +19,6 @@ import (
"github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata" M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/service"
) )
func RegisterOutbound(registry *outbound.Registry) { func RegisterOutbound(registry *outbound.Registry) {
@ -86,7 +85,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
System: options.SystemInterface, System: options.SystemInterface,
Dialer: outboundDialer, Dialer: outboundDialer,
CreateDialer: func(interfaceName string) N.Dialer { CreateDialer: func(interfaceName string) N.Dialer {
return common.Must1(dialer.NewDefault(service.FromContext[adapter.NetworkManager](ctx), option.DialerOptions{ return common.Must1(dialer.NewDefault(ctx, option.DialerOptions{
BindInterface: interfaceName, BindInterface: interfaceName,
})) }))
}, },

View File

@ -56,7 +56,7 @@ func (m *ConnectionManager) NewConnection(ctx context.Context, this N.Dialer, co
remoteConn net.Conn remoteConn net.Conn
err error err error
) )
if len(metadata.DestinationAddresses) > 0 { if len(metadata.DestinationAddresses) > 0 || metadata.Destination.IsIP() {
remoteConn, err = dialer.DialSerialNetwork(ctx, this, N.NetworkTCP, metadata.Destination, metadata.DestinationAddresses, metadata.NetworkStrategy, metadata.NetworkType, metadata.FallbackNetworkType, metadata.FallbackDelay) remoteConn, err = dialer.DialSerialNetwork(ctx, this, N.NetworkTCP, metadata.Destination, metadata.DestinationAddresses, metadata.NetworkStrategy, metadata.NetworkType, metadata.FallbackNetworkType, metadata.FallbackDelay)
} else { } else {
remoteConn, err = this.DialContext(ctx, N.NetworkTCP, metadata.Destination) remoteConn, err = this.DialContext(ctx, N.NetworkTCP, metadata.Destination)
@ -97,12 +97,19 @@ func (m *ConnectionManager) NewPacketConnection(ctx context.Context, this N.Dial
err error err error
) )
if metadata.UDPConnect { if metadata.UDPConnect {
parallelDialer, isParallelDialer := this.(dialer.ParallelInterfaceDialer)
if len(metadata.DestinationAddresses) > 0 { if len(metadata.DestinationAddresses) > 0 {
if parallelDialer, isParallelDialer := this.(dialer.ParallelInterfaceDialer); isParallelDialer { if isParallelDialer {
remoteConn, err = dialer.DialSerialNetwork(ctx, parallelDialer, N.NetworkUDP, metadata.Destination, metadata.DestinationAddresses, metadata.NetworkStrategy, metadata.NetworkType, metadata.FallbackNetworkType, metadata.FallbackDelay) remoteConn, err = dialer.DialSerialNetwork(ctx, parallelDialer, N.NetworkUDP, metadata.Destination, metadata.DestinationAddresses, metadata.NetworkStrategy, metadata.NetworkType, metadata.FallbackNetworkType, metadata.FallbackDelay)
} else { } else {
remoteConn, err = N.DialSerial(ctx, this, N.NetworkUDP, metadata.Destination, metadata.DestinationAddresses) remoteConn, err = N.DialSerial(ctx, this, N.NetworkUDP, metadata.Destination, metadata.DestinationAddresses)
} }
} else if metadata.Destination.IsIP() {
if isParallelDialer {
remoteConn, err = dialer.DialSerialNetwork(ctx, parallelDialer, N.NetworkUDP, metadata.Destination, metadata.DestinationAddresses, metadata.NetworkStrategy, metadata.NetworkType, metadata.FallbackNetworkType, metadata.FallbackDelay)
} else {
remoteConn, err = this.DialContext(ctx, N.NetworkUDP, metadata.Destination)
}
} else { } else {
remoteConn, err = this.DialContext(ctx, N.NetworkUDP, metadata.Destination) remoteConn, err = this.DialContext(ctx, N.NetworkUDP, metadata.Destination)
} }

View File

@ -62,7 +62,7 @@ func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, routeOp
defaultOptions: adapter.NetworkOptions{ defaultOptions: adapter.NetworkOptions{
BindInterface: routeOptions.DefaultInterface, BindInterface: routeOptions.DefaultInterface,
RoutingMark: uint32(routeOptions.DefaultMark), RoutingMark: uint32(routeOptions.DefaultMark),
NetworkStrategy: C.NetworkStrategy(routeOptions.DefaultNetworkStrategy), NetworkStrategy: (*C.NetworkStrategy)(routeOptions.DefaultNetworkStrategy),
NetworkType: common.Map(routeOptions.DefaultNetworkType, option.InterfaceType.Build), NetworkType: common.Map(routeOptions.DefaultNetworkType, option.InterfaceType.Build),
FallbackNetworkType: common.Map(routeOptions.DefaultFallbackNetworkType, option.InterfaceType.Build), FallbackNetworkType: common.Map(routeOptions.DefaultFallbackNetworkType, option.InterfaceType.Build),
FallbackDelay: time.Duration(routeOptions.DefaultFallbackDelay), FallbackDelay: time.Duration(routeOptions.DefaultFallbackDelay),
@ -73,7 +73,7 @@ func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, routeOp
inbound: service.FromContext[adapter.InboundManager](ctx), inbound: service.FromContext[adapter.InboundManager](ctx),
outbound: service.FromContext[adapter.OutboundManager](ctx), outbound: service.FromContext[adapter.OutboundManager](ctx),
} }
if C.NetworkStrategy(routeOptions.DefaultNetworkStrategy) != C.NetworkStrategyDefault { if routeOptions.DefaultNetworkStrategy != nil {
if routeOptions.DefaultInterface != "" { if routeOptions.DefaultInterface != "" {
return nil, E.New("`default_network_strategy` is conflict with `default_interface`") return nil, E.New("`default_network_strategy` is conflict with `default_interface`")
} }

View File

@ -415,8 +415,18 @@ match:
Fqdn: metadata.Destination.Fqdn, Fqdn: metadata.Destination.Fqdn,
} }
} }
metadata.NetworkStrategy = routeOptions.NetworkStrategy if routeOptions.NetworkStrategy != nil {
metadata.FallbackDelay = routeOptions.FallbackDelay metadata.NetworkStrategy = routeOptions.NetworkStrategy
}
if len(routeOptions.NetworkType) > 0 {
metadata.NetworkType = routeOptions.NetworkType
}
if len(routeOptions.FallbackNetworkType) > 0 {
metadata.FallbackNetworkType = routeOptions.FallbackNetworkType
}
if routeOptions.FallbackDelay != 0 {
metadata.FallbackDelay = routeOptions.FallbackDelay
}
if routeOptions.UDPDisableDomainUnmapping { if routeOptions.UDPDisableDomainUnmapping {
metadata.UDPDisableDomainUnmapping = true metadata.UDPDisableDomainUnmapping = true
} }

View File

@ -262,7 +262,7 @@ func NewRouter(ctx context.Context, logFactory log.Factory, options option.Route
Context: ctx, Context: ctx,
Name: "local", Name: "local",
Address: "local", Address: "local",
Dialer: common.Must1(dialer.NewDefault(router.network, option.DialerOptions{})), Dialer: common.Must1(dialer.NewDefault(ctx, option.DialerOptions{})),
}))) })))
} }
defaultTransport = transports[0] defaultTransport = transports[0]

View File

@ -33,7 +33,7 @@ func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action opti
RuleActionRouteOptions: RuleActionRouteOptions{ RuleActionRouteOptions: RuleActionRouteOptions{
OverrideAddress: M.ParseSocksaddrHostPort(action.RouteOptions.OverrideAddress, 0), OverrideAddress: M.ParseSocksaddrHostPort(action.RouteOptions.OverrideAddress, 0),
OverridePort: action.RouteOptions.OverridePort, OverridePort: action.RouteOptions.OverridePort,
NetworkStrategy: C.NetworkStrategy(action.RouteOptions.NetworkStrategy), NetworkStrategy: (*C.NetworkStrategy)(action.RouteOptions.NetworkStrategy),
FallbackDelay: time.Duration(action.RouteOptions.FallbackDelay), FallbackDelay: time.Duration(action.RouteOptions.FallbackDelay),
UDPDisableDomainUnmapping: action.RouteOptions.UDPDisableDomainUnmapping, UDPDisableDomainUnmapping: action.RouteOptions.UDPDisableDomainUnmapping,
UDPConnect: action.RouteOptions.UDPConnect, UDPConnect: action.RouteOptions.UDPConnect,
@ -43,7 +43,7 @@ func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action opti
return &RuleActionRouteOptions{ return &RuleActionRouteOptions{
OverrideAddress: M.ParseSocksaddrHostPort(action.RouteOptionsOptions.OverrideAddress, 0), OverrideAddress: M.ParseSocksaddrHostPort(action.RouteOptionsOptions.OverrideAddress, 0),
OverridePort: action.RouteOptionsOptions.OverridePort, OverridePort: action.RouteOptionsOptions.OverridePort,
NetworkStrategy: C.NetworkStrategy(action.RouteOptionsOptions.NetworkStrategy), NetworkStrategy: (*C.NetworkStrategy)(action.RouteOptionsOptions.NetworkStrategy),
FallbackDelay: time.Duration(action.RouteOptionsOptions.FallbackDelay), FallbackDelay: time.Duration(action.RouteOptionsOptions.FallbackDelay),
UDPDisableDomainUnmapping: action.RouteOptionsOptions.UDPDisableDomainUnmapping, UDPDisableDomainUnmapping: action.RouteOptionsOptions.UDPDisableDomainUnmapping,
UDPConnect: action.RouteOptionsOptions.UDPConnect, UDPConnect: action.RouteOptionsOptions.UDPConnect,
@ -147,7 +147,7 @@ func (r *RuleActionRoute) String() string {
type RuleActionRouteOptions struct { type RuleActionRouteOptions struct {
OverrideAddress M.Socksaddr OverrideAddress M.Socksaddr
OverridePort uint16 OverridePort uint16
NetworkStrategy C.NetworkStrategy NetworkStrategy *C.NetworkStrategy
NetworkType []C.InterfaceType NetworkType []C.InterfaceType
FallbackNetworkType []C.InterfaceType FallbackNetworkType []C.InterfaceType
FallbackDelay time.Duration FallbackDelay time.Duration

View File

@ -253,7 +253,7 @@ func (t *Transport) recreateServers(iface *control.Interface, serverAddrs []neti
return it.String() return it.String()
}), ","), "]") }), ","), "]")
} }
serverDialer := common.Must1(dialer.NewDefault(t.networkManager, option.DialerOptions{ serverDialer := common.Must1(dialer.NewDefault(t.options.Context, option.DialerOptions{
BindInterface: iface.Name, BindInterface: iface.Name,
UDPFragmentDefault: true, UDPFragmentDefault: true,
})) }))