Migrate report parsing code to library

Change-Id: I156290b8bf7fff314266f62980eb100af600198a
This commit is contained in:
Greg Colburn
2015-11-28 14:31:33 -07:00
parent df38d3871c
commit f99646808a
3 changed files with 128 additions and 105 deletions

105
dmarc.go
View File

@@ -1,105 +0,0 @@
package main
import (
"encoding/xml"
"fmt"
"os"
)
func main() {
type DateRange struct {
// TODO: should be int but Y! trailing spaces
Begin string `xml:"begin"`
End string `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"`
}
xmlFile, err := os.Open("/Users/gcolburn/go/src/github.com/gc1code/dmarcparser/samples/yahoo.xml") // For read access.
if err != nil {
fmt.Printf("os error: %v", err)
return
}
defer xmlFile.Close()
decoder := xml.NewDecoder(xmlFile)
var inElement string
for {
t, _ := decoder.Token()
if t == nil {
break
}
switch se := t.(type) {
case xml.StartElement:
inElement = se.Name.Local
if inElement == "feedback" {
f := FeedbackReport{}
xmlerr := decoder.DecodeElement(&f, &se)
if xmlerr != nil {
fmt.Printf("decode error: %v", xmlerr)
}
fmt.Printf("XMLName: %#v\n", f)
}
default:
}
}
}

98
dmarc/report.go Normal file
View File

@@ -0,0 +1,98 @@
package dmarc
import (
"encoding/xml"
"io"
)
type DateRange struct {
// TODO: should be int but Y! trailing spaces
Begin string `xml:"begin"`
End string `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"`
}
func ParseReader(xmlFileReader io.Reader) FeedbackReport {
var f FeedbackReport
decoder := xml.NewDecoder(xmlFileReader)
var inElement string
for {
t, _ := decoder.Token()
if t == nil {
break
}
switch se := t.(type) {
case xml.StartElement:
inElement = se.Name.Local
if inElement == "feedback" {
decoder.DecodeElement(&f, &se)
// xmlerr := decoder.DecodeElement(&f, &se)
// if xmlerr != nil {
// fmt.Printf("decode error: %v\n", xmlerr)
// }
// fmt.Printf("XMLName: %#v\n", f)
}
default:
}
}
return f
}

30
dmarcparser.go Normal file
View File

@@ -0,0 +1,30 @@
package main
import (
"flag"
"fmt"
"github.com/gc1code/dmarcparser/dmarc"
"os"
)
func main() {
var filename = flag.String("filename", "none", "Path to DMARC Aggregate Report XML")
flag.Parse()
if *filename == "none" {
fmt.Printf("XML File required.\n")
return
}
xmlFile, err := os.Open(*filename) // For read access.
if err != nil {
fmt.Printf("os error: %v\n", err)
return
}
defer xmlFile.Close()
feedbackReport := dmarc.ParseReader(xmlFile)
fmt.Printf("XMLName: %#v\n", feedbackReport)
}