util.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. package dns
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "net/netip"
  9. "strings"
  10. "time"
  11. "github.com/metacubex/mihomo/common/nnip"
  12. "github.com/metacubex/mihomo/common/picker"
  13. "github.com/metacubex/mihomo/component/dialer"
  14. "github.com/metacubex/mihomo/component/resolver"
  15. "github.com/metacubex/mihomo/log"
  16. D "github.com/miekg/dns"
  17. "github.com/samber/lo"
  18. )
  19. const (
  20. MaxMsgSize = 65535
  21. )
  22. const serverFailureCacheTTL uint32 = 5
  23. func minimalTTL(records []D.RR) uint32 {
  24. rr := lo.MinBy(records, func(r1 D.RR, r2 D.RR) bool {
  25. return r1.Header().Ttl < r2.Header().Ttl
  26. })
  27. if rr == nil {
  28. return 0
  29. }
  30. return rr.Header().Ttl
  31. }
  32. func updateTTL(records []D.RR, ttl uint32) {
  33. if len(records) == 0 {
  34. return
  35. }
  36. delta := minimalTTL(records) - ttl
  37. for i := range records {
  38. records[i].Header().Ttl = lo.Clamp(records[i].Header().Ttl-delta, 1, records[i].Header().Ttl)
  39. }
  40. }
  41. func putMsgToCache(c dnsCache, key string, q D.Question, msg *D.Msg) {
  42. // skip dns cache for acme challenge
  43. if q.Qtype == D.TypeTXT && strings.HasPrefix(q.Name, "_acme-challenge.") {
  44. log.Debugln("[DNS] dns cache ignored because of acme challenge for: %s", q.Name)
  45. return
  46. }
  47. var ttl uint32
  48. if msg.Rcode == D.RcodeServerFailure {
  49. // [...] a resolver MAY cache a server failure response.
  50. // If it does so it MUST NOT cache it for longer than five (5) minutes [...]
  51. ttl = serverFailureCacheTTL
  52. } else {
  53. ttl = minimalTTL(append(append(msg.Answer, msg.Ns...), msg.Extra...))
  54. }
  55. if ttl == 0 {
  56. return
  57. }
  58. c.SetWithExpire(key, msg.Copy(), time.Now().Add(time.Duration(ttl)*time.Second))
  59. }
  60. func setMsgTTL(msg *D.Msg, ttl uint32) {
  61. for _, answer := range msg.Answer {
  62. answer.Header().Ttl = ttl
  63. }
  64. for _, ns := range msg.Ns {
  65. ns.Header().Ttl = ttl
  66. }
  67. for _, extra := range msg.Extra {
  68. extra.Header().Ttl = ttl
  69. }
  70. }
  71. func updateMsgTTL(msg *D.Msg, ttl uint32) {
  72. updateTTL(msg.Answer, ttl)
  73. updateTTL(msg.Ns, ttl)
  74. updateTTL(msg.Extra, ttl)
  75. }
  76. func isIPRequest(q D.Question) bool {
  77. return q.Qclass == D.ClassINET && (q.Qtype == D.TypeA || q.Qtype == D.TypeAAAA || q.Qtype == D.TypeCNAME)
  78. }
  79. func transform(servers []NameServer, resolver *Resolver) []dnsClient {
  80. ret := make([]dnsClient, 0, len(servers))
  81. for _, s := range servers {
  82. switch s.Net {
  83. case "https":
  84. ret = append(ret, newDoHClient(s.Addr, resolver, s.PreferH3, s.Params, s.ProxyAdapter, s.ProxyName))
  85. continue
  86. case "dhcp":
  87. ret = append(ret, newDHCPClient(s.Addr))
  88. continue
  89. case "system":
  90. ret = append(ret, newSystemClient())
  91. continue
  92. case "rcode":
  93. ret = append(ret, newRCodeClient(s.Addr))
  94. continue
  95. case "quic":
  96. if doq, err := newDoQ(resolver, s.Addr, s.ProxyAdapter, s.ProxyName); err == nil {
  97. ret = append(ret, doq)
  98. } else {
  99. log.Fatalln("DoQ format error: %v", err)
  100. }
  101. continue
  102. }
  103. var options []dialer.Option
  104. if s.Interface != "" {
  105. options = append(options, dialer.WithInterface(s.Interface))
  106. }
  107. host, port, _ := net.SplitHostPort(s.Addr)
  108. ret = append(ret, &client{
  109. Client: &D.Client{
  110. Net: s.Net,
  111. TLSConfig: &tls.Config{
  112. ServerName: host,
  113. },
  114. UDPSize: 4096,
  115. Timeout: 5 * time.Second,
  116. },
  117. port: port,
  118. host: host,
  119. dialer: newDNSDialer(resolver, s.ProxyAdapter, s.ProxyName, options...),
  120. })
  121. }
  122. return ret
  123. }
  124. func handleMsgWithEmptyAnswer(r *D.Msg) *D.Msg {
  125. msg := &D.Msg{}
  126. msg.Answer = []D.RR{}
  127. msg.SetRcode(r, D.RcodeSuccess)
  128. msg.Authoritative = true
  129. msg.RecursionAvailable = true
  130. return msg
  131. }
  132. func msgToIP(msg *D.Msg) []netip.Addr {
  133. ips := []netip.Addr{}
  134. for _, answer := range msg.Answer {
  135. switch ans := answer.(type) {
  136. case *D.AAAA:
  137. ips = append(ips, nnip.IpToAddr(ans.AAAA))
  138. case *D.A:
  139. ips = append(ips, nnip.IpToAddr(ans.A))
  140. }
  141. }
  142. return ips
  143. }
  144. func msgToDomain(msg *D.Msg) string {
  145. if len(msg.Question) > 0 {
  146. return strings.TrimRight(msg.Question[0].Name, ".")
  147. }
  148. return ""
  149. }
  150. func msgToQtype(msg *D.Msg) (uint16, string) {
  151. if len(msg.Question) > 0 {
  152. qType := msg.Question[0].Qtype
  153. return qType, D.Type(qType).String()
  154. }
  155. return 0, ""
  156. }
  157. func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, cache bool, err error) {
  158. cache = true
  159. fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout)
  160. defer fast.Close()
  161. domain := msgToDomain(m)
  162. qType, qTypeStr := msgToQtype(m)
  163. var noIpMsg *D.Msg
  164. for _, client := range clients {
  165. if _, isRCodeClient := client.(rcodeClient); isRCodeClient {
  166. msg, err = client.ExchangeContext(ctx, m)
  167. return msg, false, err
  168. }
  169. client := client // shadow define client to ensure the value captured by the closure will not be changed in the next loop
  170. fast.Go(func() (*D.Msg, error) {
  171. log.Debugln("[DNS] resolve %s %s from %s", domain, qTypeStr, client.Address())
  172. m, err := client.ExchangeContext(ctx, m)
  173. if err != nil {
  174. return nil, err
  175. } else if cache && (m.Rcode == D.RcodeServerFailure || m.Rcode == D.RcodeRefused) {
  176. // currently, cache indicates whether this msg was from a RCode client,
  177. // so we would ignore RCode errors from RCode clients.
  178. return nil, errors.New("server failure: " + D.RcodeToString[m.Rcode])
  179. }
  180. ips := msgToIP(m)
  181. log.Debugln("[DNS] %s --> %s %s from %s", domain, ips, qTypeStr, client.Address())
  182. switch qType {
  183. case D.TypeAAAA:
  184. if len(ips) == 0 {
  185. noIpMsg = m
  186. return nil, resolver.ErrIPNotFound
  187. }
  188. case D.TypeA:
  189. if len(ips) == 0 {
  190. noIpMsg = m
  191. return nil, resolver.ErrIPNotFound
  192. }
  193. }
  194. return m, nil
  195. })
  196. }
  197. msg = fast.Wait()
  198. if msg == nil {
  199. if noIpMsg != nil {
  200. return noIpMsg, false, nil
  201. }
  202. err = errors.New("all DNS requests failed")
  203. if fErr := fast.Error(); fErr != nil {
  204. err = fmt.Errorf("%w, first error: %w", err, fErr)
  205. }
  206. }
  207. return
  208. }