hosts.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // Copyright 2009 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package net
  5. import (
  6. "internal/bytealg"
  7. "sync"
  8. "time"
  9. )
  10. const cacheMaxAge = 5 * time.Second
  11. func parseLiteralIP(addr string) string {
  12. var ip IP
  13. var zone string
  14. ip = parseIPv4(addr)
  15. if ip == nil {
  16. ip, zone = parseIPv6Zone(addr)
  17. }
  18. if ip == nil {
  19. return ""
  20. }
  21. if zone == "" {
  22. return ip.String()
  23. }
  24. return ip.String() + "%" + zone
  25. }
  26. // hosts contains known host entries.
  27. var hosts struct {
  28. sync.Mutex
  29. // Key for the list of literal IP addresses must be a host
  30. // name. It would be part of DNS labels, a FQDN or an absolute
  31. // FQDN.
  32. // For now the key is converted to lower case for convenience.
  33. byName map[string][]string
  34. // Key for the list of host names must be a literal IP address
  35. // including IPv6 address with zone identifier.
  36. // We don't support old-classful IP address notation.
  37. byAddr map[string][]string
  38. expire time.Time
  39. path string
  40. mtime time.Time
  41. size int64
  42. }
  43. func readHosts() {
  44. now := time.Now()
  45. hp := testHookHostsPath
  46. if now.Before(hosts.expire) && hosts.path == hp && len(hosts.byName) > 0 {
  47. return
  48. }
  49. mtime, size, err := stat(hp)
  50. if err == nil && hosts.path == hp && hosts.mtime.Equal(mtime) && hosts.size == size {
  51. hosts.expire = now.Add(cacheMaxAge)
  52. return
  53. }
  54. hs := make(map[string][]string)
  55. is := make(map[string][]string)
  56. var file *file
  57. if file, _ = open(hp); file == nil {
  58. return
  59. }
  60. for line, ok := file.readLine(); ok; line, ok = file.readLine() {
  61. if i := bytealg.IndexByteString(line, '#'); i >= 0 {
  62. // Discard comments.
  63. line = line[0:i]
  64. }
  65. f := getFields(line)
  66. if len(f) < 2 {
  67. continue
  68. }
  69. addr := parseLiteralIP(f[0])
  70. if addr == "" {
  71. continue
  72. }
  73. for i := 1; i < len(f); i++ {
  74. name := absDomainName(f[i])
  75. h := []byte(f[i])
  76. lowerASCIIBytes(h)
  77. key := absDomainName(string(h))
  78. hs[key] = append(hs[key], addr)
  79. is[addr] = append(is[addr], name)
  80. }
  81. }
  82. // Update the data cache.
  83. hosts.expire = now.Add(cacheMaxAge)
  84. hosts.path = hp
  85. hosts.byName = hs
  86. hosts.byAddr = is
  87. hosts.mtime = mtime
  88. hosts.size = size
  89. file.close()
  90. }
  91. // lookupStaticHost looks up the addresses for the given host from /etc/hosts.
  92. func lookupStaticHost(host string) []string {
  93. hosts.Lock()
  94. defer hosts.Unlock()
  95. readHosts()
  96. if len(hosts.byName) != 0 {
  97. if hasUpperCase(host) {
  98. lowerHost := []byte(host)
  99. lowerASCIIBytes(lowerHost)
  100. host = string(lowerHost)
  101. }
  102. if ips, ok := hosts.byName[absDomainName(host)]; ok {
  103. ipsCp := make([]string, len(ips))
  104. copy(ipsCp, ips)
  105. return ipsCp
  106. }
  107. }
  108. return nil
  109. }
  110. // lookupStaticAddr looks up the hosts for the given address from /etc/hosts.
  111. func lookupStaticAddr(addr string) []string {
  112. hosts.Lock()
  113. defer hosts.Unlock()
  114. readHosts()
  115. addr = parseLiteralIP(addr)
  116. if addr == "" {
  117. return nil
  118. }
  119. if len(hosts.byAddr) != 0 {
  120. if hosts, ok := hosts.byAddr[addr]; ok {
  121. hostsCp := make([]string, len(hosts))
  122. copy(hostsCp, hosts)
  123. return hostsCp
  124. }
  125. }
  126. return nil
  127. }