local_darwin.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. //go:build darwin
  2. package local
  3. import (
  4. "context"
  5. "errors"
  6. "net"
  7. "github.com/sagernet/sing-box/adapter"
  8. C "github.com/sagernet/sing-box/constant"
  9. "github.com/sagernet/sing-box/dns"
  10. "github.com/sagernet/sing-box/dns/transport/hosts"
  11. "github.com/sagernet/sing-box/log"
  12. "github.com/sagernet/sing-box/option"
  13. "github.com/sagernet/sing/common"
  14. E "github.com/sagernet/sing/common/exceptions"
  15. "github.com/sagernet/sing/common/logger"
  16. M "github.com/sagernet/sing/common/metadata"
  17. N "github.com/sagernet/sing/common/network"
  18. "github.com/sagernet/sing/service"
  19. mDNS "github.com/miekg/dns"
  20. )
  21. func RegisterTransport(registry *dns.TransportRegistry) {
  22. dns.RegisterTransport[option.LocalDNSServerOptions](registry, C.DNSTypeLocal, NewTransport)
  23. }
  24. var _ adapter.DNSTransport = (*Transport)(nil)
  25. type Transport struct {
  26. dns.TransportAdapter
  27. ctx context.Context
  28. logger logger.ContextLogger
  29. hosts *hosts.File
  30. dialer N.Dialer
  31. preferGo bool
  32. fallback bool
  33. dhcpTransport dhcpTransport
  34. resolver net.Resolver
  35. }
  36. type dhcpTransport interface {
  37. adapter.DNSTransport
  38. Fetch() ([]M.Socksaddr, error)
  39. Exchange0(ctx context.Context, message *mDNS.Msg, servers []M.Socksaddr) (*mDNS.Msg, error)
  40. }
  41. func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.LocalDNSServerOptions) (adapter.DNSTransport, error) {
  42. transportDialer, err := dns.NewLocalDialer(ctx, options)
  43. if err != nil {
  44. return nil, err
  45. }
  46. transportAdapter := dns.NewTransportAdapterWithLocalOptions(C.DNSTypeLocal, tag, options)
  47. return &Transport{
  48. TransportAdapter: transportAdapter,
  49. ctx: ctx,
  50. logger: logger,
  51. hosts: hosts.NewFile(hosts.DefaultPath),
  52. dialer: transportDialer,
  53. preferGo: options.PreferGo,
  54. }, nil
  55. }
  56. func (t *Transport) Start(stage adapter.StartStage) error {
  57. if stage != adapter.StartStateStart {
  58. return nil
  59. }
  60. inboundManager := service.FromContext[adapter.InboundManager](t.ctx)
  61. for _, inbound := range inboundManager.Inbounds() {
  62. if inbound.Type() == C.TypeTun {
  63. t.fallback = true
  64. break
  65. }
  66. }
  67. if t.fallback {
  68. t.dhcpTransport = newDHCPTransport(t.TransportAdapter, log.ContextWithOverrideLevel(t.ctx, log.LevelDebug), t.dialer, t.logger)
  69. if t.dhcpTransport != nil {
  70. err := t.dhcpTransport.Start(stage)
  71. if err != nil {
  72. return err
  73. }
  74. }
  75. }
  76. return nil
  77. }
  78. func (t *Transport) Close() error {
  79. return common.Close(
  80. t.dhcpTransport,
  81. )
  82. }
  83. func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
  84. question := message.Question[0]
  85. domain := dns.FqdnToDomain(question.Name)
  86. if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA {
  87. addresses := t.hosts.Lookup(domain)
  88. if len(addresses) > 0 {
  89. return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil
  90. }
  91. }
  92. if !t.fallback {
  93. return t.exchange(ctx, message, domain)
  94. }
  95. if t.dhcpTransport != nil {
  96. dhcpTransports, _ := t.dhcpTransport.Fetch()
  97. if len(dhcpTransports) > 0 {
  98. return t.dhcpTransport.Exchange0(ctx, message, dhcpTransports)
  99. }
  100. }
  101. if t.preferGo {
  102. // Assuming the user knows what they are doing, we still execute the query which will fail.
  103. return t.exchange(ctx, message, domain)
  104. }
  105. if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA {
  106. var network string
  107. if question.Qtype == mDNS.TypeA {
  108. network = "ip4"
  109. } else {
  110. network = "ip6"
  111. }
  112. addresses, err := t.resolver.LookupNetIP(ctx, network, domain)
  113. if err != nil {
  114. var dnsError *net.DNSError
  115. if errors.As(err, &dnsError) && dnsError.IsNotFound {
  116. return nil, dns.RcodeRefused
  117. }
  118. return nil, err
  119. }
  120. return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil
  121. }
  122. return nil, E.New("only A and AAAA queries are supported on Apple platforms when using TUN and DHCP unavailable.")
  123. }