mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-01-28 19:56:49 +00:00
refactor: Outbound domain resolver
This commit is contained in:
parent
eae2631208
commit
63ef6f972f
2
box.go
2
box.go
|
@ -309,7 +309,7 @@ func New(options Options) (*Box, error) {
|
|||
}
|
||||
}
|
||||
if ntpOptions.Enabled {
|
||||
ntpDialer, err := dialer.New(ctx, ntpOptions.DialerOptions)
|
||||
ntpDialer, err := dialer.New(ctx, ntpOptions.DialerOptions, ntpOptions.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "create NTP service")
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
|
@ -15,7 +16,7 @@ import (
|
|||
"github.com/sagernet/sing/service"
|
||||
)
|
||||
|
||||
func New(ctx context.Context, options option.DialerOptions) (N.Dialer, error) {
|
||||
func New(ctx context.Context, options option.DialerOptions, remoteIsDomain bool) (N.Dialer, error) {
|
||||
if options.IsWireGuardListener {
|
||||
return NewDefault(ctx, options)
|
||||
}
|
||||
|
@ -35,13 +36,25 @@ func New(ctx context.Context, options option.DialerOptions) (N.Dialer, error) {
|
|||
}
|
||||
dialer = NewDetour(outboundManager, options.Detour)
|
||||
}
|
||||
if options.Detour == "" {
|
||||
if remoteIsDomain && options.Detour == "" && options.DomainResolver == "" {
|
||||
deprecated.Report(ctx, deprecated.OptionMissingDomainResolverInDialOptions)
|
||||
}
|
||||
if (options.Detour == "" && remoteIsDomain) || options.DomainResolver != "" {
|
||||
router := service.FromContext[adapter.DNSRouter](ctx)
|
||||
if router != nil {
|
||||
var resolveTransport adapter.DNSTransport
|
||||
if options.DomainResolver != "" {
|
||||
transport, loaded := service.FromContext[adapter.DNSTransportManager](ctx).Transport(options.DomainResolver)
|
||||
if !loaded {
|
||||
return nil, E.New("DNS server not found: " + options.DomainResolver)
|
||||
}
|
||||
resolveTransport = transport
|
||||
}
|
||||
dialer = NewResolveDialer(
|
||||
router,
|
||||
dialer,
|
||||
options.Detour == "" && !options.TCPFastOpen,
|
||||
resolveTransport,
|
||||
C.DomainStrategy(options.DomainStrategy),
|
||||
time.Duration(options.FallbackDelay))
|
||||
}
|
||||
|
@ -60,10 +73,19 @@ func NewDirect(ctx context.Context, options option.DialerOptions) (ParallelInter
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var resolveTransport adapter.DNSTransport
|
||||
if options.DomainResolver != "" {
|
||||
transport, loaded := service.FromContext[adapter.DNSTransportManager](ctx).Transport(options.DomainResolver)
|
||||
if !loaded {
|
||||
return nil, E.New("DNS server not found: " + options.DomainResolver)
|
||||
}
|
||||
resolveTransport = transport
|
||||
}
|
||||
return NewResolveParallelInterfaceDialer(
|
||||
service.FromContext[adapter.DNSRouter](ctx),
|
||||
dialer,
|
||||
true,
|
||||
resolveTransport,
|
||||
C.DomainStrategy(options.DomainStrategy),
|
||||
time.Duration(options.FallbackDelay),
|
||||
), nil
|
||||
|
|
|
@ -22,15 +22,17 @@ type resolveDialer struct {
|
|||
dialer N.Dialer
|
||||
parallel bool
|
||||
router adapter.DNSRouter
|
||||
transport adapter.DNSTransport
|
||||
strategy C.DomainStrategy
|
||||
fallbackDelay time.Duration
|
||||
}
|
||||
|
||||
func NewResolveDialer(router adapter.DNSRouter, dialer N.Dialer, parallel bool, strategy C.DomainStrategy, fallbackDelay time.Duration) N.Dialer {
|
||||
func NewResolveDialer(router adapter.DNSRouter, dialer N.Dialer, parallel bool, transport adapter.DNSTransport, strategy C.DomainStrategy, fallbackDelay time.Duration) N.Dialer {
|
||||
return &resolveDialer{
|
||||
dialer,
|
||||
parallel,
|
||||
router,
|
||||
transport,
|
||||
strategy,
|
||||
fallbackDelay,
|
||||
}
|
||||
|
@ -41,12 +43,13 @@ type resolveParallelNetworkDialer struct {
|
|||
dialer ParallelInterfaceDialer
|
||||
}
|
||||
|
||||
func NewResolveParallelInterfaceDialer(router adapter.DNSRouter, dialer ParallelInterfaceDialer, parallel bool, strategy C.DomainStrategy, fallbackDelay time.Duration) ParallelInterfaceDialer {
|
||||
func NewResolveParallelInterfaceDialer(router adapter.DNSRouter, dialer ParallelInterfaceDialer, parallel bool, transport adapter.DNSTransport, strategy C.DomainStrategy, fallbackDelay time.Duration) ParallelInterfaceDialer {
|
||||
return &resolveParallelNetworkDialer{
|
||||
resolveDialer{
|
||||
dialer,
|
||||
parallel,
|
||||
router,
|
||||
transport,
|
||||
strategy,
|
||||
fallbackDelay,
|
||||
},
|
||||
|
@ -59,7 +62,7 @@ func (d *resolveDialer) DialContext(ctx context.Context, network string, destina
|
|||
return d.dialer.DialContext(ctx, network, destination)
|
||||
}
|
||||
ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug)
|
||||
addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Strategy: d.strategy})
|
||||
addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Transport: d.transport, Strategy: d.strategy})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -75,7 +78,7 @@ func (d *resolveDialer) ListenPacket(ctx context.Context, destination M.Socksadd
|
|||
return d.dialer.ListenPacket(ctx, destination)
|
||||
}
|
||||
ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug)
|
||||
addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Strategy: d.strategy})
|
||||
addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Transport: d.transport, Strategy: d.strategy})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -91,9 +94,7 @@ func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context
|
|||
return d.dialer.DialContext(ctx, network, destination)
|
||||
}
|
||||
ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug)
|
||||
addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{
|
||||
Strategy: d.strategy,
|
||||
})
|
||||
addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Transport: d.transport, Strategy: d.strategy})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -112,7 +113,7 @@ func (d *resolveParallelNetworkDialer) ListenSerialInterfacePacket(ctx context.C
|
|||
return d.dialer.ListenPacket(ctx, destination)
|
||||
}
|
||||
ctx = log.ContextWithOverrideLevel(ctx, log.LevelDebug)
|
||||
addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Strategy: d.strategy})
|
||||
addresses, err := d.router.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{Transport: d.transport, Strategy: d.strategy})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ func NewRealityServer(ctx context.Context, logger log.Logger, options option.Inb
|
|||
tlsConfig.ShortIds[shortID] = true
|
||||
}
|
||||
|
||||
handshakeDialer, err := dialer.New(ctx, options.Reality.Handshake.DialerOptions)
|
||||
handshakeDialer, err := dialer.New(ctx, options.Reality.Handshake.DialerOptions, options.Reality.Handshake.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -19,12 +19,20 @@ func NewLocalDialer(ctx context.Context, options option.LocalDNSServerOptions) (
|
|||
if options.LegacyDefaultDialer {
|
||||
return dialer.NewDefaultOutbound(ctx), nil
|
||||
} else {
|
||||
return dialer.New(ctx, options.DialerOptions)
|
||||
return dialer.New(ctx, options.DialerOptions, false)
|
||||
}
|
||||
}
|
||||
|
||||
func NewRemoteDialer(ctx context.Context, options option.RemoteDNSServerOptions) (N.Dialer, error) {
|
||||
transportDialer, err := NewLocalDialer(ctx, options.LocalDNSServerOptions)
|
||||
var (
|
||||
transportDialer N.Dialer
|
||||
err error
|
||||
)
|
||||
if options.LegacyDefaultDialer {
|
||||
transportDialer = dialer.NewDefaultOutbound(ctx)
|
||||
} else {
|
||||
transportDialer, err = dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -35,7 +43,7 @@ func NewRemoteDialer(ctx context.Context, options option.RemoteDNSServerOptions)
|
|||
return nil, E.New("address resolver not found: ", options.AddressResolver)
|
||||
}
|
||||
transportDialer = NewTransportDialer(transportDialer, service.FromContext[adapter.DNSRouter](ctx), resolverTransport, C.DomainStrategy(options.AddressStrategy), time.Duration(options.AddressFallbackDelay))
|
||||
} else if M.IsDomainName(options.Server) {
|
||||
} else if options.ServerIsDomain() {
|
||||
return nil, E.New("missing address resolver for server: ", options.Server)
|
||||
}
|
||||
return transportDialer, nil
|
||||
|
|
|
@ -161,6 +161,20 @@ var OptionLegacyDNSFakeIPOptions = Note{
|
|||
ScheduledVersion: "1.14.0",
|
||||
}
|
||||
|
||||
var OptionOutboundDNSRuleItem = Note{
|
||||
Name: "outbound-dns-rule-item",
|
||||
Description: "outbound DNS rule item",
|
||||
DeprecatedVersion: "1.12.0",
|
||||
ScheduledVersion: "1.14.0",
|
||||
}
|
||||
|
||||
var OptionMissingDomainResolverInDialOptions = Note{
|
||||
Name: "missing-domain-resolver-in-dial-options",
|
||||
Description: "missing domain resolver in dial options",
|
||||
DeprecatedVersion: "1.12.0",
|
||||
ScheduledVersion: "1.14.0",
|
||||
}
|
||||
|
||||
var Options = []Note{
|
||||
OptionBadMatchSource,
|
||||
OptionGEOIP,
|
||||
|
@ -172,4 +186,8 @@ var Options = []Note{
|
|||
OptionWireGuardOutbound,
|
||||
OptionWireGuardGSO,
|
||||
OptionTUNGSO,
|
||||
OptionLegacyDNSTransport,
|
||||
OptionLegacyDNSFakeIPOptions,
|
||||
OptionOutboundDNSRuleItem,
|
||||
OptionMissingDomainResolverInDialOptions,
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ type DialerOptions struct {
|
|||
TCPMultiPath bool `json:"tcp_multi_path,omitempty"`
|
||||
UDPFragment *bool `json:"udp_fragment,omitempty"`
|
||||
UDPFragmentDefault bool `json:"-"`
|
||||
DomainResolver string `json:"domain_resolver,omitempty"`
|
||||
DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"`
|
||||
NetworkStrategy *NetworkStrategy `json:"network_strategy,omitempty"`
|
||||
NetworkType badoption.Listable[InterfaceType] `json:"network_type,omitempty"`
|
||||
|
@ -107,6 +108,10 @@ func (o ServerOptions) Build() M.Socksaddr {
|
|||
return M.ParseSocksaddrHostPort(o.Server, o.ServerPort)
|
||||
}
|
||||
|
||||
func (o ServerOptions) ServerIsDomain() bool {
|
||||
return M.IsDomainName(o.Server)
|
||||
}
|
||||
|
||||
func (o *ServerOptions) TakeServerOptions() ServerOptions {
|
||||
return *o
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ type Outbound struct {
|
|||
}
|
||||
|
||||
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.HTTPOutboundOptions) (adapter.Outbound, error) {
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
return nil, E.New("unknown obfs type: ", options.Obfs.Type)
|
||||
}
|
||||
}
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
|||
if options.Version > 1 {
|
||||
handshakeForServerName = make(map[string]shadowtls.HandshakeConfig)
|
||||
for serverName, serverOptions := range options.HandshakeForServerName {
|
||||
handshakeDialer, err := dialer.New(ctx, serverOptions.DialerOptions)
|
||||
handshakeDialer, err := dialer.New(ctx, serverOptions.DialerOptions, serverOptions.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
|||
}
|
||||
}
|
||||
}
|
||||
handshakeDialer, err := dialer.New(ctx, options.Handshake.DialerOptions)
|
||||
handshakeDialer, err := dialer.New(ctx, options.Handshake.DialerOptions, options.Handshake.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
tlsHandshakeFunc = shadowtls.DefaultTLSHandshakeFunc(options.Password, stdTLSConfig)
|
||||
}
|
||||
}
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ type Outbound struct {
|
|||
}
|
||||
|
||||
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SSHOutboundOptions) (adapter.Outbound, error) {
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
}
|
||||
startConf.TorrcFile = torrcFile
|
||||
}
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ type Outbound struct {
|
|||
}
|
||||
|
||||
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TrojanOutboundOptions) (adapter.Outbound, error) {
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
case "quic":
|
||||
tuicUDPStream = true
|
||||
}
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ type Outbound struct {
|
|||
}
|
||||
|
||||
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VLESSOutboundOptions) (adapter.Outbound, error) {
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ type Outbound struct {
|
|||
}
|
||||
|
||||
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.VMessOutboundOptions) (adapter.Outbound, error) {
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
if options.Detour == "" {
|
||||
options.IsWireGuardListener = true
|
||||
}
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
} else if options.GSO {
|
||||
return nil, E.New("gso is conflict with detour")
|
||||
}
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions)
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions, options.ServerIsDomain())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action opti
|
|||
UDPTimeout: time.Duration(action.RouteOptionsOptions.UDPTimeout),
|
||||
}, nil
|
||||
case C.RuleActionTypeDirect:
|
||||
directDialer, err := dialer.New(ctx, option.DialerOptions(action.DirectOptions))
|
||||
directDialer, err := dialer.New(ctx, option.DialerOptions(action.DirectOptions), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -205,7 +205,7 @@ func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options op
|
|||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
if len(options.Outbound) > 0 {
|
||||
item := NewOutboundRule(options.Outbound)
|
||||
item := NewOutboundRule(ctx, options.Outbound)
|
||||
rule.items = append(rule.items, item)
|
||||
rule.allItems = append(rule.allItems, item)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package rule
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
)
|
||||
|
||||
|
@ -15,7 +17,8 @@ type OutboundItem struct {
|
|||
matchAny bool
|
||||
}
|
||||
|
||||
func NewOutboundRule(outbounds []string) *OutboundItem {
|
||||
func NewOutboundRule(ctx context.Context, outbounds []string) *OutboundItem {
|
||||
deprecated.Report(ctx, deprecated.OptionOutboundDNSRuleItem)
|
||||
rule := &OutboundItem{outbounds: outbounds, outboundMap: make(map[string]bool)}
|
||||
for _, outbound := range outbounds {
|
||||
if outbound == "any" {
|
||||
|
@ -28,8 +31,8 @@ func NewOutboundRule(outbounds []string) *OutboundItem {
|
|||
}
|
||||
|
||||
func (r *OutboundItem) Match(metadata *adapter.InboundContext) bool {
|
||||
if r.matchAny && metadata.Outbound != "" {
|
||||
return true
|
||||
if r.matchAny {
|
||||
return metadata.Outbound != ""
|
||||
}
|
||||
return r.outboundMap[metadata.Outbound]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue