dns_dialer.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. package tunnel
  2. // WARNING: all function in this file should only be using in dns module
  3. import (
  4. "context"
  5. "fmt"
  6. "net"
  7. "strings"
  8. N "github.com/metacubex/mihomo/common/net"
  9. "github.com/metacubex/mihomo/component/dialer"
  10. "github.com/metacubex/mihomo/component/resolver"
  11. C "github.com/metacubex/mihomo/constant"
  12. "github.com/metacubex/mihomo/tunnel/statistic"
  13. )
  14. const DnsRespectRules = "RULES"
  15. type DNSDialer struct {
  16. r resolver.Resolver
  17. proxyAdapter C.ProxyAdapter
  18. proxyName string
  19. opts []dialer.Option
  20. }
  21. func NewDNSDialer(r resolver.Resolver, proxyAdapter C.ProxyAdapter, proxyName string, opts ...dialer.Option) *DNSDialer {
  22. return &DNSDialer{r: r, proxyAdapter: proxyAdapter, proxyName: proxyName, opts: opts}
  23. }
  24. func (d *DNSDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
  25. r := d.r
  26. proxyName := d.proxyName
  27. proxyAdapter := d.proxyAdapter
  28. opts := d.opts
  29. var rule C.Rule
  30. metadata := &C.Metadata{
  31. NetWork: C.TCP,
  32. Type: C.INNER,
  33. }
  34. err := metadata.SetRemoteAddress(addr) // tcp can resolve host by remote
  35. if err != nil {
  36. return nil, err
  37. }
  38. if !strings.Contains(network, "tcp") {
  39. metadata.NetWork = C.UDP
  40. if !metadata.Resolved() {
  41. // udp must resolve host first
  42. dstIP, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, r)
  43. if err != nil {
  44. return nil, err
  45. }
  46. metadata.DstIP = dstIP
  47. }
  48. }
  49. if proxyAdapter == nil && len(proxyName) != 0 {
  50. if proxyName == DnsRespectRules {
  51. if !metadata.Resolved() {
  52. // resolve here before resolveMetadata to avoid its inner resolver.ResolveIP
  53. dstIP, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, r)
  54. if err != nil {
  55. return nil, err
  56. }
  57. metadata.DstIP = dstIP
  58. }
  59. proxyAdapter, rule, err = resolveMetadata(metadata)
  60. if err != nil {
  61. return nil, err
  62. }
  63. } else {
  64. var ok bool
  65. proxyAdapter, ok = Proxies()[proxyName]
  66. if !ok {
  67. opts = append(opts, dialer.WithInterface(proxyName))
  68. }
  69. }
  70. }
  71. if metadata.NetWork == C.TCP {
  72. if proxyAdapter == nil {
  73. opts = append(opts, dialer.WithResolver(r))
  74. return dialer.DialContext(ctx, network, addr, opts...)
  75. }
  76. if proxyAdapter.IsL3Protocol(metadata) { // L3 proxy should resolve domain before to avoid loopback
  77. if !metadata.Resolved() {
  78. dstIP, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, r)
  79. if err != nil {
  80. return nil, err
  81. }
  82. metadata.DstIP = dstIP
  83. }
  84. metadata.Host = "" // clear host to avoid double resolve in proxy
  85. }
  86. conn, err := proxyAdapter.DialContext(ctx, metadata, opts...)
  87. if err != nil {
  88. logMetadataErr(metadata, rule, proxyAdapter, err)
  89. return nil, err
  90. }
  91. logMetadata(metadata, rule, conn)
  92. conn = statistic.NewTCPTracker(conn, statistic.DefaultManager, metadata, rule, 0, 0, false)
  93. return conn, nil
  94. } else {
  95. if proxyAdapter == nil {
  96. return dialer.DialContext(ctx, network, metadata.AddrPort().String(), opts...)
  97. }
  98. if !proxyAdapter.SupportUDP() {
  99. return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", proxyAdapter)
  100. }
  101. packetConn, err := proxyAdapter.ListenPacketContext(ctx, metadata, opts...)
  102. if err != nil {
  103. logMetadataErr(metadata, rule, proxyAdapter, err)
  104. return nil, err
  105. }
  106. logMetadata(metadata, rule, packetConn)
  107. packetConn = statistic.NewUDPTracker(packetConn, statistic.DefaultManager, metadata, rule, 0, 0, false)
  108. return N.NewBindPacketConn(packetConn, metadata.UDPAddr()), nil
  109. }
  110. }
  111. func (d *DNSDialer) ListenPacket(ctx context.Context, network, addr string) (net.PacketConn, error) {
  112. r := d.r
  113. proxyAdapter := d.proxyAdapter
  114. proxyName := d.proxyName
  115. opts := d.opts
  116. metadata := &C.Metadata{
  117. NetWork: C.UDP,
  118. Type: C.INNER,
  119. }
  120. err := metadata.SetRemoteAddress(addr)
  121. if err != nil {
  122. return nil, err
  123. }
  124. if !metadata.Resolved() {
  125. // udp must resolve host first
  126. dstIP, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, r)
  127. if err != nil {
  128. return nil, err
  129. }
  130. metadata.DstIP = dstIP
  131. }
  132. var rule C.Rule
  133. if proxyAdapter == nil {
  134. if proxyName == DnsRespectRules {
  135. proxyAdapter, rule, err = resolveMetadata(metadata)
  136. if err != nil {
  137. return nil, err
  138. }
  139. } else {
  140. var ok bool
  141. proxyAdapter, ok = Proxies()[proxyName]
  142. if !ok {
  143. opts = append(opts, dialer.WithInterface(proxyName))
  144. }
  145. }
  146. }
  147. if proxyAdapter == nil {
  148. return dialer.NewDialer(opts...).ListenPacket(ctx, network, "", metadata.AddrPort())
  149. }
  150. if !proxyAdapter.SupportUDP() {
  151. return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", proxyAdapter)
  152. }
  153. packetConn, err := proxyAdapter.ListenPacketContext(ctx, metadata, opts...)
  154. if err != nil {
  155. logMetadataErr(metadata, rule, proxyAdapter, err)
  156. return nil, err
  157. }
  158. logMetadata(metadata, rule, packetConn)
  159. packetConn = statistic.NewUDPTracker(packetConn, statistic.DefaultManager, metadata, rule, 0, 0, false)
  160. return packetConn, nil
  161. }