diff --git a/providers/msdns/auditrecords.go b/providers/msdns/auditrecords.go index 5e5884dc0..dab036bee 100644 --- a/providers/msdns/auditrecords.go +++ b/providers/msdns/auditrecords.go @@ -11,21 +11,23 @@ import ( func AuditRecords(records []*models.RecordConfig) []error { a := rejectif.Auditor{} - a.Add("MX", rejectif.MxNull) // Last verified 2020-12-28 + a.Add("MX", rejectif.MxNull) // Last verified 2023-02-02 - a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 2020-12-28 + a.Add("SRV", rejectif.SrvHasNullTarget) // Last verified 20-0212-28 - a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2021-03-01 + a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2023-02-02 - a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2021-03-01 + a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2023-02-02 - a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2021-03-01 + a.Add("TXT", rejectif.TxtHasMultipleSegments) // Last verified 2023-02-02 - a.Add("TXT", rejectif.TxtHasSegmentLen256orLonger) + a.Add("TXT", rejectif.TxtHasSegmentLen256orLonger) // Last verified 2023-02-02 - a.Add("TXT", rejectif.TxtHasSingleQuotes) // Last verified 2021-03-01 + a.Add("TXT", rejectif.TxtHasSingleQuotes) // Last verified 2023-02-02 - a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-03-01 + a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2023-02-02 + + a.Add("TXT", rejectif.TxtIsExactlyLen255) // Last verified 2023-02-02 a.Add("TXT", rejectif.TxtIsExactlyLen255) // Last verified 2023-02-02 diff --git a/providers/msdns/corrections.go b/providers/msdns/corrections.go index 95989ebab..56678a089 100644 --- a/providers/msdns/corrections.go +++ b/providers/msdns/corrections.go @@ -1,6 +1,8 @@ package msdns import ( + "fmt" + "github.com/StackExchange/dnscontrol/v3/models" "github.com/StackExchange/dnscontrol/v3/pkg/diff" "github.com/StackExchange/dnscontrol/v3/pkg/diff2" @@ -20,26 +22,79 @@ func (client *msdnsProvider) GenerateDomainCorrections(dc *models.DomainConfig, if !diff2.EnableDiff2 { differ := diff.New(dc) _, creates, dels, modifications, err = differ.IncrementalDiff(foundRecords) - } else { - differ := diff.NewCompat(dc) - _, creates, dels, modifications, err = differ.IncrementalDiff(foundRecords) + if err != nil { + return nil, err + } + + // Generate changes. + for _, del := range dels { + corrections = append(corrections, client.deleteRec(client.dnsserver, dc.Name, del)) + } + for _, cre := range creates { + corrections = append(corrections, client.createRec(client.dnsserver, dc.Name, cre)...) + } + for _, m := range modifications { + corrections = append(corrections, client.modifyRec(client.dnsserver, dc.Name, m)) + } + return corrections, nil } + + changes, err := diff2.ByRecord(foundRecords, dc, nil) if err != nil { return nil, err } - // Generate changes. - for _, del := range dels { - corrections = append(corrections, client.deleteRec(client.dnsserver, dc.Name, del)) - } - for _, cre := range creates { - corrections = append(corrections, client.createRec(client.dnsserver, dc.Name, cre)...) - } - for _, m := range modifications { - corrections = append(corrections, client.modifyRec(client.dnsserver, dc.Name, m)) - } - return corrections, nil + var corr *models.Correction + for _, change := range changes { + msgsJoined := change.MsgsJoined + switch change.Type { + case diff2.REPORT: + corr = &models.Correction{Msg: msgsJoined} + case diff2.CREATE: + newrec := change.New[0] + corr = &models.Correction{ + Msg: msgsJoined, + F: func() error { + return client.createOneRecord(client.dnsserver, dc.Name, newrec) + }, + } + case diff2.CHANGE: + oldrec := change.Old[0] + newrec := change.New[0] + corr = &models.Correction{ + Msg: msgsJoined, + F: func() error { + return client.modifyOneRecord(client.dnsserver, dc.Name, oldrec, newrec) + }, + } + case diff2.DELETE: + oldrec := change.Old[0] + corr = &models.Correction{ + Msg: msgsJoined, + F: func() error { + return client.deleteOneRecord(client.dnsserver, dc.Name, oldrec) + }, + } + default: + panic(fmt.Sprintf("unhandled change.Type %s", change.Type)) + } + corrections = append(corrections, corr) + } + + return corrections, nil +} + +func (client *msdnsProvider) deleteOneRecord(dnsserver, zonename string, oldrec *models.RecordConfig) error { + return client.shell.RecordDelete(dnsserver, zonename, oldrec) +} + +func (client *msdnsProvider) createOneRecord(dnsserver, zonename string, newrec *models.RecordConfig) error { + return client.shell.RecordCreate(dnsserver, zonename, newrec) +} + +func (client *msdnsProvider) modifyOneRecord(dnsserver, zonename string, oldrec, newrec *models.RecordConfig) error { + return client.shell.RecordModify(dnsserver, zonename, oldrec, newrec) } func (client *msdnsProvider) deleteRec(dnsserver, domainname string, cor diff.Correlation) *models.Correction { diff --git a/providers/msdns/powershell.go b/providers/msdns/powershell.go index 20e3c4bd2..95f11555d 100644 --- a/providers/msdns/powershell.go +++ b/providers/msdns/powershell.go @@ -19,6 +19,13 @@ type psHandle struct { shell ps.Shell } +// func eLog(s string) { +// f, _ := os.OpenFile("powershell.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) +// f.WriteString(s) +// f.WriteString("\n") +// f.Close() +// } + func newPowerShell(config map[string]string) (*psHandle, error) { back := &backend.Local{} @@ -200,8 +207,10 @@ func (psh *psHandle) RecordDelete(dnsserver, domain string, rec *models.RecordCo c = generatePSDelete(dnsserver, domain, rec) } + //eLog(c) _, stderr, err := psh.shell.Execute(c) if err != nil { + printer.Printf("PowerShell code was:\nSTART\n%s\nEND\n", c) return err } if stderr != "" { @@ -215,7 +224,7 @@ func (psh *psHandle) RecordDelete(dnsserver, domain string, rec *models.RecordCo func generatePSDelete(dnsserver, domain string, rec *models.RecordConfig) string { var b bytes.Buffer - fmt.Fprintf(&b, `echo DELETE "%s" "%s" "..."`, rec.Type, rec.Name) + fmt.Fprintf(&b, `echo DELETE "%s" "%s" "[target]"`, rec.Type, rec.Name) fmt.Fprintf(&b, " ; ") if rec.Type == "NAPTR" { @@ -229,13 +238,13 @@ func generatePSDelete(dnsserver, domain string, rec *models.RecordConfig) string fmt.Fprintf(&b, ` -ComputerName "%s"`, dnsserver) } fmt.Fprintf(&b, ` -Force`) - fmt.Fprintf(&b, ` -ZoneName "%s"`, domain) - fmt.Fprintf(&b, ` -Name "%s"`, rec.Name) + fmt.Fprintf(&b, ` -ZoneName %q`, domain) + fmt.Fprintf(&b, ` -Name %q`, rec.Name) fmt.Fprintf(&b, ` -RRType "%s"`, rec.Type) if rec.Type == "MX" { - fmt.Fprintf(&b, ` -RecordData %d,"%s"`, rec.MxPreference, rec.GetTargetField()) + fmt.Fprintf(&b, ` -RecordData %d,%q`, rec.MxPreference, rec.GetTargetField()) } else if rec.Type == "TXT" { - fmt.Fprintf(&b, ` -RecordData %s`, rec.GetTargetField()) + fmt.Fprintf(&b, ` -RecordData %q`, rec.GetTargetTXTJoined()) } else if rec.Type == "SRV" { // https://www.gitmemory.com/issue/MicrosoftDocs/windows-powershell-docs/1149/511916884 fmt.Fprintf(&b, ` -RecordData %d,%d,%d,"%s"`, rec.SrvPriority, rec.SrvWeight, rec.SrvPort, rec.GetTargetField()) @@ -257,6 +266,7 @@ func (psh *psHandle) RecordCreate(dnsserver, domain string, rec *models.RecordCo //printer.Printf("DEBUG: PScreate\n") } + //eLog(c) stdout, stderr, err := psh.shell.Execute(c) if err != nil { printer.Printf("PowerShell code was:\nSTART\n%s\nEND\n", c) @@ -265,6 +275,7 @@ func (psh *psHandle) RecordCreate(dnsserver, domain string, rec *models.RecordCo if stderr != "" { printer.Printf("STDOUT RecordCreate = %s\n", stdout) printer.Printf("STDERROR RecordCreate = %q\n", stderr) + printer.Printf("PowerShell code was:\nSTART\n%s\nEND\n", c) return fmt.Errorf("unexpected stderr from PSCreate: %q", stderr) } return nil @@ -272,7 +283,7 @@ func (psh *psHandle) RecordCreate(dnsserver, domain string, rec *models.RecordCo func generatePSCreate(dnsserver, domain string, rec *models.RecordConfig) string { var b bytes.Buffer - fmt.Fprintf(&b, `echo CREATE "%s" "%s" "..."`, rec.Type, rec.Name) + fmt.Fprintf(&b, `echo CREATE "%s" "%s" "[target]"`, rec.Type, rec.Name) fmt.Fprintf(&b, " ; ") if rec.Type == "NAPTR" { @@ -339,6 +350,7 @@ func generatePSCreate(dnsserver, domain string, rec *models.RecordConfig) string func (psh *psHandle) RecordModify(dnsserver, domain string, old, rec *models.RecordConfig) error { c := generatePSModify(dnsserver, domain, old, rec) + //eLog(c) _, stderr, err := psh.shell.Execute(c) if err != nil { printer.Printf("PowerShell code was:\nSTART\n%s\nEND\n", c) diff --git a/providers/msdns/powershell_test.go b/providers/msdns/powershell_test.go index 06680bbc8..cdfa29cda 100644 --- a/providers/msdns/powershell_test.go +++ b/providers/msdns/powershell_test.go @@ -146,16 +146,16 @@ func Test_generatePSModify(t *testing.T) { want string }{ {name: "A", args: args{domain: "example.com", dnsserver: "", old: recA1, rec: recA2}, - want: `echo DELETE "A" "@" "..." ; Remove-DnsServerResourceRecord -Force -ZoneName "example.com" -Name "@" -RRType "A" -RecordData "1.2.3.4" ; echo CREATE "A" "@" "..." ; Add-DnsServerResourceRecord -ZoneName "example.com" -Name "@" -TimeToLive $(New-TimeSpan -Seconds 0) -A -IPv4Address "10.20.30.40"`, + want: `echo DELETE "A" "@" "[target]" ; Remove-DnsServerResourceRecord -Force -ZoneName "example.com" -Name "@" -RRType "A" -RecordData "1.2.3.4" ; echo CREATE "A" "@" "[target]" ; Add-DnsServerResourceRecord -ZoneName "example.com" -Name "@" -TimeToLive $(New-TimeSpan -Seconds 0) -A -IPv4Address "10.20.30.40"`, }, {name: "MX1", args: args{domain: "example.com", dnsserver: "", old: recMX1, rec: recMX2}, - want: `echo DELETE "MX" "@" "..." ; Remove-DnsServerResourceRecord -Force -ZoneName "example.com" -Name "@" -RRType "MX" -RecordData 5,"foo.com." ; echo CREATE "MX" "@" "..." ; Add-DnsServerResourceRecord -ZoneName "example.com" -Name "@" -TimeToLive $(New-TimeSpan -Seconds 0) -MX -MailExchange "foo2.com." -Preference 50`, + want: `echo DELETE "MX" "@" "[target]" ; Remove-DnsServerResourceRecord -Force -ZoneName "example.com" -Name "@" -RRType "MX" -RecordData 5,"foo.com." ; echo CREATE "MX" "@" "[target]" ; Add-DnsServerResourceRecord -ZoneName "example.com" -Name "@" -TimeToLive $(New-TimeSpan -Seconds 0) -MX -MailExchange "foo2.com." -Preference 50`, }, {name: "A-remote", args: args{domain: "example.com", dnsserver: "myremote", old: recA1, rec: recA2}, - want: `echo DELETE "A" "@" "..." ; Remove-DnsServerResourceRecord -ComputerName "myremote" -Force -ZoneName "example.com" -Name "@" -RRType "A" -RecordData "1.2.3.4" ; echo CREATE "A" "@" "..." ; Add-DnsServerResourceRecord -ComputerName "myremote" -ZoneName "example.com" -Name "@" -TimeToLive $(New-TimeSpan -Seconds 0) -A -IPv4Address "10.20.30.40"`, + want: `echo DELETE "A" "@" "[target]" ; Remove-DnsServerResourceRecord -ComputerName "myremote" -Force -ZoneName "example.com" -Name "@" -RRType "A" -RecordData "1.2.3.4" ; echo CREATE "A" "@" "[target]" ; Add-DnsServerResourceRecord -ComputerName "myremote" -ZoneName "example.com" -Name "@" -TimeToLive $(New-TimeSpan -Seconds 0) -A -IPv4Address "10.20.30.40"`, }, {name: "MX1-remote", args: args{domain: "example.com", dnsserver: "yourremote", old: recMX1, rec: recMX2}, - want: `echo DELETE "MX" "@" "..." ; Remove-DnsServerResourceRecord -ComputerName "yourremote" -Force -ZoneName "example.com" -Name "@" -RRType "MX" -RecordData 5,"foo.com." ; echo CREATE "MX" "@" "..." ; Add-DnsServerResourceRecord -ComputerName "yourremote" -ZoneName "example.com" -Name "@" -TimeToLive $(New-TimeSpan -Seconds 0) -MX -MailExchange "foo2.com." -Preference 50`, + want: `echo DELETE "MX" "@" "[target]" ; Remove-DnsServerResourceRecord -ComputerName "yourremote" -Force -ZoneName "example.com" -Name "@" -RRType "MX" -RecordData 5,"foo.com." ; echo CREATE "MX" "@" "[target]" ; Add-DnsServerResourceRecord -ComputerName "yourremote" -ZoneName "example.com" -Name "@" -TimeToLive $(New-TimeSpan -Seconds 0) -MX -MailExchange "foo2.com." -Preference 50`, }, } for _, tt := range tests {