SPF Optimizer: Add "redirect:" support (#506)

FYI: The support is very minimal. It only supports redirect if it is the last item in an SPF record. At that point, it is equivalent to include.

* In SFP, treat redirect like a special include.
* Document SPF redirect: limited implementation.
This commit is contained in:
Tom Limoncelli 2019-06-19 18:46:56 +01:00 committed by GitHub
parent 4a7a5515a0
commit 2d9d93653b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 44 additions and 3 deletions

View file

@ -178,6 +178,10 @@ could exceed 512 bytes, and will require EDNS or a TCP request.
3. Dnscontrol does not warn if the number of lookups exceeds 10. 3. Dnscontrol does not warn if the number of lookups exceeds 10.
We hope to implement this some day. We hope to implement this some day.
4. The `redirect:` directive is only partially implemented. We only
handle the case where redirect is the last item in the SPF record.
In which case, it is equivalent to `include:`.
## Advanced Technique: Interactive SPF Debugger ## Advanced Technique: Interactive SPF Debugger

View file

@ -52,7 +52,7 @@ func Parse(text string, dnsres Resolver) (*SPFRecord, error) {
} }
parts := strings.Split(text, " ") parts := strings.Split(text, " ")
rec := &SPFRecord{} rec := &SPFRecord{}
for _, part := range parts[1:] { for pi, part := range parts[1:] {
if part == "" { if part == "" {
continue continue
} }
@ -69,9 +69,18 @@ func Parse(text string, dnsres Resolver) (*SPFRecord, error) {
} else if strings.HasPrefix(part, "ip4:") || strings.HasPrefix(part, "ip6:") { } else if strings.HasPrefix(part, "ip4:") || strings.HasPrefix(part, "ip6:") {
// ip address, 0 lookups // ip address, 0 lookups
continue continue
} else if strings.HasPrefix(part, "include:") { } else if strings.HasPrefix(part, "include:") || strings.HasPrefix(part, "redirect:") {
if strings.HasPrefix(part, "redirect:") {
// pi + 2: because pi starts at 0 when it iterates starting on parts[1],
// and because len(parts) is one bigger than the highest index.
if (pi + 2) != len(parts) {
return nil, errors.Errorf("%s must be last item", part)
}
p.IncludeDomain = strings.TrimPrefix(part, "redirect:")
} else {
p.IncludeDomain = strings.TrimPrefix(part, "include:")
}
p.IsLookup = true p.IsLookup = true
p.IncludeDomain = strings.TrimPrefix(part, "include:")
if dnsres != nil { if dnsres != nil {
subRecord, err := dnsres.GetSPF(p.IncludeDomain) subRecord, err := dnsres.GetSPF(p.IncludeDomain)
if err != nil { if err != nil {

View file

@ -40,3 +40,31 @@ func TestParseWithDoubleSpaces(t *testing.T) {
} }
t.Log(rec.Print()) t.Log(rec.Print())
} }
func TestParseRedirectNotLast(t *testing.T) {
// Make sure redirect:foo fails if it isn't the last item.
dnsres, err := NewCache("testdata-dns1.json")
if err != nil {
t.Fatal(err)
}
_, err = Parse(strings.Join([]string{"v=spf1",
"redirect:servers.mcsv.net",
"~all"}, " "), dnsres)
if err == nil {
t.Fatal("should fail")
}
}
func TestParseRedirectLast(t *testing.T) {
dnsres, err := NewCache("testdata-dns1.json")
if err != nil {
t.Fatal(err)
}
rec, err := Parse(strings.Join([]string{"v=spf1",
"ip4:198.252.206.0/24",
"redirect:servers.mcsv.net"}, " "), dnsres)
if err != nil {
t.Fatal(err)
}
t.Log(rec.Print())
}