package model import ( "slices" "strings" ) type RecordType string const ( A RecordType = "A" AAAA RecordType = "AAAA" CNAME RecordType = "CNAME" MX RecordType = "MX" TXT RecordType = "TXT" SRV RecordType = "SRV" NS RecordType = "NS" SOA RecordType = "SOA" ) // Managed reports whether the type participates in diff+apply. // NS and SOA are read-only. func (t RecordType) Managed() bool { switch t { case A, AAAA, CNAME, MX, TXT, SRV: return true default: return false } } // Record is the provider-neutral representation of a DNS RRset. // For MX the value is " "; for SRV it is // " ". Values is an unordered set. type Record struct { Type RecordType Name string TTL int Values []string } // Key uniquely identifies an RRset within a zone. func (r Record) Key() string { return string(r.Type) + " " + normalizeName(r.Name) } func normalizeName(name string) string { n := strings.ToLower(strings.TrimSpace(name)) if n != "" && !strings.HasSuffix(n, ".") { n += "." } return n } // normalizeValue canonicalizes a single RR value for comparison. func normalizeValue(t RecordType, content string) string { if t == TXT { return content // byte-exact — case and whitespace are significant (DKIM/SPF/DMARC) } c := strings.Join(strings.Fields(content), " ") // collapse whitespace switch t { case MX: parts := strings.SplitN(c, " ", 2) if len(parts) == 2 { return parts[0] + " " + normalizeName(parts[1]) } return c case SRV: f := strings.Fields(c) if len(f) == 4 { return f[0] + " " + f[1] + " " + f[2] + " " + normalizeName(f[3]) } return c case CNAME, NS: return normalizeName(c) default: // A, AAAA, SOA return strings.ToLower(c) } } // NormalizedValues returns sorted, normalized values. func (r Record) NormalizedValues() []string { out := make([]string, len(r.Values)) for i, v := range r.Values { out[i] = normalizeValue(r.Type, v) } slices.Sort(out) return out } // Equal reports whether two records have the same TTL and value set. func (r Record) Equal(o Record) bool { if r.TTL != o.TTL { return false } return slices.Equal(r.NormalizedValues(), o.NormalizedValues()) }