Migrate from dns.RR to dnscontrol.RecordConfig
continuous-integration/drone/push Build is failing Details

This commit is contained in:
nemunaire 2023-09-15 20:25:31 +02:00
parent eb39197e11
commit 857e70c079
25 changed files with 451 additions and 425 deletions

View File

@ -337,7 +337,14 @@ func importZone(c *gin.Context) {
rrs = append(rrs, rr)
}
zone.Services, _, err = svcs.AnalyzeZone(domain.DomainName, rrs)
rcs, err := models.RRstoRCs(rrs, strings.TrimSuffix(domain.DomainName, "."))
if err != nil {
log.Printf("Error when converting RRs to RCs of %s: %s", c.ClientIP(), err.Error())
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": fmt.Sprintf("Unable to read your zone file: %s", err.Error())})
return
}
zone.Services, _, err = svcs.AnalyzeZone(domain.DomainName, rcs)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
@ -395,11 +402,7 @@ func diffZones(c *gin.Context) {
return
}
records, err := models.RRstoRCs(zone.GenerateRRs(domain.DomainName), strings.TrimSuffix(domain.DomainName, "."))
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
}
records := zone.GenerateRRs(domain.DomainName)
dc := &models.DomainConfig{
Name: strings.TrimSuffix(domain.DomainName, "."),
@ -449,11 +452,7 @@ func applyZone(c *gin.Context) {
return
}
records, err := models.RRstoRCs(zone.GenerateRRs(domain.DomainName), strings.TrimSuffix(domain.DomainName, "."))
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
return
}
records := zone.GenerateRRs(domain.DomainName)
dc := &models.DomainConfig{
Name: strings.TrimSuffix(domain.DomainName, "."),
@ -550,8 +549,12 @@ func viewZone(c *gin.Context) {
var ret string
for _, rr := range zone.GenerateRRs(domain.DomainName) {
ret += rr.String() + "\n"
for _, rc := range zone.GenerateRRs(domain.DomainName) {
if _, ok := dns.StringToType[rc.Type]; ok {
ret += rc.ToRR().String() + "\n"
} else {
ret += fmt.Sprintf("%s %d IN %s %s\n", rc.NameFQDN, rc.TTL, rc.Type, rc.String())
}
}
c.JSON(http.StatusOK, ret)
@ -646,8 +649,10 @@ func deleteZoneService(c *gin.Context) {
}
type serviceRecord struct {
String string `json:"str"`
Fields *dns.RR `json:"fields,omitempty"`
Type string `json:"type"`
String string `json:"str"`
Fields *models.RecordConfig `json:"fields,omitempty"`
RR dns.RR `json:"rr,omitempty"`
}
// getServiceRecords retrieves the records that will be generated by a Service.
@ -680,10 +685,17 @@ func getServiceRecords(c *gin.Context) {
}
var ret []serviceRecord
for _, rr := range svc.GenRRs(subdomain, 3600, domain.DomainName) {
for _, rc := range svc.GenRRs(subdomain, 3600, domain.DomainName) {
var rr dns.RR
if _, ok := dns.StringToType[rc.Type]; ok {
rr = rc.ToRR()
}
ret = append(ret, serviceRecord{
String: rr.String(),
Fields: &rr,
Type: rc.Type,
String: rc.String(),
Fields: rc,
RR: rr,
})
}

View File

@ -37,7 +37,6 @@ import (
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/providers"
"github.com/miekg/dns"
)
// Provider is where Domains and Zones can be managed.
@ -108,17 +107,8 @@ func (p *ProviderCombined) DomainExists(fqdn string) (err error) {
return nil
}
func (p *ProviderCombined) ImportZone(dn *Domain) (rrs []dns.RR, err error) {
rcs, err := p.getZoneRecords(dn.DomainName)
if err != nil {
return rrs, err
}
for _, rc := range rcs {
rrs = append(rrs, rc.ToRR())
}
return
func (p *ProviderCombined) ImportZone(dn *Domain) (rcs models.Records, err error) {
return p.getZoneRecords(dn.DomainName)
}
func (p *ProviderCombined) GetDomainCorrections(dn *Domain, dc *models.DomainConfig) (rrs []*models.Correction, err error) {

View File

@ -36,7 +36,7 @@ import (
"fmt"
"io"
"github.com/miekg/dns"
"github.com/StackExchange/dnscontrol/v4/models"
)
// Service represents a service provided by one or more DNS record.
@ -48,7 +48,7 @@ type Service interface {
GenComment(origin string) string
// genRRs generates corresponding RRs.
GenRRs(domain string, ttl uint32, origin string) []dns.RR
GenRRs(domain string, ttl uint32, origin string) models.Records
}
// ServiceMeta holds the metadata associated to a Service.

View File

@ -36,7 +36,7 @@ import (
"errors"
"time"
"github.com/miekg/dns"
"github.com/StackExchange/dnscontrol/v4/models"
)
// ZoneMeta holds the metadata associated to a Zone.
@ -174,7 +174,7 @@ func (z *Zone) EraseServiceWithoutMeta(subdomain string, origin string, id []byt
}
// GenerateRRs returns all the reals records of the Zone.
func (z *Zone) GenerateRRs(origin string) (rrs []dns.RR) {
func (z *Zone) GenerateRRs(origin string) (rrs models.Records) {
for subdomain, svcs := range z.Services {
if subdomain == "" {
subdomain = origin

View File

@ -34,6 +34,7 @@ package abstract
import (
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
@ -53,25 +54,19 @@ func (s *ACMEChallenge) GenComment(origin string) string {
return s.Challenge
}
func (s *ACMEChallenge) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
rrs = append(rrs, &dns.TXT{
Hdr: dns.RR_Header{
Name: utils.DomainJoin("_acme-challenge", domain),
Rrtype: dns.TypeTXT,
Class: dns.ClassINET,
Ttl: ttl,
},
Txt: []string{s.Challenge},
})
func (s *ACMEChallenge) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
rr := utils.NewRecordConfig(utils.DomainJoin("_acme-challenge", domain), "TXT", ttl, origin)
rr.SetTargetTXT(s.Challenge)
rrs = append(rrs, rr)
return
}
func acmechallenge_analyze(a *svcs.Analyzer) error {
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeTXT, Prefix: "_acme-challenge"}) {
domain := strings.TrimPrefix(record.Header().Name, "_acme-challenge.")
if txt, ok := record.(*dns.TXT); ok {
domain := strings.TrimPrefix(record.NameFQDN, "_acme-challenge.")
if record.Type == "TXT" {
a.UseRR(record, domain, &ACMEChallenge{
Challenge: strings.Join(txt.Txt, ""),
Challenge: record.GetTargetTXTJoined(),
})
}
}

View File

@ -34,6 +34,7 @@ package abstract
import (
"fmt"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
@ -59,31 +60,21 @@ func (s *Delegation) GenComment(origin string) string {
return fmt.Sprintf("%d name servers"+ds, len(s.NameServers))
}
func (s *Delegation) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
func (s *Delegation) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
for _, ns := range s.NameServers {
rrs = append(rrs, &dns.NS{
Hdr: dns.RR_Header{
Name: domain,
Rrtype: dns.TypeNS,
Class: dns.ClassINET,
Ttl: ttl,
},
Ns: utils.DomainFQDN(ns, origin),
})
rc := utils.NewRecordConfig(utils.DomainJoin(domain), "NS", ttl, origin)
rc.SetTarget(utils.DomainFQDN(ns, origin))
rrs = append(rrs, rc)
}
for _, ds := range s.DS {
rrs = append(rrs, &dns.DS{
Hdr: dns.RR_Header{
Name: domain,
Rrtype: dns.TypeDS,
Class: dns.ClassINET,
Ttl: ttl,
},
KeyTag: ds.KeyTag,
Algorithm: ds.Algorithm,
DigestType: ds.DigestType,
Digest: ds.Digest,
})
rc := utils.NewRecordConfig(utils.DomainJoin(domain), "DS", ttl, origin)
rc.DsKeyTag = ds.KeyTag
rc.DsAlgorithm = ds.Algorithm
rc.DsDigestType = ds.DigestType
rc.DsDigest = ds.Digest
rrs = append(rrs, rc)
}
return
}
@ -92,33 +83,33 @@ func delegation_analyze(a *svcs.Analyzer) error {
delegations := map[string]*Delegation{}
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeNS}) {
if record.Header().Name == a.GetOrigin() {
if record.NameFQDN == a.GetOrigin() {
continue
}
if ns, ok := record.(*dns.NS); ok {
if _, ok := delegations[ns.Header().Name]; !ok {
delegations[ns.Header().Name] = &Delegation{}
if record.Type == "NS" {
if _, ok := delegations[record.NameFQDN]; !ok {
delegations[record.NameFQDN] = &Delegation{}
}
delegations[ns.Header().Name].NameServers = append(delegations[ns.Header().Name].NameServers, ns.Ns)
delegations[record.NameFQDN].NameServers = append(delegations[record.NameFQDN].NameServers, record.GetTargetField())
a.UseRR(
record,
ns.Header().Name,
delegations[ns.Header().Name],
record.NameFQDN,
delegations[record.NameFQDN],
)
}
}
for subdomain := range delegations {
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeDS, Domain: subdomain}) {
if ds, ok := record.(*dns.DS); ok {
if record.Type == "DS" {
delegations[subdomain].DS = append(delegations[subdomain].DS, svcs.DS{
KeyTag: ds.KeyTag,
Algorithm: ds.Algorithm,
DigestType: ds.DigestType,
Digest: ds.Digest,
KeyTag: record.DsKeyTag,
Algorithm: record.DsAlgorithm,
DigestType: record.DsDigestType,
Digest: record.DsDigest,
})
a.UseRR(

View File

@ -36,6 +36,8 @@ import (
"fmt"
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/spflib"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
@ -113,80 +115,50 @@ func (s *EMail) GenComment(origin string) string {
return buffer.String()
}
func (s *EMail) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
func (s *EMail) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
if len(s.MX) > 0 {
for _, mx := range s.MX {
rrs = append(rrs, &dns.MX{
Hdr: dns.RR_Header{
Name: utils.DomainJoin(domain),
Rrtype: dns.TypeMX,
Class: dns.ClassINET,
Ttl: ttl,
},
Mx: utils.DomainFQDN(mx.Target, origin),
Preference: mx.Preference,
})
rc := utils.NewRecordConfig(domain, "MX", ttl, origin)
rc.MxPreference = mx.Preference
rc.SetTarget(utils.DomainFQDN(mx.Target, origin))
rrs = append(rrs, rc)
}
}
if s.SPF != nil {
rrs = append(rrs, &dns.TXT{
Hdr: dns.RR_Header{
Name: utils.DomainJoin(domain),
Rrtype: dns.TypeTXT,
Class: dns.ClassINET,
Ttl: ttl,
},
Txt: utils.SplitN(s.SPF.String(), 255),
})
rc := utils.NewRecordConfig(domain, "TXT", ttl, origin)
rc.SetTargetTXT(s.SPF.String())
rrs = append(rrs, rc)
}
for selector, d := range s.DKIM {
rrs = append(rrs, &dns.TXT{
Hdr: dns.RR_Header{
Name: utils.DomainJoin(selector+"._domainkey", domain),
Rrtype: dns.TypeTXT,
Class: dns.ClassINET,
Ttl: ttl,
},
Txt: utils.SplitN(d.String(), 255),
})
rc := utils.NewRecordConfig(utils.DomainJoin(selector+"._domainkey", domain), "TXT", ttl, origin)
rc.SetTargetTXT(d.String())
rrs = append(rrs, rc)
}
if s.DMARC != nil {
rrs = append(rrs, &dns.TXT{
Hdr: dns.RR_Header{
Name: utils.DomainJoin("_dmarc", domain),
Rrtype: dns.TypeTXT,
Class: dns.ClassINET,
Ttl: ttl,
},
Txt: utils.SplitN(s.DMARC.String(), 255),
})
rc := utils.NewRecordConfig(utils.DomainJoin("_dmarc", domain), "TXT", ttl, origin)
rc.SetTargetTXT(s.DMARC.String())
rrs = append(rrs, rc)
}
if s.MTA_STS != nil {
rrs = append(rrs, &dns.TXT{
Hdr: dns.RR_Header{
Name: utils.DomainJoin("_mta-sts", domain),
Rrtype: dns.TypeTXT,
Class: dns.ClassINET,
Ttl: ttl,
},
Txt: utils.SplitN(s.MTA_STS.String(), 255),
})
rc := utils.NewRecordConfig(utils.DomainJoin("_mta-sts", domain), "TXT", ttl, origin)
rc.SetTargetTXT(s.MTA_STS.String())
rrs = append(rrs, rc)
}
if s.TLS_RPT != nil {
rrs = append(rrs, &dns.TXT{
Hdr: dns.RR_Header{
Name: utils.DomainJoin("_smtp._tls", domain),
Rrtype: dns.TypeTXT,
Class: dns.ClassINET,
Ttl: ttl,
},
Txt: utils.SplitN(s.TLS_RPT.String(), 255),
})
rc := utils.NewRecordConfig(utils.DomainJoin("_smtp._tls", domain), "TXT", ttl, origin)
rc.SetTargetTXT(s.TLS_RPT.String())
rrs = append(rrs, rc)
}
return
}
@ -196,8 +168,8 @@ func email_analyze(a *svcs.Analyzer) (err error) {
// Handle only MX records
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeMX}) {
if mx, ok := record.(*dns.MX); ok {
dn := mx.Header().Name
if record.Type == "MX" {
dn := record.NameFQDN
if _, ok := services[dn]; !ok {
services[dn] = &EMail{}
@ -206,8 +178,8 @@ func email_analyze(a *svcs.Analyzer) (err error) {
services[dn].MX = append(
services[dn].MX,
svcs.MX{
Target: mx.Mx,
Preference: mx.Preference,
Target: record.GetTargetField(),
Preference: record.MxPreference,
},
)
@ -225,12 +197,17 @@ func email_analyze(a *svcs.Analyzer) (err error) {
for domain, service := range services {
// Is there SPF record?
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeTXT, Domain: domain, Contains: "v=spf1"}) {
if service.SPF == nil {
service.SPF = &svcs.SPF{}
}
if record.Type == "TXT" || record.Type == "SPF" {
_, err := spflib.Parse(record.GetTargetTXTJoined(), nil)
if err != nil {
continue
}
if txt, ok := record.(*dns.TXT); ok {
fields := strings.Fields(service.SPF.Content + " " + strings.TrimPrefix(strings.TrimSpace(strings.Join(txt.Txt, "")), "v=spf1"))
if service.SPF == nil {
service.SPF = &svcs.SPF{}
}
fields := strings.Fields(service.SPF.Content + " " + strings.TrimPrefix(strings.TrimSpace(record.GetTargetTXTJoined()), "v=spf1"))
for i := 0; i < len(fields); i += 1 {
for j := i + 1; j < len(fields); j += 1 {
@ -253,14 +230,14 @@ func email_analyze(a *svcs.Analyzer) (err error) {
service.DKIM = map[string]*svcs.DKIM{}
// Is there DKIM record?
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeTXT, SubdomainsOf: "_domainkey." + domain}) {
selector := strings.TrimSuffix(record.Header().Name, "._domainkey."+domain)
selector := strings.TrimSuffix(record.NameFQDN, "._domainkey."+domain)
if _, ok := service.DKIM[selector]; !ok {
service.DKIM[selector] = &svcs.DKIM{}
}
if txt, ok := record.(*dns.TXT); ok {
service.DKIM[selector].Fields = append(service.DKIM[selector].Fields, strings.Split(strings.Join(txt.Txt, ""), ";")...)
if record.Type == "TXT" {
service.DKIM[selector].Fields = append(service.DKIM[selector].Fields, strings.Split(record.GetTargetTXTJoined(), ";")...)
}
err = a.UseRR(record, domain, service)
@ -275,8 +252,8 @@ func email_analyze(a *svcs.Analyzer) (err error) {
service.DMARC = &svcs.DMARC{}
}
if txt, ok := record.(*dns.TXT); ok {
service.DMARC.Fields = append(service.DMARC.Fields, strings.Split(strings.TrimPrefix(strings.Join(txt.Txt, ""), "v=DMARC1;"), ";")...)
if record.Type == "TXT" {
service.DMARC.Fields = append(service.DMARC.Fields, strings.Split(strings.TrimPrefix(record.GetTargetTXTJoined(), "v=DMARC1;"), ";")...)
}
err = a.UseRR(record, domain, service)
@ -291,8 +268,8 @@ func email_analyze(a *svcs.Analyzer) (err error) {
service.MTA_STS = &svcs.MTA_STS{}
}
if txt, ok := record.(*dns.TXT); ok {
service.MTA_STS.Fields = append(service.MTA_STS.Fields, strings.Split(strings.Join(txt.Txt, ""), ";")...)
if record.Type == "TXT" {
service.MTA_STS.Fields = append(service.MTA_STS.Fields, strings.Split(record.GetTargetTXTJoined(), ";")...)
}
err = a.UseRR(record, domain, service)
@ -307,8 +284,8 @@ func email_analyze(a *svcs.Analyzer) (err error) {
service.TLS_RPT = &svcs.TLS_RPT{}
}
if txt, ok := record.(*dns.TXT); ok {
service.TLS_RPT.Fields = append(service.TLS_RPT.Fields, strings.Split(strings.Join(txt.Txt, ""), ";")...)
if record.Type == "TXT" {
service.TLS_RPT.Fields = append(service.TLS_RPT.Fields, strings.Split(record.GetTargetTXTJoined(), ";")...)
}
err = a.UseRR(record, domain, service)

View File

@ -34,10 +34,12 @@ package abstract
import (
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
"git.happydns.org/happyDomain/services"
"git.happydns.org/happyDomain/utils"
)
type GoogleVerif struct {
@ -52,25 +54,20 @@ func (s *GoogleVerif) GenComment(origin string) string {
return s.SiteVerification
}
func (s *GoogleVerif) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
rrs = append(rrs, &dns.TXT{
Hdr: dns.RR_Header{
Name: domain,
Rrtype: dns.TypeTXT,
Class: dns.ClassINET,
Ttl: ttl,
},
Txt: []string{"google-site-verification=" + strings.TrimPrefix(s.SiteVerification, "google-site-verification=")},
})
func (s *GoogleVerif) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
rc := utils.NewRecordConfig(domain, "TXT", ttl, origin)
rc.SetTargetTXT("google-site-verification=" + strings.TrimPrefix(s.SiteVerification, "google-site-verification="))
rrs = append(rrs, rc)
return
}
func googleverification_analyze(a *svcs.Analyzer) error {
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeTXT}) {
domain := record.Header().Name
if txt, ok := record.(*dns.TXT); ok && strings.HasPrefix(strings.Join(txt.Txt, ""), "google-site-verification=") {
domain := record.NameFQDN
if record.Type == "TXT" && strings.HasPrefix(record.GetTargetTXTJoined(), "google-site-verification=") {
a.UseRR(record, domain, &GoogleVerif{
SiteVerification: strings.TrimPrefix(strings.Join(txt.Txt, ""), "google-site-verification="),
SiteVerification: strings.TrimPrefix(record.GetTargetTXTJoined(), "google-site-verification="),
})
}
}

View File

@ -34,6 +34,7 @@ package abstract
import (
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
@ -53,25 +54,19 @@ func (s *KeybaseVerif) GenComment(origin string) string {
return s.SiteVerification
}
func (s *KeybaseVerif) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
rrs = append(rrs, &dns.TXT{
Hdr: dns.RR_Header{
Name: utils.DomainJoin("_keybase", domain),
Rrtype: dns.TypeTXT,
Class: dns.ClassINET,
Ttl: ttl,
},
Txt: []string{"keybase-site-verification=" + strings.TrimPrefix(s.SiteVerification, "keybase-site-verification=")},
})
func (s *KeybaseVerif) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
rc := utils.NewRecordConfig(utils.DomainJoin("_keybase", domain), "TXT", ttl, origin)
rc.SetTargetTXT("keybase-site-verification=" + strings.TrimPrefix(s.SiteVerification, "keybase-site-verification="))
rrs = append(rrs, rc)
return
}
func keybaseverification_analyze(a *svcs.Analyzer) error {
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeTXT, Prefix: "_keybase"}) {
domain := strings.TrimPrefix(record.Header().Name, "_keybase.")
if txt, ok := record.(*dns.TXT); ok {
domain := strings.TrimPrefix(record.NameFQDN, "_keybase.")
if record.Type == "TXT" {
a.UseRR(record, domain, &KeybaseVerif{
SiteVerification: strings.TrimPrefix(strings.Join(txt.Txt, ""), "keybase-site-verification="),
SiteVerification: strings.TrimPrefix(record.GetTargetTXTJoined(), "keybase-site-verification="),
})
}
}

View File

@ -36,6 +36,7 @@ import (
"strconv"
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
@ -90,7 +91,7 @@ destloop:
return buffer.String()
}
func (s *MatrixIM) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
func (s *MatrixIM) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
for _, matrix := range s.Matrix {
rrs = append(rrs, matrix.GenRRs(utils.DomainJoin("_matrix._tcp", domain), ttl, origin)...)
}
@ -102,7 +103,7 @@ func matrix_analyze(a *svcs.Analyzer) error {
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Prefix: "_matrix._tcp.", Type: dns.TypeSRV}) {
if srv := svcs.ParseSRV(record); srv != nil {
domain := strings.TrimPrefix(record.Header().Name, "_matrix._tcp.")
domain := strings.TrimPrefix(record.NameFQDN, "_matrix._tcp.")
if _, ok := matrixDomains[domain]; !ok {
matrixDomains[domain] = &MatrixIM{}

View File

@ -38,6 +38,7 @@ import (
"fmt"
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
@ -59,21 +60,16 @@ func (s *OpenPGP) GenComment(origin string) string {
return fmt.Sprintf("%s", s.Username)
}
func (s *OpenPGP) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
func (s *OpenPGP) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
if len(s.PublicKey) > 0 {
if s.Username != "" {
s.Identifier = fmt.Sprintf("%x", sha256.Sum224([]byte(s.Username)))
}
rrs = append(rrs, &dns.OPENPGPKEY{
Hdr: dns.RR_Header{
Name: utils.DomainJoin(fmt.Sprintf("%s._openpgpkey", s.Identifier), domain),
Rrtype: dns.TypeOPENPGPKEY,
Class: dns.ClassINET,
Ttl: ttl,
},
PublicKey: base64.StdEncoding.EncodeToString(s.PublicKey),
})
rc := utils.NewRecordConfig(utils.DomainJoin(fmt.Sprintf("%s._openpgpkey", s.Identifier), domain), "OPENPGPKEY", ttl, origin)
rc.SetTargetOpenPGPKey(base64.StdEncoding.EncodeToString(s.PublicKey))
rrs = append(rrs, rc)
}
return
}
@ -95,38 +91,30 @@ func (s *SMimeCert) GenComment(origin string) string {
return fmt.Sprintf("%s", s.Username)
}
func (s *SMimeCert) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
func (s *SMimeCert) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
if len(s.Certificate) > 0 {
if s.Username != "" {
s.Identifier = fmt.Sprintf("%x", sha256.Sum224([]byte(s.Username)))
}
rrs = append(rrs, &dns.SMIMEA{
Hdr: dns.RR_Header{
Name: utils.DomainJoin(fmt.Sprintf("%s._smimecert", s.Identifier), domain),
Rrtype: dns.TypeSMIMEA,
Class: dns.ClassINET,
Ttl: ttl,
},
Usage: s.CertUsage,
Selector: s.Selector,
MatchingType: s.MatchingType,
Certificate: hex.EncodeToString(s.Certificate),
})
rc := utils.NewRecordConfig(utils.DomainJoin(fmt.Sprintf("%s._smimecert", s.Identifier), domain), "SMIMEA", ttl, origin)
rc.SetTarget(fmt.Sprintf("%d %d %d %s", s.CertUsage, s.Selector, s.MatchingType, hex.EncodeToString(s.Certificate)))
rrs = append(rrs, rc)
}
return
}
func openpgpkey_analyze(a *svcs.Analyzer) (err error) {
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeOPENPGPKEY, Contains: "._openpgpkey."}) {
if openpgpkey, ok := record.(*dns.OPENPGPKEY); ok {
domain := record.Header().Name
if record.Type == "OPENPGPKEY" {
domain := record.NameFQDN
domain = domain[strings.Index(domain, "._openpgpkey")+13:]
identifier := strings.TrimSuffix(record.Header().Name, "._openpgpkey."+domain)
identifier := strings.TrimSuffix(record.NameFQDN, "._openpgpkey."+domain)
var pubkey []byte
pubkey, err = base64.StdEncoding.DecodeString(strings.TrimSuffix(strings.TrimPrefix(openpgpkey.PublicKey, "( "), " )"))
pubkey, err = base64.StdEncoding.DecodeString(strings.Join(strings.Fields(strings.TrimSuffix(strings.TrimPrefix(record.GetOpenPGPKeyField(), "("), ")")), ""))
if err != nil {
return
}
@ -149,11 +137,13 @@ func openpgpkey_analyze(a *svcs.Analyzer) (err error) {
func smimea_analyze(a *svcs.Analyzer) (err error) {
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeSMIMEA, Contains: "._smimecert."}) {
if smimecert, ok := record.(*dns.SMIMEA); ok {
domain := record.Header().Name
if record.Type == "SMIMEA" {
domain := record.NameFQDN
domain = domain[strings.Index(domain, "._smimecert")+12:]
identifier := strings.TrimSuffix(record.Header().Name, "._smimecert."+domain)
smimecert := record.ToRR().(*dns.SMIMEA)
identifier := strings.TrimSuffix(record.NameFQDN, "._smimecert."+domain)
var cert []byte
cert, err = hex.DecodeString(smimecert.Certificate)

View File

@ -36,6 +36,7 @@ import (
"strings"
"time"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
@ -68,61 +69,51 @@ func (s *Origin) GenComment(origin string) string {
return fmt.Sprintf("%s %s %d"+ns, strings.TrimSuffix(s.Ns, "."+origin), strings.TrimSuffix(s.Mbox, "."+origin), s.Serial)
}
func (s *Origin) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
rrs = append(rrs, &dns.SOA{
Hdr: dns.RR_Header{
Name: utils.DomainJoin(domain),
Rrtype: dns.TypeSOA,
Class: dns.ClassINET,
Ttl: ttl,
},
Ns: utils.DomainFQDN(s.Ns, origin),
Mbox: utils.DomainFQDN(s.Mbox, origin),
Serial: s.Serial,
Refresh: uint32(s.Refresh.Seconds()),
Retry: uint32(s.Retry.Seconds()),
Expire: uint32(s.Expire.Seconds()),
Minttl: uint32(s.Negttl.Seconds()),
})
func (s *Origin) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
rc := utils.NewRecordConfig(domain, "SOA", ttl, origin)
rc.SoaMbox = utils.DomainFQDN(s.Mbox, origin)
rc.SoaSerial = s.Serial
rc.SoaRefresh = uint32(s.Refresh.Seconds())
rc.SoaRetry = uint32(s.Retry.Seconds())
rc.SoaExpire = uint32(s.Expire.Seconds())
rc.SoaMinttl = uint32(s.Negttl.Seconds())
rc.SetTarget(utils.DomainFQDN(s.Ns, origin))
rrs = append(rrs, rc)
for _, ns := range s.NameServers {
rrs = append(rrs, &dns.NS{
Hdr: dns.RR_Header{
Name: utils.DomainJoin(domain),
Rrtype: dns.TypeNS,
Class: dns.ClassINET,
Ttl: ttl,
},
Ns: utils.DomainFQDN(ns, origin),
})
rc = utils.NewRecordConfig(domain, "NS", ttl, origin)
rc.SetTarget(utils.DomainFQDN(ns, origin))
rrs = append(rrs, rc)
}
return
}
func origin_analyze(a *svcs.Analyzer) error {
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeSOA}) {
if soa, ok := record.(*dns.SOA); ok {
if record.Type == "SOA" {
origin := &Origin{
Ns: soa.Ns,
Mbox: soa.Mbox,
Serial: soa.Serial,
Refresh: common.Duration(time.Duration(soa.Refresh) * time.Second),
Retry: common.Duration(time.Duration(soa.Retry) * time.Second),
Expire: common.Duration(time.Duration(soa.Expire) * time.Second),
Negttl: common.Duration(time.Duration(soa.Minttl) * time.Second),
Ns: record.GetTargetField(),
Mbox: record.SoaMbox,
Serial: record.SoaSerial,
Refresh: common.Duration(time.Duration(record.SoaRefresh) * time.Second),
Retry: common.Duration(time.Duration(record.SoaRetry) * time.Second),
Expire: common.Duration(time.Duration(record.SoaExpire) * time.Second),
Negttl: common.Duration(time.Duration(record.SoaMinttl) * time.Second),
}
a.UseRR(
record,
soa.Header().Name,
record.NameFQDN,
origin,
)
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeNS, Domain: soa.Header().Name}) {
if ns, ok := record.(*dns.NS); ok {
origin.NameServers = append(origin.NameServers, ns.Ns)
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeNS, Domain: record.NameFQDN}) {
if record.Type == "NS" {
origin.NameServers = append(origin.NameServers, record.GetTargetField())
a.UseRR(
record,
ns.Header().Name,
record.NameFQDN,
origin,
)
}

View File

@ -34,6 +34,7 @@ package abstract
import (
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
@ -53,25 +54,19 @@ func (s *ScalewayChallenge) GenComment(origin string) string {
return s.Challenge
}
func (s *ScalewayChallenge) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
rrs = append(rrs, &dns.TXT{
Hdr: dns.RR_Header{
Name: utils.DomainJoin("_scaleway-challenge", domain),
Rrtype: dns.TypeTXT,
Class: dns.ClassINET,
Ttl: ttl,
},
Txt: []string{s.Challenge},
})
func (s *ScalewayChallenge) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
rc := utils.NewRecordConfig(utils.DomainJoin("_scaleway-challenge", domain), "TXT", ttl, origin)
rc.SetTargetTXT(s.Challenge)
rrs = append(rrs, rc)
return
}
func scalewaychallenge_analyze(a *svcs.Analyzer) error {
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeTXT, Prefix: "_scaleway-challenge"}) {
domain := strings.TrimPrefix(record.Header().Name, "_scaleway-challenge.")
if txt, ok := record.(*dns.TXT); ok {
domain := strings.TrimPrefix(record.NameFQDN, "_scaleway-challenge.")
if record.Type == "TXT" {
a.UseRR(record, domain, &ScalewayChallenge{
Challenge: strings.Join(txt.Txt, ""),
Challenge: record.GetTargetTXTJoined(),
})
}
}

View File

@ -36,6 +36,7 @@ import (
"fmt"
"net"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
@ -74,51 +75,36 @@ func (s *Server) GenComment(origin string) string {
return buffer.String()
}
func (s *Server) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
func (s *Server) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
if s.A != nil && len(*s.A) != 0 {
rrs = append(rrs, &dns.A{
Hdr: dns.RR_Header{
Name: utils.DomainJoin(domain),
Rrtype: dns.TypeA,
Class: dns.ClassINET,
Ttl: ttl,
},
A: *s.A,
})
rc := utils.NewRecordConfig(domain, "A", ttl, origin)
rc.SetTargetIP(*s.A)
rrs = append(rrs, rc)
}
if s.AAAA != nil && len(*s.AAAA) != 0 {
rrs = append(rrs, &dns.AAAA{
Hdr: dns.RR_Header{
Name: utils.DomainJoin(domain),
Rrtype: dns.TypeAAAA,
Class: dns.ClassINET,
Ttl: ttl,
},
AAAA: *s.AAAA,
})
rc := utils.NewRecordConfig(domain, "AAAA", ttl, origin)
rc.SetTargetIP(*s.AAAA)
rrs = append(rrs, rc)
}
for _, sshfp := range s.SSHFP {
rrs = append(rrs, &dns.SSHFP{
Hdr: dns.RR_Header{
Name: utils.DomainJoin(domain),
Rrtype: dns.TypeSSHFP,
Class: dns.ClassINET,
Ttl: ttl,
},
Algorithm: sshfp.Algorithm,
Type: sshfp.Type,
FingerPrint: sshfp.FingerPrint,
})
rc := utils.NewRecordConfig(domain, "SSHFP", ttl, origin)
rc.SshfpAlgorithm = sshfp.Algorithm
rc.SshfpFingerprint = sshfp.Type
rc.SetTarget(sshfp.FingerPrint)
rrs = append(rrs, rc)
}
return
}
func server_analyze(a *svcs.Analyzer) error {
pool := map[string][]dns.RR{}
pool := map[string]models.Records{}
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeA}, svcs.AnalyzerRecordFilter{Type: dns.TypeAAAA}, svcs.AnalyzerRecordFilter{Type: dns.TypeSSHFP}) {
domain := record.Header().Name
domain := record.NameFQDN
pool[domain] = append(pool[domain], record)
}
@ -128,24 +114,25 @@ next_pool:
s := &Server{}
for _, rr := range rrs {
if rr.Header().Rrtype == dns.TypeA {
if rr.Type == "A" {
if s.A != nil {
continue next_pool
}
s.A = &rr.(*dns.A).A
} else if rr.Header().Rrtype == dns.TypeAAAA {
addr := rr.GetTargetIP()
s.A = &addr
} else if rr.Type == "AAAA" {
if s.AAAA != nil {
continue next_pool
}
s.AAAA = &rr.(*dns.AAAA).AAAA
} else if rr.Header().Rrtype == dns.TypeSSHFP {
sshfp := rr.(*dns.SSHFP)
addr := rr.GetTargetIP()
s.AAAA = &addr
} else if rr.Type == "SSHFP" {
s.SSHFP = append(s.SSHFP, &svcs.SSHFP{
Algorithm: sshfp.Algorithm,
Type: sshfp.Type,
FingerPrint: sshfp.FingerPrint,
Algorithm: rr.SshfpAlgorithm,
Type: rr.SshfpFingerprint,
FingerPrint: rr.GetTargetField(),
})
}
}

View File

@ -37,6 +37,7 @@ import (
"strconv"
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
@ -97,7 +98,7 @@ destloop:
return buffer.String()
}
func (s *XMPP) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
func (s *XMPP) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
for _, jabber := range s.Client {
rrs = append(rrs, jabber.GenRRs(utils.DomainJoin("_jabber._tcp", domain), ttl, origin)...)
}
@ -116,7 +117,7 @@ func (s *XMPP) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
func xmpp_subanalyze(a *svcs.Analyzer, prefix string, xmppDomains map[string]*XMPP, field string) error {
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Prefix: prefix, Type: dns.TypeSRV}) {
if srv := svcs.ParseSRV(record); srv != nil {
domain := strings.TrimPrefix(record.Header().Name, prefix)
domain := strings.TrimPrefix(record.NameFQDN, prefix)
if _, ok := xmppDomains[domain]; !ok {
xmppDomains[domain] = &XMPP{}

View File

@ -34,10 +34,12 @@ package svcs
import (
"crypto/sha1"
"errors"
"fmt"
"io"
"reflect"
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
@ -46,7 +48,7 @@ import (
type Analyzer struct {
origin string
zone []dns.RR
zone models.Records
services map[string][]*happydns.ServiceCombined
defaultTTL uint32
}
@ -61,20 +63,18 @@ type AnalyzerRecordFilter struct {
SubdomainsOf string
Contains string
Type uint16
Class uint16
Ttl uint32
}
func (a *Analyzer) SearchRR(arrs ...AnalyzerRecordFilter) (rrs []dns.RR) {
func (a *Analyzer) SearchRR(arrs ...AnalyzerRecordFilter) (rrs models.Records) {
for _, record := range a.zone {
for _, arr := range arrs {
if strings.HasPrefix(record.Header().Name, arr.Prefix) &&
strings.HasSuffix(record.Header().Name, arr.SubdomainsOf) &&
(arr.Domain == "" || record.Header().Name == arr.Domain) &&
(arr.Type == 0 || record.Header().Rrtype == arr.Type) &&
(arr.Class == 0 || record.Header().Class == arr.Class) &&
(arr.Ttl == 0 || record.Header().Ttl == arr.Ttl) &&
(arr.Contains == "" || strings.Contains(record.String(), arr.Contains)) {
if rdtype, ok := dns.StringToType[record.Type]; strings.HasPrefix(record.NameFQDN, arr.Prefix) &&
strings.HasSuffix(record.NameFQDN, arr.SubdomainsOf) &&
(arr.Domain == "" || record.NameFQDN == arr.Domain) &&
(arr.Type == 0 || (ok && rdtype == arr.Type)) &&
(arr.Ttl == 0 || record.TTL == arr.Ttl) &&
(arr.Contains == "" || strings.Contains(fmt.Sprintf("%s. %d IN %s %s", record.NameFQDN, record.TTL, record.Type, record.String()), arr.Contains)) {
rrs = append(rrs, record)
}
}
@ -83,7 +83,7 @@ func (a *Analyzer) SearchRR(arrs ...AnalyzerRecordFilter) (rrs []dns.RR) {
return
}
func (a *Analyzer) UseRR(rr dns.RR, domain string, svc happydns.Service) error {
func (a *Analyzer) UseRR(rr *models.RecordConfig, domain string, svc happydns.Service) error {
found := false
for k, record := range a.zone {
if record == rr {
@ -103,7 +103,7 @@ func (a *Analyzer) UseRR(rr dns.RR, domain string, svc happydns.Service) error {
}
// Remove origin to get an relative domain here
domain = strings.TrimSuffix(strings.TrimSuffix(domain, "."+a.origin), a.origin)
domain = strings.TrimSuffix(strings.TrimSuffix(strings.TrimSuffix(domain, "."), strings.TrimSuffix(a.origin, ".")), ".")
for _, service := range a.services[domain] {
if service.Service == svc {
@ -117,8 +117,8 @@ func (a *Analyzer) UseRR(rr dns.RR, domain string, svc happydns.Service) error {
io.WriteString(hash, rr.String())
var ttl uint32 = 0
if rr.Header().Ttl != a.defaultTTL {
ttl = rr.Header().Ttl
if rr.TTL != a.defaultTTL {
ttl = rr.TTL
}
a.services[domain] = append(a.services[domain], &happydns.ServiceCombined{
@ -136,10 +136,10 @@ func (a *Analyzer) UseRR(rr dns.RR, domain string, svc happydns.Service) error {
return nil
}
func getMostUsedTTL(zone []dns.RR) uint32 {
func getMostUsedTTL(zone models.Records) uint32 {
ttls := map[uint32]int{}
for _, rr := range zone {
ttls[rr.Header().Ttl] += 1
ttls[rr.TTL] += 1
}
var max uint32 = 0
@ -152,7 +152,7 @@ func getMostUsedTTL(zone []dns.RR) uint32 {
return max
}
func AnalyzeZone(origin string, zone []dns.RR) (svcs map[string][]*happydns.ServiceCombined, defaultTTL uint32, err error) {
func AnalyzeZone(origin string, zone models.Records) (svcs map[string][]*happydns.ServiceCombined, defaultTTL uint32, err error) {
defaultTTL = getMostUsedTTL(zone)
a := Analyzer{
@ -178,26 +178,26 @@ func AnalyzeZone(origin string, zone []dns.RR) (svcs map[string][]*happydns.Serv
// Consider records not used by services as Orphan
for _, record := range a.zone {
// Skip DNSSEC records
if utils.IsDNSSECType(record.Header().Rrtype) {
if rdtype, ok := dns.StringToType[record.Type]; ok && utils.IsDNSSECType(rdtype) {
continue
}
if record.Header().Name == "__dnssec."+origin && record.Header().Rrtype == dns.TypeTXT {
if record.NameFQDN == "__dnssec."+origin && record.Type == "TXT" {
continue
}
domain := strings.TrimSuffix(strings.TrimSuffix(record.Header().Name, "."+a.origin), a.origin)
domain := strings.TrimSuffix(strings.TrimSuffix(strings.TrimSuffix(record.NameFQDN, "."), strings.TrimSuffix(a.origin, ".")), ".")
hash := sha1.New()
io.WriteString(hash, record.String())
orphan := &Orphan{record.String()[strings.LastIndex(record.Header().String(), "\tIN\t")+4:]}
orphan := &Orphan{record.Type, record.String()}
svcs[domain] = append(svcs[domain], &happydns.ServiceCombined{
Service: orphan,
ServiceMeta: happydns.ServiceMeta{
Id: hash.Sum(nil),
Type: reflect.Indirect(reflect.ValueOf(orphan)).Type().String(),
Domain: domain,
Ttl: record.Header().Ttl,
Ttl: record.TTL,
NbResources: 1,
Comment: orphan.GenComment(a.origin),
},

View File

@ -35,6 +35,7 @@ import (
"fmt"
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
@ -53,16 +54,10 @@ func (s *CNAME) GenComment(origin string) string {
return strings.TrimSuffix(s.Target, "."+origin)
}
func (s *CNAME) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
rrs = append(rrs, &dns.CNAME{
Hdr: dns.RR_Header{
Name: utils.DomainJoin(domain),
Rrtype: dns.TypeCNAME,
Class: dns.ClassINET,
Ttl: ttl,
},
Target: utils.DomainFQDN(s.Target, origin),
})
func (s *CNAME) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
rr := utils.NewRecordConfig(domain, "CNAME", ttl, origin)
rr.SetTarget(utils.DomainFQDN(s.Target, origin))
rrs = append(rrs, rr)
return
}
@ -79,27 +74,21 @@ func (s *SpecialCNAME) GenComment(origin string) string {
return "(" + s.SubDomain + ") -> " + strings.TrimSuffix(s.Target, "."+origin)
}
func (s *SpecialCNAME) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
rrs = append(rrs, &dns.CNAME{
Hdr: dns.RR_Header{
Name: utils.DomainJoin(s.SubDomain, domain),
Rrtype: dns.TypeCNAME,
Class: dns.ClassINET,
Ttl: ttl,
},
Target: utils.DomainFQDN(s.Target, origin),
})
func (s *SpecialCNAME) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
rr := utils.NewRecordConfig(utils.DomainJoin(s.SubDomain, domain), "CNAME", ttl, origin)
rr.SetTarget(utils.DomainFQDN(s.Target, origin))
rrs = append(rrs, rr)
return
}
func specialalias_analyze(a *Analyzer) error {
// Try handle specials domains using CNAME
for _, record := range a.SearchRR(AnalyzerRecordFilter{Type: dns.TypeCNAME, Prefix: "_"}) {
subdomains := SRV_DOMAIN.FindStringSubmatch(record.Header().Name)
if cname, ok := record.(*dns.CNAME); len(subdomains) == 4 && ok {
subdomains := SRV_DOMAIN.FindStringSubmatch(record.NameFQDN)
if record.Type == "CNAME" && len(subdomains) == 4 {
a.UseRR(record, subdomains[3], &SpecialCNAME{
SubDomain: fmt.Sprintf("_%s._%s", subdomains[1], subdomains[2]),
Target: cname.Target,
Target: record.String(),
})
}
}
@ -108,12 +97,12 @@ func specialalias_analyze(a *Analyzer) error {
func alias_analyze(a *Analyzer) error {
for _, record := range a.SearchRR(AnalyzerRecordFilter{Type: dns.TypeCNAME}) {
if cname, ok := record.(*dns.CNAME); ok {
if record.Type == "CNAME" {
newrr := &CNAME{
Target: strings.TrimSuffix(cname.Target, "."+a.origin),
Target: strings.TrimSuffix(record.String(), "."+a.origin),
}
a.UseRR(record, cname.Header().Name, newrr)
a.UseRR(record, record.NameFQDN, newrr)
}
}
return nil

View File

@ -33,14 +33,18 @@ package svcs
import (
"fmt"
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
"git.happydns.org/happyDomain/utils"
)
type Orphan struct {
RR string
Type string
RR string
}
func (s *Orphan) GetNbResources() int {
@ -48,15 +52,25 @@ func (s *Orphan) GetNbResources() int {
}
func (s *Orphan) GenComment(origin string) string {
return s.RR
return fmt.Sprintf("%s %s", s.Type, s.RR)
}
func (s *Orphan) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
rr, _ := dns.NewRR(fmt.Sprintf("$ORIGIN %s\n%s %d IN %s", origin, domain, ttl, s.RR))
if rr != nil {
rrs = append(rrs, rr)
func (s *Orphan) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
if _, ok := dns.StringToType[s.Type]; ok {
rr, err := dns.NewRR(fmt.Sprintf("%s %d IN %s %s", utils.DomainJoin(domain), ttl, s.Type, s.RR))
if err == nil {
rc, err := models.RRtoRC(rr, strings.TrimSuffix(origin, "."))
if err == nil {
rrs = append(rrs, &rc)
return
}
}
}
rr := utils.NewRecordConfig(domain, s.Type, ttl, origin)
rr.SetTarget(s.RR)
rrs = append(rrs, rr)
return
}

View File

@ -34,6 +34,7 @@ package google // import "git.happydns.org/happyDomain/services/providers/google
import (
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
@ -81,7 +82,7 @@ func (s *GSuite) GenComment(origin string) string {
return strings.Join(comments, ", ")
}
func (s *GSuite) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
func (s *GSuite) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
for _, svc := range s.GenKnownSvcs() {
rrs = append(rrs, svc.GenRRs(domain, ttl, origin)...)
}
@ -92,9 +93,9 @@ func gsuite_analyze(a *svcs.Analyzer) (err error) {
var googlemx []string
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeMX}) {
if mx, ok := record.(*dns.MX); ok {
if strings.ToLower(mx.Mx) == "aspmx.l.google.com." {
googlemx = append(googlemx, mx.Header().Name)
if record.Type == "MX" {
if strings.ToLower(record.GetTargetField()) == "aspmx.l.google.com." {
googlemx = append(googlemx, record.NameFQDN)
break
}
}
@ -105,9 +106,9 @@ func gsuite_analyze(a *svcs.Analyzer) (err error) {
googlerr := &GSuite{}
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeMX, Domain: dn}) {
if mx, ok := record.(*dns.MX); ok {
if strings.HasSuffix(mx.Mx, "mx-verification.google.com.") {
googlerr.ValidationCode = mx.Mx
if record.Type == "MX" {
if strings.HasSuffix(record.GetTargetField(), "mx-verification.google.com.") {
googlerr.ValidationCode = record.GetTargetField()
if err = a.UseRR(
record,
dn,
@ -115,7 +116,7 @@ func gsuite_analyze(a *svcs.Analyzer) (err error) {
); err != nil {
return
}
} else if strings.HasSuffix(mx.Mx, "google.com.") {
} else if strings.HasSuffix(record.GetTargetField(), "google.com.") {
if err = a.UseRR(
record,
dn,
@ -128,8 +129,8 @@ func gsuite_analyze(a *svcs.Analyzer) (err error) {
}
for _, record := range a.SearchRR(svcs.AnalyzerRecordFilter{Type: dns.TypeTXT, Domain: dn}) {
if txt, ok := record.(*dns.TXT); ok {
content := strings.Join(txt.Txt, "")
if record.Type == "TXT" {
content := record.GetTargetTXTJoined()
if strings.HasPrefix(content, "v=spf1") && strings.Contains(content, "_spf.google.com") {
if err = a.UseRR(
record,

View File

@ -36,6 +36,7 @@ import (
"regexp"
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
@ -57,29 +58,24 @@ func (s *SRV) GenComment(origin string) string {
return fmt.Sprintf("%s:%d", strings.TrimSuffix(s.Target, "."+origin), s.Port)
}
func (s *SRV) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
rrs = append(rrs, &dns.SRV{
Hdr: dns.RR_Header{
Name: domain,
Rrtype: dns.TypeSRV,
Class: dns.ClassINET,
Ttl: ttl,
},
Priority: s.Priority,
Weight: s.Weight,
Port: s.Port,
Target: utils.DomainFQDN(s.Target, origin),
})
func (s *SRV) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
rr := utils.NewRecordConfig(domain, "SRV", ttl, origin)
rr.SrvPriority = s.Priority
rr.SrvWeight = s.Weight
rr.SrvPort = s.Port
rr.SetTarget(utils.DomainFQDN(s.Target, origin))
rrs = append(rrs, rr)
return
}
func ParseSRV(record dns.RR) (ret *SRV) {
if srv, ok := record.(*dns.SRV); ok {
func ParseSRV(record *models.RecordConfig) (ret *SRV) {
if record.Type == "SRV" {
ret = &SRV{
Priority: srv.Priority,
Weight: srv.Weight,
Port: srv.Port,
Target: srv.Target,
Priority: record.SrvPriority,
Weight: record.SrvWeight,
Port: record.SrvPort,
Target: record.GetTargetField(),
}
}
@ -104,7 +100,7 @@ func (s *UnknownSRV) GenComment(origin string) string {
return fmt.Sprintf("%s (%s)", s.Name, s.Proto)
}
func (s *UnknownSRV) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
func (s *UnknownSRV) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
for _, service := range s.SRV {
rrs = append(rrs, service.GenRRs(utils.DomainJoin(fmt.Sprintf("_%s._%s", s.Name, s.Proto), domain), ttl, origin)...)
}
@ -115,7 +111,7 @@ func srv_analyze(a *Analyzer) error {
srvDomains := map[string]map[string]*UnknownSRV{}
for _, record := range a.SearchRR(AnalyzerRecordFilter{Type: dns.TypeSRV}) {
subdomains := SRV_DOMAIN.FindStringSubmatch(record.Header().Name)
subdomains := SRV_DOMAIN.FindStringSubmatch(record.NameFQDN)
if srv := ParseSRV(record); len(subdomains) == 4 && srv != nil {
svc := subdomains[1] + "." + subdomains[2]
domain := subdomains[3]

View File

@ -38,6 +38,7 @@ import (
"regexp"
"strconv"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
@ -98,21 +99,15 @@ protoloop:
return buffer.String()
}
func (ss *TLSAs) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
func (ss *TLSAs) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
for _, s := range ss.TLSA {
if len(s.Certificate) > 0 {
rrs = append(rrs, &dns.TLSA{
Hdr: dns.RR_Header{
Name: utils.DomainJoin(fmt.Sprintf("_%d._%s", s.Port, s.Proto), domain),
Rrtype: dns.TypeTLSA,
Class: dns.ClassINET,
Ttl: ttl,
},
Usage: s.CertUsage,
Selector: s.Selector,
MatchingType: s.MatchingType,
Certificate: hex.EncodeToString(s.Certificate),
})
rr := utils.NewRecordConfig(utils.DomainJoin(fmt.Sprintf("_%d._%s", s.Port, s.Proto), domain), "TLSA", ttl, origin)
rr.TlsaUsage = s.CertUsage
rr.TlsaSelector = s.Selector
rr.TlsaMatchingType = s.MatchingType
rr.SetTarget(hex.EncodeToString(s.Certificate))
rrs = append(rrs, rr)
}
}
return
@ -125,13 +120,13 @@ var (
func tlsa_analyze(a *Analyzer) (err error) {
pool := map[string]*TLSAs{}
for _, record := range a.SearchRR(AnalyzerRecordFilter{Type: dns.TypeTLSA}) {
subdomains := TLSA_DOMAIN.FindStringSubmatch(record.Header().Name)
if tlsa, ok := record.(*dns.TLSA); len(subdomains) == 4 && ok {
subdomains := TLSA_DOMAIN.FindStringSubmatch(record.NameFQDN)
if record.Type == "TLSA" && len(subdomains) == 4 {
var port uint64
port, err = strconv.ParseUint(subdomains[1], 10, 16)
var cert []byte
cert, err = hex.DecodeString(tlsa.Certificate)
cert, err = hex.DecodeString(record.GetTargetField())
if err != nil {
return
}
@ -145,9 +140,9 @@ func tlsa_analyze(a *Analyzer) (err error) {
&TLSA{
Port: uint16(port),
Proto: subdomains[2],
CertUsage: tlsa.Usage,
Selector: tlsa.Selector,
MatchingType: tlsa.MatchingType,
CertUsage: record.TlsaUsage,
Selector: record.TlsaSelector,
MatchingType: record.TlsaMatchingType,
Certificate: cert,
},
)

View File

@ -34,9 +34,11 @@ package svcs
import (
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
"git.happydns.org/happyDomain/model"
"git.happydns.org/happyDomain/utils"
)
type TXT struct {
@ -51,31 +53,25 @@ func (ss *TXT) GenComment(origin string) string {
return ss.Content
}
func (ss *TXT) GenRRs(domain string, ttl uint32, origin string) (rrs []dns.RR) {
rrs = append(rrs, &dns.TXT{
Hdr: dns.RR_Header{
Name: domain,
Rrtype: dns.TypeTXT,
Class: dns.ClassINET,
Ttl: ttl,
},
Txt: []string{ss.Content},
})
func (ss *TXT) GenRRs(domain string, ttl uint32, origin string) (rrs models.Records) {
rr := utils.NewRecordConfig(domain, "TXT", ttl, origin)
rr.SetTargetTXT(ss.Content)
rrs = append(rrs, rr)
return
}
func txt_analyze(a *Analyzer) (err error) {
for _, record := range a.SearchRR(AnalyzerRecordFilter{Type: dns.TypeTXT}) {
// Skip DNSSEC record added by dnscontrol
if strings.HasPrefix(record.Header().Name, "__dnssec.") {
if strings.HasPrefix(record.Name, "__dnssec") {
continue
}
if txt, ok := record.(*dns.TXT); ok {
if record.Type == "TXT" {
err = a.UseRR(
record,
txt.Header().Name,
&TXT{Content: strings.Join(txt.Txt, "")},
record.NameFQDN,
&TXT{Content: record.GetTargetTXTJoined()},
)
if err != nil {
return

View File

@ -0,0 +1,99 @@
// Copyright or © or Copr. happyDNS (2023)
//
// contact@happydomain.org
//
// This software is a computer program whose purpose is to provide a modern
// interface to interact with DNS systems.
//
// This software is governed by the CeCILL license under French law and abiding
// by the rules of distribution of free software. You can use, modify and/or
// redistribute the software under the terms of the CeCILL license as
// circulated by CEA, CNRS and INRIA at the following URL
// "http://www.cecill.info".
//
// As a counterpart to the access to the source code and rights to copy, modify
// and redistribute granted by the license, users are provided only with a
// limited warranty and the software's author, the holder of the economic
// rights, and the successive licensors have only limited liability.
//
// In this respect, the user's attention is drawn to the risks associated with
// loading, using, modifying and/or developing or reproducing the software by
// the user in light of its specific status of free software, that may mean
// that it is complicated to manipulate, and that also therefore means that it
// is reserved for developers and experienced professionals having in-depth
// computer knowledge. Users are therefore encouraged to load and test the
// software's suitability as regards their requirements in conditions enabling
// the security of their systems and/or data to be ensured and, more generally,
// to use and operate it in the same conditions as regards security.
//
// The fact that you are presently reading this means that you have had
// knowledge of the CeCILL license and that you accept its terms.
package database
import (
"fmt"
"log"
"strings"
"git.happydns.org/happyDomain/model"
"git.happydns.org/happyDomain/services"
)
func migrateFrom4(s *LevelDBStorage) (err error) {
err = migrateFrom4_orphanrecords(s)
if err != nil {
return
}
err = s.Tidy()
if err != nil {
return
}
return
}
func migrateFrom4_orphanrecords(s *LevelDBStorage) (err error) {
iter := s.search("domain.zone-")
for iter.Next() {
var tmpid string
fmt.Sscanf(string(iter.Key()), "domain.zone-%s", &tmpid)
var id happydns.Identifier
id, err = happydns.NewIdentifierFromString(tmpid)
if err != nil {
return fmt.Errorf("unable to determine identifier of %s: %w", iter.Key(), err)
}
var zone *happydns.Zone
zone, err = s.GetZone(id)
if err != nil {
return fmt.Errorf("%s: %w", iter.Key(), err)
}
changed := false
for _, zServices := range zone.Services {
for _, svc := range zServices {
if orphan, ok := svc.Service.(*svcs.Orphan); ok {
tmp := strings.Fields(orphan.RR)
orphan.Type = tmp[0]
orphan.RR = strings.TrimSpace(orphan.RR[len(tmp[0]):])
changed = true
}
}
}
if changed {
err = s.UpdateZone(zone)
if err != nil {
return fmt.Errorf("unable to write %s: %w", iter.Key(), err)
}
log.Printf("Migrating v3 -> v4: %s (contains Orphan)...", iter.Key())
}
}
return nil
}

View File

@ -43,6 +43,7 @@ var migrations []LevelDBMigrationFunc = []LevelDBMigrationFunc{
migrateFrom1,
migrateFrom2,
migrateFrom3,
migrateFrom4,
}
func (s *LevelDBStorage) DoMigration() (err error) {

View File

@ -32,6 +32,9 @@
package utils
import (
"strings"
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/miekg/dns"
)
@ -100,3 +103,13 @@ func DomainJoin(domains ...string) (ret string) {
return
}
// DomainJoin appends each relative domains passed as argument.
func NewRecordConfig(domain string, rtype string, ttl uint32, origin string) *models.RecordConfig {
return &models.RecordConfig{
Name: strings.TrimSuffix(strings.TrimSuffix(DomainJoin(domain), origin), "."),
NameFQDN: strings.TrimSuffix(DomainJoin(domain), "."),
Type: rtype,
TTL: ttl,
}
}