Resolve PTR names over DNS-over-HTTPS and cache them for the record TTL (closes #238)
check / check (push) Failing after 1m22s

`internal/ptr` asks Google, Cloudflare, AdGuard and Quad9 in turn, 2 seconds in all per address. It keeps answers in memory and writes them through to `cache.db`, opened by the new `internal/cachedb`.

Judgement calls:
- Each resolver gets an equal share of the time left, so a hung resolver does not use up the 2 seconds.
- The negative TTL is the smaller of the SOA minimum and the SOA's own TTL (RFC 2308).
- Names that are not host names are dropped, as `net.Resolver.LookupAddr` does.

Model: opus-5-5
This commit is contained in:
sneak committed 2026-11-10 10:03:08 +00:00
1 parent cf50d195ad
commit 018372363f
18 files changed
+1608 -53

No files matched your search

+11 -12
View File
@@ -39,12 +39,9 @@ const (
const (
// maxLookupTargets is the most addresses and host names an IP lookup may
// list, and the most addresses it may have once the names are resolved:
// each address costs two database reads and a PTR lookup.
// each address costs two database reads and a PTR lookup. Ten PTR lookups
// that run to ptr.LookupTimeout fit in the request's 30-second limit.
maxLookupTargets = 10
// ptrLookupTimeout is each PTR lookup's own time limit, so that ten
// addresses whose PTR lookups never answer fit in the 30-second limit.
ptrLookupTimeout = 2 * time.Second
)
// The Cache-Control header of an IP lookup answer, such as
@@ -1194,15 +1191,17 @@ func publicAddresses(addrs []string) []string {
}
// lookupPTRNames returns the PTR records of ip without their trailing dots. It
// returns an empty list, never nil, when there are none, when the lookup fails
// and when it runs past ptrLookupTimeout, so that an answer's ptr is [] rather
// than null.
// returns an empty list, never nil, when there are none and when the lookup
// fails, so that an answer's ptr is [] rather than null.
func (s *Server) lookupPTRNames(ctx context.Context, ip string) []string {
ctx, cancel := context.WithTimeout(ctx, ptrLookupTimeout)
defer cancel()
ptrs, err := s.ptrResolver.LookupAddr(ctx, ip)
if err != nil {
s.logger.Warn("PTR lookup failed", "ip", ip, "error", err)
ptrs, err := s.resolver.LookupAddr(ctx, ip)
if err != nil || ptrs == nil {
return []string{}
}
if ptrs == nil {
return []string{}
}