go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/network/resources/dnsshake/spf.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package dnsshake 5 6 import ( 7 "strings" 8 9 "github.com/alecthomas/participle/v2" 10 "github.com/alecthomas/participle/v2/lexer" 11 ) 12 13 // Sender Policy Framework (SPF) for Authorizing Use of Domains in Email, Version 1 14 // https://datatracker.ietf.org/doc/html/rfc7208 15 // 16 // 1. Parse SPF records 17 // 2. Validate SPF record 18 // 3. Validate EMAIL + DOMAIN 19 20 // Model after https://datatracker.ietf.org/doc/html/rfc7208#section-12 21 var spfLexer = lexer.MustSimple([]lexer.SimpleRule{ 22 {`Header`, `v=`}, 23 {`Version`, `spf\d`}, 24 {"whitespace", `\s+`}, 25 {`Colon`, `[:]`}, 26 {`Slash`, `[/]`}, 27 {`Equal`, `[=]`}, 28 {`Mechanism`, `\b(all|include|a|mx|ptr|ip4|ip6|exists)\b`}, 29 {`Modifier`, `\b(redirect|exp)\b`}, 30 {`String`, `[^+\-:\s=\/][\w.%\-+{}]+`}, 31 {`Qualifier`, `[\+\-~?]`}, 32 {`Number`, `\d+`}, 33 }) 34 35 // nolint: govet 36 type SpfRecord struct { 37 Version string `"v=" @Version` 38 Directives []Directive `@@*` 39 Modifiers []Modifier `@@*` 40 } 41 42 // nolint: govet 43 type Directive struct { 44 Qualifier string `(@Qualifier)?` 45 Mechanism string `@Mechanism` 46 Value string `(":" @String)?` 47 CIDR string `("/" @String)?` 48 } 49 50 // nolint: govet 51 type Modifier struct { 52 Modifier string `@Modifier "="` 53 Value string `@String` 54 } 55 56 var spfParser = participle.MustBuild[SpfRecord]( 57 participle.Lexer(spfLexer), 58 ) 59 60 func NewSpf() *spf { 61 return &spf{} 62 } 63 64 type spf struct{} 65 66 func (s *spf) Parse(txt string) (*SpfRecord, error) { 67 lines := strings.Split(txt, " ") 68 69 return spfParser.Parse("", strings.NewReader(strings.Join(lines, "\n"))) 70 }