diff --git a/go.mod b/go.mod index da2402f..939924e 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( darvaza.org/slog/handlers/discard v0.4.5 github.com/gofrs/uuid/v5 v5.0.0 github.com/hack-pad/hackpadfs v0.2.1 + github.com/libdns/libdns v0.2.1 github.com/mgechev/revive v1.3.3 github.com/spf13/cobra v1.7.0 golang.org/x/crypto v0.12.0 diff --git a/go.sum b/go.sum index 3029c5c..b0a0a72 100644 --- a/go.sum +++ b/go.sum @@ -36,6 +36,8 @@ github.com/hack-pad/hackpadfs v0.2.1 h1:FelFhIhv26gyjujoA/yeFO+6YGlqzmc9la/6iKMI github.com/hack-pad/hackpadfs v0.2.1/go.mod h1:khQBuCEwGXWakkmq8ZiFUvUZz84ZkJ2KNwKvChs4OrU= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis= +github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= diff --git a/pkg/dns/dns.go b/pkg/dns/dns.go new file mode 100644 index 0000000..ca95946 --- /dev/null +++ b/pkg/dns/dns.go @@ -0,0 +1,2 @@ +// Package dns manages DNS entries for the cluster +package dns diff --git a/pkg/dns/record.go b/pkg/dns/record.go new file mode 100644 index 0000000..2f8810d --- /dev/null +++ b/pkg/dns/record.go @@ -0,0 +1,89 @@ +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 +} + +// 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() +}