package transport import ( "context" "net" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/dialer" "github.com/sagernet/sing-box/common/tls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/dns" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing/common" E "github.com/sagernet/sing/common/exceptions" "github.com/sagernet/sing/common/logger" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" mDNS "github.com/miekg/dns" ) var _ adapter.DNSTransport = (*TLSTransport)(nil) func RegisterTLS(registry *dns.TransportRegistry) { dns.RegisterTransport[option.RemoteTLSDNSServerOptions](registry, C.DNSTypeTLS, NewTLS) } type TLSTransport struct { dns.TransportAdapter logger logger.ContextLogger dialer tls.Dialer serverAddr M.Socksaddr multiplexer *queryMultiplexer } func NewTLS(ctx context.Context, logger log.ContextLogger, tag string, options option.RemoteTLSDNSServerOptions) (adapter.DNSTransport, error) { transportDialer, err := dns.NewRemoteDialer(ctx, options.RemoteDNSServerOptions) if err != nil { return nil, err } tlsOptions := common.PtrValueOrDefault(options.TLS) tlsOptions.Enabled = true tlsConfig, err := tls.NewClient(ctx, logger, options.Server, tlsOptions) if err != nil { return nil, err } serverAddr := options.DNSServerAddressOptions.Build() if serverAddr.Port == 0 { serverAddr.Port = 853 } if !serverAddr.IsValid() { return nil, E.New("invalid server address: ", serverAddr) } return NewTLSRaw(logger, dns.NewTransportAdapterWithRemoteOptions(C.DNSTypeTLS, tag, options.RemoteDNSServerOptions), transportDialer, serverAddr, tlsConfig), nil } func NewTLSRaw(logger logger.ContextLogger, adapter dns.TransportAdapter, dialer N.Dialer, serverAddr M.Socksaddr, tlsConfig tls.Config) *TLSTransport { t := &TLSTransport{ TransportAdapter: adapter, logger: logger, dialer: tls.NewDialer(dialer, tlsConfig), serverAddr: serverAddr, } t.multiplexer = newQueryMultiplexer(queryMultiplexerOptions{ dial: func(ctx context.Context) (net.Conn, error) { conn, err := t.dialer.DialTLSContext(ctx, t.serverAddr) if err != nil { return nil, E.Cause(err, "dial TLS connection") } return conn, nil }, write: func(conn net.Conn, message *mDNS.Msg, queryId uint16) error { return WriteMessage(conn, queryId, message) }, readNext: func(conn net.Conn) (*mDNS.Msg, error) { return ReadMessage(conn) }, retryReadError: true, probeReuse: true, }) return t } func (t *TLSTransport) Start(stage adapter.StartStage) error { if stage != adapter.StartStateStart { return nil } return dialer.InitializeDetour(t.dialer) } func (t *TLSTransport) Close() error { return t.multiplexer.Close() } func (t *TLSTransport) Reset() { t.multiplexer.Reset() } func (t *TLSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { return t.multiplexer.Exchange(ctx, message) } func (t *TLSTransport) ExchangeAsync(ctx context.Context, message *mDNS.Msg, callback func(response *mDNS.Msg, err error)) { t.multiplexer.ExchangeAsync(ctx, message, callback) }