Source file
src/net/hosts.go
1
2
3
4
5 package net
6
7 import (
8 "errors"
9 "internal/bytealg"
10 "io/fs"
11 "net/netip"
12 "sync"
13 "time"
14 )
15
16 const cacheMaxAge = 5 * time.Second
17
18 func parseLiteralIP(addr string) string {
19 ip, err := netip.ParseAddr(addr)
20 if err != nil {
21 return ""
22 }
23 return ip.String()
24 }
25
26 type byName struct {
27 addrs []string
28 canonicalName string
29 }
30
31
32 var hosts struct {
33 sync.Mutex
34
35
36
37
38
39 byName map[string]byName
40
41
42
43
44 byAddr map[string][]string
45
46 expire time.Time
47 path string
48 mtime time.Time
49 size int64
50 }
51
52 func readHosts() {
53 now := time.Now()
54 hp := hostsFilePath
55
56 if now.Before(hosts.expire) && hosts.path == hp && len(hosts.byName) > 0 {
57 return
58 }
59 mtime, size, err := stat(hp)
60 if err == nil && hosts.path == hp && hosts.mtime.Equal(mtime) && hosts.size == size {
61 hosts.expire = now.Add(cacheMaxAge)
62 return
63 }
64
65 hs := make(map[string]byName)
66 is := make(map[string][]string)
67
68 file, err := open(hp)
69 if err != nil {
70 if !errors.Is(err, fs.ErrNotExist) && !errors.Is(err, fs.ErrPermission) {
71 return
72 }
73 }
74
75 if file != nil {
76 defer file.close()
77 for line, ok := file.readLine(); ok; line, ok = file.readLine() {
78 if i := bytealg.IndexByteString(line, '#'); i >= 0 {
79
80 line = line[0:i]
81 }
82 f := getFields(line)
83 if len(f) < 2 {
84 continue
85 }
86 addr := parseLiteralIP(f[0])
87 if addr == "" {
88 continue
89 }
90
91 var canonical string
92 for i := 1; i < len(f); i++ {
93 name := absDomainName(f[i])
94 h := []byte(f[i])
95 lowerASCIIBytes(h)
96 key := absDomainName(string(h))
97
98 if i == 1 {
99 canonical = key
100 }
101
102 is[addr] = append(is[addr], name)
103
104 if v, ok := hs[key]; ok {
105 hs[key] = byName{
106 addrs: append(v.addrs, addr),
107 canonicalName: v.canonicalName,
108 }
109 continue
110 }
111
112 hs[key] = byName{
113 addrs: []string{addr},
114 canonicalName: canonical,
115 }
116 }
117 }
118 }
119
120 hosts.expire = now.Add(cacheMaxAge)
121 hosts.path = hp
122 hosts.byName = hs
123 hosts.byAddr = is
124 hosts.mtime = mtime
125 hosts.size = size
126 }
127
128
129 func lookupStaticHost(host string) ([]string, string) {
130 hosts.Lock()
131 defer hosts.Unlock()
132 readHosts()
133 if len(hosts.byName) != 0 {
134 if hasUpperCase(host) {
135 lowerHost := []byte(host)
136 lowerASCIIBytes(lowerHost)
137 host = string(lowerHost)
138 }
139 if byName, ok := hosts.byName[absDomainName(host)]; ok {
140 ipsCp := make([]string, len(byName.addrs))
141 copy(ipsCp, byName.addrs)
142 return ipsCp, byName.canonicalName
143 }
144 }
145 return nil, ""
146 }
147
148
149 func lookupStaticAddr(addr string) []string {
150 hosts.Lock()
151 defer hosts.Unlock()
152 readHosts()
153 addr = parseLiteralIP(addr)
154 if addr == "" {
155 return nil
156 }
157 if len(hosts.byAddr) != 0 {
158 if hosts, ok := hosts.byAddr[addr]; ok {
159 hostsCp := make([]string, len(hosts))
160 copy(hostsCp, hosts)
161 return hostsCp
162 }
163 }
164 return nil
165 }
166
View as plain text