package main import ( // Standard "fmt" "slices" "strings" ) type DNSRecord struct { ID string `json:".id"` Disabled string Dynamic string Name string TTL string Type string ParsedValue string // not from RouterOS, here to not having to have the value logics in frontend too. MatchSubdomain string routerosEntry DNSEntry } type DNSEntry struct { ID string `json:".id"` Disabled string `json:"disabled"` Name string `json:"name"` TTL string `json:"ttl"` Type string `json:"type"` Address string `json:"address,omitempty"` CNAME string `json:"cname,omitempty"` ForwardTo string `json:"forward-to,omitempty"` NS string `json:"ns,omitempty"` Text string `json:"text,omitempty"` AddressList string `json:"address-list,omitempty"` MatchSubdomain string `json:"match-subdomain,omitempty"` } type DomainPart struct { Record []DNSRecord Subparts map[string]*DomainPart `json:",omitempty"` } type RecordsTree struct { Children []RecordsTree } func SortDNSRecord(a, b DNSRecord) int { aComponents := strings.Split(a.Name, ".") bComponents := strings.Split(b.Name, ".") slices.Reverse(aComponents) slices.Reverse(bComponents) for i, aComp := range aComponents { if i >= len(bComponents) { return -1 } bComp := bComponents[i] if aComp > bComp { return 1 } if aComp < bComp { return -1 } } return 0 } func NewDNSRecord(e DNSEntry) (r DNSRecord) { r.routerosEntry = e r.ID = e.ID r.Disabled = e.Disabled r.Name = e.Name r.TTL = e.TTL r.Type = e.Type r.MatchSubdomain = e.MatchSubdomain // Some routeros instances doesn't provide "type" when record is of type "A" :'( if r.Type == "" { r.Type = "A" } r.ParsedValue = r.String() return } func (r DNSRecord) String() string { // {{{ switch r.Type { case "A", "AAAA": return r.routerosEntry.Address case "CNAME": return r.routerosEntry.CNAME case "FWD": return r.routerosEntry.ForwardTo case "NS": return r.routerosEntry.NS case "NXDOMAIN": return r.routerosEntry.AddressList case "TXT": return r.routerosEntry.Text } return fmt.Sprintf("Implement type '%s'", r.Type) } // }}} func (r DNSRecord) Parts() int { // {{{ return len(strings.Split(r.Name, ".")) } // }}} func (r DNSRecord) Part(numParts int) string { // {{{ splitName := strings.Split(r.Name, ".") slices.Reverse(splitName) parts := []string{} for i := range numParts { if i >= len(splitName) { break } parts = append(parts, splitName[i]) } slices.Reverse(parts) return strings.Join(parts, ".") } // }}} func (r DNSRecord) NameReversed() string { // {{{ parts := strings.Split(r.Name, ".") slices.Reverse(parts) return strings.Join(parts, ".") } // }}} func (r DNSRecord) toDNSEntry() (e DNSEntry) { // {{{ e.ID = r.ID e.Disabled = r.Disabled e.Name = r.Name e.TTL = r.TTL e.Type = r.Type e.MatchSubdomain = r.MatchSubdomain switch r.Type { case "A", "AAAA": e.Address = r.ParsedValue case "CNAME": e.CNAME = r.ParsedValue case "FWD": e.ForwardTo = r.ParsedValue case "NS": e.NS = r.ParsedValue case "NXDOMAIN": e.AddressList = r.ParsedValue case "TXT": e.Text = r.ParsedValue } return } // }}}