mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-11-26 06:55:48 +03:00
c21f958eaf
Squashed commit of the following: commit ccad155c34989943d88a0a260c50845d1f4ece6b Merge: 0cd889f6a5a195b441
Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Thu Jul 6 17:00:58 2023 +0300 Merge branch 'master' into AG-22597-imp-rdns commit 0cd889f6a500f5616af0f8d8fdcde0403b87ad4f Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Thu Jul 6 12:20:49 2023 +0300 dnsforward: imp code commit 1aaa1998b914b0d53142c21fa3bdcae502e4f3f6 Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Tue Jul 4 20:11:55 2023 +0300 home: add todo commit aed232fcf70ef546f373d5235b73abcb4fbb4b6c Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Tue Jul 4 13:25:28 2023 +0300 all: imp code, tests commit 5c028c2766ffb8ebdc358a245a249c6a55d9ad81 Merge: 83d6ae7f697af062f7
Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Mon Jul 3 18:54:42 2023 +0300 Merge branch 'master' into AG-22597-imp-rdns commit 83d6ae7f61a7b81a8d73cd6d747035278c64fb70 Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Mon Jul 3 18:53:05 2023 +0300 home: imp code commit 8153988dece0406e51a90a43eaffae59dba30a36 Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Fri Jun 30 18:06:09 2023 +0300 all: imp code commit 00d3cc11a9378318f176aae00ddf972f255d575c Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Fri Jun 30 13:05:04 2023 +0300 all: add tests commit ffdc95f237bfdb780922b4390d82cdc0154b0621 Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Thu Jun 29 15:20:00 2023 +0300 all: imp code, docs commit 0dc60e2b355750ca701558927d22fb9ad187ea7e Merge: 69dd56bdbd4a4bda64
Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Thu Jun 29 15:13:19 2023 +0300 Merge branch 'master' into AG-22597-imp-rdns commit 69dd56bdb75056b0fa6bcf6538af7fff93383323 Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Fri Jun 23 14:36:29 2023 +0300 rdns: add tests commit 16909b51adbe3a3f230291834cc9486dd8a0e8f8 Author: Stanislav Chzhen <s.chzhen@adguard.com> Date: Mon Jun 19 16:28:26 2023 +0300 rdns: extract rdns
132 lines
3.3 KiB
Go
132 lines
3.3 KiB
Go
// Package rdns processes reverse DNS lookup queries.
|
|
package rdns
|
|
|
|
import (
|
|
"net/netip"
|
|
"time"
|
|
|
|
"github.com/AdguardTeam/golibs/errors"
|
|
"github.com/AdguardTeam/golibs/log"
|
|
"github.com/bluele/gcache"
|
|
)
|
|
|
|
// Interface processes rDNS queries.
|
|
type Interface interface {
|
|
// Process makes rDNS request and returns domain name. changed indicates
|
|
// that domain name was updated since last request.
|
|
Process(ip netip.Addr) (host string, changed bool)
|
|
}
|
|
|
|
// Empty is an empty [Inteface] implementation which does nothing.
|
|
type Empty struct{}
|
|
|
|
// type check
|
|
var _ Interface = (*Empty)(nil)
|
|
|
|
// Process implements the [Interface] interface for Empty.
|
|
func (Empty) Process(_ netip.Addr) (host string, changed bool) {
|
|
return "", false
|
|
}
|
|
|
|
// Exchanger is a resolver for clients' addresses.
|
|
type Exchanger interface {
|
|
// Exchange tries to resolve the ip in a suitable way, i.e. either as local
|
|
// or as external.
|
|
Exchange(ip netip.Addr) (host string, err error)
|
|
}
|
|
|
|
// Config is the configuration structure for Default.
|
|
type Config struct {
|
|
// Exchanger resolves IP addresses to domain names.
|
|
Exchanger Exchanger
|
|
|
|
// CacheSize is the maximum size of the cache. It must be greater than
|
|
// zero.
|
|
CacheSize int
|
|
|
|
// CacheTTL is the Time to Live duration for cached IP addresses.
|
|
CacheTTL time.Duration
|
|
}
|
|
|
|
// Default is the default rDNS query processor.
|
|
type Default struct {
|
|
// cache is the cache containing IP addresses of clients. An active IP
|
|
// address is resolved once again after it expires. If IP address couldn't
|
|
// be resolved, it stays here for some time to prevent further attempts to
|
|
// resolve the same IP.
|
|
cache gcache.Cache
|
|
|
|
// exchanger resolves IP addresses to domain names.
|
|
exchanger Exchanger
|
|
|
|
// cacheTTL is the Time to Live duration for cached IP addresses.
|
|
cacheTTL time.Duration
|
|
}
|
|
|
|
// New returns a new default rDNS query processor. conf must not be nil.
|
|
func New(conf *Config) (r *Default) {
|
|
return &Default{
|
|
cache: gcache.New(conf.CacheSize).LRU().Build(),
|
|
exchanger: conf.Exchanger,
|
|
cacheTTL: conf.CacheTTL,
|
|
}
|
|
}
|
|
|
|
// type check
|
|
var _ Interface = (*Default)(nil)
|
|
|
|
// Process implements the [Interface] interface for Default.
|
|
func (r *Default) Process(ip netip.Addr) (host string, changed bool) {
|
|
fromCache, expired := r.findInCache(ip)
|
|
if !expired {
|
|
return fromCache, false
|
|
}
|
|
|
|
host, err := r.exchanger.Exchange(ip)
|
|
if err != nil {
|
|
log.Debug("rdns: resolving %q: %s", ip, err)
|
|
}
|
|
|
|
item := &cacheItem{
|
|
expiry: time.Now().Add(r.cacheTTL),
|
|
host: host,
|
|
}
|
|
|
|
err = r.cache.Set(ip, item)
|
|
if err != nil {
|
|
log.Debug("rdns: cache: adding item %q: %s", ip, err)
|
|
}
|
|
|
|
return host, fromCache == "" || host != fromCache
|
|
}
|
|
|
|
// findInCache finds domain name in the cache. expired is true if host is not
|
|
// valid anymore.
|
|
func (r *Default) findInCache(ip netip.Addr) (host string, expired bool) {
|
|
val, err := r.cache.Get(ip)
|
|
if err != nil {
|
|
if !errors.Is(err, gcache.KeyNotFoundError) {
|
|
log.Debug("rdns: cache: retrieving %q: %s", ip, err)
|
|
}
|
|
|
|
return "", true
|
|
}
|
|
|
|
item, ok := val.(*cacheItem)
|
|
if !ok {
|
|
log.Debug("rdns: cache: %q bad type %T", ip, val)
|
|
|
|
return "", true
|
|
}
|
|
|
|
return item.host, time.Now().After(item.expiry)
|
|
}
|
|
|
|
// cacheItem represents an item that we will store in the cache.
|
|
type cacheItem struct {
|
|
// expiry is the time when cacheItem will expire.
|
|
expiry time.Time
|
|
|
|
// host is the domain name of a runtime client.
|
|
host string
|
|
}
|