From b698ad385d077be6f2dbf8a6f731afe6e6db7cdf Mon Sep 17 00:00:00 2001 From: Greg Colburn Date: Thu, 26 Nov 2015 21:06:50 -0700 Subject: [PATCH] Initial submit of simple DMARC Aggregate Report Parser Change-Id: Id25647d03dc6aa18aa4034e98c213f9e91fef1fc --- .gitignore | 1 + dmarc.go | 165 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 .gitignore create mode 100644 dmarc.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..781fb73 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +samples/* diff --git a/dmarc.go b/dmarc.go new file mode 100644 index 0000000..c1cd4d2 --- /dev/null +++ b/dmarc.go @@ -0,0 +1,165 @@ +package main + +import ( + "encoding/xml" + "fmt" +) + +func main() { + + type DateRange struct { + Begin int `xml:"begin"` + End int `xml:"end"` + } + + type ReportMetadata struct { + OrgName string `xml:"org_name"` + Email string `xml:"email"` + ExtraContact string `xml:"extra_contact_info"` + ReportId string `xml:"report_id"` + DateRange DateRange `xml:"date_range"` + } + + type PolicyPublished struct { + Domain string `xml:"domain"` + Adkim string `xml:"adkim"` + Aspf string `xml:"aspf"` + Policy string `xml:"p"` + SubdomainPolicy string `xml:"sp"` + Percentage int `xml:"pct"` + } + + type PolicyEvaluated struct { + Disposition string `xml:"disposition"` + Dkim string `xml:"dkim"` + Spf string `xml:"spf"` + } + + type Row struct { + // TODO: Figure out how to cast this to an IP + SourceIp string `xml:"source_ip"` + Count int `xml:"count"` + PolicyEvaluated PolicyEvaluated `xml:"policy_evaluated"` + } + + type Identifiers struct { + HeaderFrom string `xml:"header_from"` + } + + type AuthResult struct { + // FIXME: this could be either DKIM or SPF + XMLName xml.Name + Domain string `xml:"domain"` + Result string `xml:"result"` + } + + type AuthResults struct { + AuthResult []AuthResult `xml:",any"` + } + + type Record struct { + Row Row `xml:"row"` + Identifiers Identifiers `xml:"identifiers"` + AuthResults AuthResults `xml:"auth_results"` + } + + type FeedbackReport struct { + XMLName xml.Name `xml:"feedback"` + ReportMetadata ReportMetadata `xml:"report_metadata"` + PolicyPublished PolicyPublished `xml:"policy_published"` + Record []Record `xml:"record"` + } + + v := FeedbackReport{} + + data := ` + + + + google.com + noreply-dmarc-support@google.com + https://support.google.com/a/answer/2466580 + 11295852759969162400 + + 1448236800 + 1448323199 + + + + colbs.net + r + r +

reject

+ reject + 100 +
+ + + 2607:f8b0:400c:c05::249 + 1 + + none + pass + fail + + + + colbs.net + + + + google.com + pass + + + colbs.net + pass + + + calendar-server.bounces.google.com + pass + + + + + + 2a00:1450:400c:c09::235 + 1 + + none + pass + pass + + + + colbs.net + + + + colbs.net + pass + + + colbs.net + pass + + + +
+ ` + + err := xml.Unmarshal([]byte(data), &v) + if err != nil { + fmt.Printf("error: %v", err) + return + } + + fmt.Printf("XMLName: %#v\n", v) + // fmt.Printf("org_name: %#q\n", v.ReportMetadata.OrgName) + // fmt.Printf("domain: %#q\n", v.PolicyPublished.Domain) + // fmt.Printf("Name: %q\n", v.Name) + // fmt.Printf("Phone: %q\n", v.Phone) + // fmt.Printf("Email: %v\n", v.Email) + // fmt.Printf("Groups: %v\n", v.Groups) + // fmt.Printf("Address: %v\n", v.Address) +}