2022-06-05 21:58:34 +02:00
|
|
|
package netxlite
|
2021-02-02 12:05:47 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2022-06-05 21:22:27 +02:00
|
|
|
"net"
|
2021-02-02 12:05:47 +01:00
|
|
|
"sync"
|
2022-01-07 18:33:37 +01:00
|
|
|
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/model"
|
2021-02-02 12:05:47 +01:00
|
|
|
)
|
|
|
|
|
2022-06-05 21:22:27 +02:00
|
|
|
// MaybeWrapWithCachingResolver wraps the provided resolver with a resolver
|
|
|
|
// that remembers the result of previous successful resolutions, if the enabled
|
|
|
|
// argument is true. Otherwise, we return the unmodified provided resolver.
|
|
|
|
//
|
|
|
|
// Bug: the returned resolver only applies caching to LookupHost and any other
|
|
|
|
// lookup operation returns ErrNoDNSTransport to the caller.
|
|
|
|
func MaybeWrapWithCachingResolver(enabled bool, reso model.Resolver) model.Resolver {
|
|
|
|
if enabled {
|
|
|
|
reso = &cacheResolver{
|
|
|
|
cache: map[string][]string{},
|
|
|
|
mu: sync.Mutex{},
|
|
|
|
readOnly: false,
|
|
|
|
resolver: reso,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return reso
|
|
|
|
}
|
|
|
|
|
|
|
|
// MaybeWrapWithStaticDNSCache wraps the provided resolver with a resolver that
|
|
|
|
// checks the given cache before issuing queries to the underlying DNS resolver.
|
|
|
|
//
|
|
|
|
// Bug: the returned resolver only applies caching to LookupHost and any other
|
|
|
|
// lookup operation returns ErrNoDNSTransport to the caller.
|
|
|
|
func MaybeWrapWithStaticDNSCache(cache map[string][]string, reso model.Resolver) model.Resolver {
|
|
|
|
if len(cache) > 0 {
|
|
|
|
reso = &cacheResolver{
|
|
|
|
cache: cache,
|
|
|
|
mu: sync.Mutex{},
|
|
|
|
readOnly: true,
|
|
|
|
resolver: reso,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return reso
|
|
|
|
}
|
|
|
|
|
|
|
|
// cacheResolver implements CachingResolver and StaticDNSCache.
|
|
|
|
type cacheResolver struct {
|
|
|
|
// cache is the underlying DNS cache.
|
2021-02-02 12:05:47 +01:00
|
|
|
cache map[string][]string
|
2022-06-05 21:22:27 +02:00
|
|
|
|
|
|
|
// mu provides mutual exclusion.
|
|
|
|
mu sync.Mutex
|
|
|
|
|
|
|
|
// readOnly means that we won't cache the result of successful resolutions.
|
|
|
|
readOnly bool
|
|
|
|
|
|
|
|
// resolver is the underlying resolver.
|
|
|
|
resolver model.Resolver
|
2021-02-02 12:05:47 +01:00
|
|
|
}
|
|
|
|
|
2022-06-05 21:22:27 +02:00
|
|
|
var _ model.Resolver = &cacheResolver{}
|
|
|
|
|
|
|
|
// LookupHost implements model.Resolver.LookupHost
|
|
|
|
func (r *cacheResolver) LookupHost(
|
2021-02-02 12:05:47 +01:00
|
|
|
ctx context.Context, hostname string) ([]string, error) {
|
2022-06-05 21:22:27 +02:00
|
|
|
if entry := r.get(hostname); entry != nil {
|
2021-02-02 12:05:47 +01:00
|
|
|
return entry, nil
|
|
|
|
}
|
2022-06-05 21:22:27 +02:00
|
|
|
entry, err := r.resolver.LookupHost(ctx, hostname)
|
2021-02-02 12:05:47 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-06-05 21:22:27 +02:00
|
|
|
if !r.readOnly {
|
|
|
|
r.set(hostname, entry)
|
2021-02-02 12:05:47 +01:00
|
|
|
}
|
|
|
|
return entry, nil
|
|
|
|
}
|
|
|
|
|
2022-06-05 21:22:27 +02:00
|
|
|
// get gets the currently configured entry for domain, or nil
|
|
|
|
func (r *cacheResolver) get(domain string) []string {
|
2021-02-02 12:05:47 +01:00
|
|
|
r.mu.Lock()
|
|
|
|
defer r.mu.Unlock()
|
|
|
|
return r.cache[domain]
|
|
|
|
}
|
|
|
|
|
2022-06-05 21:22:27 +02:00
|
|
|
// set sets a valid inside the cache iff readOnly is false.
|
|
|
|
func (r *cacheResolver) set(domain string, addresses []string) {
|
2021-02-02 12:05:47 +01:00
|
|
|
r.mu.Lock()
|
|
|
|
if r.cache == nil {
|
|
|
|
r.cache = make(map[string][]string)
|
|
|
|
}
|
|
|
|
r.cache[domain] = addresses
|
|
|
|
r.mu.Unlock()
|
|
|
|
}
|
2022-06-05 21:22:27 +02:00
|
|
|
|
|
|
|
// Address implements model.Resolver.Address.
|
|
|
|
func (r *cacheResolver) Address() string {
|
|
|
|
return r.resolver.Address()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Network implements model.Resolver.Network.
|
|
|
|
func (r *cacheResolver) Network() string {
|
|
|
|
return r.resolver.Network()
|
|
|
|
}
|
|
|
|
|
|
|
|
// CloseIdleConnections implements model.Resolver.CloseIdleConnections.
|
|
|
|
func (r *cacheResolver) CloseIdleConnections() {
|
|
|
|
r.resolver.CloseIdleConnections()
|
|
|
|
}
|
|
|
|
|
|
|
|
// LookupHTTPS implements model.Resolver.LookupHTTPS.
|
|
|
|
func (r *cacheResolver) LookupHTTPS(ctx context.Context, domain string) (*model.HTTPSSvc, error) {
|
2022-06-05 21:58:34 +02:00
|
|
|
return nil, ErrNoDNSTransport
|
2022-06-05 21:22:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// LookupNS implements model.Resolver.LookupNS.
|
|
|
|
func (r *cacheResolver) LookupNS(ctx context.Context, domain string) ([]*net.NS, error) {
|
2022-06-05 21:58:34 +02:00
|
|
|
return nil, ErrNoDNSTransport
|
2022-06-05 21:22:27 +02:00
|
|
|
}
|