#11: implement MTA-STS, TLS-RPT & Autoconfig HTTP services
This commit is contained in:
1 parent
c0042ef207
commit
314eb67dda
20 files changed
+1177
-31
No files matched your search
@@ -0,0 +1,103 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DmarcRecord struct {
|
||||
SourceIP string
|
||||
Count int
|
||||
Disposition string
|
||||
DKIMResult string
|
||||
SPFResult string
|
||||
HeaderFrom string
|
||||
}
|
||||
|
||||
type DmarcReport struct {
|
||||
OrgName string
|
||||
ReportID string
|
||||
Domain string
|
||||
DateRangeBegin time.Time
|
||||
DateRangeEnd time.Time
|
||||
Records []DmarcRecord
|
||||
}
|
||||
|
||||
type dmarcXmlReport struct {
|
||||
ReportMetadata struct {
|
||||
OrgName string `xml:"org_name"`
|
||||
ReportID string `xml:"report_id"`
|
||||
DateRange struct {
|
||||
Begin int64 `xml:"begin"`
|
||||
End int64 `xml:"end"`
|
||||
} `xml:"date_range"`
|
||||
} `xml:"report_metadata"`
|
||||
PolicyPublished struct {
|
||||
Domain string `xml:"domain"`
|
||||
} `xml:"policy_published"`
|
||||
Record []struct {
|
||||
Row struct {
|
||||
SourceIP string `xml:"source_ip"`
|
||||
Count int `xml:"count"`
|
||||
PolicyEvaluated struct {
|
||||
Disposition string `xml:"disposition"`
|
||||
DKIM string `xml:"dkim"`
|
||||
SPF string `xml:"spf"`
|
||||
} `xml:"policy_evaluated"`
|
||||
} `xml:"row"`
|
||||
Identifiers struct {
|
||||
HeaderFrom string `xml:"header_from"`
|
||||
} `xml:"identifiers"`
|
||||
} `xml:"record"`
|
||||
}
|
||||
|
||||
// ParseDmarcXmlReport parses raw XML or gzipped XML DMARC aggregate report.
|
||||
func ParseDmarcXmlReport(payload []byte) (*DmarcReport, error) {
|
||||
data := payload
|
||||
if isGzip(payload) {
|
||||
gz, err := gzip.NewReader(bytes.NewReader(payload))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("gzip reader: %w", err)
|
||||
}
|
||||
defer gz.Close()
|
||||
decompressed, err := io.ReadAll(gz)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decompress gzip: %w", err)
|
||||
}
|
||||
data = decompressed
|
||||
}
|
||||
|
||||
var parsed dmarcXmlReport
|
||||
if err := xml.Unmarshal(data, &parsed); err != nil {
|
||||
return nil, fmt.Errorf("unmarshal dmarc xml: %w", err)
|
||||
}
|
||||
|
||||
report := &DmarcReport{
|
||||
OrgName: parsed.ReportMetadata.OrgName,
|
||||
ReportID: parsed.ReportMetadata.ReportID,
|
||||
Domain: parsed.PolicyPublished.Domain,
|
||||
DateRangeBegin: time.Unix(parsed.ReportMetadata.DateRange.Begin, 0),
|
||||
DateRangeEnd: time.Unix(parsed.ReportMetadata.DateRange.End, 0),
|
||||
}
|
||||
|
||||
for _, r := range parsed.Record {
|
||||
report.Records = append(report.Records, DmarcRecord{
|
||||
SourceIP: r.Row.SourceIP,
|
||||
Count: r.Row.Count,
|
||||
Disposition: r.Row.PolicyEvaluated.Disposition,
|
||||
DKIMResult: r.Row.PolicyEvaluated.DKIM,
|
||||
SPFResult: r.Row.PolicyEvaluated.SPF,
|
||||
HeaderFrom: r.Identifiers.HeaderFrom,
|
||||
})
|
||||
}
|
||||
|
||||
return report, nil
|
||||
}
|
||||
|
||||
func isGzip(payload []byte) bool {
|
||||
return len(payload) >= 2 && payload[0] == 0x1f && payload[1] == 0x8b
|
||||
}
|
||||
Reference in new issue
Block a user