mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
* stash * Use rejectif idea * rename * wip! * Convert old systems to new * fixup! * fix typo
This commit is contained in:
@@ -485,8 +485,10 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) {
|
||||
// be performed.
|
||||
continue
|
||||
}
|
||||
if err := providers.AuditRecords(provider.ProviderBase.ProviderType, domain.Records); err != nil {
|
||||
errs = append(errs, fmt.Errorf("%s rejects domain %s: %w", provider.ProviderBase.ProviderType, domain.Name, err))
|
||||
if es := providers.AuditRecords(provider.ProviderBase.ProviderType, domain.Records); len(es) != 0 {
|
||||
for _, e := range es {
|
||||
errs = append(errs, fmt.Errorf("%s rejects domain %s: %w", provider.ProviderBase.ProviderType, domain.Name, e))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -153,6 +153,7 @@ func (z *ZoneGenData) generateZoneFileHelper(w io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// FormatLine formats a zonefile line.
|
||||
func FormatLine(lengths []int, fields []string) string {
|
||||
c := 0
|
||||
result := ""
|
||||
|
@@ -411,7 +411,7 @@ zt.mup IN A 1.2.3.14
|
||||
zap IN A 1.2.3.15
|
||||
`
|
||||
|
||||
// func formatLine
|
||||
// func FormatLine
|
||||
|
||||
func TestFormatLine(t *testing.T) {
|
||||
tests := []struct {
|
||||
|
@@ -1,159 +0,0 @@
|
||||
package recordaudit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v3/models"
|
||||
)
|
||||
|
||||
// Keep these in alphabetical order.
|
||||
|
||||
// TxtNoBackticks audits TXT records for strings that contain backticks.
|
||||
func TxtNoBackticks(records []*models.RecordConfig) error {
|
||||
for _, rc := range records {
|
||||
|
||||
if rc.HasFormatIdenticalToTXT() {
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if strings.Contains(txt, "`") {
|
||||
return fmt.Errorf("txtstring contains backtick")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtNoSingleQuotes audits TXT records for strings that contain single-quotes.
|
||||
func TxtNoSingleQuotes(records []*models.RecordConfig) error {
|
||||
for _, rc := range records {
|
||||
|
||||
if rc.HasFormatIdenticalToTXT() {
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if strings.Contains(txt, "'") {
|
||||
return fmt.Errorf("txtstring contains single-quotes")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtNoDoubleQuotes audits TXT records for strings that contain doublequotes.
|
||||
func TxtNoDoubleQuotes(records []*models.RecordConfig) error {
|
||||
for _, rc := range records {
|
||||
|
||||
if rc.HasFormatIdenticalToTXT() {
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if strings.Contains(txt, `"`) {
|
||||
return fmt.Errorf("txtstring contains doublequotes")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtNoStringsExactlyLen255 audits TXT records for strings exactly 255 octets long.
|
||||
// This is rare; you probably want to use TxtNoLongStrings() instead.
|
||||
func TxtNoStringsExactlyLen255(records []*models.RecordConfig) error {
|
||||
for _, rc := range records {
|
||||
|
||||
if rc.HasFormatIdenticalToTXT() { // TXT and similar:
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if len(txt) == 255 {
|
||||
return fmt.Errorf("txtstring length is 255")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtNoStringsLen256orLonger audits TXT records for strings that are >255 octets.
|
||||
func TxtNoStringsLen256orLonger(records []*models.RecordConfig) error {
|
||||
for _, rc := range records {
|
||||
|
||||
if rc.HasFormatIdenticalToTXT() { // TXT and similar:
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if len(txt) > 255 {
|
||||
return fmt.Errorf("%q txtstring length > 255", rc.GetLabel())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtNoMultipleStrings audits TXT records for multiple strings
|
||||
func TxtNoMultipleStrings(records []*models.RecordConfig) error {
|
||||
for _, rc := range records {
|
||||
|
||||
if rc.HasFormatIdenticalToTXT() { // TXT and similar:
|
||||
if len(rc.TxtStrings) > 1 {
|
||||
return fmt.Errorf("multiple strings in one txt")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtNoTrailingSpace audits TXT records for strings that end with space.
|
||||
func TxtNoTrailingSpace(records []*models.RecordConfig) error {
|
||||
for _, rc := range records {
|
||||
|
||||
if rc.HasFormatIdenticalToTXT() { // TXT and similar:
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if txt != "" && txt[ultimate(txt)] == ' ' {
|
||||
return fmt.Errorf("txtstring ends with space")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtNotEmpty audits TXT records for empty strings.
|
||||
func TxtNotEmpty(records []*models.RecordConfig) error {
|
||||
for _, rc := range records {
|
||||
|
||||
if rc.HasFormatIdenticalToTXT() { // TXT and similar:
|
||||
// There must be strings.
|
||||
if len(rc.TxtStrings) == 0 {
|
||||
return fmt.Errorf("txt with no strings")
|
||||
}
|
||||
// Each string must be non-empty.
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if len(txt) == 0 {
|
||||
return fmt.Errorf("txtstring is empty")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtNoUnpairedDoubleQuotes audits TXT records for strings that contain unpaired doublequotes.
|
||||
func TxtNoUnpairedDoubleQuotes(records []*models.RecordConfig) error {
|
||||
for _, rc := range records {
|
||||
|
||||
if rc.HasFormatIdenticalToTXT() {
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if strings.Count(txt, `"`)%2 == 1 {
|
||||
return fmt.Errorf("txtstring contains unpaired doublequotes")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
46
pkg/rejectif/audit.go
Normal file
46
pkg/rejectif/audit.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package rejectif
|
||||
|
||||
import (
|
||||
"github.com/StackExchange/dnscontrol/v3/models"
|
||||
)
|
||||
|
||||
// Auditor stores a list of checks to be executed during Audit().
|
||||
type Auditor struct {
|
||||
checksFor map[string][]checker
|
||||
}
|
||||
|
||||
type checker = func(*models.RecordConfig) error
|
||||
|
||||
// Add registers a function to call on each record of a given type.
|
||||
func (aud *Auditor) Add(rtype string, fn checker) {
|
||||
if aud.checksFor == nil {
|
||||
aud.checksFor = map[string][]checker{}
|
||||
}
|
||||
aud.checksFor[rtype] = append(aud.checksFor[rtype], fn)
|
||||
|
||||
// SPF records get any checkers that TXT records do.
|
||||
if rtype == "TXT" {
|
||||
aud.Add("SPF", fn)
|
||||
}
|
||||
}
|
||||
|
||||
// Audit performs the audit. For each record it calls each function in
|
||||
// the list of checks.
|
||||
func (aud *Auditor) Audit(records models.Records) (errs []error) {
|
||||
// No checks? Exit early.
|
||||
if aud.checksFor == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// For each record, call the checks for that type, gather errors.
|
||||
for _, rc := range records {
|
||||
for _, f := range aud.checksFor[rc.Type] {
|
||||
e := f(rc)
|
||||
if e != nil {
|
||||
errs = append(errs, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
18
pkg/rejectif/caa.go
Normal file
18
pkg/rejectif/caa.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package rejectif
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v3/models"
|
||||
)
|
||||
|
||||
// Keep these in alphabetical order.
|
||||
|
||||
// CaaTargetHasSemicolon audits CAA records for issues that contain semicolons.
|
||||
func CaaTargetHasSemicolon(rc *models.RecordConfig) error {
|
||||
if strings.Contains(rc.GetTargetField(), ";") {
|
||||
return fmt.Errorf("caa target contains semicolon")
|
||||
}
|
||||
return nil
|
||||
}
|
104
pkg/rejectif/txt.go
Normal file
104
pkg/rejectif/txt.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package rejectif
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v3/models"
|
||||
)
|
||||
|
||||
// Keep these in alphabetical order.
|
||||
|
||||
// TxtHasBackticks audits TXT records for strings that contain backticks.
|
||||
func TxtHasBackticks(rc *models.RecordConfig) error {
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if strings.Contains(txt, "`") {
|
||||
return fmt.Errorf("txtstring contains backtick")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtHasSingleQuotes audits TXT records for strings that contain single-quotes.
|
||||
func TxtHasSingleQuotes(rc *models.RecordConfig) error {
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if strings.Contains(txt, "'") {
|
||||
return fmt.Errorf("txtstring contains single-quotes")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtHasDoubleQuotes audits TXT records for strings that contain doublequotes.
|
||||
func TxtHasDoubleQuotes(rc *models.RecordConfig) error {
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if strings.Contains(txt, `"`) {
|
||||
return fmt.Errorf("txtstring contains doublequotes")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtIsExactlyLen255 audits TXT records for strings exactly 255 octets long.
|
||||
// This is rare; you probably want to use TxtNoStringsLen256orLonger() instead.
|
||||
func TxtIsExactlyLen255(rc *models.RecordConfig) error {
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if len(txt) == 255 {
|
||||
return fmt.Errorf("txtstring length is 255")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtHasSegmentLen256orLonger audits TXT records for strings that are >255 octets.
|
||||
func TxtHasSegmentLen256orLonger(rc *models.RecordConfig) error {
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if len(txt) > 255 {
|
||||
return fmt.Errorf("%q txtstring length > 255", rc.GetLabel())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtHasMultipleSegments audits TXT records for multiple strings
|
||||
func TxtHasMultipleSegments(rc *models.RecordConfig) error {
|
||||
if len(rc.TxtStrings) > 1 {
|
||||
return fmt.Errorf("multiple strings in one txt")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtHasTrailingSpace audits TXT records for strings that end with space.
|
||||
func TxtHasTrailingSpace(rc *models.RecordConfig) error {
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if txt != "" && txt[ultimate(txt)] == ' ' {
|
||||
return fmt.Errorf("txtstring ends with space")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtIsEmpty audits TXT records for empty strings.
|
||||
func TxtIsEmpty(rc *models.RecordConfig) error {
|
||||
// There must be strings.
|
||||
if len(rc.TxtStrings) == 0 {
|
||||
return fmt.Errorf("txt with no strings")
|
||||
}
|
||||
// Each string must be non-empty.
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if len(txt) == 0 {
|
||||
return fmt.Errorf("txtstring is empty")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxtHasUnpairedDoubleQuotes audits TXT records for strings that contain unpaired doublequotes.
|
||||
func TxtHasUnpairedDoubleQuotes(rc *models.RecordConfig) error {
|
||||
for _, txt := range rc.TxtStrings {
|
||||
if strings.Count(txt, `"`)%2 == 1 {
|
||||
return fmt.Errorf("txtstring contains unpaired doublequotes")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
package recordaudit
|
||||
package rejectif
|
||||
|
||||
/*
|
||||
I proposed that Go add something like "len()" that returns the highest
|
Reference in New Issue
Block a user