mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-10-19 15:54:24 +00:00
Fix hysteria2 realm STUN resolution ignoring default domain resolver
This commit is contained in:
@@ -8,9 +8,7 @@ import (
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
"github.com/sagernet/sing/service"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
@@ -45,26 +43,6 @@ type DNSQueryOptions struct {
|
||||
RemoveClientSubnet bool
|
||||
}
|
||||
|
||||
func DNSQueryOptionsFrom(ctx context.Context, options *option.DomainResolveOptions) (DNSQueryOptions, error) {
|
||||
if options == nil || options.Server == "" {
|
||||
return DNSQueryOptions{}, nil
|
||||
}
|
||||
transportManager := service.FromContext[DNSTransportManager](ctx)
|
||||
transport, loaded := transportManager.Transport(options.Server)
|
||||
if !loaded {
|
||||
return DNSQueryOptions{}, E.New("domain resolver not found: " + options.Server)
|
||||
}
|
||||
return DNSQueryOptions{
|
||||
Transport: transport,
|
||||
Strategy: C.DomainStrategy(options.Strategy),
|
||||
DisableCache: options.DisableCache,
|
||||
DisableOptimisticCache: options.DisableOptimisticCache,
|
||||
RewriteTTL: options.RewriteTTL,
|
||||
Timeout: time.Duration(options.Timeout),
|
||||
ClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type RDRCStore interface {
|
||||
LoadRDRC(transportName string, qName string, qType uint16) (rejected bool)
|
||||
SaveRDRC(transportName string, qName string, qType uint16) error
|
||||
|
||||
+62
-64
@@ -63,75 +63,31 @@ func NewWithOptions(options Options) (N.Dialer, error) {
|
||||
}
|
||||
}
|
||||
if options.RemoteIsDomain && (!hasDetour || options.ResolverOnDetour || dialOptions.DomainResolver != nil && dialOptions.DomainResolver.Server != "") {
|
||||
networkManager := service.FromContext[adapter.NetworkManager](options.Context)
|
||||
dnsTransport := service.FromContext[adapter.DNSTransportManager](options.Context)
|
||||
var defaultOptions adapter.NetworkOptions
|
||||
if networkManager != nil {
|
||||
defaultOptions = networkManager.DefaultOptions()
|
||||
}
|
||||
var (
|
||||
server string
|
||||
dnsQueryOptions adapter.DNSQueryOptions
|
||||
resolveFallbackDelay time.Duration
|
||||
server string
|
||||
dnsQueryOptions adapter.DNSQueryOptions
|
||||
)
|
||||
if dialOptions.DomainResolver != nil && dialOptions.DomainResolver.Server != "" {
|
||||
var transport adapter.DNSTransport
|
||||
if !options.DirectResolver {
|
||||
var loaded bool
|
||||
transport, loaded = dnsTransport.Transport(dialOptions.DomainResolver.Server)
|
||||
if !loaded {
|
||||
return nil, E.New("domain resolver not found: " + dialOptions.DomainResolver.Server)
|
||||
}
|
||||
hasDomainResolver := dialOptions.DomainResolver != nil && dialOptions.DomainResolver.Server != ""
|
||||
if options.DirectResolver {
|
||||
if !hasDomainResolver {
|
||||
return nil, E.New("missing domain resolver for domain server address")
|
||||
}
|
||||
var strategy C.DomainStrategy
|
||||
if dialOptions.DomainResolver.Strategy != option.DomainStrategy(C.DomainStrategyAsIS) {
|
||||
strategy = C.DomainStrategy(dialOptions.DomainResolver.Strategy)
|
||||
} else if
|
||||
//nolint:staticcheck
|
||||
dialOptions.DomainStrategy != option.DomainStrategy(C.DomainStrategyAsIS) {
|
||||
//nolint:staticcheck
|
||||
strategy = C.DomainStrategy(dialOptions.DomainStrategy)
|
||||
deprecated.Report(options.Context, deprecated.OptionLegacyDomainStrategyOptions)
|
||||
}
|
||||
server = dialOptions.DomainResolver.Server
|
||||
dnsQueryOptions = adapter.DNSQueryOptions{
|
||||
Transport: transport,
|
||||
Strategy: strategy,
|
||||
Timeout: time.Duration(dialOptions.DomainResolver.Timeout),
|
||||
DisableCache: dialOptions.DomainResolver.DisableCache,
|
||||
DisableOptimisticCache: dialOptions.DomainResolver.DisableOptimisticCache,
|
||||
RewriteTTL: dialOptions.DomainResolver.RewriteTTL,
|
||||
ClientSubnet: dialOptions.DomainResolver.ClientSubnet.Build(netip.Prefix{}),
|
||||
}
|
||||
resolveFallbackDelay = time.Duration(dialOptions.FallbackDelay)
|
||||
} else if options.DirectResolver {
|
||||
return nil, E.New("missing domain resolver for domain server address")
|
||||
dnsQueryOptions = domainResolveQueryOptions(dialOptions.DomainResolver)
|
||||
} else {
|
||||
if defaultOptions.DomainResolver != "" {
|
||||
dnsQueryOptions = defaultOptions.DomainResolveOptions
|
||||
transport, loaded := dnsTransport.Transport(defaultOptions.DomainResolver)
|
||||
if !loaded {
|
||||
return nil, E.New("default domain resolver not found: " + defaultOptions.DomainResolver)
|
||||
}
|
||||
dnsQueryOptions.Transport = transport
|
||||
resolveFallbackDelay = time.Duration(dialOptions.FallbackDelay)
|
||||
} else {
|
||||
transports := dnsTransport.Transports()
|
||||
if len(transports) < 2 {
|
||||
dnsQueryOptions.Transport = dnsTransport.Default()
|
||||
} else if options.NewDialer {
|
||||
return nil, E.New("missing domain resolver for domain server address")
|
||||
} else {
|
||||
deprecated.Report(options.Context, deprecated.OptionMissingDomainResolver)
|
||||
}
|
||||
dnsQueryOptions, err = NewDNSQueryOptions(options.Context, dialOptions.DomainResolver, options.NewDialer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if
|
||||
}
|
||||
if hasDomainResolver {
|
||||
server = dialOptions.DomainResolver.Server
|
||||
}
|
||||
if
|
||||
//nolint:staticcheck
|
||||
dialOptions.DomainStrategy != option.DomainStrategy(C.DomainStrategyAsIS) && (!hasDomainResolver || dialOptions.DomainResolver.Strategy == option.DomainStrategy(C.DomainStrategyAsIS)) {
|
||||
//nolint:staticcheck
|
||||
dialOptions.DomainStrategy != option.DomainStrategy(C.DomainStrategyAsIS) {
|
||||
//nolint:staticcheck
|
||||
dnsQueryOptions.Strategy = C.DomainStrategy(dialOptions.DomainStrategy)
|
||||
deprecated.Report(options.Context, deprecated.OptionLegacyDomainStrategyOptions)
|
||||
}
|
||||
dnsQueryOptions.Strategy = C.DomainStrategy(dialOptions.DomainStrategy)
|
||||
deprecated.Report(options.Context, deprecated.OptionLegacyDomainStrategyOptions)
|
||||
}
|
||||
dialer = NewResolveDialer(
|
||||
options.Context,
|
||||
@@ -139,12 +95,54 @@ func NewWithOptions(options Options) (N.Dialer, error) {
|
||||
dialOptions.Detour == "" && !dialOptions.TCPFastOpen,
|
||||
server,
|
||||
dnsQueryOptions,
|
||||
resolveFallbackDelay,
|
||||
time.Duration(dialOptions.FallbackDelay),
|
||||
)
|
||||
}
|
||||
return dialer, nil
|
||||
}
|
||||
|
||||
func NewDNSQueryOptions(ctx context.Context, domainResolver *option.DomainResolveOptions, newDialer bool) (adapter.DNSQueryOptions, error) {
|
||||
dnsTransport := service.FromContext[adapter.DNSTransportManager](ctx)
|
||||
if domainResolver != nil && domainResolver.Server != "" {
|
||||
transport, loaded := dnsTransport.Transport(domainResolver.Server)
|
||||
if !loaded {
|
||||
return adapter.DNSQueryOptions{}, E.New("domain resolver not found: ", domainResolver.Server)
|
||||
}
|
||||
dnsQueryOptions := domainResolveQueryOptions(domainResolver)
|
||||
dnsQueryOptions.Transport = transport
|
||||
return dnsQueryOptions, nil
|
||||
}
|
||||
defaultOptions := service.FromContext[adapter.NetworkManager](ctx).DefaultOptions()
|
||||
if defaultOptions.DomainResolver != "" {
|
||||
transport, loaded := dnsTransport.Transport(defaultOptions.DomainResolver)
|
||||
if !loaded {
|
||||
return adapter.DNSQueryOptions{}, E.New("default domain resolver not found: ", defaultOptions.DomainResolver)
|
||||
}
|
||||
dnsQueryOptions := defaultOptions.DomainResolveOptions
|
||||
dnsQueryOptions.Transport = transport
|
||||
return dnsQueryOptions, nil
|
||||
}
|
||||
if len(dnsTransport.Transports()) < 2 {
|
||||
return adapter.DNSQueryOptions{Transport: dnsTransport.Default()}, nil
|
||||
}
|
||||
if newDialer {
|
||||
return adapter.DNSQueryOptions{}, E.New("missing domain resolver for domain server address")
|
||||
}
|
||||
deprecated.Report(ctx, deprecated.OptionMissingDomainResolver)
|
||||
return adapter.DNSQueryOptions{}, nil
|
||||
}
|
||||
|
||||
func domainResolveQueryOptions(domainResolver *option.DomainResolveOptions) adapter.DNSQueryOptions {
|
||||
return adapter.DNSQueryOptions{
|
||||
Strategy: C.DomainStrategy(domainResolver.Strategy),
|
||||
Timeout: time.Duration(domainResolver.Timeout),
|
||||
DisableCache: domainResolver.DisableCache,
|
||||
DisableOptimisticCache: domainResolver.DisableOptimisticCache,
|
||||
RewriteTTL: domainResolver.RewriteTTL,
|
||||
ClientSubnet: domainResolver.ClientSubnet.Build(netip.Prefix{}),
|
||||
}
|
||||
}
|
||||
|
||||
type ParallelInterfaceDialer interface {
|
||||
N.Dialer
|
||||
DialParallelInterface(ctx context.Context, network string, destination M.Socksaddr, strategy *C.NetworkStrategy, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error)
|
||||
|
||||
@@ -3,6 +3,7 @@ package option
|
||||
import (
|
||||
"net/url"
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/schema"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"github.com/sagernet/sing/common/json"
|
||||
"github.com/sagernet/sing/common/json/badjson"
|
||||
"github.com/sagernet/sing/common/json/badoption"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
)
|
||||
|
||||
type Hysteria2InboundOptions struct {
|
||||
@@ -37,6 +39,12 @@ type Hysteria2Realm struct {
|
||||
HTTPClient *HTTPClientOptions `json:"http_client,omitempty"`
|
||||
}
|
||||
|
||||
func (r Hysteria2Realm) STUNServersIsDomain() bool {
|
||||
return slices.ContainsFunc(r.STUNServers, func(server string) bool {
|
||||
return M.ParseSocksaddr(server).IsDomain()
|
||||
})
|
||||
}
|
||||
|
||||
type Hysteria2RealmPortMapping struct {
|
||||
Enabled bool `json:"enabled,omitempty"`
|
||||
Timeout badoption.Duration `json:"timeout,omitempty"`
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/adapter/inbound"
|
||||
"github.com/sagernet/sing-box/common/dialer"
|
||||
"github.com/sagernet/sing-box/common/listener"
|
||||
"github.com/sagernet/sing-box/common/tls"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
@@ -141,11 +142,15 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
return nil, E.New("realm.ip_version 4 conflicts with listen address ", listenAddr)
|
||||
}
|
||||
}
|
||||
queryOptions, err := adapter.DNSQueryOptionsFrom(ctx, options.Realm.STUNDomainResolver)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var queryOptions adapter.DNSQueryOptions
|
||||
if options.Realm.STUNServersIsDomain() {
|
||||
queryOptions, err = dialer.NewDNSQueryOptions(ctx, options.Realm.STUNDomainResolver, true)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "create realm STUN domain resolver")
|
||||
}
|
||||
}
|
||||
httpClientTransport, err := service.FromContext[adapter.HTTPClientManager](ctx).ResolveTransport(ctx, logger, common.PtrValueOrDefault(options.Realm.HTTPClient))
|
||||
var httpClientTransport adapter.HTTPTransport
|
||||
httpClientTransport, err = service.FromContext[adapter.HTTPClientManager](ctx).ResolveTransport(ctx, logger, common.PtrValueOrDefault(options.Realm.HTTPClient))
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "create realm http client")
|
||||
}
|
||||
|
||||
@@ -76,21 +76,25 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
return nil, E.New("unknown obfs type: ", options.Obfs.Type)
|
||||
}
|
||||
}
|
||||
realmSTUNServersIsDomain := options.Realm != nil && options.Realm.STUNServersIsDomain()
|
||||
outboundDialer, err := dialer.NewWithOptions(dialer.Options{
|
||||
Context: ctx,
|
||||
Options: options.DialerOptions,
|
||||
RemoteIsDomain: options.ServerIsDomain(),
|
||||
Context: ctx,
|
||||
Options: options.DialerOptions,
|
||||
RemoteIsDomain: options.ServerIsDomain() || realmSTUNServersIsDomain,
|
||||
ResolverOnDetour: realmSTUNServersIsDomain,
|
||||
NewDialer: realmSTUNServersIsDomain,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var realmOptions *realm.Options
|
||||
if options.Realm != nil {
|
||||
queryOptions, err := adapter.DNSQueryOptionsFrom(ctx, options.DialerOptions.DomainResolver)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var queryOptions adapter.DNSQueryOptions
|
||||
if realmSTUNServersIsDomain {
|
||||
queryOptions = outboundDialer.(dialer.ResolveDialer).QueryOptions()
|
||||
}
|
||||
httpClientTransport, err := service.FromContext[adapter.HTTPClientManager](ctx).ResolveTransport(ctx, logger, common.PtrValueOrDefault(options.Realm.HTTPClient))
|
||||
var httpClientTransport adapter.HTTPTransport
|
||||
httpClientTransport, err = service.FromContext[adapter.HTTPClientManager](ctx).ResolveTransport(ctx, logger, common.PtrValueOrDefault(options.Realm.HTTPClient))
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "create realm http client")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user