check / check (push) Successful in 2m4s
Each domain check now looks up the addresses every nameserver's name resolves to, with the resolver's ResolveIPAddresses, and saves them sorted in the domain's state. A nameserver that stays in the delegation and resolves to different addresses sends one NS Address Change notification naming the domain, the nameserver and the old and new addresses. Added or removed nameservers get only the NS change notification. A failed or empty lookup keeps the previous addresses, because the resolver returns no address without an error when every server it asks times out. State files without the field load, and the next check fills it in silently. Watcher tests that run domain checks use example.com, which has two nameservers, to stay within the per-attempt limit. Model: opus-5-5
77 lines
1.8 KiB
Go
77 lines
1.8 KiB
Go
package watcher
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"time"
|
|
|
|
"sneak.berlin/go/dnswatcher/internal/config"
|
|
"sneak.berlin/go/dnswatcher/internal/resolver"
|
|
"sneak.berlin/go/dnswatcher/internal/state"
|
|
)
|
|
|
|
// NewForTest creates a Watcher without fx for unit testing.
|
|
func NewForTest(
|
|
cfg *config.Config,
|
|
st *state.State,
|
|
res DNSResolver,
|
|
pc PortChecker,
|
|
tc TLSChecker,
|
|
n Notifier,
|
|
) *Watcher {
|
|
return &Watcher{
|
|
log: slog.Default(),
|
|
config: cfg,
|
|
state: st,
|
|
resolver: res,
|
|
portCheck: pc,
|
|
tlsCheck: tc,
|
|
notify: n,
|
|
firstRun: true,
|
|
expiryNotified: make(map[string]time.Time),
|
|
}
|
|
}
|
|
|
|
// NewlyDisagreeingPairs exports newlyDisagreeingPairs for testing.
|
|
func NewlyDisagreeingPairs(
|
|
prev, current *state.HostnameState,
|
|
) [][2]string {
|
|
return newlyDisagreeingPairs(prev, current)
|
|
}
|
|
|
|
// DetectHostnameChanges exports detectHostnameChanges for testing.
|
|
func (w *Watcher) DetectHostnameChanges(
|
|
ctx context.Context,
|
|
hostname string,
|
|
prev, current *state.HostnameState,
|
|
) {
|
|
w.detectHostnameChanges(ctx, hostname, prev, current)
|
|
}
|
|
|
|
// ResolveNameserverAddresses exports resolveNameserverAddresses for
|
|
// testing.
|
|
func (w *Watcher) ResolveNameserverAddresses(
|
|
ctx context.Context,
|
|
nameservers []string,
|
|
prev map[string][]string,
|
|
) map[string][]string {
|
|
return w.resolveNameserverAddresses(ctx, nameservers, prev)
|
|
}
|
|
|
|
// DetectNSAddressChanges exports detectNSAddressChanges for testing.
|
|
func (w *Watcher) DetectNSAddressChanges(
|
|
ctx context.Context,
|
|
domain string,
|
|
prev, current map[string][]string,
|
|
) {
|
|
w.detectNSAddressChanges(ctx, domain, prev, current)
|
|
}
|
|
|
|
// BuildHostnameState exports buildHostnameState for testing.
|
|
func BuildHostnameState(
|
|
results map[string]*resolver.NameserverResponse,
|
|
now time.Time,
|
|
) *state.HostnameState {
|
|
return buildHostnameState(results, now)
|
|
}
|