mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-16 10:12:21 +08:00
Refactor multi networks strategy
This commit is contained in:
parent
2be7482e32
commit
55b2e114f6
|
@ -69,6 +69,8 @@ type InboundContext struct {
|
|||
UDPDisableDomainUnmapping bool
|
||||
UDPConnect bool
|
||||
NetworkStrategy C.NetworkStrategy
|
||||
NetworkType []C.InterfaceType
|
||||
FallbackNetworkType []C.InterfaceType
|
||||
FallbackDelay time.Duration
|
||||
|
||||
DNSServer string
|
||||
|
|
|
@ -28,10 +28,12 @@ type NetworkManager interface {
|
|||
}
|
||||
|
||||
type NetworkOptions struct {
|
||||
DefaultNetworkStrategy C.NetworkStrategy
|
||||
DefaultFallbackDelay time.Duration
|
||||
DefaultInterface string
|
||||
DefaultMark uint32
|
||||
NetworkStrategy C.NetworkStrategy
|
||||
NetworkType []C.InterfaceType
|
||||
FallbackNetworkType []C.InterfaceType
|
||||
FallbackDelay time.Duration
|
||||
BindInterface string
|
||||
RoutingMark uint32
|
||||
}
|
||||
|
||||
type InterfaceUpdateListener interface {
|
||||
|
@ -45,7 +47,7 @@ type WIFIState struct {
|
|||
|
||||
type NetworkInterface struct {
|
||||
control.Interface
|
||||
Type string
|
||||
Type C.InterfaceType
|
||||
DNSServers []string
|
||||
Expensive bool
|
||||
Constrained bool
|
||||
|
|
|
@ -26,7 +26,7 @@ func NewConnection(ctx context.Context, this N.Dialer, conn net.Conn, metadata a
|
|||
var err error
|
||||
if len(metadata.DestinationAddresses) > 0 {
|
||||
if parallelDialer, isParallelDialer := this.(dialer.ParallelInterfaceDialer); isParallelDialer {
|
||||
outConn, err = dialer.DialSerialNetwork(ctx, parallelDialer, N.NetworkTCP, metadata.Destination, metadata.DestinationAddresses, metadata.NetworkStrategy, metadata.FallbackDelay)
|
||||
outConn, err = dialer.DialSerialNetwork(ctx, parallelDialer, N.NetworkTCP, metadata.Destination, metadata.DestinationAddresses, metadata.NetworkStrategy, metadata.NetworkType, metadata.FallbackNetworkType, metadata.FallbackDelay)
|
||||
} else {
|
||||
outConn, err = N.DialSerial(ctx, this, N.NetworkTCP, metadata.Destination, metadata.DestinationAddresses)
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn,
|
|||
if metadata.UDPConnect {
|
||||
if len(metadata.DestinationAddresses) > 0 {
|
||||
if parallelDialer, isParallelDialer := this.(dialer.ParallelInterfaceDialer); isParallelDialer {
|
||||
outConn, err = dialer.DialSerialNetwork(ctx, parallelDialer, N.NetworkUDP, metadata.Destination, metadata.DestinationAddresses, metadata.NetworkStrategy, metadata.FallbackDelay)
|
||||
outConn, err = dialer.DialSerialNetwork(ctx, parallelDialer, N.NetworkUDP, metadata.Destination, metadata.DestinationAddresses, metadata.NetworkStrategy, metadata.NetworkType, metadata.FallbackNetworkType, metadata.FallbackDelay)
|
||||
} else {
|
||||
outConn, err = N.DialSerial(ctx, this, N.NetworkUDP, metadata.Destination, metadata.DestinationAddresses)
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn,
|
|||
} else {
|
||||
if len(metadata.DestinationAddresses) > 0 {
|
||||
if parallelDialer, isParallelDialer := this.(dialer.ParallelInterfaceDialer); isParallelDialer {
|
||||
outPacketConn, destinationAddress, err = dialer.ListenSerialNetworkPacket(ctx, parallelDialer, metadata.Destination, metadata.DestinationAddresses, metadata.NetworkStrategy, metadata.FallbackDelay)
|
||||
outPacketConn, destinationAddress, err = dialer.ListenSerialNetworkPacket(ctx, parallelDialer, metadata.Destination, metadata.DestinationAddresses, metadata.NetworkStrategy, metadata.NetworkType, metadata.FallbackNetworkType, metadata.FallbackDelay)
|
||||
} else {
|
||||
outPacketConn, destinationAddress, err = N.ListenSerial(ctx, this, metadata.Destination, metadata.DestinationAddresses)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/sagernet/sing-box/common/conntrack"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/atomic"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
|
@ -33,6 +34,8 @@ type DefaultDialer struct {
|
|||
isWireGuardListener bool
|
||||
networkManager adapter.NetworkManager
|
||||
networkStrategy C.NetworkStrategy
|
||||
networkType []C.InterfaceType
|
||||
fallbackNetworkType []C.InterfaceType
|
||||
networkFallbackDelay time.Duration
|
||||
networkLastFallback atomic.TypedValue[time.Time]
|
||||
}
|
||||
|
@ -43,6 +46,8 @@ func NewDefault(networkManager adapter.NetworkManager, options option.DialerOpti
|
|||
listener net.ListenConfig
|
||||
interfaceFinder control.InterfaceFinder
|
||||
networkStrategy C.NetworkStrategy
|
||||
networkType []C.InterfaceType
|
||||
fallbackNetworkType []C.InterfaceType
|
||||
networkFallbackDelay time.Duration
|
||||
)
|
||||
if networkManager != nil {
|
||||
|
@ -56,8 +61,8 @@ func NewDefault(networkManager adapter.NetworkManager, options option.DialerOpti
|
|||
listener.Control = control.Append(listener.Control, bindFunc)
|
||||
}
|
||||
if options.RoutingMark > 0 {
|
||||
dialer.Control = control.Append(dialer.Control, control.RoutingMark(options.RoutingMark))
|
||||
listener.Control = control.Append(listener.Control, control.RoutingMark(options.RoutingMark))
|
||||
dialer.Control = control.Append(dialer.Control, control.RoutingMark(uint32(options.RoutingMark)))
|
||||
listener.Control = control.Append(listener.Control, control.RoutingMark(uint32(options.RoutingMark)))
|
||||
}
|
||||
if networkManager != nil {
|
||||
autoRedirectOutputMark := networkManager.AutoRedirectOutputMark()
|
||||
|
@ -74,6 +79,8 @@ func NewDefault(networkManager adapter.NetworkManager, options option.DialerOpti
|
|||
return nil, E.New("`network_strategy` is conflict with `bind_interface`, `inet4_bind_address` and `inet6_bind_address`")
|
||||
}
|
||||
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`")
|
||||
|
@ -81,14 +88,16 @@ func NewDefault(networkManager adapter.NetworkManager, options option.DialerOpti
|
|||
}
|
||||
if networkManager != nil && options.BindInterface == "" && options.Inet4BindAddress == nil && options.Inet6BindAddress == nil {
|
||||
defaultOptions := networkManager.DefaultOptions()
|
||||
if defaultOptions.DefaultInterface != "" {
|
||||
bindFunc := control.BindToInterface(networkManager.InterfaceFinder(), defaultOptions.DefaultInterface, -1)
|
||||
if defaultOptions.BindInterface != "" {
|
||||
bindFunc := control.BindToInterface(networkManager.InterfaceFinder(), defaultOptions.BindInterface, -1)
|
||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||
listener.Control = control.Append(listener.Control, bindFunc)
|
||||
} else if networkManager.AutoDetectInterface() {
|
||||
if defaultOptions.DefaultNetworkStrategy != C.NetworkStrategyDefault && C.NetworkStrategy(options.NetworkStrategy) == C.NetworkStrategyDefault {
|
||||
networkStrategy = defaultOptions.DefaultNetworkStrategy
|
||||
networkFallbackDelay = defaultOptions.DefaultFallbackDelay
|
||||
if defaultOptions.NetworkStrategy != C.NetworkStrategyDefault && C.NetworkStrategy(options.NetworkStrategy) == C.NetworkStrategyDefault {
|
||||
networkStrategy = defaultOptions.NetworkStrategy
|
||||
networkType = defaultOptions.NetworkType
|
||||
fallbackNetworkType = defaultOptions.FallbackNetworkType
|
||||
networkFallbackDelay = defaultOptions.FallbackDelay
|
||||
bindFunc := networkManager.ProtectFunc()
|
||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||
listener.Control = control.Append(listener.Control, bindFunc)
|
||||
|
@ -179,6 +188,8 @@ func NewDefault(networkManager adapter.NetworkManager, options option.DialerOpti
|
|||
isWireGuardListener: options.IsWireGuardListener,
|
||||
networkManager: networkManager,
|
||||
networkStrategy: networkStrategy,
|
||||
networkType: networkType,
|
||||
fallbackNetworkType: fallbackNetworkType,
|
||||
networkFallbackDelay: networkFallbackDelay,
|
||||
}, nil
|
||||
}
|
||||
|
@ -202,11 +213,11 @@ func (d *DefaultDialer) DialContext(ctx context.Context, network string, address
|
|||
return trackConn(DialSlowContext(&d.dialer6, ctx, network, address))
|
||||
}
|
||||
} else {
|
||||
return d.DialParallelInterface(ctx, network, address, d.networkStrategy, d.networkFallbackDelay)
|
||||
return d.DialParallelInterface(ctx, network, address, d.networkStrategy, d.networkType, d.fallbackNetworkType, d.networkFallbackDelay)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DefaultDialer) DialParallelInterface(ctx context.Context, network string, address M.Socksaddr, strategy C.NetworkStrategy, 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 {
|
||||
return d.DialContext(ctx, network, address)
|
||||
}
|
||||
|
@ -226,9 +237,9 @@ func (d *DefaultDialer) DialParallelInterface(ctx context.Context, network strin
|
|||
err error
|
||||
)
|
||||
if !fastFallback {
|
||||
conn, isPrimary, err = d.dialParallelInterface(ctx, dialer, network, address.String(), strategy, fallbackDelay)
|
||||
conn, isPrimary, err = d.dialParallelInterface(ctx, dialer, network, address.String(), strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||
} else {
|
||||
conn, isPrimary, err = d.dialParallelInterfaceFastFallback(ctx, dialer, network, address.String(), strategy, fallbackDelay, d.networkLastFallback.Store)
|
||||
conn, isPrimary, err = d.dialParallelInterfaceFastFallback(ctx, dialer, network, address.String(), strategy, interfaceType, fallbackInterfaceType, fallbackDelay, d.networkLastFallback.Store)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -249,11 +260,11 @@ func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksadd
|
|||
return trackPacketConn(d.udpListener.ListenPacket(ctx, N.NetworkUDP, d.udpAddr4))
|
||||
}
|
||||
} else {
|
||||
return d.ListenSerialInterfacePacket(ctx, destination, d.networkStrategy, d.networkFallbackDelay)
|
||||
return d.ListenSerialInterfacePacket(ctx, destination, d.networkStrategy, d.networkType, d.fallbackNetworkType, d.networkFallbackDelay)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DefaultDialer) ListenSerialInterfacePacket(ctx context.Context, destination M.Socksaddr, strategy C.NetworkStrategy, 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 {
|
||||
return d.ListenPacket(ctx, destination)
|
||||
}
|
||||
|
@ -264,11 +275,11 @@ 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, fallbackDelay))
|
||||
return trackPacketConn(d.listenSerialInterfacePacket(ctx, d.udpListener, network, "", strategy, interfaceType, fallbackInterfaceType, fallbackDelay))
|
||||
}
|
||||
|
||||
func (d *DefaultDialer) ListenPacketCompat(network, address string) (net.PacketConn, error) {
|
||||
return trackPacketConn(d.listenSerialInterfacePacket(context.Background(), d.udpListener, network, address, d.networkStrategy, d.networkFallbackDelay))
|
||||
return trackPacketConn(d.listenSerialInterfacePacket(context.Background(), d.udpListener, network, address, d.networkStrategy, d.networkType, d.fallbackNetworkType, d.networkFallbackDelay))
|
||||
}
|
||||
|
||||
func trackConn(conn net.Conn, err error) (net.Conn, error) {
|
||||
|
|
|
@ -7,14 +7,14 @@ import (
|
|||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
func (d *DefaultDialer) dialParallelInterface(ctx context.Context, dialer net.Dialer, network string, addr string, strategy C.NetworkStrategy, fallbackDelay time.Duration) (net.Conn, bool, error) {
|
||||
primaryInterfaces, fallbackInterfaces := selectInterfaces(d.networkManager, strategy)
|
||||
func (d *DefaultDialer) dialParallelInterface(ctx context.Context, dialer net.Dialer, network string, addr string, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, bool, error) {
|
||||
primaryInterfaces, fallbackInterfaces := selectInterfaces(d.networkManager, strategy, interfaceType, fallbackInterfaceType)
|
||||
if len(primaryInterfaces)+len(fallbackInterfaces) == 0 {
|
||||
return nil, false, E.New("no available network interface")
|
||||
}
|
||||
|
@ -84,8 +84,8 @@ func (d *DefaultDialer) dialParallelInterface(ctx context.Context, dialer net.Di
|
|||
}
|
||||
}
|
||||
|
||||
func (d *DefaultDialer) dialParallelInterfaceFastFallback(ctx context.Context, dialer net.Dialer, network string, addr string, strategy C.NetworkStrategy, fallbackDelay time.Duration, resetFastFallback func(time.Time)) (net.Conn, bool, error) {
|
||||
primaryInterfaces, fallbackInterfaces := selectInterfaces(d.networkManager, strategy)
|
||||
func (d *DefaultDialer) dialParallelInterfaceFastFallback(ctx context.Context, dialer net.Dialer, network string, addr string, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration, resetFastFallback func(time.Time)) (net.Conn, bool, error) {
|
||||
primaryInterfaces, fallbackInterfaces := selectInterfaces(d.networkManager, strategy, interfaceType, fallbackInterfaceType)
|
||||
if len(primaryInterfaces)+len(fallbackInterfaces) == 0 {
|
||||
return nil, false, E.New("no available network interface")
|
||||
}
|
||||
|
@ -144,8 +144,8 @@ func (d *DefaultDialer) dialParallelInterfaceFastFallback(ctx context.Context, d
|
|||
}
|
||||
}
|
||||
|
||||
func (d *DefaultDialer) listenSerialInterfacePacket(ctx context.Context, listener net.ListenConfig, network string, addr string, strategy C.NetworkStrategy, fallbackDelay time.Duration) (net.PacketConn, error) {
|
||||
primaryInterfaces, fallbackInterfaces := selectInterfaces(d.networkManager, strategy)
|
||||
func (d *DefaultDialer) listenSerialInterfacePacket(ctx context.Context, listener net.ListenConfig, network string, addr string, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, error) {
|
||||
primaryInterfaces, fallbackInterfaces := selectInterfaces(d.networkManager, strategy, interfaceType, fallbackInterfaceType)
|
||||
if len(primaryInterfaces)+len(fallbackInterfaces) == 0 {
|
||||
return nil, E.New("no available network interface")
|
||||
}
|
||||
|
@ -174,12 +174,12 @@ func (d *DefaultDialer) listenSerialInterfacePacket(ctx context.Context, listene
|
|||
return nil, E.Errors(errors...)
|
||||
}
|
||||
|
||||
func selectInterfaces(networkManager adapter.NetworkManager, strategy C.NetworkStrategy) (primaryInterfaces []adapter.NetworkInterface, fallbackInterfaces []adapter.NetworkInterface) {
|
||||
func selectInterfaces(networkManager adapter.NetworkManager, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType) (primaryInterfaces []adapter.NetworkInterface, fallbackInterfaces []adapter.NetworkInterface) {
|
||||
interfaces := networkManager.NetworkInterfaces()
|
||||
switch strategy {
|
||||
case C.NetworkStrategyFallback:
|
||||
case C.NetworkStrategyDefault:
|
||||
if len(interfaceType) == 0 {
|
||||
defaultIf := networkManager.InterfaceMonitor().DefaultInterface()
|
||||
if defaultIf != nil {
|
||||
for _, iif := range interfaces {
|
||||
if iif.Index == defaultIf.Index {
|
||||
primaryInterfaces = append(primaryInterfaces, iif)
|
||||
|
@ -188,54 +188,36 @@ func selectInterfaces(networkManager adapter.NetworkManager, strategy C.NetworkS
|
|||
}
|
||||
}
|
||||
} else {
|
||||
primaryInterfaces = interfaces
|
||||
primaryInterfaces = common.Filter(interfaces, func(iif adapter.NetworkInterface) bool {
|
||||
return common.Contains(interfaceType, iif.Type)
|
||||
})
|
||||
}
|
||||
case C.NetworkStrategyHybrid:
|
||||
if len(interfaceType) == 0 {
|
||||
primaryInterfaces = interfaces
|
||||
case C.NetworkStrategyWIFI:
|
||||
} else {
|
||||
primaryInterfaces = common.Filter(interfaces, func(iif adapter.NetworkInterface) bool {
|
||||
return common.Contains(interfaceType, iif.Type)
|
||||
})
|
||||
}
|
||||
case C.NetworkStrategyFallback:
|
||||
if len(interfaceType) == 0 {
|
||||
defaultIf := networkManager.InterfaceMonitor().DefaultInterface()
|
||||
for _, iif := range interfaces {
|
||||
if iif.Type == C.InterfaceTypeWIFI {
|
||||
if iif.Index == defaultIf.Index {
|
||||
primaryInterfaces = append(primaryInterfaces, iif)
|
||||
} else {
|
||||
fallbackInterfaces = append(fallbackInterfaces, iif)
|
||||
}
|
||||
}
|
||||
case C.NetworkStrategyCellular:
|
||||
for _, iif := range interfaces {
|
||||
if iif.Type == C.InterfaceTypeCellular {
|
||||
primaryInterfaces = append(primaryInterfaces, iif)
|
||||
} else {
|
||||
fallbackInterfaces = append(fallbackInterfaces, iif)
|
||||
primaryInterfaces = common.Filter(interfaces, func(iif adapter.NetworkInterface) bool {
|
||||
return common.Contains(interfaceType, iif.Type)
|
||||
})
|
||||
}
|
||||
}
|
||||
case C.NetworkStrategyEthernet:
|
||||
for _, iif := range interfaces {
|
||||
if iif.Type == C.InterfaceTypeEthernet {
|
||||
primaryInterfaces = append(primaryInterfaces, iif)
|
||||
} else {
|
||||
fallbackInterfaces = append(fallbackInterfaces, iif)
|
||||
}
|
||||
}
|
||||
case C.NetworkStrategyWIFIOnly:
|
||||
for _, iif := range interfaces {
|
||||
if iif.Type == C.InterfaceTypeWIFI {
|
||||
primaryInterfaces = append(primaryInterfaces, iif)
|
||||
}
|
||||
}
|
||||
case C.NetworkStrategyCellularOnly:
|
||||
for _, iif := range interfaces {
|
||||
if iif.Type == C.InterfaceTypeCellular {
|
||||
primaryInterfaces = append(primaryInterfaces, iif)
|
||||
}
|
||||
}
|
||||
case C.NetworkStrategyEthernetOnly:
|
||||
for _, iif := range interfaces {
|
||||
if iif.Type == C.InterfaceTypeEthernet {
|
||||
primaryInterfaces = append(primaryInterfaces, iif)
|
||||
}
|
||||
}
|
||||
default:
|
||||
panic(F.ToString("unknown network strategy: ", strategy))
|
||||
fallbackInterfaces = common.Filter(interfaces, func(iif adapter.NetworkInterface) bool {
|
||||
return common.Contains(fallbackInterfaceType, iif.Type)
|
||||
})
|
||||
}
|
||||
return primaryInterfaces, fallbackInterfaces
|
||||
}
|
||||
|
|
|
@ -13,13 +13,13 @@ import (
|
|||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
func DialSerialNetwork(ctx context.Context, dialer ParallelInterfaceDialer, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, strategy C.NetworkStrategy, fallbackDelay time.Duration) (net.Conn, error) {
|
||||
func DialSerialNetwork(ctx context.Context, dialer ParallelInterfaceDialer, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) {
|
||||
if parallelDialer, isParallel := dialer.(ParallelNetworkDialer); isParallel {
|
||||
return parallelDialer.DialParallelNetwork(ctx, network, destination, destinationAddresses, strategy, fallbackDelay)
|
||||
return parallelDialer.DialParallelNetwork(ctx, network, destination, destinationAddresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||
}
|
||||
var errors []error
|
||||
for _, address := range destinationAddresses {
|
||||
conn, err := dialer.DialParallelInterface(ctx, network, M.SocksaddrFrom(address, destination.Port), strategy, fallbackDelay)
|
||||
conn, err := dialer.DialParallelInterface(ctx, network, M.SocksaddrFrom(address, destination.Port), strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||
if err == nil {
|
||||
return conn, nil
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ func DialSerialNetwork(ctx context.Context, dialer ParallelInterfaceDialer, netw
|
|||
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, 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 fallbackDelay == 0 {
|
||||
fallbackDelay = N.DefaultFallbackDelay
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ func DialParallelNetwork(ctx context.Context, dialer ParallelInterfaceDialer, ne
|
|||
return address.Is6() && !address.Is4In6()
|
||||
})
|
||||
if len(addresses4) == 0 || len(addresses6) == 0 {
|
||||
return DialSerialNetwork(ctx, dialer, network, destination, destinationAddresses, strategy, fallbackDelay)
|
||||
return DialSerialNetwork(ctx, dialer, network, destination, destinationAddresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||
}
|
||||
var primaries, fallbacks []netip.Addr
|
||||
if preferIPv6 {
|
||||
|
@ -65,7 +65,7 @@ func DialParallelNetwork(ctx context.Context, dialer ParallelInterfaceDialer, ne
|
|||
if !primary {
|
||||
ras = fallbacks
|
||||
}
|
||||
c, err := DialSerialNetwork(ctx, dialer, network, destination, ras, strategy, fallbackDelay)
|
||||
c, err := DialSerialNetwork(ctx, dialer, network, destination, ras, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||
select {
|
||||
case results <- dialResult{Conn: c, error: err, primary: primary, done: true}:
|
||||
case <-returned:
|
||||
|
@ -106,13 +106,13 @@ func DialParallelNetwork(ctx context.Context, dialer ParallelInterfaceDialer, ne
|
|||
}
|
||||
}
|
||||
|
||||
func ListenSerialNetworkPacket(ctx context.Context, dialer ParallelInterfaceDialer, destination M.Socksaddr, destinationAddresses []netip.Addr, strategy C.NetworkStrategy, fallbackDelay time.Duration) (net.PacketConn, netip.Addr, error) {
|
||||
func ListenSerialNetworkPacket(ctx context.Context, dialer ParallelInterfaceDialer, destination M.Socksaddr, destinationAddresses []netip.Addr, strategy C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, netip.Addr, error) {
|
||||
if parallelDialer, isParallel := dialer.(ParallelNetworkDialer); isParallel {
|
||||
return parallelDialer.ListenSerialNetworkPacket(ctx, destination, destinationAddresses, strategy, fallbackDelay)
|
||||
return parallelDialer.ListenSerialNetworkPacket(ctx, destination, destinationAddresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||
}
|
||||
var errors []error
|
||||
for _, address := range destinationAddresses {
|
||||
conn, err := dialer.ListenSerialInterfacePacket(ctx, M.SocksaddrFrom(address, destination.Port), strategy, fallbackDelay)
|
||||
conn, err := dialer.ListenSerialInterfacePacket(ctx, M.SocksaddrFrom(address, destination.Port), strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||
if err == nil {
|
||||
return conn, address, nil
|
||||
}
|
||||
|
|
|
@ -77,11 +77,11 @@ func NewDirect(ctx context.Context, options option.DialerOptions) (ParallelInter
|
|||
|
||||
type ParallelInterfaceDialer interface {
|
||||
N.Dialer
|
||||
DialParallelInterface(ctx context.Context, network string, destination M.Socksaddr, strategy C.NetworkStrategy, fallbackDelay time.Duration) (net.Conn, error)
|
||||
ListenSerialInterfacePacket(ctx context.Context, destination M.Socksaddr, strategy C.NetworkStrategy, fallbackDelay time.Duration) (net.PacketConn, 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)
|
||||
}
|
||||
|
||||
type ParallelNetworkDialer interface {
|
||||
DialParallelNetwork(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, strategy C.NetworkStrategy, fallbackDelay time.Duration) (net.Conn, error)
|
||||
ListenSerialNetworkPacket(ctx context.Context, destination M.Socksaddr, destinationAddresses []netip.Addr, strategy C.NetworkStrategy, fallbackDelay time.Duration) (net.PacketConn, netip.Addr, 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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context, network string, destination M.Socksaddr, strategy C.NetworkStrategy, 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() {
|
||||
return d.dialer.DialContext(ctx, network, destination)
|
||||
}
|
||||
|
@ -128,13 +128,13 @@ func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context
|
|||
fallbackDelay = d.fallbackDelay
|
||||
}
|
||||
if d.parallel {
|
||||
return DialParallelNetwork(ctx, d.dialer, network, destination, addresses, d.strategy == dns.DomainStrategyPreferIPv6, strategy, fallbackDelay)
|
||||
return DialParallelNetwork(ctx, d.dialer, network, destination, addresses, d.strategy == dns.DomainStrategyPreferIPv6, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||
} else {
|
||||
return DialSerialNetwork(ctx, d.dialer, network, destination, addresses, strategy, fallbackDelay)
|
||||
return DialSerialNetwork(ctx, d.dialer, network, destination, addresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *resolveParallelNetworkDialer) ListenSerialInterfacePacket(ctx context.Context, destination M.Socksaddr, strategy C.NetworkStrategy, 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() {
|
||||
return d.dialer.ListenPacket(ctx, destination)
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ func (d *resolveParallelNetworkDialer) ListenSerialInterfacePacket(ctx context.C
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, destinationAddress, err := ListenSerialNetworkPacket(ctx, d.dialer, destination, addresses, strategy, fallbackDelay)
|
||||
conn, destinationAddress, err := ListenSerialNetworkPacket(ctx, d.dialer, destination, addresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -226,7 +226,7 @@ func readDefaultRule(reader varbin.Reader, recover bool) (rule option.DefaultHea
|
|||
}
|
||||
rule.AdGuardDomainMatcher = matcher
|
||||
case ruleItemNetworkType:
|
||||
rule.NetworkType, err = readRuleItemString(reader)
|
||||
rule.NetworkType, err = readRuleItemUint8[option.InterfaceType](reader)
|
||||
case ruleItemNetworkIsExpensive:
|
||||
rule.NetworkIsExpensive = true
|
||||
case ruleItemNetworkIsConstrained:
|
||||
|
@ -349,7 +349,7 @@ func writeDefaultRule(writer varbin.Writer, rule option.DefaultHeadlessRule, gen
|
|||
if generateVersion < C.RuleSetVersion3 {
|
||||
return E.New("network_type rule item is only supported in version 3 or later")
|
||||
}
|
||||
err = writeRuleItemString(writer, ruleItemNetworkType, rule.NetworkType)
|
||||
err = writeRuleItemUint8(writer, ruleItemNetworkType, rule.NetworkType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -414,6 +414,18 @@ func writeRuleItemString(writer varbin.Writer, itemType uint8, value []string) e
|
|||
return varbin.Write(writer, binary.BigEndian, value)
|
||||
}
|
||||
|
||||
func readRuleItemUint8[E ~uint8](reader varbin.Reader) ([]E, error) {
|
||||
return varbin.ReadValue[[]E](reader, binary.BigEndian)
|
||||
}
|
||||
|
||||
func writeRuleItemUint8[E ~uint8](writer varbin.Writer, itemType uint8, value []E) error {
|
||||
err := writer.WriteByte(itemType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return varbin.Write(writer, binary.BigEndian, value)
|
||||
}
|
||||
|
||||
func readRuleItemUint16(reader varbin.Reader) ([]uint16, error) {
|
||||
return varbin.ReadValue[[]uint16](reader, binary.BigEndian)
|
||||
}
|
||||
|
|
|
@ -5,44 +5,52 @@ import (
|
|||
F "github.com/sagernet/sing/common/format"
|
||||
)
|
||||
|
||||
type InterfaceType uint8
|
||||
|
||||
const (
|
||||
InterfaceTypeWIFI = "wifi"
|
||||
InterfaceTypeCellular = "cellular"
|
||||
InterfaceTypeEthernet = "ethernet"
|
||||
InterfaceTypeOther = "other"
|
||||
InterfaceTypeWIFI InterfaceType = iota
|
||||
InterfaceTypeCellular
|
||||
InterfaceTypeEthernet
|
||||
InterfaceTypeOther
|
||||
)
|
||||
|
||||
type NetworkStrategy int
|
||||
var (
|
||||
interfaceTypeToString = map[InterfaceType]string{
|
||||
InterfaceTypeWIFI: "wifi",
|
||||
InterfaceTypeCellular: "cellular",
|
||||
InterfaceTypeEthernet: "ethernet",
|
||||
InterfaceTypeOther: "other",
|
||||
}
|
||||
StringToInterfaceType = common.ReverseMap(interfaceTypeToString)
|
||||
)
|
||||
|
||||
func (t InterfaceType) String() string {
|
||||
name, loaded := interfaceTypeToString[t]
|
||||
if !loaded {
|
||||
return F.ToString(int(t))
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
type NetworkStrategy uint8
|
||||
|
||||
const (
|
||||
NetworkStrategyDefault NetworkStrategy = iota
|
||||
NetworkStrategyFallback
|
||||
NetworkStrategyHybrid
|
||||
NetworkStrategyWIFI
|
||||
NetworkStrategyCellular
|
||||
NetworkStrategyEthernet
|
||||
NetworkStrategyWIFIOnly
|
||||
NetworkStrategyCellularOnly
|
||||
NetworkStrategyEthernetOnly
|
||||
)
|
||||
|
||||
var (
|
||||
NetworkStrategyToString = map[NetworkStrategy]string{
|
||||
networkStrategyToString = map[NetworkStrategy]string{
|
||||
NetworkStrategyDefault: "default",
|
||||
NetworkStrategyFallback: "fallback",
|
||||
NetworkStrategyHybrid: "hybrid",
|
||||
NetworkStrategyWIFI: "wifi",
|
||||
NetworkStrategyCellular: "cellular",
|
||||
NetworkStrategyEthernet: "ethernet",
|
||||
NetworkStrategyWIFIOnly: "wifi_only",
|
||||
NetworkStrategyCellularOnly: "cellular_only",
|
||||
NetworkStrategyEthernetOnly: "ethernet_only",
|
||||
}
|
||||
StringToNetworkStrategy = common.ReverseMap(NetworkStrategyToString)
|
||||
StringToNetworkStrategy = common.ReverseMap(networkStrategyToString)
|
||||
)
|
||||
|
||||
func (s NetworkStrategy) String() string {
|
||||
name, loaded := NetworkStrategyToString[s]
|
||||
name, loaded := networkStrategyToString[s]
|
||||
if !loaded {
|
||||
return F.ToString(int(s))
|
||||
}
|
||||
|
|
|
@ -34,10 +34,10 @@ type InterfaceUpdateListener interface {
|
|||
}
|
||||
|
||||
const (
|
||||
InterfaceTypeWIFI = C.InterfaceTypeWIFI
|
||||
InterfaceTypeCellular = C.InterfaceTypeCellular
|
||||
InterfaceTypeEthernet = C.InterfaceTypeEthernet
|
||||
InterfaceTypeOther = C.InterfaceTypeOther
|
||||
InterfaceTypeWIFI = int32(C.InterfaceTypeWIFI)
|
||||
InterfaceTypeCellular = int32(C.InterfaceTypeCellular)
|
||||
InterfaceTypeEthernet = int32(C.InterfaceTypeEthernet)
|
||||
InterfaceTypeOther = int32(C.InterfaceTypeOther)
|
||||
)
|
||||
|
||||
type NetworkInterface struct {
|
||||
|
@ -47,7 +47,7 @@ type NetworkInterface struct {
|
|||
Addresses StringIterator
|
||||
Flags int32
|
||||
|
||||
Type string
|
||||
Type int32
|
||||
DNSServer StringIterator
|
||||
Metered bool
|
||||
}
|
||||
|
|
|
@ -189,7 +189,7 @@ func (w *platformInterfaceWrapper) Interfaces() ([]adapter.NetworkInterface, err
|
|||
Addresses: common.Map(iteratorToArray[string](netInterface.Addresses), netip.MustParsePrefix),
|
||||
Flags: linkFlags(uint32(netInterface.Flags)),
|
||||
},
|
||||
Type: netInterface.Type,
|
||||
Type: C.InterfaceType(netInterface.Type),
|
||||
DNSServers: iteratorToArray[string](netInterface.DNSServer),
|
||||
Expensive: netInterface.Metered || isDefault && w.isExpensive,
|
||||
Constrained: isDefault && w.isConstrained,
|
||||
|
|
2
go.mod
2
go.mod
|
@ -25,7 +25,7 @@ require (
|
|||
github.com/sagernet/gvisor v0.0.0-20241021032506-a4324256e4a3
|
||||
github.com/sagernet/quic-go v0.48.1-beta.1
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
|
||||
github.com/sagernet/sing v0.6.0-alpha.8
|
||||
github.com/sagernet/sing v0.6.0-alpha.9
|
||||
github.com/sagernet/sing-dns v0.4.0-alpha.1
|
||||
github.com/sagernet/sing-mux v0.3.0-alpha.1
|
||||
github.com/sagernet/sing-quic v0.3.0-rc.2
|
||||
|
|
4
go.sum
4
go.sum
|
@ -110,8 +110,8 @@ github.com/sagernet/quic-go v0.48.1-beta.1/go.mod h1:1WgdDIVD1Gybp40JTWketeSfKA/
|
|||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
|
||||
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
|
||||
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
|
||||
github.com/sagernet/sing v0.6.0-alpha.8 h1:j0ghX5QAXH/ozUjsTidMyHclkLw/mpRzHlQagByRsJI=
|
||||
github.com/sagernet/sing v0.6.0-alpha.8/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.6.0-alpha.9 h1:tOeHdRECQwe9R/1edVHbckF/IBoJoGzqhHRnHsNAQb8=
|
||||
github.com/sagernet/sing v0.6.0-alpha.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-dns v0.4.0-alpha.1 h1:2KlP8DeqtGkULFiZtvG2r7SuoJP6orANFzJwC5vDKvg=
|
||||
github.com/sagernet/sing-dns v0.4.0-alpha.1/go.mod h1:vgHATsm4wdymwpvBZPei8RY+546iGXS6hlWv2x6YKcM=
|
||||
github.com/sagernet/sing-mux v0.3.0-alpha.1 h1:IgNX5bJBpL41gGbp05pdDOvh/b5eUQ6cv9240+Ngipg=
|
||||
|
|
|
@ -70,7 +70,7 @@ type DialerOptions struct {
|
|||
Inet4BindAddress *badoption.Addr `json:"inet4_bind_address,omitempty"`
|
||||
Inet6BindAddress *badoption.Addr `json:"inet6_bind_address,omitempty"`
|
||||
ProtectPath string `json:"protect_path,omitempty"`
|
||||
RoutingMark uint32 `json:"routing_mark,omitempty"`
|
||||
RoutingMark FwMark `json:"routing_mark,omitempty"`
|
||||
ReuseAddr bool `json:"reuse_addr,omitempty"`
|
||||
ConnectTimeout badoption.Duration `json:"connect_timeout,omitempty"`
|
||||
TCPFastOpen bool `json:"tcp_fast_open,omitempty"`
|
||||
|
@ -79,6 +79,8 @@ type DialerOptions struct {
|
|||
UDPFragmentDefault bool `json:"-"`
|
||||
DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"`
|
||||
NetworkStrategy NetworkStrategy `json:"network_strategy,omitempty"`
|
||||
NetworkType badoption.Listable[InterfaceType] `json:"network_type,omitempty"`
|
||||
FallbackNetworkType badoption.Listable[InterfaceType] `json:"fallback_network_type,omitempty"`
|
||||
FallbackDelay badoption.Duration `json:"fallback_delay,omitempty"`
|
||||
NetworkFallbackDelay badoption.Duration `json:"network_fallback_delay,omitempty"`
|
||||
IsWireGuardListener bool `json:"-"`
|
||||
|
|
|
@ -14,6 +14,8 @@ type RouteOptions struct {
|
|||
DefaultInterface string `json:"default_interface,omitempty"`
|
||||
DefaultMark uint32 `json:"default_mark,omitempty"`
|
||||
DefaultNetworkStrategy NetworkStrategy `json:"default_network_strategy,omitempty"`
|
||||
DefaultNetworkType badoption.Listable[InterfaceType] `json:"default_network_type,omitempty"`
|
||||
DefaultFallbackNetworkType badoption.Listable[InterfaceType] `json:"default_fallback_network_type,omitempty"`
|
||||
DefaultFallbackDelay badoption.Duration `json:"default_fallback_delay,omitempty"`
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ type RawDefaultRule struct {
|
|||
User badoption.Listable[string] `json:"user,omitempty"`
|
||||
UserID badoption.Listable[int32] `json:"user_id,omitempty"`
|
||||
ClashMode string `json:"clash_mode,omitempty"`
|
||||
NetworkType badoption.Listable[string] `json:"network_type,omitempty"`
|
||||
NetworkType badoption.Listable[InterfaceType] `json:"network_type,omitempty"`
|
||||
NetworkIsExpensive bool `json:"network_is_expensive,omitempty"`
|
||||
NetworkIsConstrained bool `json:"network_is_constrained,omitempty"`
|
||||
WIFISSID badoption.Listable[string] `json:"wifi_ssid,omitempty"`
|
||||
|
|
|
@ -97,7 +97,7 @@ type RawDefaultDNSRule struct {
|
|||
UserID badoption.Listable[int32] `json:"user_id,omitempty"`
|
||||
Outbound badoption.Listable[string] `json:"outbound,omitempty"`
|
||||
ClashMode string `json:"clash_mode,omitempty"`
|
||||
NetworkType badoption.Listable[string] `json:"network_type,omitempty"`
|
||||
NetworkType badoption.Listable[InterfaceType] `json:"network_type,omitempty"`
|
||||
NetworkIsExpensive bool `json:"network_is_expensive,omitempty"`
|
||||
NetworkIsConstrained bool `json:"network_is_constrained,omitempty"`
|
||||
WIFISSID badoption.Listable[string] `json:"wifi_ssid,omitempty"`
|
||||
|
|
|
@ -162,7 +162,7 @@ type DefaultHeadlessRule struct {
|
|||
ProcessPath badoption.Listable[string] `json:"process_path,omitempty"`
|
||||
ProcessPathRegex badoption.Listable[string] `json:"process_path_regex,omitempty"`
|
||||
PackageName badoption.Listable[string] `json:"package_name,omitempty"`
|
||||
NetworkType badoption.Listable[string] `json:"network_type,omitempty"`
|
||||
NetworkType badoption.Listable[InterfaceType] `json:"network_type,omitempty"`
|
||||
NetworkIsExpensive bool `json:"network_is_expensive,omitempty"`
|
||||
NetworkIsConstrained bool `json:"network_is_constrained,omitempty"`
|
||||
WIFISSID badoption.Listable[string] `json:"wifi_ssid,omitempty"`
|
||||
|
|
|
@ -171,3 +171,27 @@ func (n *NetworkStrategy) UnmarshalJSON(content []byte) error {
|
|||
*n = NetworkStrategy(strategy)
|
||||
return nil
|
||||
}
|
||||
|
||||
type InterfaceType C.InterfaceType
|
||||
|
||||
func (t InterfaceType) Build() C.InterfaceType {
|
||||
return C.InterfaceType(t)
|
||||
}
|
||||
|
||||
func (t InterfaceType) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(C.InterfaceType(t).String())
|
||||
}
|
||||
|
||||
func (t *InterfaceType) UnmarshalJSON(content []byte) error {
|
||||
var value string
|
||||
err := json.Unmarshal(content, &value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
interfaceType, loaded := C.StringToInterfaceType[value]
|
||||
if !loaded {
|
||||
return E.New("unknown interface type: ", value)
|
||||
}
|
||||
*t = InterfaceType(interfaceType)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
dns "github.com/sagernet/sing-dns"
|
||||
"github.com/sagernet/sing-dns"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
|
@ -37,6 +37,8 @@ type Outbound struct {
|
|||
domainStrategy dns.DomainStrategy
|
||||
fallbackDelay time.Duration
|
||||
networkStrategy C.NetworkStrategy
|
||||
networkType []C.InterfaceType
|
||||
fallbackNetworkType []C.InterfaceType
|
||||
networkFallbackDelay time.Duration
|
||||
overrideOption int
|
||||
overrideDestination M.Socksaddr
|
||||
|
@ -55,6 +57,8 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
domainStrategy: dns.DomainStrategy(options.DomainStrategy),
|
||||
fallbackDelay: time.Duration(options.FallbackDelay),
|
||||
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),
|
||||
dialer: outboundDialer,
|
||||
// loopBack: newLoopBackDetector(router),
|
||||
|
@ -171,10 +175,10 @@ func (h *Outbound) DialParallel(ctx context.Context, network string, 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.fallbackDelay)
|
||||
return dialer.DialParallelNetwork(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == dns.DomainStrategyPreferIPv6, h.networkStrategy, h.networkType, h.fallbackNetworkType, h.fallbackDelay)
|
||||
}
|
||||
|
||||
func (h *Outbound) DialParallelNetwork(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, networkStrategy C.NetworkStrategy, 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)
|
||||
metadata.Outbound = h.Tag()
|
||||
metadata.Destination = destination
|
||||
|
@ -210,10 +214,10 @@ func (h *Outbound) DialParallelNetwork(ctx context.Context, network string, dest
|
|||
return nil, E.New("no IPv6 address available for ", destination)
|
||||
}
|
||||
}
|
||||
return dialer.DialParallelNetwork(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == dns.DomainStrategyPreferIPv6, networkStrategy, 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, 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)
|
||||
metadata.Outbound = h.Tag()
|
||||
metadata.Destination = destination
|
||||
|
@ -232,7 +236,7 @@ func (h *Outbound) ListenSerialNetworkPacket(ctx context.Context, destination M.
|
|||
} else {
|
||||
h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
|
||||
}
|
||||
conn, newDestination, err := dialer.ListenSerialNetworkPacket(ctx, h.dialer, destination, destinationAddresses, networkStrategy, fallbackDelay)
|
||||
conn, newDestination, err := dialer.ListenSerialNetworkPacket(ctx, h.dialer, destination, destinationAddresses, networkStrategy, networkType, fallbackNetworkType, fallbackDelay)
|
||||
if err != nil {
|
||||
return nil, netip.Addr{}, err
|
||||
}
|
||||
|
|
|
@ -59,10 +59,12 @@ func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, routeOp
|
|||
interfaceFinder: control.NewDefaultInterfaceFinder(),
|
||||
autoDetectInterface: routeOptions.AutoDetectInterface,
|
||||
defaultOptions: adapter.NetworkOptions{
|
||||
DefaultInterface: routeOptions.DefaultInterface,
|
||||
DefaultMark: routeOptions.DefaultMark,
|
||||
DefaultNetworkStrategy: C.NetworkStrategy(routeOptions.DefaultNetworkStrategy),
|
||||
DefaultFallbackDelay: time.Duration(routeOptions.DefaultFallbackDelay),
|
||||
BindInterface: routeOptions.DefaultInterface,
|
||||
RoutingMark: routeOptions.DefaultMark,
|
||||
NetworkStrategy: C.NetworkStrategy(routeOptions.DefaultNetworkStrategy),
|
||||
NetworkType: common.Map(routeOptions.DefaultNetworkType, option.InterfaceType.Build),
|
||||
FallbackNetworkType: common.Map(routeOptions.DefaultFallbackNetworkType, option.InterfaceType.Build),
|
||||
FallbackDelay: time.Duration(routeOptions.DefaultFallbackDelay),
|
||||
},
|
||||
pauseManager: service.FromContext[pause.Manager](ctx),
|
||||
platformInterface: service.FromContext[platform.Interface](ctx),
|
||||
|
@ -385,7 +387,7 @@ func (r *NetworkManager) notifyInterfaceUpdate(defaultInterface *control.Interfa
|
|||
networkInterface := common.Find(r.networkInterfaces.Load(), func(it adapter.NetworkInterface) bool {
|
||||
return it.Interface.Index == defaultInterface.Index
|
||||
})
|
||||
if networkInterface.Type == "" {
|
||||
if networkInterface.Name == "" {
|
||||
// race
|
||||
return
|
||||
}
|
||||
|
|
|
@ -140,6 +140,8 @@ func (r *RuleActionRoute) String() string {
|
|||
|
||||
type RuleActionRouteOptions struct {
|
||||
NetworkStrategy C.NetworkStrategy
|
||||
NetworkType []C.InterfaceType
|
||||
FallbackNetworkType []C.InterfaceType
|
||||
FallbackDelay time.Duration
|
||||
UDPDisableDomainUnmapping bool
|
||||
UDPConnect bool
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/service"
|
||||
)
|
||||
|
@ -224,7 +225,7 @@ func NewDefaultRule(ctx context.Context, logger log.ContextLogger, options optio
|
|||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.NetworkType) > 0 {
|
||||
item := NewNetworkTypeItem(networkManager, options.NetworkType)
|
||||
item := NewNetworkTypeItem(networkManager, common.Map(options.NetworkType, option.InterfaceType.Build))
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
|
|
@ -221,7 +221,7 @@ func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options op
|
|||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.NetworkType) > 0 {
|
||||
item := NewNetworkTypeItem(networkManager, options.NetworkType)
|
||||
item := NewNetworkTypeItem(networkManager, common.Map(options.NetworkType, option.InterfaceType.Build))
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/service"
|
||||
)
|
||||
|
@ -142,7 +143,7 @@ func NewDefaultHeadlessRule(ctx context.Context, options option.DefaultHeadlessR
|
|||
}
|
||||
if networkManager != nil {
|
||||
if len(options.NetworkType) > 0 {
|
||||
item := NewNetworkTypeItem(networkManager, options.NetworkType)
|
||||
item := NewNetworkTypeItem(networkManager, common.Map(options.NetworkType, option.InterfaceType.Build))
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing/common"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
)
|
||||
|
@ -12,10 +13,10 @@ var _ RuleItem = (*NetworkTypeItem)(nil)
|
|||
|
||||
type NetworkTypeItem struct {
|
||||
networkManager adapter.NetworkManager
|
||||
networkType []string
|
||||
networkType []C.InterfaceType
|
||||
}
|
||||
|
||||
func NewNetworkTypeItem(networkManager adapter.NetworkManager, networkType []string) *NetworkTypeItem {
|
||||
func NewNetworkTypeItem(networkManager adapter.NetworkManager, networkType []C.InterfaceType) *NetworkTypeItem {
|
||||
return &NetworkTypeItem{
|
||||
networkManager: networkManager,
|
||||
networkType: networkType,
|
||||
|
|
Loading…
Reference in New Issue
Block a user