system.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package dns
  2. import (
  3. "context"
  4. "fmt"
  5. "net"
  6. "strings"
  7. "sync"
  8. "time"
  9. "github.com/metacubex/mihomo/component/resolver"
  10. "github.com/metacubex/mihomo/log"
  11. D "github.com/miekg/dns"
  12. "golang.org/x/exp/slices"
  13. )
  14. const (
  15. SystemDnsFlushTime = 5 * time.Minute
  16. SystemDnsDeleteTimes = 12 // 12*5 = 60min
  17. )
  18. type systemDnsClient struct {
  19. disableTimes uint32
  20. dnsClient
  21. }
  22. type systemClient struct {
  23. mu sync.Mutex
  24. dnsClients map[string]*systemDnsClient
  25. lastFlush time.Time
  26. }
  27. func (c *systemClient) getDnsClients() ([]dnsClient, error) {
  28. c.mu.Lock()
  29. defer c.mu.Unlock()
  30. var err error
  31. if time.Since(c.lastFlush) > SystemDnsFlushTime {
  32. var nameservers []string
  33. if nameservers, err = dnsReadConfig(); err == nil {
  34. log.Debugln("[DNS] system dns update to %s", nameservers)
  35. for _, addr := range nameservers {
  36. if resolver.IsSystemDnsBlacklisted(addr) {
  37. continue
  38. }
  39. if _, ok := c.dnsClients[addr]; !ok {
  40. clients := transform(
  41. []NameServer{{
  42. Addr: net.JoinHostPort(addr, "53"),
  43. Net: "udp",
  44. }},
  45. nil,
  46. )
  47. if len(clients) > 0 {
  48. c.dnsClients[addr] = &systemDnsClient{
  49. disableTimes: 0,
  50. dnsClient: clients[0],
  51. }
  52. }
  53. }
  54. }
  55. available := 0
  56. for nameserver, sdc := range c.dnsClients {
  57. if slices.Contains(nameservers, nameserver) {
  58. sdc.disableTimes = 0 // enable
  59. available++
  60. } else {
  61. if sdc.disableTimes > SystemDnsDeleteTimes {
  62. delete(c.dnsClients, nameserver) // drop too old dnsClient
  63. } else {
  64. sdc.disableTimes++
  65. }
  66. }
  67. }
  68. if available > 0 {
  69. c.lastFlush = time.Now()
  70. }
  71. }
  72. }
  73. dnsClients := make([]dnsClient, 0, len(c.dnsClients))
  74. for _, sdc := range c.dnsClients {
  75. if sdc.disableTimes == 0 {
  76. dnsClients = append(dnsClients, sdc.dnsClient)
  77. }
  78. }
  79. if len(dnsClients) > 0 {
  80. return dnsClients, nil
  81. }
  82. return nil, err
  83. }
  84. func (c *systemClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
  85. dnsClients, err := c.getDnsClients()
  86. if err != nil {
  87. return
  88. }
  89. msg, _, err = batchExchange(ctx, dnsClients, m)
  90. return
  91. }
  92. // Address implements dnsClient
  93. func (c *systemClient) Address() string {
  94. dnsClients, _ := c.getDnsClients()
  95. addrs := make([]string, 0, len(dnsClients))
  96. for _, c := range dnsClients {
  97. addrs = append(addrs, c.Address())
  98. }
  99. return fmt.Sprintf("system(%s)", strings.Join(addrs, ","))
  100. }
  101. var _ dnsClient = (*systemClient)(nil)
  102. func newSystemClient() *systemClient {
  103. return &systemClient{
  104. dnsClients: map[string]*systemDnsClient{},
  105. }
  106. }