package dns import ( "bytes" "fmt" "io" "net/netip" "sort" "time" "darvaza.org/core" "github.com/libdns/libdns" ) func (mgr *Manager) WriteTo(w io.Writer) (int64, error) { var buf bytes.Buffer var zones sort.StringSlice // sort zones for name := range mgr.zones { zones = append(zones, name) } sort.Sort(zones) for _, name := range zones { z := mgr.zones[name] if buf.Len() > 0 { _, _ = buf.WriteRune('\n') } // servers err := mgr.writeZoneMachinesToBuffer(&buf, name, z) if err != nil { return 0, err } } return buf.WriteTo(w) } func (mgr *Manager) writeRecordsToBuffer(buf *bytes.Buffer, records ...libdns.Record) { for _, rr := range records { fqdn := fmt.Sprintf("%s.%s", rr.Name, mgr.domain) _, _ = fmt.Fprintf(buf, "%s\t%v\tIN\t%s\t%v\n", fqdn, int(rr.TTL/time.Second), rr.Type, rr.Value) } } func (mgr *Manager) writeZoneMachinesToBuffer(buf *bytes.Buffer, zone_name string, z *Zone) error { // title _, _ = fmt.Fprintf(buf, ";\n; %s\n;\n", zone_name) records := mgr.genMachineRecords(z) mgr.writeRecordsToBuffer(buf, records...) // zone alias _, _ = fmt.Fprintf(buf, "; %s\n", zone_name) records = mgr.genAliasRecords(zone_name, true, z) mgr.Sort(records) mgr.writeRecordsToBuffer(buf, records...) return nil } func (mgr *Manager) genMachineRecords(z *Zone) []libdns.Record { var out []libdns.Record for _, p := range z.Machines { pqdn := fmt.Sprintf("%s-%v%s", z.Name, p.ID, mgr.suffix) for _, addr := range p.Addrs { out = append(out, libdns.Record{ Name: pqdn, Type: core.IIf(addr.Is6(), "AAAA", "A"), TTL: time.Second, Value: addr.String(), }) } } mgr.Sort(out) return out } func (mgr *Manager) genAliasRecords(name string, activeOnly bool, zones ...*Zone) []libdns.Record { var out []libdns.Record fqdn := fmt.Sprintf("%s%s", name, mgr.suffix) for _, z := range zones { for _, p := range z.Machines { if p.Active || !activeOnly { for _, addr := range p.Addrs { out = append(out, libdns.Record{ Name: fqdn, Type: core.IIf(addr.Is6(), "AAAA", "A"), TTL: time.Second, Value: addr.String(), }) } } } } return out } func (mgr *Manager) Sort(records []libdns.Record) { sort.SliceStable(records, func(i, j int) bool { a := &records[i] b := &records[j] switch { case a.Name < b.Name: return true case a.Name > b.Name: return false case a.Type < b.Type: return true case a.Type > b.Type: return false case a.Type == "A" || a.Type == "AAAA": var aAddr, bAddr netip.Addr aAddr.UnmarshalText([]byte(a.Value)) bAddr.UnmarshalText([]byte(b.Value)) return aAddr.Less(bAddr) case a.Value < b.Value: return true default: return false } }) }