146 lines
3.9 KiB
Go
146 lines
3.9 KiB
Go
package home
|
|
|
|
import (
|
|
"context"
|
|
"net/netip"
|
|
"time"
|
|
|
|
"github.com/AdguardTeam/AdGuardHome/internal/rdns"
|
|
"github.com/AdguardTeam/AdGuardHome/internal/whois"
|
|
"github.com/AdguardTeam/golibs/log"
|
|
)
|
|
|
|
// TODO(a.garipov): It is currently hard to add tests for this structure due to
|
|
// strong coupling between it and Context.dnsServer with Context.clients.
|
|
// Resolve this coupling and add proper testing.
|
|
|
|
// clientAddrProcessor processes incoming client addresses with rDNS and WHOIS,
|
|
// if configured.
|
|
type clientAddrProcessor struct {
|
|
rdns rdns.Interface
|
|
whois whois.Interface
|
|
}
|
|
|
|
const (
|
|
// defaultQueueSize is the size of queue of IPs for rDNS and WHOIS
|
|
// processing.
|
|
defaultQueueSize = 255
|
|
|
|
// defaultCacheSize is the maximum size of the cache for rDNS and WHOIS
|
|
// processing. It must be greater than zero.
|
|
defaultCacheSize = 10_000
|
|
|
|
// defaultIPTTL is the Time to Live duration for IP addresses cached by
|
|
// rDNS and WHOIS.
|
|
defaultIPTTL = 1 * time.Hour
|
|
)
|
|
|
|
// newClientAddrProcessor returns a new client address processor. c must not be
|
|
// nil.
|
|
func newClientAddrProcessor(c *clientSourcesConfig) (p *clientAddrProcessor) {
|
|
p = &clientAddrProcessor{
|
|
rdns: &rdns.Empty{},
|
|
whois: &whois.Empty{},
|
|
}
|
|
|
|
if c.RDNS {
|
|
p.rdns = rdns.New(&rdns.Config{
|
|
Exchanger: Context.dnsServer,
|
|
CacheSize: defaultCacheSize,
|
|
CacheTTL: defaultIPTTL,
|
|
})
|
|
}
|
|
|
|
if c.WHOIS {
|
|
// TODO(s.chzhen): Consider making configurable.
|
|
const (
|
|
// defaultTimeout is the timeout for WHOIS requests.
|
|
defaultTimeout = 5 * time.Second
|
|
|
|
// defaultMaxConnReadSize is an upper limit in bytes for reading from a
|
|
// net.Conn.
|
|
defaultMaxConnReadSize = 64 * 1024
|
|
|
|
// defaultMaxRedirects is the maximum redirects count.
|
|
defaultMaxRedirects = 5
|
|
|
|
// defaultMaxInfoLen is the maximum length of whois.Info fields.
|
|
defaultMaxInfoLen = 250
|
|
)
|
|
|
|
p.whois = whois.New(&whois.Config{
|
|
DialContext: customDialContext,
|
|
ServerAddr: whois.DefaultServer,
|
|
Port: whois.DefaultPort,
|
|
Timeout: defaultTimeout,
|
|
CacheSize: defaultCacheSize,
|
|
MaxConnReadSize: defaultMaxConnReadSize,
|
|
MaxRedirects: defaultMaxRedirects,
|
|
MaxInfoLen: defaultMaxInfoLen,
|
|
CacheTTL: defaultIPTTL,
|
|
})
|
|
}
|
|
|
|
return p
|
|
}
|
|
|
|
// process processes the incoming client IP-address information. It is intended
|
|
// to be used as a goroutine. Once clientIPs is closed, process exits.
|
|
func (p *clientAddrProcessor) process(clientIPs <-chan netip.Addr) {
|
|
defer log.OnPanic("clientAddrProcessor.process")
|
|
|
|
log.Info("home: processing client addresses")
|
|
|
|
for ip := range clientIPs {
|
|
p.processRDNS(ip)
|
|
p.processWHOIS(ip)
|
|
}
|
|
|
|
log.Info("home: finished processing client addresses")
|
|
}
|
|
|
|
// processRDNS resolves the clients' IP addresses using reverse DNS.
|
|
func (p *clientAddrProcessor) processRDNS(ip netip.Addr) {
|
|
start := time.Now()
|
|
log.Debug("home: processing client %s with rdns", ip)
|
|
defer func() {
|
|
log.Debug("home: finished processing client %s with rdns in %s", ip, time.Since(start))
|
|
}()
|
|
|
|
ok := Context.dnsServer.ShouldResolveClient(ip)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
host, changed := p.rdns.Process(ip)
|
|
if host == "" || !changed {
|
|
return
|
|
}
|
|
|
|
ok = Context.clients.AddHost(ip, host, ClientSourceRDNS)
|
|
if ok {
|
|
return
|
|
}
|
|
|
|
log.Debug("dns: setting rdns info for client %q: already set with higher priority source", ip)
|
|
}
|
|
|
|
// processWHOIS looks up the information aobut clients' IP addresses in the
|
|
// WHOIS databases.
|
|
func (p *clientAddrProcessor) processWHOIS(ip netip.Addr) {
|
|
start := time.Now()
|
|
log.Debug("home: processing client %s with whois", ip)
|
|
defer func() {
|
|
log.Debug("home: finished processing client %s with whois in %s", ip, time.Since(start))
|
|
}()
|
|
|
|
// TODO(s.chzhen): Move the timeout logic from WHOIS configuration to the
|
|
// context.
|
|
info, changed := p.whois.Process(context.Background(), ip)
|
|
if info == nil || !changed {
|
|
return
|
|
}
|
|
|
|
Context.clients.setWHOISInfo(ip, info)
|
|
}
|