mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-09-25 01:10:30 +00:00
108 lines
3.6 KiB
Go
108 lines
3.6 KiB
Go
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"
|
|
"github.com/sagernet/sing-box/dns/transport/local/systemconfig"
|
|
E "github.com/sagernet/sing/common/exceptions"
|
|
|
|
mDNS "github.com/miekg/dns"
|
|
)
|
|
|
|
type localServerSet struct {
|
|
config *systemconfig.Config
|
|
transports []adapter.DNSTransport
|
|
}
|
|
|
|
func (s *localServerSet) Close() {
|
|
for _, serverTransport := range s.transports {
|
|
serverTransport.Close()
|
|
}
|
|
}
|
|
|
|
func (t *Transport) serverSetFor(systemConfig *systemconfig.Config) (*localServerSet, error) {
|
|
serverSet := t.serverSet.Load()
|
|
if serverSet != nil && serverSet.config == systemConfig {
|
|
return serverSet, nil
|
|
}
|
|
t.serverSetAccess.Lock()
|
|
defer t.serverSetAccess.Unlock()
|
|
serverSet = t.serverSet.Load()
|
|
if serverSet != nil && serverSet.config == systemConfig {
|
|
return serverSet, nil
|
|
}
|
|
transports := make([]adapter.DNSTransport, 0, len(systemConfig.Servers))
|
|
for _, serverAddr := range systemConfig.Servers {
|
|
var serverTransport adapter.DNSTransport
|
|
if systemConfig.UseTCP {
|
|
serverTransport = transport.NewTCPRaw(dns.NewTransportAdapter(C.DNSTypeTCP, "", nil), t.dialer, serverAddr)
|
|
} else {
|
|
serverTransport = transport.NewUDPRaw(t.logger, dns.NewTransportAdapter(C.DNSTypeUDP, "", nil), t.dialer, serverAddr)
|
|
}
|
|
err := serverTransport.Start(adapter.StartStateStart)
|
|
if err != nil {
|
|
for _, startedTransport := range transports {
|
|
startedTransport.Close()
|
|
}
|
|
return nil, E.Cause(err, "initialize transport for ", serverAddr)
|
|
}
|
|
transports = append(transports, serverTransport)
|
|
}
|
|
newServerSet := &localServerSet{
|
|
config: systemConfig,
|
|
transports: transports,
|
|
}
|
|
oldServerSet := t.serverSet.Swap(newServerSet)
|
|
if oldServerSet != nil {
|
|
oldServerSet.Close()
|
|
}
|
|
return newServerSet, nil
|
|
}
|
|
|
|
func (t *Transport) exchangeAsync(ctx context.Context, message *mDNS.Msg, domain string, callback func(response *mDNS.Msg, err error)) {
|
|
systemConfig := t.configSource.Configuration()
|
|
serverSet, err := t.serverSetFor(systemConfig)
|
|
if err != nil {
|
|
callback(nil, err)
|
|
return
|
|
}
|
|
names := systemConfig.NameList(domain)
|
|
if len(names) == 0 {
|
|
callback(nil, E.New("invalid domain: ", domain))
|
|
return
|
|
}
|
|
transport.ExchangeNames(ctx, names, message.Question[0], func(fqdn string) transport.AsyncExchanger {
|
|
return newNameExchanger(systemConfig, serverSet, message, fqdn)
|
|
}, callback)
|
|
}
|
|
|
|
func newNameExchanger(systemConfig *systemconfig.Config, serverSet *localServerSet, message *mDNS.Msg, fqdn string) transport.AsyncExchanger {
|
|
serverOffset := systemConfig.ServerOffset()
|
|
serverCount := uint32(len(serverSet.transports))
|
|
attemptExchangers := make([]transport.AsyncExchanger, 0, systemConfig.Attempts*int(serverCount))
|
|
for i := 0; i < systemConfig.Attempts; i++ {
|
|
for j := range serverCount {
|
|
serverTransport := serverSet.transports[(serverOffset+j)%serverCount]
|
|
attemptExchangers = append(attemptExchangers, func(ctx context.Context, callback func(response *mDNS.Msg, err error)) {
|
|
attemptCtx, cancel := context.WithTimeout(ctx, systemConfig.Timeout)
|
|
serverTransport.ExchangeAsync(attemptCtx, transport.NewFanOutRequest(message, fqdn, systemConfig.TrustAD), func(response *mDNS.Msg, err error) {
|
|
cancel()
|
|
callback(response, err)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
return func(ctx context.Context, callback func(response *mDNS.Msg, err error)) {
|
|
transport.ExchangeSequential(ctx, attemptExchangers, nil, func(response *mDNS.Msg, err error) {
|
|
if err != nil {
|
|
err = E.Cause(err, fqdn)
|
|
}
|
|
callback(response, err)
|
|
})
|
|
}
|
|
}
|