github.com/philhug/dnscontrol@v0.2.4-0.20180625181521-921fa9849001/pkg/normalize/flatten.go (about) 1 package normalize 2 3 import ( 4 "strings" 5 6 "github.com/pkg/errors" 7 8 "github.com/StackExchange/dnscontrol/models" 9 "github.com/StackExchange/dnscontrol/pkg/spflib" 10 ) 11 12 // hasSpfRecords returns true if this record requests SPF unrolling. 13 func flattenSPFs(cfg *models.DNSConfig) []error { 14 var cache spflib.CachingResolver 15 var errs []error 16 var err error 17 for _, domain := range cfg.Domains { 18 apexTXTs := domain.Records.Grouped()[models.RecordKey{Type: "TXT", Name: "@"}] 19 // flatten all spf records that have the "flatten" metadata 20 for _, txt := range apexTXTs { 21 var rec *spflib.SPFRecord 22 if txt.Metadata["flatten"] != "" || txt.Metadata["split"] != "" { 23 if cache == nil { 24 cache, err = spflib.NewCache("spfcache.json") 25 if err != nil { 26 return []error{err} 27 } 28 } 29 rec, err = spflib.Parse(txt.GetTargetField(), cache) 30 if err != nil { 31 errs = append(errs, err) 32 continue 33 } 34 } 35 if flatten, ok := txt.Metadata["flatten"]; ok && strings.HasPrefix(txt.GetTargetField(), "v=spf1") { 36 rec = rec.Flatten(flatten) 37 err = txt.SetTargetTXT(rec.TXT()) 38 if err != nil { 39 errs = append(errs, err) 40 continue 41 } 42 } 43 // now split if needed 44 if split, ok := txt.Metadata["split"]; ok { 45 if !strings.Contains(split, "%d") { 46 errs = append(errs, Warning{errors.Errorf("Split format `%s` in `%s` is not proper format (should have %%d in it)", split, txt.GetLabelFQDN())}) 47 continue 48 } 49 recs := rec.TXTSplit(split + "." + domain.Name) 50 for k, v := range recs { 51 if k == "@" { 52 txt.SetTargetTXT(v) 53 } else { 54 cp, _ := txt.Copy() 55 cp.SetTargetTXT(v) 56 cp.SetLabelFromFQDN(k, domain.Name) 57 domain.Records = append(domain.Records, cp) 58 } 59 } 60 } 61 } 62 } 63 if cache == nil { 64 return errs 65 } 66 // check if cache is stale 67 for _, e := range cache.ResolveErrors() { 68 errs = append(errs, Warning{errors.Errorf("problem resolving SPF record: %s", e)}) 69 } 70 if len(cache.ResolveErrors()) == 0 { 71 changed := cache.ChangedRecords() 72 if len(changed) > 0 { 73 if err := cache.Save("spfcache.updated.json"); err != nil { 74 errs = append(errs, err) 75 } else { 76 errs = append(errs, Warning{errors.Errorf("%d spf record lookups are out of date with cache (%s).\nWrote changes to spfcache.updated.json. Please rename and commit:\n $ mv spfcache.updated.json spfcache.json\n $ git commit spfcache.json", len(changed), strings.Join(changed, ","))}) 77 } 78 } 79 } 80 return errs 81 }