mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-16 07:16:38 +00:00
implements DNS query caching in the DNSForwarder to improve performance and provide fallback responses when upstream DNS servers fail. The cache stores successful DNS query results and serves them when upstream resolution fails. - Added a new cache component to store DNS query results by domain and query type - Integrated cache storage after successful DNS resolutions - Enhanced error handling to serve cached responses as fallback when upstream DNS fails
79 lines
1.5 KiB
Go
79 lines
1.5 KiB
Go
package dnsfwd
|
|
|
|
import (
|
|
"net/netip"
|
|
"slices"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
type cache struct {
|
|
mu sync.RWMutex
|
|
records map[string]*cacheEntry
|
|
}
|
|
|
|
type cacheEntry struct {
|
|
ip4Addrs []netip.Addr
|
|
ip6Addrs []netip.Addr
|
|
}
|
|
|
|
func newCache() *cache {
|
|
return &cache{
|
|
records: make(map[string]*cacheEntry),
|
|
}
|
|
}
|
|
|
|
func (c *cache) get(domain string, reqType uint16) ([]netip.Addr, bool) {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
|
|
entry, exists := c.records[normalizeDomain(domain)]
|
|
if !exists {
|
|
return nil, false
|
|
}
|
|
|
|
switch reqType {
|
|
case dns.TypeA:
|
|
return slices.Clone(entry.ip4Addrs), true
|
|
case dns.TypeAAAA:
|
|
return slices.Clone(entry.ip6Addrs), true
|
|
default:
|
|
return nil, false
|
|
}
|
|
|
|
}
|
|
|
|
func (c *cache) set(domain string, reqType uint16, addrs []netip.Addr) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
norm := normalizeDomain(domain)
|
|
entry, exists := c.records[norm]
|
|
if !exists {
|
|
entry = &cacheEntry{}
|
|
c.records[norm] = entry
|
|
}
|
|
|
|
switch reqType {
|
|
case dns.TypeA:
|
|
entry.ip4Addrs = slices.Clone(addrs)
|
|
case dns.TypeAAAA:
|
|
entry.ip6Addrs = slices.Clone(addrs)
|
|
}
|
|
}
|
|
|
|
// unset removes cached entries for the given domain and request type.
|
|
func (c *cache) unset(domain string) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
delete(c.records, normalizeDomain(domain))
|
|
}
|
|
|
|
// normalizeDomain converts an input domain into a canonical form used as cache key:
|
|
// lowercase and fully-qualified (with trailing dot).
|
|
func normalizeDomain(domain string) string {
|
|
// dns.Fqdn ensures trailing dot; ToLower for consistent casing
|
|
return dns.Fqdn(strings.ToLower(domain))
|
|
}
|