package watcher_test import ( "context" "log/slog" "slices" "testing" "sneak.berlin/go/dnswatcher/internal/livednstest" "sneak.berlin/go/dnswatcher/internal/resolver" "sneak.berlin/go/dnswatcher/internal/state" "sneak.berlin/go/dnswatcher/internal/watcher" ) // cnameHost is a CNAME into another zone: its nameservers answer with // the CNAME and no address. const cnameHost = "www.python.org" // TestCNAMEIntoAnotherZonePortAndTLSChecks checks cnameHost against // live DNS. Its port and TLS checks must use the addresses at the end // of its CNAME chain. func TestCNAMEIntoAnotherZonePortAndTLSChecks(t *testing.T) { t.Parallel() cfg := defaultTestConfig(t) cfg.Hostnames = []string{cnameHost} deps := runChecks(t, cfg, nil, nil) snap := deps.state.GetSnapshot() hs := snap.Hostnames[cnameHost] if len(hs.CNAMEAddresses) == 0 { t.Fatalf( "%s: no addresses saved from following its CNAME; if it "+ "is no longer a CNAME into another zone, this test "+ "needs another name", cnameHost, ) } for _, ip := range hs.CNAMEAddresses { ps, ok := snap.Ports[ip+":443"] if !ok || !slices.Contains(ps.Hostnames, cnameHost) { t.Errorf("no port state for %s at %s:443", cnameHost, ip) } certKey := ip + ":443:" + cnameHost if _, ok := snap.Certificates[certKey]; !ok { t.Errorf("no certificate state %s", certKey) } } } // TestCNAMEThatCannotBeFollowedKeepsPrevious gives a name under // .invalid, whose lookup fails, answers with a CNAME and no address. // The addresses the previous check saved from following its CNAME are // kept. func TestCNAMEThatCannotBeFollowedKeepsPrevious(t *testing.T) { t.Parallel() const name = "www.example.invalid" w := watcher.NewForTest( nil, nil, resolver.NewFromLogger(slog.Default()), nil, nil, nil, ) current := hostnameState(map[string]map[string][]string{ nsA: {"CNAME": {"target.example.invalid."}}, }) prev := &state.HostnameState{CNAMEAddresses: []string{oldIP}} // The result is the same whether or not live DNS answers, so the // lookup is not retried. _ = livednstest.Run(func(ctx context.Context) error { w.ResolveCNAMEAddresses(ctx, name, current, prev) return nil }) if !slices.Equal(current.CNAMEAddresses, prev.CNAMEAddresses) { t.Errorf( "saved %v, want %v", current.CNAMEAddresses, prev.CNAMEAddresses, ) } }