mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-06-13 21:54:13 +08:00
Add outbound sniff option
This commit is contained in:
parent
ea18d75a28
commit
1abe1a8ca8
@ -19,6 +19,11 @@ type Outbound interface {
|
||||
NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error
|
||||
}
|
||||
|
||||
type SniffOutbound interface {
|
||||
Outbound
|
||||
UseSniffedDestination() bool
|
||||
}
|
||||
|
||||
type IPOutbound interface {
|
||||
Outbound
|
||||
NewIPConnection(ctx context.Context, conn tun.RouteContext, metadata InboundContext) (tun.DirectDestination, error)
|
||||
|
@ -14,6 +14,7 @@
|
||||
"password": "admin",
|
||||
"network": "udp",
|
||||
"udp_over_tcp": false | {},
|
||||
"use_sniffed_destination": false
|
||||
|
||||
... // Dial Fields
|
||||
}
|
||||
@ -61,6 +62,10 @@ UDP over TCP protocol settings.
|
||||
|
||||
See [UDP Over TCP](/configuration/shared/udp-over-tcp) for details.
|
||||
|
||||
#### use_sniffed_destination
|
||||
|
||||
When an inbound request is routed to the outbound, the detected domain name will be used to override the connection target address before establishing a connection. This option is only effective when `sniff` is set to `true` and `sniff_override_destination` is `false` in the inbound.
|
||||
|
||||
### Dial Fields
|
||||
|
||||
See [Dial Fields](/configuration/shared/dial) for details.
|
||||
|
@ -14,6 +14,7 @@
|
||||
"password": "admin",
|
||||
"network": "udp",
|
||||
"udp_over_tcp": false | {},
|
||||
"use_sniffed_destination": false
|
||||
|
||||
... // 拨号字段
|
||||
}
|
||||
@ -61,6 +62,10 @@ UDP over TCP 配置。
|
||||
|
||||
参阅 [UDP Over TCP](/zh/configuration/shared/udp-over-tcp)。
|
||||
|
||||
#### use_sniffed_destination
|
||||
|
||||
当入站请求路由到该出站时,在建立连接前会用探测出的域名覆盖连接目标地址,仅当入站设置了`sniff`为`true`同时`sniff_override_destination`为`false`时该选项有效。
|
||||
|
||||
### 拨号字段
|
||||
|
||||
参阅 [拨号字段](/zh/configuration/shared/dial/)。
|
||||
|
@ -144,6 +144,10 @@ func (o ServerOptions) Build() M.Socksaddr {
|
||||
return M.ParseSocksaddrHostPort(o.Server, o.ServerPort)
|
||||
}
|
||||
|
||||
type SniffOptions struct {
|
||||
UseSniffedDestination bool `json:"use_sniffed_destination,omitempty"`
|
||||
}
|
||||
|
||||
type MultiplexOptions struct {
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
Protocol string `json:"protocol,omitempty"`
|
||||
|
@ -17,6 +17,7 @@ type HTTPMixedInboundOptions struct {
|
||||
type SocksOutboundOptions struct {
|
||||
DialerOptions
|
||||
ServerOptions
|
||||
SniffOptions
|
||||
Version string `json:"version,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
|
@ -17,13 +17,18 @@ import (
|
||||
"github.com/sagernet/sing/protocol/socks"
|
||||
)
|
||||
|
||||
var _ adapter.Outbound = (*Socks)(nil)
|
||||
var _ adapter.SniffOutbound = (*Socks)(nil)
|
||||
|
||||
type Socks struct {
|
||||
myOutboundAdapter
|
||||
client *socks.Client
|
||||
resolve bool
|
||||
uotClient *uot.Client
|
||||
client *socks.Client
|
||||
resolve bool
|
||||
uotClient *uot.Client
|
||||
useSniffedDestination bool
|
||||
}
|
||||
|
||||
func (h *Socks) UseSniffedDestination() bool {
|
||||
return h.useSniffedDestination
|
||||
}
|
||||
|
||||
func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, options option.SocksOutboundOptions) (*Socks, error) {
|
||||
@ -45,8 +50,9 @@ func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, optio
|
||||
logger: logger,
|
||||
tag: tag,
|
||||
},
|
||||
client: socks.NewClient(dialer.New(router, options.DialerOptions), options.ServerOptions.Build(), version, options.Username, options.Password),
|
||||
resolve: version == socks.Version4,
|
||||
client: socks.NewClient(dialer.New(router, options.DialerOptions), options.ServerOptions.Build(), version, options.Username, options.Password),
|
||||
resolve: version == socks.Version4,
|
||||
useSniffedDestination: options.UseSniffedDestination,
|
||||
}
|
||||
uotOptions := common.PtrValueOrDefault(options.UDPOverTCPOptions)
|
||||
if uotOptions.Enabled {
|
||||
|
@ -657,6 +657,7 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
|
||||
r.logger.DebugContext(ctx, "found fakeip domain: ", domain)
|
||||
}
|
||||
|
||||
var sniffedDestination M.Socksaddr
|
||||
if metadata.InboundOptions.SniffEnabled {
|
||||
buffer := buf.NewPacket()
|
||||
buffer.FullReset()
|
||||
@ -664,11 +665,14 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
|
||||
if sniffMetadata != nil {
|
||||
metadata.Protocol = sniffMetadata.Protocol
|
||||
metadata.Domain = sniffMetadata.Domain
|
||||
if metadata.InboundOptions.SniffOverrideDestination && M.IsDomainName(metadata.Domain) {
|
||||
metadata.Destination = M.Socksaddr{
|
||||
if M.IsDomainName(metadata.Domain) {
|
||||
sniffedDestination = M.Socksaddr{
|
||||
Fqdn: metadata.Domain,
|
||||
Port: metadata.Destination.Port,
|
||||
}
|
||||
if metadata.InboundOptions.SniffOverrideDestination {
|
||||
metadata.Destination = sniffedDestination
|
||||
}
|
||||
}
|
||||
if metadata.Domain != "" {
|
||||
r.logger.DebugContext(ctx, "sniffed protocol: ", metadata.Protocol, ", domain: ", metadata.Domain)
|
||||
@ -706,6 +710,13 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
|
||||
if !common.Contains(detour.Network(), N.NetworkTCP) {
|
||||
return E.New("missing supported outbound, closing connection")
|
||||
}
|
||||
if metadata.InboundOptions.SniffEnabled && !metadata.InboundOptions.SniffOverrideDestination && sniffedDestination.IsValid() {
|
||||
sniffOutbound, loaded := detour.(adapter.SniffOutbound)
|
||||
if loaded && sniffOutbound.UseSniffedDestination() {
|
||||
r.logger.DebugContext(ctx, "use sniffed destination, detor: ", detour.Tag(), ", domain: ", metadata.Domain)
|
||||
metadata.Destination = sniffedDestination
|
||||
}
|
||||
}
|
||||
if r.clashServer != nil {
|
||||
trackerConn, tracker := r.clashServer.RoutedConnection(ctx, conn, metadata, matchedRule)
|
||||
defer tracker.Leave()
|
||||
@ -760,6 +771,7 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
|
||||
r.logger.DebugContext(ctx, "found fakeip domain: ", domain)
|
||||
}
|
||||
|
||||
var sniffedDestination M.Socksaddr
|
||||
if metadata.InboundOptions.SniffEnabled {
|
||||
buffer := buf.NewPacket()
|
||||
buffer.FullReset()
|
||||
@ -772,11 +784,14 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
|
||||
if sniffMetadata != nil {
|
||||
metadata.Protocol = sniffMetadata.Protocol
|
||||
metadata.Domain = sniffMetadata.Domain
|
||||
if metadata.InboundOptions.SniffOverrideDestination && M.IsDomainName(metadata.Domain) {
|
||||
metadata.Destination = M.Socksaddr{
|
||||
if M.IsDomainName(metadata.Domain) {
|
||||
sniffedDestination = M.Socksaddr{
|
||||
Fqdn: metadata.Domain,
|
||||
Port: metadata.Destination.Port,
|
||||
}
|
||||
if metadata.InboundOptions.SniffOverrideDestination {
|
||||
metadata.Destination = sniffedDestination
|
||||
}
|
||||
}
|
||||
if metadata.Domain != "" {
|
||||
r.logger.DebugContext(ctx, "sniffed packet protocol: ", metadata.Protocol, ", domain: ", metadata.Domain)
|
||||
@ -808,6 +823,13 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
|
||||
if !common.Contains(detour.Network(), N.NetworkUDP) {
|
||||
return E.New("missing supported outbound, closing packet connection")
|
||||
}
|
||||
if metadata.InboundOptions.SniffEnabled && !metadata.InboundOptions.SniffOverrideDestination && sniffedDestination.IsValid() {
|
||||
sniffOutbound, loaded := detour.(adapter.SniffOutbound)
|
||||
if loaded && sniffOutbound.UseSniffedDestination() {
|
||||
r.logger.DebugContext(ctx, "use sniffed destination, detor: ", detour.Tag(), ", domain: ", metadata.Domain)
|
||||
metadata.Destination = sniffedDestination
|
||||
}
|
||||
}
|
||||
if r.clashServer != nil {
|
||||
trackerConn, tracker := r.clashServer.RoutedPacketConnection(ctx, conn, metadata, matchedRule)
|
||||
defer tracker.Leave()
|
||||
|
Loading…
x
Reference in New Issue
Block a user