|
@@ -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
|
|
|
}
|