@@ -30,8 +30,9 @@ import (
3030)
3131
3232const (
33- MaxDnsLookupDepth = 3
34- minFirefoxCacheTtl = 120
33+ MaxDnsLookupDepth = 3
34+ minFirefoxCacheTtl = 120
35+ maxDnsForwarderCacheSize = 128
3536)
3637
3738type IpVersionPrefer int
@@ -82,6 +83,7 @@ type DnsController struct {
8283 dnsCache map [string ]* DnsCache
8384 dnsForwarderCacheMu sync.Mutex
8485 dnsForwarderCache map [dnsForwarderKey ]DnsForwarder
86+ dnsForwarderLastUse map [dnsForwarderKey ]time.Time
8587}
8688
8789type handlingState struct {
@@ -125,9 +127,36 @@ func NewDnsController(routing *dns.Dns, option *DnsControllerOption) (c *DnsCont
125127 dnsCache : make (map [string ]* DnsCache ),
126128 dnsForwarderCacheMu : sync.Mutex {},
127129 dnsForwarderCache : make (map [dnsForwarderKey ]DnsForwarder ),
130+ dnsForwarderLastUse : make (map [dnsForwarderKey ]time.Time ),
128131 }, nil
129132}
130133
134+ func (c * DnsController ) evictDnsForwarderCacheOneLocked () {
135+ if len (c .dnsForwarderCache ) < maxDnsForwarderCacheSize {
136+ return
137+ }
138+ var (
139+ oldestKey dnsForwarderKey
140+ oldestTime time.Time
141+ initialized bool
142+ )
143+ for key , lastUse := range c .dnsForwarderLastUse {
144+ if ! initialized || lastUse .Before (oldestTime ) {
145+ oldestKey = key
146+ oldestTime = lastUse
147+ initialized = true
148+ }
149+ }
150+ if ! initialized {
151+ return
152+ }
153+ if forwarder , ok := c .dnsForwarderCache [oldestKey ]; ok {
154+ _ = forwarder .Close ()
155+ delete (c .dnsForwarderCache , oldestKey )
156+ }
157+ delete (c .dnsForwarderLastUse , oldestKey )
158+ }
159+
131160func (c * DnsController ) cacheKey (qname string , qtype uint16 ) string {
132161 // To fqdn.
133162 return dnsmessage .CanonicalName (qname ) + strconv .Itoa (int (qtype ))
@@ -582,16 +611,19 @@ func (c *DnsController) dialSend(invokingDepth int, req *udpRequest, data []byte
582611 defer cancel ()
583612
584613 // get forwarder from cache
614+ cacheKeyForwarder := dnsForwarderKey {upstream : upstream .String (), dialArgument : * dialArgument }
585615 c .dnsForwarderCacheMu .Lock ()
586- forwarder , ok := c .dnsForwarderCache [dnsForwarderKey { upstream : upstream . String (), dialArgument : * dialArgument } ]
616+ forwarder , ok := c .dnsForwarderCache [cacheKeyForwarder ]
587617 if ! ok {
618+ c .evictDnsForwarderCacheOneLocked ()
588619 forwarder , err = newDnsForwarder (upstream , * dialArgument )
589620 if err != nil {
590621 c .dnsForwarderCacheMu .Unlock ()
591622 return err
592623 }
593- c .dnsForwarderCache [dnsForwarderKey { upstream : upstream . String (), dialArgument : * dialArgument } ] = forwarder
624+ c .dnsForwarderCache [cacheKeyForwarder ] = forwarder
594625 }
626+ c .dnsForwarderLastUse [cacheKeyForwarder ] = time .Now ()
595627 c .dnsForwarderCacheMu .Unlock ()
596628
597629 defer func () {
0 commit comments