|
|
@@ -2,27 +2,38 @@ package network
|
|
2
|
2
|
|
|
3
|
3
|
import (
|
|
4
|
4
|
"net/http"
|
|
|
5
|
+ "sync"
|
|
5
|
6
|
"time"
|
|
6
|
7
|
|
|
7
|
8
|
doh "github.com/babolivier/go-doh-client"
|
|
8
|
|
- "github.com/dgraph-io/ristretto"
|
|
9
|
9
|
)
|
|
10
|
10
|
|
|
11
|
|
-const (
|
|
12
|
|
- dnsResolverSize = 1024 * 1024 // 1mb
|
|
13
|
|
- dnsResolverKeepTime = 10 * time.Minute
|
|
14
|
|
-)
|
|
|
11
|
+const dnsResolverKeepTime = 10 * time.Minute
|
|
|
12
|
+
|
|
|
13
|
+type dnsResolverCacheEntry struct {
|
|
|
14
|
+ ips []string
|
|
|
15
|
+ createdAt time.Time
|
|
|
16
|
+}
|
|
|
17
|
+
|
|
|
18
|
+func (c dnsResolverCacheEntry) Ok() bool {
|
|
|
19
|
+ return time.Since(c.createdAt) < dnsResolverKeepTime
|
|
|
20
|
+}
|
|
15
|
21
|
|
|
16
|
22
|
type dnsResolver struct {
|
|
17
|
|
- resolver doh.Resolver
|
|
18
|
|
- cache *ristretto.Cache
|
|
|
23
|
+ resolver doh.Resolver
|
|
|
24
|
+ cache map[string]dnsResolverCacheEntry
|
|
|
25
|
+ cacheMutex sync.RWMutex
|
|
19
|
26
|
}
|
|
20
|
27
|
|
|
21
|
|
-func (d dnsResolver) LookupA(hostname string) []string {
|
|
22
|
|
- key := "\x00." + hostname
|
|
|
28
|
+func (d *dnsResolver) LookupA(hostname string) []string {
|
|
|
29
|
+ key := "\x00" + hostname
|
|
|
30
|
+
|
|
|
31
|
+ d.cacheMutex.RLock()
|
|
|
32
|
+ entry, ok := d.cache[key]
|
|
|
33
|
+ d.cacheMutex.RUnlock()
|
|
23
|
34
|
|
|
24
|
|
- if value, ok := d.cache.Get(key); ok {
|
|
25
|
|
- return value.([]string)
|
|
|
35
|
+ if ok && entry.Ok() {
|
|
|
36
|
+ return entry.ips
|
|
26
|
37
|
}
|
|
27
|
38
|
|
|
28
|
39
|
var ips []string
|
|
|
@@ -32,17 +43,26 @@ func (d dnsResolver) LookupA(hostname string) []string {
|
|
32
|
43
|
ips = append(ips, v.IP4)
|
|
33
|
44
|
}
|
|
34
|
45
|
|
|
35
|
|
- d.cache.SetWithTTL(key, ips, 0, dnsResolverKeepTime)
|
|
|
46
|
+ d.cacheMutex.Lock()
|
|
|
47
|
+ d.cache[key] = dnsResolverCacheEntry{
|
|
|
48
|
+ ips: ips,
|
|
|
49
|
+ createdAt: time.Now(),
|
|
|
50
|
+ }
|
|
|
51
|
+ d.cacheMutex.Unlock()
|
|
36
|
52
|
}
|
|
37
|
53
|
|
|
38
|
54
|
return ips
|
|
39
|
55
|
}
|
|
40
|
56
|
|
|
41
|
|
-func (d dnsResolver) LookupAAAA(hostname string) []string {
|
|
42
|
|
- key := "\x01." + hostname
|
|
|
57
|
+func (d *dnsResolver) LookupAAAA(hostname string) []string {
|
|
|
58
|
+ key := "\x01" + hostname
|
|
43
|
59
|
|
|
44
|
|
- if value, ok := d.cache.Get(key); ok {
|
|
45
|
|
- return value.([]string)
|
|
|
60
|
+ d.cacheMutex.RLock()
|
|
|
61
|
+ entry, ok := d.cache[key]
|
|
|
62
|
+ d.cacheMutex.RUnlock()
|
|
|
63
|
+
|
|
|
64
|
+ if ok && entry.Ok() {
|
|
|
65
|
+ return entry.ips
|
|
46
|
66
|
}
|
|
47
|
67
|
|
|
48
|
68
|
var ips []string
|
|
|
@@ -52,37 +72,24 @@ func (d dnsResolver) LookupAAAA(hostname string) []string {
|
|
52
|
72
|
ips = append(ips, v.IP6)
|
|
53
|
73
|
}
|
|
54
|
74
|
|
|
55
|
|
- d.cache.SetWithTTL(key, ips, 0, dnsResolverKeepTime)
|
|
|
75
|
+ d.cacheMutex.Lock()
|
|
|
76
|
+ d.cache[key] = dnsResolverCacheEntry{
|
|
|
77
|
+ ips: ips,
|
|
|
78
|
+ createdAt: time.Now(),
|
|
|
79
|
+ }
|
|
|
80
|
+ d.cacheMutex.Unlock()
|
|
56
|
81
|
}
|
|
57
|
82
|
|
|
58
|
83
|
return ips
|
|
59
|
84
|
}
|
|
60
|
85
|
|
|
61
|
|
-func newDNSResolver(hostname string, httpClient *http.Client) dnsResolver {
|
|
62
|
|
- cache, err := ristretto.NewCache(&ristretto.Config{
|
|
63
|
|
- NumCounters: 10 * dnsResolverSize, // nolint: gomnd // taken from official doc as a best practice value
|
|
64
|
|
- MaxCost: dnsResolverSize,
|
|
65
|
|
- BufferItems: 64, // nolint: gomnd // taken from official doc as a best practice value
|
|
66
|
|
- Cost: func(value interface{}) int64 {
|
|
67
|
|
- var cost int64
|
|
68
|
|
-
|
|
69
|
|
- for _, v := range value.([]string) {
|
|
70
|
|
- cost += int64(len([]byte(v)))
|
|
71
|
|
- }
|
|
72
|
|
-
|
|
73
|
|
- return cost
|
|
74
|
|
- },
|
|
75
|
|
- })
|
|
76
|
|
- if err != nil {
|
|
77
|
|
- panic(err)
|
|
78
|
|
- }
|
|
79
|
|
-
|
|
80
|
|
- return dnsResolver{
|
|
|
86
|
+func newDNSResolver(hostname string, httpClient *http.Client) *dnsResolver {
|
|
|
87
|
+ return &dnsResolver{
|
|
81
|
88
|
resolver: doh.Resolver{
|
|
82
|
89
|
Host: hostname,
|
|
83
|
90
|
Class: doh.IN,
|
|
84
|
91
|
HTTPClient: httpClient,
|
|
85
|
92
|
},
|
|
86
|
|
- cache: cache,
|
|
|
93
|
+ cache: map[string]dnsResolverCacheEntry{},
|
|
87
|
94
|
}
|
|
88
|
95
|
}
|