package dns import ( "bytes" "fmt" "io" "net/netip" "sort" "time" "darvaza.org/core" "github.com/libdns/libdns" ) // SortAddrSlice sorts a slice of [netip.Addr] func SortAddrSlice(s []netip.Addr) []netip.Addr { sort.Slice(s, func(i, j int) bool { return s[i].Less(s[j]) }) return s } // SortAddrRecords sorts a slice of [AddrRecord] // by Name and Address func SortAddrRecords(s []AddrRecord) []AddrRecord { sort.Slice(s, func(i, j int) bool { return s[i].Name < s[j].Name }) for _, p := range s { SortAddrSlice(p.Addr) } return s } // SortRegions sorts regions. first by length those 3-character // or shorter, and then by length. It's mostly aimed at // supporting ISO-3166 order func SortRegions(regions []string) []string { sort.Slice(regions, func(i, j int) bool { r1, r2 := regions[i], regions[j] switch { case len(r1) < 4: switch { case len(r1) < len(r2): return true case len(r1) > len(r2): return false default: return r1 < r2 } case len(r2) < 4: return false default: return r1 < r2 } }) return regions } // AddrRecord represents an A or AAAA record type AddrRecord struct { Name string Addr []netip.Addr } // Sort sorts the addresses of the record func (rr *AddrRecord) Sort() { SortAddrSlice(rr.Addr) } // Export converts the record into libdns.Record func (rr *AddrRecord) Export() []libdns.Record { out := make([]libdns.Record, len(rr.Addr)) for i, addr := range rr.Addr { out[i] = libdns.Record{ Name: rr.Name, TTL: time.Second * 1, Type: core.IIf(addr.Is6(), "AAAA", "A"), Value: addr.String(), } } return out } // WriteTo writes the record in BIND notation func (rr *AddrRecord) WriteTo(w io.Writer) (int64, error) { var total int for _, addr := range rr.Addr { n, err := fmt.Fprint(w, rr.Name, "\t", 1, "\t", core.IIf(addr.Is6(), "AAAA", "A"), "\t", addr.String(), "\n") switch { case err != nil: return 0, err case n > 0: total += n } } return int64(total), nil } // String converts the record into BIND entries func (rr *AddrRecord) String() string { var buf bytes.Buffer _, _ = rr.WriteTo(&buf) return buf.String() }