修复DNS逻辑错误的问题
This commit is contained in:
@@ -39,13 +39,42 @@ type DNSQueryOptions struct {
|
||||
ClientSubnet netip.Prefix
|
||||
}
|
||||
|
||||
func LookupDNSTransport(manager DNSTransportManager, reference string) (DNSTransport, bool, bool) {
|
||||
transport, loaded := manager.Transport(reference)
|
||||
if loaded {
|
||||
return transport, true, false
|
||||
}
|
||||
switch reference {
|
||||
case C.DNSTypeLocal, C.DNSTypeFakeIP:
|
||||
default:
|
||||
return nil, false, false
|
||||
}
|
||||
var matchedTransport DNSTransport
|
||||
for _, transport := range manager.Transports() {
|
||||
if transport.Type() != reference {
|
||||
continue
|
||||
}
|
||||
if matchedTransport != nil {
|
||||
return nil, false, true
|
||||
}
|
||||
matchedTransport = transport
|
||||
}
|
||||
if matchedTransport != nil {
|
||||
return matchedTransport, true, false
|
||||
}
|
||||
return nil, false, false
|
||||
}
|
||||
|
||||
func DNSQueryOptionsFrom(ctx context.Context, options *option.DomainResolveOptions) (*DNSQueryOptions, error) {
|
||||
if options == nil {
|
||||
return &DNSQueryOptions{}, nil
|
||||
}
|
||||
transportManager := service.FromContext[DNSTransportManager](ctx)
|
||||
transport, loaded := transportManager.Transport(options.Server)
|
||||
transport, loaded, ambiguous := LookupDNSTransport(transportManager, options.Server)
|
||||
if !loaded {
|
||||
if ambiguous {
|
||||
return nil, E.New("domain resolver is ambiguous: " + options.Server)
|
||||
}
|
||||
return nil, E.New("domain resolver not found: " + options.Server)
|
||||
}
|
||||
return &DNSQueryOptions{
|
||||
|
||||
122
adapter/dns.go.834007539997830043
Normal file
122
adapter/dns.go.834007539997830043
Normal file
@@ -0,0 +1,122 @@
|
||||
package adapter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
type DNSRouter interface {
|
||||
Lifecycle
|
||||
Exchange(ctx context.Context, message *dns.Msg, options DNSQueryOptions) (*dns.Msg, error)
|
||||
Lookup(ctx context.Context, domain string, options DNSQueryOptions) ([]netip.Addr, error)
|
||||
ClearCache()
|
||||
LookupReverseMapping(ip netip.Addr) (string, bool)
|
||||
ResetNetwork()
|
||||
}
|
||||
|
||||
type DNSClient interface {
|
||||
Start()
|
||||
Exchange(ctx context.Context, transport DNSTransport, message *dns.Msg, options DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) (*dns.Msg, error)
|
||||
Lookup(ctx context.Context, transport DNSTransport, domain string, options DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) ([]netip.Addr, error)
|
||||
ClearCache()
|
||||
}
|
||||
|
||||
type DNSQueryOptions struct {
|
||||
Transport DNSTransport
|
||||
Strategy C.DomainStrategy
|
||||
LookupStrategy C.DomainStrategy
|
||||
DisableCache bool
|
||||
RewriteTTL *uint32
|
||||
ClientSubnet netip.Prefix
|
||||
}
|
||||
|
||||
func LookupDNSTransport(manager DNSTransportManager, reference string) (DNSTransport, bool, bool) {
|
||||
transport, loaded := manager.Transport(reference)
|
||||
if loaded {
|
||||
return transport, true, false
|
||||
}
|
||||
switch reference {
|
||||
case C.DNSTypeLocal, C.DNSTypeFakeIP:
|
||||
default:
|
||||
return nil, false, false
|
||||
}
|
||||
var matchedTransport DNSTransport
|
||||
for _, transport := range manager.Transports() {
|
||||
if transport.Type() != reference {
|
||||
continue
|
||||
}
|
||||
if matchedTransport != nil {
|
||||
return nil, false, true
|
||||
}
|
||||
matchedTransport = transport
|
||||
}
|
||||
if matchedTransport != nil {
|
||||
return matchedTransport, true, false
|
||||
}
|
||||
return nil, false, false
|
||||
}
|
||||
|
||||
func DNSQueryOptionsFrom(ctx context.Context, options *option.DomainResolveOptions) (*DNSQueryOptions, error) {
|
||||
if options == nil {
|
||||
return &DNSQueryOptions{}, nil
|
||||
}
|
||||
transportManager := service.FromContext[DNSTransportManager](ctx)
|
||||
transport, loaded, ambiguous := LookupDNSTransport(transportManager, options.Server)
|
||||
if !loaded {
|
||||
if ambiguous {
|
||||
return nil, E.New("domain resolver is ambiguous: " + options.Server)
|
||||
}
|
||||
return nil, E.New("domain resolver not found: " + options.Server)
|
||||
}
|
||||
return &DNSQueryOptions{
|
||||
Transport: transport,
|
||||
Strategy: C.DomainStrategy(options.Strategy),
|
||||
DisableCache: options.DisableCache,
|
||||
RewriteTTL: options.RewriteTTL,
|
||||
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
|
||||
SaveRDRCAsync(transportName string, qName string, qType uint16, logger logger.Logger)
|
||||
}
|
||||
|
||||
type DNSTransport interface {
|
||||
Lifecycle
|
||||
Type() string
|
||||
Tag() string
|
||||
Dependencies() []string
|
||||
Reset()
|
||||
Exchange(ctx context.Context, message *dns.Msg) (*dns.Msg, error)
|
||||
}
|
||||
|
||||
type LegacyDNSTransport interface {
|
||||
LegacyStrategy() C.DomainStrategy
|
||||
LegacyClientSubnet() netip.Prefix
|
||||
}
|
||||
|
||||
type DNSTransportRegistry interface {
|
||||
option.DNSTransportOptionsRegistry
|
||||
CreateDNSTransport(ctx context.Context, logger log.ContextLogger, tag string, transportType string, options any) (DNSTransport, error)
|
||||
}
|
||||
|
||||
type DNSTransportManager interface {
|
||||
Lifecycle
|
||||
Transports() []DNSTransport
|
||||
Transport(tag string) (DNSTransport, bool)
|
||||
Default() DNSTransport
|
||||
FakeIP() FakeIPTransport
|
||||
Remove(tag string) error
|
||||
Create(ctx context.Context, logger log.ContextLogger, tag string, outboundType string, options any) error
|
||||
}
|
||||
137
adapter/dns_test.go
Normal file
137
adapter/dns_test.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package adapter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
)
|
||||
|
||||
type testDNSTransport struct {
|
||||
transportType string
|
||||
tag string
|
||||
}
|
||||
|
||||
func (t *testDNSTransport) Start(stage StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *testDNSTransport) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *testDNSTransport) Type() string {
|
||||
return t.transportType
|
||||
}
|
||||
|
||||
func (t *testDNSTransport) Tag() string {
|
||||
return t.tag
|
||||
}
|
||||
|
||||
func (t *testDNSTransport) Dependencies() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *testDNSTransport) Reset() {
|
||||
}
|
||||
|
||||
func (t *testDNSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type testDNSTransportManager struct {
|
||||
transports []DNSTransport
|
||||
transportByTag map[string]DNSTransport
|
||||
fakeIPTransport FakeIPTransport
|
||||
}
|
||||
|
||||
func newTestDNSTransportManager(transports ...DNSTransport) *testDNSTransportManager {
|
||||
manager := &testDNSTransportManager{
|
||||
transports: transports,
|
||||
transportByTag: make(map[string]DNSTransport),
|
||||
}
|
||||
for _, transport := range transports {
|
||||
manager.transportByTag[transport.Tag()] = transport
|
||||
}
|
||||
return manager
|
||||
}
|
||||
|
||||
func (m *testDNSTransportManager) Start(stage StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *testDNSTransportManager) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *testDNSTransportManager) Transports() []DNSTransport {
|
||||
return m.transports
|
||||
}
|
||||
|
||||
func (m *testDNSTransportManager) Transport(tag string) (DNSTransport, bool) {
|
||||
transport, loaded := m.transportByTag[tag]
|
||||
return transport, loaded
|
||||
}
|
||||
|
||||
func (m *testDNSTransportManager) Default() DNSTransport {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *testDNSTransportManager) FakeIP() FakeIPTransport {
|
||||
return m.fakeIPTransport
|
||||
}
|
||||
|
||||
func (m *testDNSTransportManager) Remove(tag string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *testDNSTransportManager) Create(ctx context.Context, logger log.ContextLogger, tag string, outboundType string, options any) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestLookupDNSTransportLocalAlias(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localTransport := &testDNSTransport{
|
||||
transportType: "local",
|
||||
tag: "dns-local",
|
||||
}
|
||||
manager := newTestDNSTransportManager(localTransport)
|
||||
|
||||
transport, loaded, ambiguous := LookupDNSTransport(manager, "local")
|
||||
require.True(t, loaded)
|
||||
require.False(t, ambiguous)
|
||||
require.Same(t, localTransport, transport)
|
||||
}
|
||||
|
||||
func TestLookupDNSTransportExactTagPreferred(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
localTransport := &testDNSTransport{
|
||||
transportType: "local",
|
||||
tag: "local",
|
||||
}
|
||||
manager := newTestDNSTransportManager(localTransport)
|
||||
|
||||
transport, loaded, ambiguous := LookupDNSTransport(manager, "local")
|
||||
require.True(t, loaded)
|
||||
require.False(t, ambiguous)
|
||||
require.Same(t, localTransport, transport)
|
||||
}
|
||||
|
||||
func TestLookupDNSTransportLocalAliasAmbiguous(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
manager := newTestDNSTransportManager(
|
||||
&testDNSTransport{transportType: "local", tag: "dns-local-a"},
|
||||
&testDNSTransport{transportType: "local", tag: "dns-local-b"},
|
||||
)
|
||||
|
||||
transport, loaded, ambiguous := LookupDNSTransport(manager, "local")
|
||||
require.Nil(t, transport)
|
||||
require.False(t, loaded)
|
||||
require.True(t, ambiguous)
|
||||
}
|
||||
Reference in New Issue
Block a user