mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-09-10 05:14:07 +08:00
Compare commits
6 Commits
ddcc05f2ac
...
c67692085d
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c67692085d | ||
![]() |
0ef7e8eca2 | ||
![]() |
1a18e43a88 | ||
![]() |
6849288d6d | ||
![]() |
2edfed7d91 | ||
![]() |
30c069f5b7 |
@ -57,6 +57,7 @@ type InboundContext struct {
|
||||
Domain string
|
||||
Client string
|
||||
SniffContext any
|
||||
SnifferNames []string
|
||||
SniffError error
|
||||
|
||||
// cache
|
||||
|
@ -88,43 +88,41 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
|
||||
|
||||
if networkManager != nil {
|
||||
defaultOptions := networkManager.DefaultOptions()
|
||||
if !disableDefaultBind {
|
||||
if defaultOptions.BindInterface != "" {
|
||||
bindFunc := control.BindToInterface(networkManager.InterfaceFinder(), defaultOptions.BindInterface, -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() && !disableDefaultBind {
|
||||
if platformInterface != nil {
|
||||
networkStrategy = (*C.NetworkStrategy)(options.NetworkStrategy)
|
||||
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
|
||||
}
|
||||
if networkStrategy == nil {
|
||||
networkStrategy = common.Ptr(C.NetworkStrategyDefault)
|
||||
defaultNetworkStrategy = true
|
||||
}
|
||||
bindFunc := networkManager.ProtectFunc()
|
||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||
listener.Control = control.Append(listener.Control, bindFunc)
|
||||
} else {
|
||||
bindFunc := networkManager.AutoDetectInterfaceFunc()
|
||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||
listener.Control = control.Append(listener.Control, bindFunc)
|
||||
} else if networkManager.AutoDetectInterface() {
|
||||
if platformInterface != nil {
|
||||
networkStrategy = (*C.NetworkStrategy)(options.NetworkStrategy)
|
||||
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
|
||||
}
|
||||
if networkStrategy == nil {
|
||||
networkStrategy = common.Ptr(C.NetworkStrategyDefault)
|
||||
defaultNetworkStrategy = true
|
||||
}
|
||||
bindFunc := networkManager.ProtectFunc()
|
||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||
listener.Control = control.Append(listener.Control, bindFunc)
|
||||
} else {
|
||||
bindFunc := networkManager.AutoDetectInterfaceFunc()
|
||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||
listener.Control = control.Append(listener.Control, bindFunc)
|
||||
}
|
||||
}
|
||||
if options.RoutingMark == 0 && defaultOptions.RoutingMark != 0 {
|
||||
dialer.Control = control.Append(dialer.Control, setMarkWrapper(networkManager, defaultOptions.RoutingMark, true))
|
||||
listener.Control = control.Append(listener.Control, setMarkWrapper(networkManager, defaultOptions.RoutingMark, true))
|
||||
}
|
||||
}
|
||||
if options.RoutingMark == 0 && defaultOptions.RoutingMark != 0 {
|
||||
dialer.Control = control.Append(dialer.Control, setMarkWrapper(networkManager, defaultOptions.RoutingMark, true))
|
||||
listener.Control = control.Append(listener.Control, setMarkWrapper(networkManager, defaultOptions.RoutingMark, true))
|
||||
}
|
||||
}
|
||||
if networkManager != nil {
|
||||
markFunc := networkManager.AutoRedirectOutputMarkFunc()
|
||||
|
4
go.mod
4
go.mod
@ -27,13 +27,13 @@ require (
|
||||
github.com/sagernet/gomobile v0.1.8
|
||||
github.com/sagernet/gvisor v0.0.0-20250325023245-7a9c0f5725fb
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1
|
||||
github.com/sagernet/sing v0.7.6-0.20250902093152-bd5790e3b4db
|
||||
github.com/sagernet/sing v0.7.6
|
||||
github.com/sagernet/sing-mux v0.3.3
|
||||
github.com/sagernet/sing-quic v0.5.0
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
|
||||
github.com/sagernet/sing-tun v0.7.0-beta.1
|
||||
github.com/sagernet/sing-tun v0.7.0
|
||||
github.com/sagernet/sing-vmess v0.2.7
|
||||
github.com/sagernet/smux v1.5.34-mod.2
|
||||
github.com/sagernet/tailscale v1.80.3-sing-box-1.12-mod.1
|
||||
|
8
go.sum
8
go.sum
@ -167,8 +167,8 @@ github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/l
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1 h1:hWkojLg64zjV+MJOvJU/kOeWndm3tiEfBLx5foisszs=
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4=
|
||||
github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.7.6-0.20250902093152-bd5790e3b4db h1:D+56hVUg42b+nbXVYMwDNyFaN6vTviSXqF96dvBqRiM=
|
||||
github.com/sagernet/sing v0.7.6-0.20250902093152-bd5790e3b4db/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.7.6 h1:6LBfDH+aI/26J3r9UHlaxTNjJeMhBpU/wrk0JKDZYI4=
|
||||
github.com/sagernet/sing v0.7.6/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-mux v0.3.3 h1:YFgt9plMWzH994BMZLmyKL37PdIVaIilwP0Jg+EcLfw=
|
||||
github.com/sagernet/sing-mux v0.3.3/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA=
|
||||
github.com/sagernet/sing-quic v0.5.0 h1:jNLIyVk24lFPvu8A4x+ZNEnZdI+Tg1rp7eCJ6v0Csak=
|
||||
@ -179,8 +179,8 @@ github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnq
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
|
||||
github.com/sagernet/sing-tun v0.7.0-beta.1 h1:mBIFXYAnGO5ey/HcCYanqnBx61E7yF8zTFGRZonGYmY=
|
||||
github.com/sagernet/sing-tun v0.7.0-beta.1/go.mod h1:AHJuRrLbNRJuivuFZ2VhXwDj4ViYp14szG5EkkKAqRQ=
|
||||
github.com/sagernet/sing-tun v0.7.0 h1:zda+KYbxVyeWKdE9k73Ax02jg7cmPZ7/4ZTVCloFBYo=
|
||||
github.com/sagernet/sing-tun v0.7.0/go.mod h1:pUEjh9YHQ2gJT6Lk0TYDklh3WJy7lz+848vleGM3JPM=
|
||||
github.com/sagernet/sing-vmess v0.2.7 h1:2ee+9kO0xW5P4mfe6TYVWf9VtY8k1JhNysBqsiYj0sk=
|
||||
github.com/sagernet/sing-vmess v0.2.7/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs=
|
||||
github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4=
|
||||
|
@ -27,6 +27,8 @@ import (
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/uot"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
// Deprecated: use RouteConnectionEx instead.
|
||||
@ -501,7 +503,7 @@ func (r *Router) actionSniff(
|
||||
if inputConn != nil {
|
||||
if len(action.StreamSniffers) == 0 && len(action.PacketSniffers) > 0 {
|
||||
return
|
||||
} else if metadata.SniffError != nil && !errors.Is(metadata.SniffError, sniff.ErrNeedMoreData) {
|
||||
} else if slices.Equal(metadata.SnifferNames, action.SnifferNames) && metadata.SniffError != nil && !errors.Is(metadata.SniffError, sniff.ErrNeedMoreData) {
|
||||
r.logger.DebugContext(ctx, "packet sniff skipped due to previous error: ", metadata.SniffError)
|
||||
return
|
||||
}
|
||||
@ -528,6 +530,7 @@ func (r *Router) actionSniff(
|
||||
action.Timeout,
|
||||
streamSniffers...,
|
||||
)
|
||||
metadata.SnifferNames = action.SnifferNames
|
||||
metadata.SniffError = err
|
||||
if err == nil {
|
||||
//goland:noinspection GoDeprecation
|
||||
@ -553,10 +556,13 @@ func (r *Router) actionSniff(
|
||||
} else if inputPacketConn != nil {
|
||||
if len(action.PacketSniffers) == 0 && len(action.StreamSniffers) > 0 {
|
||||
return
|
||||
} else if metadata.SniffError != nil && !errors.Is(metadata.SniffError, sniff.ErrNeedMoreData) {
|
||||
} else if slices.Equal(metadata.SnifferNames, action.SnifferNames) && metadata.SniffError != nil && !errors.Is(metadata.SniffError, sniff.ErrNeedMoreData) {
|
||||
r.logger.DebugContext(ctx, "packet sniff skipped due to previous error: ", metadata.SniffError)
|
||||
return
|
||||
}
|
||||
quicMoreData := func() bool {
|
||||
return slices.Equal(metadata.SnifferNames, action.SnifferNames) && errors.Is(metadata.SniffError, sniff.ErrNeedMoreData)
|
||||
}
|
||||
var packetSniffers []sniff.PacketSniffer
|
||||
if len(action.PacketSniffers) > 0 {
|
||||
packetSniffers = action.PacketSniffers
|
||||
@ -571,12 +577,36 @@ func (r *Router) actionSniff(
|
||||
sniff.NTP,
|
||||
}
|
||||
}
|
||||
var err error
|
||||
for _, packetBuffer := range packetBuffers {
|
||||
if quicMoreData() {
|
||||
err = sniff.PeekPacket(
|
||||
ctx,
|
||||
metadata,
|
||||
packetBuffer.Buffer.Bytes(),
|
||||
sniff.QUICClientHello,
|
||||
)
|
||||
} else {
|
||||
err = sniff.PeekPacket(
|
||||
ctx, metadata,
|
||||
packetBuffer.Buffer.Bytes(),
|
||||
packetSniffers...,
|
||||
)
|
||||
}
|
||||
metadata.SnifferNames = action.SnifferNames
|
||||
metadata.SniffError = err
|
||||
if errors.Is(err, sniff.ErrNeedMoreData) {
|
||||
// TODO: replace with generic message when there are more multi-packet protocols
|
||||
r.logger.DebugContext(ctx, "attempt to sniff fragmented QUIC client hello")
|
||||
continue
|
||||
}
|
||||
goto finally
|
||||
}
|
||||
for {
|
||||
var (
|
||||
sniffBuffer = buf.NewPacket()
|
||||
destination M.Socksaddr
|
||||
done = make(chan struct{})
|
||||
err error
|
||||
)
|
||||
go func() {
|
||||
sniffTimeout := C.ReadPayloadTimeout
|
||||
@ -602,7 +632,7 @@ func (r *Router) actionSniff(
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if len(packetBuffers) > 0 || metadata.SniffError != nil {
|
||||
if quicMoreData() {
|
||||
err = sniff.PeekPacket(
|
||||
ctx,
|
||||
metadata,
|
||||
@ -622,32 +652,34 @@ func (r *Router) actionSniff(
|
||||
Destination: destination,
|
||||
}
|
||||
packetBuffers = append(packetBuffers, packetBuffer)
|
||||
metadata.SnifferNames = action.SnifferNames
|
||||
metadata.SniffError = err
|
||||
if errors.Is(err, sniff.ErrNeedMoreData) {
|
||||
// TODO: replace with generic message when there are more multi-packet protocols
|
||||
r.logger.DebugContext(ctx, "attempt to sniff fragmented QUIC client hello")
|
||||
continue
|
||||
}
|
||||
if metadata.Protocol != "" {
|
||||
//goland:noinspection GoDeprecation
|
||||
if action.OverrideDestination && M.IsDomainName(metadata.Domain) {
|
||||
metadata.Destination = M.Socksaddr{
|
||||
Fqdn: metadata.Domain,
|
||||
Port: metadata.Destination.Port,
|
||||
}
|
||||
}
|
||||
if metadata.Domain != "" && metadata.Client != "" {
|
||||
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain, ", client: ", metadata.Client)
|
||||
} else if metadata.Domain != "" {
|
||||
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain)
|
||||
} else if metadata.Client != "" {
|
||||
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", client: ", metadata.Client)
|
||||
} else {
|
||||
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol)
|
||||
}
|
||||
}
|
||||
goto finally
|
||||
}
|
||||
finally:
|
||||
if err == nil {
|
||||
//goland:noinspection GoDeprecation
|
||||
if action.OverrideDestination && M.IsDomainName(metadata.Domain) {
|
||||
metadata.Destination = M.Socksaddr{
|
||||
Fqdn: metadata.Domain,
|
||||
Port: metadata.Destination.Port,
|
||||
}
|
||||
}
|
||||
break
|
||||
if metadata.Domain != "" && metadata.Client != "" {
|
||||
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain, ", client: ", metadata.Client)
|
||||
} else if metadata.Domain != "" {
|
||||
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain)
|
||||
} else if metadata.Client != "" {
|
||||
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", client: ", metadata.Client)
|
||||
} else {
|
||||
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -87,7 +87,7 @@ func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action opti
|
||||
return &RuleActionHijackDNS{}, nil
|
||||
case C.RuleActionTypeSniff:
|
||||
sniffAction := &RuleActionSniff{
|
||||
snifferNames: action.SniffOptions.Sniffer,
|
||||
SnifferNames: action.SniffOptions.Sniffer,
|
||||
Timeout: time.Duration(action.SniffOptions.Timeout),
|
||||
}
|
||||
return sniffAction, sniffAction.build()
|
||||
@ -361,7 +361,7 @@ func (r *RuleActionHijackDNS) String() string {
|
||||
}
|
||||
|
||||
type RuleActionSniff struct {
|
||||
snifferNames []string
|
||||
SnifferNames []string
|
||||
StreamSniffers []sniff.StreamSniffer
|
||||
PacketSniffers []sniff.PacketSniffer
|
||||
Timeout time.Duration
|
||||
@ -374,7 +374,7 @@ func (r *RuleActionSniff) Type() string {
|
||||
}
|
||||
|
||||
func (r *RuleActionSniff) build() error {
|
||||
for _, name := range r.snifferNames {
|
||||
for _, name := range r.SnifferNames {
|
||||
switch name {
|
||||
case C.ProtocolTLS:
|
||||
r.StreamSniffers = append(r.StreamSniffers, sniff.TLSClientHello)
|
||||
@ -407,14 +407,14 @@ func (r *RuleActionSniff) build() error {
|
||||
}
|
||||
|
||||
func (r *RuleActionSniff) String() string {
|
||||
if len(r.snifferNames) == 0 && r.Timeout == 0 {
|
||||
if len(r.SnifferNames) == 0 && r.Timeout == 0 {
|
||||
return "sniff"
|
||||
} else if len(r.snifferNames) > 0 && r.Timeout == 0 {
|
||||
return F.ToString("sniff(", strings.Join(r.snifferNames, ","), ")")
|
||||
} else if len(r.snifferNames) == 0 && r.Timeout > 0 {
|
||||
} else if len(r.SnifferNames) > 0 && r.Timeout == 0 {
|
||||
return F.ToString("sniff(", strings.Join(r.SnifferNames, ","), ")")
|
||||
} else if len(r.SnifferNames) == 0 && r.Timeout > 0 {
|
||||
return F.ToString("sniff(", r.Timeout.String(), ")")
|
||||
} else {
|
||||
return F.ToString("sniff(", strings.Join(r.snifferNames, ","), ",", r.Timeout.String(), ")")
|
||||
return F.ToString("sniff(", strings.Join(r.SnifferNames, ","), ",", r.Timeout.String(), ")")
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user