mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-03-15 19:23:51 +00:00
refactor: Outbound domain resolver
This commit is contained in:
parent
f81518ea82
commit
476552eeb4
33 changed files with 392 additions and 167 deletions
adapter
box.gocommon
dns
experimental/deprecated
option
protocol
direct
http
hysteria
hysteria2
shadowsocks
shadowtls
socks
ssh
tor
trojan
tuic
vless
vmess
wireguard
route
|
@ -29,12 +29,14 @@ type NetworkManager interface {
|
|||
}
|
||||
|
||||
type NetworkOptions struct {
|
||||
NetworkStrategy *C.NetworkStrategy
|
||||
NetworkType []C.InterfaceType
|
||||
FallbackNetworkType []C.InterfaceType
|
||||
FallbackDelay time.Duration
|
||||
BindInterface string
|
||||
RoutingMark uint32
|
||||
BindInterface string
|
||||
RoutingMark uint32
|
||||
DomainResolver string
|
||||
DomainResolveOptions DNSQueryOptions
|
||||
NetworkStrategy *C.NetworkStrategy
|
||||
NetworkType []C.InterfaceType
|
||||
FallbackNetworkType []C.InterfaceType
|
||||
FallbackDelay time.Duration
|
||||
}
|
||||
|
||||
type InterfaceUpdateListener interface {
|
||||
|
|
6
box.go
6
box.go
|
@ -187,7 +187,7 @@ func New(options Options) (*Box, error) {
|
|||
transportOptions.Options,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "initialize inbound[", i, "]")
|
||||
return nil, E.Cause(err, "initialize DNS server[", i, "]")
|
||||
}
|
||||
}
|
||||
err = dnsRouter.Initialize(dnsOptions.Rules)
|
||||
|
@ -217,7 +217,7 @@ func New(options Options) (*Box, error) {
|
|||
endpointOptions.Options,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "initialize inbound[", i, "]")
|
||||
return nil, E.Cause(err, "initialize endpoint[", i, "]")
|
||||
}
|
||||
}
|
||||
for i, inboundOptions := range options.Inbounds {
|
||||
|
@ -316,7 +316,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")
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ type DefaultDialer struct {
|
|||
udpListener net.ListenConfig
|
||||
udpAddr4 string
|
||||
udpAddr6 string
|
||||
isWireGuardListener bool
|
||||
networkManager adapter.NetworkManager
|
||||
networkStrategy *C.NetworkStrategy
|
||||
defaultNetworkStrategy bool
|
||||
|
@ -183,11 +182,6 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
|
|||
}
|
||||
setMultiPathTCP(&dialer4)
|
||||
}
|
||||
if options.IsWireGuardListener {
|
||||
for _, controlFn := range WgControlFns {
|
||||
listener.Control = control.Append(listener.Control, controlFn)
|
||||
}
|
||||
}
|
||||
tcpDialer4, err := newTCPDialer(dialer4, options.TCPFastOpen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -204,7 +198,6 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
|
|||
udpListener: listener,
|
||||
udpAddr4: udpAddr4,
|
||||
udpAddr6: udpAddr6,
|
||||
isWireGuardListener: options.IsWireGuardListener,
|
||||
networkManager: networkManager,
|
||||
networkStrategy: networkStrategy,
|
||||
defaultNetworkStrategy: defaultNetworkStrategy,
|
||||
|
|
|
@ -29,16 +29,18 @@ func (d *DetourDialer) Start() error {
|
|||
}
|
||||
|
||||
func (d *DetourDialer) Dialer() (N.Dialer, error) {
|
||||
d.initOnce.Do(func() {
|
||||
var loaded bool
|
||||
d.dialer, loaded = d.outboundManager.Outbound(d.detour)
|
||||
if !loaded {
|
||||
d.initErr = E.New("outbound detour not found: ", d.detour)
|
||||
}
|
||||
})
|
||||
d.initOnce.Do(d.init)
|
||||
return d.dialer, d.initErr
|
||||
}
|
||||
|
||||
func (d *DetourDialer) init() {
|
||||
var loaded bool
|
||||
d.dialer, loaded = d.outboundManager.Outbound(d.detour)
|
||||
if !loaded {
|
||||
d.initErr = E.New("outbound detour not found: ", d.detour)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DetourDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
dialer, err := d.Dialer()
|
||||
if err != nil {
|
||||
|
|
|
@ -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,60 +16,105 @@ import (
|
|||
"github.com/sagernet/sing/service"
|
||||
)
|
||||
|
||||
func New(ctx context.Context, options option.DialerOptions) (N.Dialer, error) {
|
||||
if options.IsWireGuardListener {
|
||||
return NewDefault(ctx, options)
|
||||
}
|
||||
type Options struct {
|
||||
Context context.Context
|
||||
Options option.DialerOptions
|
||||
RemoteIsDomain bool
|
||||
DirectResolver bool
|
||||
ResolverOnDetour bool
|
||||
}
|
||||
|
||||
// TODO: merge with NewWithOptions
|
||||
func New(ctx context.Context, options option.DialerOptions, remoteIsDomain bool) (N.Dialer, error) {
|
||||
return NewWithOptions(Options{
|
||||
Context: ctx,
|
||||
Options: options,
|
||||
RemoteIsDomain: remoteIsDomain,
|
||||
})
|
||||
}
|
||||
|
||||
func NewWithOptions(options Options) (N.Dialer, error) {
|
||||
dialOptions := options.Options
|
||||
var (
|
||||
dialer N.Dialer
|
||||
err error
|
||||
)
|
||||
if options.Detour == "" {
|
||||
dialer, err = NewDefault(ctx, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
outboundManager := service.FromContext[adapter.OutboundManager](ctx)
|
||||
if dialOptions.Detour != "" {
|
||||
outboundManager := service.FromContext[adapter.OutboundManager](options.Context)
|
||||
if outboundManager == nil {
|
||||
return nil, E.New("missing outbound manager")
|
||||
}
|
||||
dialer = NewDetour(outboundManager, options.Detour)
|
||||
}
|
||||
if options.Detour == "" {
|
||||
router := service.FromContext[adapter.DNSRouter](ctx)
|
||||
if router != nil {
|
||||
dialer = NewResolveDialer(
|
||||
router,
|
||||
dialer,
|
||||
options.Detour == "" && !options.TCPFastOpen,
|
||||
C.DomainStrategy(options.DomainStrategy),
|
||||
time.Duration(options.FallbackDelay))
|
||||
dialer = NewDetour(outboundManager, dialOptions.Detour)
|
||||
} else {
|
||||
dialer, err = NewDefault(options.Context, dialOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if options.RemoteIsDomain && (dialOptions.Detour == "" || options.ResolverOnDetour) {
|
||||
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
|
||||
)
|
||||
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)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
server = dialOptions.DomainResolver.Server
|
||||
dnsQueryOptions = adapter.DNSQueryOptions{
|
||||
Transport: transport,
|
||||
Strategy: strategy,
|
||||
DisableCache: dialOptions.DomainResolver.DisableCache,
|
||||
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")
|
||||
} 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 {
|
||||
deprecated.Report(options.Context, deprecated.OptionMissingDomainResolver)
|
||||
}
|
||||
dialer = NewResolveDialer(
|
||||
options.Context,
|
||||
dialer,
|
||||
dialOptions.Detour == "" && !dialOptions.TCPFastOpen,
|
||||
server,
|
||||
dnsQueryOptions,
|
||||
resolveFallbackDelay,
|
||||
)
|
||||
}
|
||||
return dialer, nil
|
||||
}
|
||||
|
||||
func NewDirect(ctx context.Context, options option.DialerOptions) (ParallelInterfaceDialer, error) {
|
||||
if options.Detour != "" {
|
||||
return nil, E.New("`detour` is not supported in direct context")
|
||||
}
|
||||
if options.IsWireGuardListener {
|
||||
return NewDefault(ctx, options)
|
||||
}
|
||||
dialer, err := NewDefault(ctx, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewResolveParallelInterfaceDialer(
|
||||
service.FromContext[adapter.DNSRouter](ctx),
|
||||
dialer,
|
||||
true,
|
||||
C.DomainStrategy(options.DomainStrategy),
|
||||
time.Duration(options.FallbackDelay),
|
||||
), nil
|
||||
}
|
||||
|
||||
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,14 +3,17 @@ package dialer
|
|||
import (
|
||||
"context"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/service"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -18,21 +21,37 @@ var (
|
|||
_ ParallelInterfaceDialer = (*resolveParallelNetworkDialer)(nil)
|
||||
)
|
||||
|
||||
type ResolveDialer interface {
|
||||
N.Dialer
|
||||
QueryOptions() adapter.DNSQueryOptions
|
||||
}
|
||||
|
||||
type ParallelInterfaceResolveDialer interface {
|
||||
ParallelInterfaceDialer
|
||||
QueryOptions() adapter.DNSQueryOptions
|
||||
}
|
||||
|
||||
type resolveDialer struct {
|
||||
transport adapter.DNSTransportManager
|
||||
router adapter.DNSRouter
|
||||
dialer N.Dialer
|
||||
parallel bool
|
||||
router adapter.DNSRouter
|
||||
strategy C.DomainStrategy
|
||||
server string
|
||||
initOnce sync.Once
|
||||
initErr error
|
||||
queryOptions adapter.DNSQueryOptions
|
||||
fallbackDelay time.Duration
|
||||
}
|
||||
|
||||
func NewResolveDialer(router adapter.DNSRouter, dialer N.Dialer, parallel bool, strategy C.DomainStrategy, fallbackDelay time.Duration) N.Dialer {
|
||||
func NewResolveDialer(ctx context.Context, dialer N.Dialer, parallel bool, server string, queryOptions adapter.DNSQueryOptions, fallbackDelay time.Duration) ResolveDialer {
|
||||
return &resolveDialer{
|
||||
dialer,
|
||||
parallel,
|
||||
router,
|
||||
strategy,
|
||||
fallbackDelay,
|
||||
transport: service.FromContext[adapter.DNSTransportManager](ctx),
|
||||
router: service.FromContext[adapter.DNSRouter](ctx),
|
||||
dialer: dialer,
|
||||
parallel: parallel,
|
||||
server: server,
|
||||
queryOptions: queryOptions,
|
||||
fallbackDelay: fallbackDelay,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,41 +60,68 @@ type resolveParallelNetworkDialer struct {
|
|||
dialer ParallelInterfaceDialer
|
||||
}
|
||||
|
||||
func NewResolveParallelInterfaceDialer(router adapter.DNSRouter, dialer ParallelInterfaceDialer, parallel bool, strategy C.DomainStrategy, fallbackDelay time.Duration) ParallelInterfaceDialer {
|
||||
func NewResolveParallelInterfaceDialer(ctx context.Context, dialer ParallelInterfaceDialer, parallel bool, server string, queryOptions adapter.DNSQueryOptions, fallbackDelay time.Duration) ParallelInterfaceResolveDialer {
|
||||
return &resolveParallelNetworkDialer{
|
||||
resolveDialer{
|
||||
dialer,
|
||||
parallel,
|
||||
router,
|
||||
strategy,
|
||||
fallbackDelay,
|
||||
transport: service.FromContext[adapter.DNSTransportManager](ctx),
|
||||
router: service.FromContext[adapter.DNSRouter](ctx),
|
||||
dialer: dialer,
|
||||
parallel: parallel,
|
||||
server: server,
|
||||
queryOptions: queryOptions,
|
||||
fallbackDelay: fallbackDelay,
|
||||
},
|
||||
dialer,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *resolveDialer) initialize() error {
|
||||
d.initOnce.Do(d.initServer)
|
||||
return d.initErr
|
||||
}
|
||||
|
||||
func (d *resolveDialer) initServer() {
|
||||
if d.server == "" {
|
||||
return
|
||||
}
|
||||
transport, loaded := d.transport.Transport(d.server)
|
||||
if !loaded {
|
||||
d.initErr = E.New("domain resolver not found: " + d.server)
|
||||
return
|
||||
}
|
||||
d.queryOptions.Transport = transport
|
||||
}
|
||||
|
||||
func (d *resolveDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
err := d.initialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !destination.IsFqdn() {
|
||||
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, d.queryOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if d.parallel {
|
||||
return N.DialParallel(ctx, d.dialer, network, destination, addresses, d.strategy == C.DomainStrategyPreferIPv6, d.fallbackDelay)
|
||||
return N.DialParallel(ctx, d.dialer, network, destination, addresses, d.queryOptions.Strategy == C.DomainStrategyPreferIPv6, d.fallbackDelay)
|
||||
} else {
|
||||
return N.DialSerial(ctx, d.dialer, network, destination, addresses)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *resolveDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
err := d.initialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !destination.IsFqdn() {
|
||||
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, d.queryOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -86,14 +132,24 @@ 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 *resolveDialer) QueryOptions() adapter.DNSQueryOptions {
|
||||
return d.queryOptions
|
||||
}
|
||||
|
||||
func (d *resolveDialer) Upstream() any {
|
||||
return d.dialer
|
||||
}
|
||||
|
||||
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) {
|
||||
err := d.initialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !destination.IsFqdn() {
|
||||
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, d.queryOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -101,21 +157,28 @@ func (d *resolveParallelNetworkDialer) DialParallelInterface(ctx context.Context
|
|||
fallbackDelay = d.fallbackDelay
|
||||
}
|
||||
if d.parallel {
|
||||
return DialParallelNetwork(ctx, d.dialer, network, destination, addresses, d.strategy == C.DomainStrategyPreferIPv6, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||
return DialParallelNetwork(ctx, d.dialer, network, destination, addresses, d.queryOptions.Strategy == C.DomainStrategyPreferIPv6, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||
} else {
|
||||
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, interfaceType []C.InterfaceType, fallbackInterfaceType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, error) {
|
||||
err := d.initialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !destination.IsFqdn() {
|
||||
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, d.queryOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if fallbackDelay == 0 {
|
||||
fallbackDelay = d.fallbackDelay
|
||||
}
|
||||
conn, destinationAddress, err := ListenSerialNetworkPacket(ctx, d.dialer, destination, addresses, strategy, interfaceType, fallbackInterfaceType, fallbackDelay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -123,6 +186,10 @@ func (d *resolveParallelNetworkDialer) ListenSerialInterfacePacket(ctx context.C
|
|||
return bufio.NewNATPacketConn(bufio.NewPacketConn(conn), M.SocksaddrFrom(destinationAddress, destination.Port), destination), nil
|
||||
}
|
||||
|
||||
func (d *resolveDialer) Upstream() any {
|
||||
func (d *resolveParallelNetworkDialer) QueryOptions() adapter.DNSQueryOptions {
|
||||
return d.queryOptions
|
||||
}
|
||||
|
||||
func (d *resolveParallelNetworkDialer) Upstream() any {
|
||||
return d.dialer
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -27,9 +27,14 @@ func NewTransportAdapter(transportType string, transportTag string, dependencies
|
|||
}
|
||||
|
||||
func NewTransportAdapterWithLocalOptions(transportType string, transportTag string, localOptions option.LocalDNSServerOptions) TransportAdapter {
|
||||
var dependencies []string
|
||||
if localOptions.DomainResolver != nil && localOptions.DomainResolver.Server != "" {
|
||||
dependencies = append(dependencies, localOptions.DomainResolver.Server)
|
||||
}
|
||||
return TransportAdapter{
|
||||
transportType: transportType,
|
||||
transportTag: transportTag,
|
||||
dependencies: dependencies,
|
||||
strategy: C.DomainStrategy(localOptions.LegacyStrategy),
|
||||
clientSubnet: localOptions.LegacyClientSubnet,
|
||||
}
|
||||
|
@ -37,8 +42,11 @@ func NewTransportAdapterWithLocalOptions(transportType string, transportTag stri
|
|||
|
||||
func NewTransportAdapterWithRemoteOptions(transportType string, transportTag string, remoteOptions option.RemoteDNSServerOptions) TransportAdapter {
|
||||
var dependencies []string
|
||||
if remoteOptions.AddressResolver != "" {
|
||||
dependencies = []string{remoteOptions.AddressResolver}
|
||||
if remoteOptions.DomainResolver != nil && remoteOptions.DomainResolver.Server != "" {
|
||||
dependencies = append(dependencies, remoteOptions.DomainResolver.Server)
|
||||
}
|
||||
if remoteOptions.LegacyAddressResolver != "" {
|
||||
dependencies = append(dependencies, remoteOptions.LegacyAddressResolver)
|
||||
}
|
||||
return TransportAdapter{
|
||||
transportType: transportType,
|
||||
|
|
|
@ -19,29 +19,39 @@ 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.NewWithOptions(dialer.Options{
|
||||
Context: ctx,
|
||||
Options: options.DialerOptions,
|
||||
DirectResolver: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func NewRemoteDialer(ctx context.Context, options option.RemoteDNSServerOptions) (N.Dialer, error) {
|
||||
transportDialer, err := NewLocalDialer(ctx, options.LocalDNSServerOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if options.AddressResolver != "" {
|
||||
transport := service.FromContext[adapter.DNSTransportManager](ctx)
|
||||
resolverTransport, loaded := transport.Transport(options.AddressResolver)
|
||||
if !loaded {
|
||||
return nil, E.New("address resolver not found: ", options.AddressResolver)
|
||||
if options.LegacyDefaultDialer {
|
||||
transportDialer := dialer.NewDefaultOutbound(ctx)
|
||||
if options.LegacyAddressResolver != "" {
|
||||
transport := service.FromContext[adapter.DNSTransportManager](ctx)
|
||||
resolverTransport, loaded := transport.Transport(options.LegacyAddressResolver)
|
||||
if !loaded {
|
||||
return nil, E.New("address resolver not found: ", options.LegacyAddressResolver)
|
||||
}
|
||||
transportDialer = newTransportDialer(transportDialer, service.FromContext[adapter.DNSRouter](ctx), resolverTransport, C.DomainStrategy(options.LegacyAddressStrategy), time.Duration(options.LegacyAddressFallbackDelay))
|
||||
} else if options.ServerIsDomain() {
|
||||
return nil, E.New("missing address resolver for server: ", options.Server)
|
||||
}
|
||||
transportDialer = NewTransportDialer(transportDialer, service.FromContext[adapter.DNSRouter](ctx), resolverTransport, C.DomainStrategy(options.AddressStrategy), time.Duration(options.AddressFallbackDelay))
|
||||
} else if M.IsDomainName(options.Server) {
|
||||
return nil, E.New("missing address resolver for server: ", options.Server)
|
||||
return transportDialer, nil
|
||||
} else {
|
||||
return dialer.NewWithOptions(dialer.Options{
|
||||
Context: ctx,
|
||||
Options: options.DialerOptions,
|
||||
RemoteIsDomain: options.ServerIsDomain(),
|
||||
DirectResolver: true,
|
||||
})
|
||||
}
|
||||
return transportDialer, nil
|
||||
}
|
||||
|
||||
type TransportDialer struct {
|
||||
type legacyTransportDialer struct {
|
||||
dialer N.Dialer
|
||||
dnsRouter adapter.DNSRouter
|
||||
transport adapter.DNSTransport
|
||||
|
@ -49,8 +59,8 @@ type TransportDialer struct {
|
|||
fallbackDelay time.Duration
|
||||
}
|
||||
|
||||
func NewTransportDialer(dialer N.Dialer, dnsRouter adapter.DNSRouter, transport adapter.DNSTransport, strategy C.DomainStrategy, fallbackDelay time.Duration) *TransportDialer {
|
||||
return &TransportDialer{
|
||||
func newTransportDialer(dialer N.Dialer, dnsRouter adapter.DNSRouter, transport adapter.DNSTransport, strategy C.DomainStrategy, fallbackDelay time.Duration) *legacyTransportDialer {
|
||||
return &legacyTransportDialer{
|
||||
dialer,
|
||||
dnsRouter,
|
||||
transport,
|
||||
|
@ -59,7 +69,7 @@ func NewTransportDialer(dialer N.Dialer, dnsRouter adapter.DNSRouter, transport
|
|||
}
|
||||
}
|
||||
|
||||
func (d *TransportDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
func (d *legacyTransportDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
if destination.IsIP() {
|
||||
return d.dialer.DialContext(ctx, network, destination)
|
||||
}
|
||||
|
@ -73,7 +83,7 @@ func (d *TransportDialer) DialContext(ctx context.Context, network string, desti
|
|||
return N.DialParallel(ctx, d.dialer, network, destination, addresses, d.strategy == C.DomainStrategyPreferIPv6, d.fallbackDelay)
|
||||
}
|
||||
|
||||
func (d *TransportDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
func (d *legacyTransportDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
if destination.IsIP() {
|
||||
return d.dialer.ListenPacket(ctx, destination)
|
||||
}
|
||||
|
@ -88,6 +98,6 @@ func (d *TransportDialer) ListenPacket(ctx context.Context, destination M.Socksa
|
|||
return conn, err
|
||||
}
|
||||
|
||||
func (d *TransportDialer) Upstream() any {
|
||||
func (d *legacyTransportDialer) Upstream() any {
|
||||
return d.dialer
|
||||
}
|
||||
|
|
|
@ -148,10 +148,11 @@ var OptionTUNGSO = Note{
|
|||
|
||||
var OptionLegacyDNSTransport = Note{
|
||||
Name: "legacy-dns-transport",
|
||||
Description: "legacy DNS transport",
|
||||
Description: "legacy DNS servers",
|
||||
DeprecatedVersion: "1.12.0",
|
||||
ScheduledVersion: "1.14.0",
|
||||
EnvName: "LEGACY_DNS_TRANSPORT",
|
||||
EnvName: "LEGACY_DNS_SERVERS",
|
||||
MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-to-new-dns-server-formats",
|
||||
}
|
||||
|
||||
var OptionLegacyDNSFakeIPOptions = Note{
|
||||
|
@ -159,6 +160,23 @@ var OptionLegacyDNSFakeIPOptions = Note{
|
|||
Description: "legacy DNS fakeip options",
|
||||
DeprecatedVersion: "1.12.0",
|
||||
ScheduledVersion: "1.14.0",
|
||||
MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-to-new-dns-server-formats",
|
||||
}
|
||||
|
||||
var OptionOutboundDNSRuleItem = Note{
|
||||
Name: "outbound-dns-rule-item",
|
||||
Description: "outbound DNS rule item",
|
||||
DeprecatedVersion: "1.12.0",
|
||||
ScheduledVersion: "1.14.0",
|
||||
MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-outbound-dns-rule-items-to-domain-resolver",
|
||||
}
|
||||
|
||||
var OptionMissingDomainResolver = Note{
|
||||
Name: "missing-domain-resolver",
|
||||
Description: "missing `route.default_domain_resolver` or `domain_resolver` in dial fields",
|
||||
DeprecatedVersion: "1.12.0",
|
||||
ScheduledVersion: "1.14.0",
|
||||
MigrationLink: "https://sing-box.sagernet.org/migration/#migrate-outbound-dns-rule-items-to-domain-resolver",
|
||||
}
|
||||
|
||||
var Options = []Note{
|
||||
|
@ -172,4 +190,8 @@ var Options = []Note{
|
|||
OptionWireGuardOutbound,
|
||||
OptionWireGuardGSO,
|
||||
OptionTUNGSO,
|
||||
OptionLegacyDNSTransport,
|
||||
OptionLegacyDNSFakeIPOptions,
|
||||
OptionOutboundDNSRuleItem,
|
||||
OptionMissingDomainResolver,
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/experimental/deprecated"
|
||||
|
@ -121,11 +120,6 @@ func (o *NewDNSServerOptions) Upgrade(ctx context.Context) error {
|
|||
if o.Type != C.DNSTypeLegacy {
|
||||
return nil
|
||||
}
|
||||
defer func() {
|
||||
encoder := json.NewEncoder(os.Stderr)
|
||||
encoder.SetIndent("", " ")
|
||||
encoder.Encode(o)
|
||||
}()
|
||||
options := o.Options.(*LegacyDNSServerOptions)
|
||||
serverURL, _ := url.Parse(options.Address)
|
||||
var serverType string
|
||||
|
@ -139,18 +133,34 @@ func (o *NewDNSServerOptions) Upgrade(ctx context.Context) error {
|
|||
serverType = C.DNSTypeUDP
|
||||
}
|
||||
}
|
||||
remoteOptions := RemoteDNSServerOptions{
|
||||
LocalDNSServerOptions: LocalDNSServerOptions{
|
||||
DialerOptions: DialerOptions{
|
||||
Detour: options.Detour,
|
||||
var remoteOptions RemoteDNSServerOptions
|
||||
if options.Detour == "" {
|
||||
remoteOptions = RemoteDNSServerOptions{
|
||||
LocalDNSServerOptions: LocalDNSServerOptions{
|
||||
LegacyStrategy: options.Strategy,
|
||||
LegacyDefaultDialer: options.Detour == "",
|
||||
LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
|
||||
},
|
||||
LegacyStrategy: options.Strategy,
|
||||
LegacyDefaultDialer: options.Detour == "",
|
||||
LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
|
||||
},
|
||||
AddressResolver: options.AddressResolver,
|
||||
AddressStrategy: options.AddressStrategy,
|
||||
AddressFallbackDelay: options.AddressFallbackDelay,
|
||||
LegacyAddressResolver: options.AddressResolver,
|
||||
LegacyAddressStrategy: options.AddressStrategy,
|
||||
LegacyAddressFallbackDelay: options.AddressFallbackDelay,
|
||||
}
|
||||
} else {
|
||||
remoteOptions = RemoteDNSServerOptions{
|
||||
LocalDNSServerOptions: LocalDNSServerOptions{
|
||||
DialerOptions: DialerOptions{
|
||||
Detour: options.Detour,
|
||||
DomainResolver: &DomainResolveOptions{
|
||||
Server: options.AddressResolver,
|
||||
Strategy: options.AddressStrategy,
|
||||
},
|
||||
FallbackDelay: options.AddressFallbackDelay,
|
||||
},
|
||||
LegacyStrategy: options.Strategy,
|
||||
LegacyDefaultDialer: options.Detour == "",
|
||||
LegacyClientSubnet: options.ClientSubnet.Build(netip.Prefix{}),
|
||||
},
|
||||
}
|
||||
}
|
||||
switch serverType {
|
||||
case C.DNSTypeLocal:
|
||||
|
@ -291,9 +301,9 @@ type LocalDNSServerOptions struct {
|
|||
type RemoteDNSServerOptions struct {
|
||||
LocalDNSServerOptions
|
||||
ServerOptions
|
||||
AddressResolver string `json:"address_resolver,omitempty"`
|
||||
AddressStrategy DomainStrategy `json:"address_strategy,omitempty"`
|
||||
AddressFallbackDelay badoption.Duration `json:"address_fallback_delay,omitempty"`
|
||||
LegacyAddressResolver string `json:"-"`
|
||||
LegacyAddressStrategy DomainStrategy `json:"-"`
|
||||
LegacyAddressFallbackDelay badoption.Duration `json:"-"`
|
||||
}
|
||||
|
||||
type RemoteTLSDNSServerOptions struct {
|
||||
|
|
|
@ -77,12 +77,46 @@ type DialerOptions struct {
|
|||
TCPMultiPath bool `json:"tcp_multi_path,omitempty"`
|
||||
UDPFragment *bool `json:"udp_fragment,omitempty"`
|
||||
UDPFragmentDefault bool `json:"-"`
|
||||
DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"`
|
||||
DomainResolver *DomainResolveOptions `json:"domain_resolver,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"`
|
||||
IsWireGuardListener bool `json:"-"`
|
||||
|
||||
// Deprecated: migrated to domain resolver
|
||||
DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"`
|
||||
}
|
||||
|
||||
type _DomainResolveOptions struct {
|
||||
Server string `json:"server"`
|
||||
Strategy DomainStrategy `json:"strategy,omitempty"`
|
||||
DisableCache bool `json:"disable_cache,omitempty"`
|
||||
RewriteTTL *uint32 `json:"rewrite_ttl,omitempty"`
|
||||
ClientSubnet *badoption.Prefixable `json:"client_subnet,omitempty"`
|
||||
}
|
||||
|
||||
type DomainResolveOptions _DomainResolveOptions
|
||||
|
||||
func (o DomainResolveOptions) MarshalJSON() ([]byte, error) {
|
||||
if o.Strategy == DomainStrategy(C.DomainStrategyAsIS) &&
|
||||
!o.DisableCache &&
|
||||
o.RewriteTTL == nil &&
|
||||
o.ClientSubnet == nil {
|
||||
return json.Marshal(o.Server)
|
||||
} else {
|
||||
return json.Marshal((_DomainResolveOptions)(o))
|
||||
}
|
||||
}
|
||||
|
||||
func (o *DomainResolveOptions) UnmarshalJSON(bytes []byte) error {
|
||||
var stringValue string
|
||||
err := json.Unmarshal(bytes, &stringValue)
|
||||
if err == nil {
|
||||
o.Server = stringValue
|
||||
return nil
|
||||
}
|
||||
return json.Unmarshal(bytes, (*_DomainResolveOptions)(o))
|
||||
}
|
||||
|
||||
func (o *DialerOptions) TakeDialerOptions() DialerOptions {
|
||||
|
@ -107,6 +141,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
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ type RouteOptions struct {
|
|||
OverrideAndroidVPN bool `json:"override_android_vpn,omitempty"`
|
||||
DefaultInterface string `json:"default_interface,omitempty"`
|
||||
DefaultMark FwMark `json:"default_mark,omitempty"`
|
||||
DefaultDomainResolver *DomainResolveOptions `json:"default_domain_resolver,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"`
|
||||
|
|
|
@ -42,16 +42,20 @@ type Outbound struct {
|
|||
|
||||
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) (adapter.Outbound, error) {
|
||||
options.UDPFragmentDefault = true
|
||||
outboundDialer, err := dialer.NewDirect(ctx, options.DialerOptions)
|
||||
if options.Detour != "" {
|
||||
return nil, E.New("`detour` is not supported in direct context")
|
||||
}
|
||||
outboundDialer, err := dialer.New(ctx, options.DialerOptions, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outbound := &Outbound{
|
||||
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions),
|
||||
logger: logger,
|
||||
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions),
|
||||
logger: logger,
|
||||
//nolint:staticcheck
|
||||
domainStrategy: C.DomainStrategy(options.DomainStrategy),
|
||||
fallbackDelay: time.Duration(options.FallbackDelay),
|
||||
dialer: outboundDialer,
|
||||
dialer: outboundDialer.(dialer.ParallelInterfaceDialer),
|
||||
// loopBack: newLoopBackDetector(router),
|
||||
}
|
||||
//nolint:staticcheck
|
||||
|
|
|
@ -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,14 @@ 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.NewWithOptions(dialer.Options{
|
||||
Context: ctx,
|
||||
Options: options.DialerOptions,
|
||||
RemoteIsDomain: common.Any(options.Peers, func(it option.WireGuardPeer) bool {
|
||||
return !M.ParseAddr(it.Address).IsValid()
|
||||
}),
|
||||
ResolverOnDetour: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -81,9 +88,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
PrivateKey: options.PrivateKey,
|
||||
ListenPort: options.ListenPort,
|
||||
ResolvePeer: func(domain string) (netip.Addr, error) {
|
||||
endpointAddresses, lookupErr := ep.dnsRouter.Lookup(ctx, domain, adapter.DNSQueryOptions{
|
||||
Strategy: C.DomainStrategy(options.DomainStrategy),
|
||||
})
|
||||
endpointAddresses, lookupErr := ep.dnsRouter.Lookup(ctx, domain, outboundDialer.(dialer.ResolveDialer).QueryOptions())
|
||||
if lookupErr != nil {
|
||||
return netip.Addr{}, lookupErr
|
||||
}
|
||||
|
|
|
@ -56,7 +56,14 @@ 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.NewWithOptions(dialer.Options{
|
||||
Context: ctx,
|
||||
Options: options.DialerOptions,
|
||||
RemoteIsDomain: options.ServerIsDomain() || common.Any(options.Peers, func(it option.LegacyWireGuardPeer) bool {
|
||||
return it.ServerIsDomain()
|
||||
}),
|
||||
ResolverOnDetour: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -94,9 +101,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||
Address: options.LocalAddress,
|
||||
PrivateKey: options.PrivateKey,
|
||||
ResolvePeer: func(domain string) (netip.Addr, error) {
|
||||
endpointAddresses, lookupErr := outbound.dnsRouter.Lookup(ctx, domain, adapter.DNSQueryOptions{
|
||||
Strategy: C.DomainStrategy(options.DomainStrategy),
|
||||
})
|
||||
endpointAddresses, lookupErr := outbound.dnsRouter.Lookup(ctx, domain, outboundDialer.(dialer.ResolveDialer).QueryOptions())
|
||||
if lookupErr != nil {
|
||||
return netip.Addr{}, lookupErr
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -55,13 +56,21 @@ type NetworkManager struct {
|
|||
}
|
||||
|
||||
func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, routeOptions option.RouteOptions) (*NetworkManager, error) {
|
||||
defaultDomainResolver := common.PtrValueOrDefault(routeOptions.DefaultDomainResolver)
|
||||
nm := &NetworkManager{
|
||||
logger: logger,
|
||||
interfaceFinder: control.NewDefaultInterfaceFinder(),
|
||||
autoDetectInterface: routeOptions.AutoDetectInterface,
|
||||
defaultOptions: adapter.NetworkOptions{
|
||||
BindInterface: routeOptions.DefaultInterface,
|
||||
RoutingMark: uint32(routeOptions.DefaultMark),
|
||||
BindInterface: routeOptions.DefaultInterface,
|
||||
RoutingMark: uint32(routeOptions.DefaultMark),
|
||||
DomainResolver: defaultDomainResolver.Server,
|
||||
DomainResolveOptions: adapter.DNSQueryOptions{
|
||||
Strategy: C.DomainStrategy(defaultDomainResolver.Strategy),
|
||||
DisableCache: defaultDomainResolver.DisableCache,
|
||||
RewriteTTL: defaultDomainResolver.RewriteTTL,
|
||||
ClientSubnet: defaultDomainResolver.ClientSubnet.Build(netip.Prefix{}),
|
||||
},
|
||||
NetworkStrategy: (*C.NetworkStrategy)(routeOptions.DefaultNetworkStrategy),
|
||||
NetworkType: common.Map(routeOptions.DefaultNetworkType, option.InterfaceType.Build),
|
||||
FallbackNetworkType: common.Map(routeOptions.DefaultFallbackNetworkType, option.InterfaceType.Build),
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -210,7 +210,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…
Add table
Reference in a new issue