Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 22 additions & 47 deletions dns/transport/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/dns"
"github.com/sagernet/sing-box/dns/transport/hosts"
"github.com/sagernet/sing-box/dns/transport/mdns"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
Expand All @@ -33,21 +32,18 @@ var (

type Transport struct {
dns.TransportAdapter
ctx context.Context
logger logger.ContextLogger
hosts *hosts.File
dialer N.Dialer
preferGo bool
fallback bool
resolved ResolvedResolver
mdnsTransport adapter.DNSTransport
dhcpTransport dhcpTransport
system systemResolver
serverSet atomic.Pointer[localServerSet]
serverSetAccess sync.Mutex

neighborResolver adapter.NeighborResolver
neighborSuffixes []string
ctx context.Context
logger logger.ContextLogger
preferredResolver *PreferredDomainResolver
dialer N.Dialer
preferGo bool
fallback bool
resolved ResolvedResolver
mdnsTransport adapter.DNSTransport
dhcpTransport dhcpTransport
system systemResolver
serverSet atomic.Pointer[localServerSet]
serverSetAccess sync.Mutex
}

type dhcpTransport interface {
Expand All @@ -60,29 +56,24 @@ func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, opt
if err != nil {
return nil, err
}
suffixes, err := buildNeighborMatchers(options.NeighborDomain)
preferredResolver, err := NewPreferredDomainResolver(ctx, logger, options)
if err != nil {
return nil, err
}
return &Transport{
TransportAdapter: dns.NewTransportAdapterWithLocalOptions(C.DNSTypeLocal, tag, options),
ctx: ctx,
logger: logger,
dialer: transportDialer,
preferGo: options.PreferGo,
neighborSuffixes: suffixes,
TransportAdapter: dns.NewTransportAdapterWithLocalOptions(C.DNSTypeLocal, tag, options),
ctx: ctx,
logger: logger,
preferredResolver: preferredResolver,
dialer: transportDialer,
preferGo: options.PreferGo,
}, nil
}

func (t *Transport) Start(stage adapter.StartStage) error {
t.preferredResolver.Start(stage)
switch stage {
case adapter.StartStateInitialize:
defaultHosts, err := hosts.NewDefault()
if err != nil {
t.logger.Warn(err)
} else {
t.hosts = defaultHosts
}
if !t.preferGo && isSystemdResolvedManaged() {
resolvedResolver, err := NewResolvedResolver(t.ctx, t.logger)
if err == nil {
Expand All @@ -109,10 +100,6 @@ func (t *Transport) Start(stage adapter.StartStage) error {
} else {
t.mdnsTransport = mdns.NewRawTransport(t.TransportAdapter, t.ctx, t.logger)
}
router := service.FromContext[adapter.Router](t.ctx)
if router != nil {
t.neighborResolver = router.NeighborResolver()
}
fallthrough
default:
if t.dhcpTransport != nil {
Expand Down Expand Up @@ -160,12 +147,7 @@ func (t *Transport) Reset() {
}

func (t *Transport) PreferredDomain(domain string) bool {
if t.hosts != nil {
if len(t.hosts.Lookup(dns.FqdnToDomain(domain))) > 0 {
return true
}
}
return t.hasNeighborHost(domain) || mdns.IsLocalDomain(domain)
return t.preferredResolver.PreferredDomain(domain)
}

func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
Expand All @@ -185,14 +167,7 @@ func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg,

func (t *Transport) ExchangeAsync(ctx context.Context, message *mDNS.Msg, callback func(response *mDNS.Msg, err error)) {
question := message.Question[0]
if t.hosts != nil && (question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA) {
addresses := t.hosts.Lookup(dns.FqdnToDomain(question.Name))
if len(addresses) > 0 {
callback(dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil)
return
}
}
response := t.lookupNeighbor(message)
response := t.preferredResolver.Lookup(message)
if response != nil {
callback(response, nil)
return
Expand Down
16 changes: 8 additions & 8 deletions dns/transport/local/local_neighbor.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,34 +24,34 @@ func buildNeighborMatchers(domains []string) ([]string, error) {
return suffixes, nil
}

func (t *Transport) lookupNeighbor(message *mDNS.Msg) *mDNS.Msg {
if t.neighborResolver == nil {
func (r *PreferredDomainResolver) lookupNeighbor(message *mDNS.Msg) *mDNS.Msg {
if r.neighborResolver == nil {
return nil
}
question := message.Question[0]
if question.Qtype != mDNS.TypeA && question.Qtype != mDNS.TypeAAAA {
return nil
}
host := extractNeighborHost(mDNS.CanonicalName(question.Name), t.neighborSuffixes)
host := extractNeighborHost(mDNS.CanonicalName(question.Name), r.neighborSuffixes)
if host == "" {
return nil
}
addresses := t.neighborResolver.LookupAddresses(host)
addresses := r.neighborResolver.LookupAddresses(host)
if len(addresses) == 0 {
return nil
}
return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL)
}

func (t *Transport) hasNeighborHost(domain string) bool {
if t.neighborResolver == nil {
func (r *PreferredDomainResolver) hasNeighborHost(domain string) bool {
if r.neighborResolver == nil {
return false
}
host := extractNeighborHost(domain, t.neighborSuffixes)
host := extractNeighborHost(domain, r.neighborSuffixes)
if host == "" {
return false
}
return len(t.neighborResolver.LookupAddresses(host)) > 0
return len(r.neighborResolver.LookupAddresses(host)) > 0
}

func extractNeighborHost(canonical string, suffixes []string) string {
Expand Down
76 changes: 76 additions & 0 deletions dns/transport/local/local_preferred.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package local

import (
"context"

"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/dns"
"github.com/sagernet/sing-box/dns/transport/hosts"
"github.com/sagernet/sing-box/dns/transport/mdns"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/logger"
"github.com/sagernet/sing/service"

mDNS "github.com/miekg/dns"
)

type PreferredDomainResolver struct {
ctx context.Context
logger logger.ContextLogger
hosts *hosts.File
neighborResolver adapter.NeighborResolver
neighborSuffixes []string
}

func NewPreferredDomainResolver(ctx context.Context, contextLogger logger.ContextLogger, options option.LocalDNSServerOptions) (*PreferredDomainResolver, error) {
suffixes, err := buildNeighborMatchers(options.NeighborDomain)
if err != nil {
return nil, err
}
return &PreferredDomainResolver{
ctx: ctx,
logger: contextLogger,
neighborSuffixes: suffixes,
}, nil
}

func (r *PreferredDomainResolver) Start(stage adapter.StartStage) {
switch stage {
case adapter.StartStateInitialize:
defaultHosts, err := hosts.NewDefault()
if err != nil {
r.logger.Warn(err)
} else {
r.hosts = defaultHosts
}
case adapter.StartStateStart:
router := service.FromContext[adapter.Router](r.ctx)
if router != nil {
r.neighborResolver = router.NeighborResolver()
}
}
}

func (r *PreferredDomainResolver) PreferredDomain(domain string) bool {
if r.hosts != nil {
if len(r.hosts.Lookup(dns.FqdnToDomain(domain))) > 0 {
return true
}
}
return r.hasNeighborHost(domain) || mdns.IsLocalDomain(domain)
}

func (r *PreferredDomainResolver) Lookup(message *mDNS.Msg) *mDNS.Msg {
question := message.Question[0]
if question.Qtype != mDNS.TypeA && question.Qtype != mDNS.TypeAAAA {
return nil
}
if r.hosts != nil {
addresses := r.hosts.Lookup(dns.FqdnToDomain(question.Name))
if len(addresses) > 0 {
return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL)
}
}
return r.lookupNeighbor(message)
}
2 changes: 1 addition & 1 deletion experimental/libbox/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func baseContext(platformInterface PlatformInterface) context.Context {
if platformInterface != nil {
if localTransport := platformInterface.LocalDNSTransport(); localTransport != nil {
dns.RegisterTransport[option.LocalDNSServerOptions](dnsRegistry, C.DNSTypeLocal, func(ctx context.Context, logger log.ContextLogger, tag string, options option.LocalDNSServerOptions) (adapter.DNSTransport, error) {
return newPlatformTransport(localTransport, tag, options), nil
return newPlatformTransport(ctx, logger, localTransport, tag, options)
})
}
}
Expand Down
34 changes: 27 additions & 7 deletions experimental/libbox/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/dns"
"github.com/sagernet/sing-box/dns/transport/local"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
Expand All @@ -23,21 +25,26 @@ type LocalDNSTransport interface {
Exchange(ctx *ExchangeContext, message []byte) error
}

var _ adapter.DNSTransport = (*platformTransport)(nil)

type platformTransport struct {
dns.TransportAdapter
iif LocalDNSTransport
iif LocalDNSTransport
preferredResolver *local.PreferredDomainResolver
}

func newPlatformTransport(iif LocalDNSTransport, tag string, options option.LocalDNSServerOptions) *platformTransport {
return &platformTransport{
TransportAdapter: dns.NewTransportAdapterWithLocalOptions(C.DNSTypeLocal, tag, options),
iif: iif,
func newPlatformTransport(ctx context.Context, logger log.ContextLogger, iif LocalDNSTransport, tag string, options option.LocalDNSServerOptions) (*platformTransport, error) {
preferredResolver, err := local.NewPreferredDomainResolver(ctx, logger, options)
if err != nil {
return nil, err
}
return &platformTransport{
TransportAdapter: dns.NewTransportAdapterWithLocalOptions(C.DNSTypeLocal, tag, options),
iif: iif,
preferredResolver: preferredResolver,
}, nil
}

func (p *platformTransport) Start(stage adapter.StartStage) error {
p.preferredResolver.Start(stage)
return nil
}

Expand All @@ -48,7 +55,15 @@ func (p *platformTransport) Close() error {
func (p *platformTransport) Reset() {
}

func (p *platformTransport) PreferredDomain(domain string) bool {
return p.preferredResolver.PreferredDomain(domain)
}

func (p *platformTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
localResponse := p.preferredResolver.Lookup(message)
if localResponse != nil {
return localResponse, nil
}
response := &ExchangeContext{
context: ctx,
}
Expand Down Expand Up @@ -151,3 +166,8 @@ func (c *ExchangeContext) ErrorCode(code int32) {
func (c *ExchangeContext) ErrnoCode(code int32) {
c.error = syscall.Errno(code)
}

var (
_ adapter.DNSTransport = (*platformTransport)(nil)
_ adapter.DNSTransportWithPreferredDomain = (*platformTransport)(nil)
)