Skip to content

Instantly share code, notes, and snippets.

@akamajoris
Created April 3, 2019 12:01
Show Gist options
  • Save akamajoris/e18e44c66c5bcf0e869c58ac84b08e91 to your computer and use it in GitHub Desktop.
Save akamajoris/e18e44c66c5bcf0e869c58ac84b08e91 to your computer and use it in GitHub Desktop.
Simple maillog parser
package main
import (
"bufio"
"fmt"
"log"
"net"
"os"
"regexp"
"sort"
"github.com/oschwald/geoip2-golang"
)
type Record struct {
From string
To string
IP string
}
var (
smtpdPattern = `([a-zA-Z0-9]+):\sclient=(.*)`
smtpPattern = `([a-zA-Z0-9]+|NOQUEUE):\sto=(.*?),\srelay=(.*?),\sdelay=(.*?),\sdelays=(.*?),\sdsn=(.*?),\sstatus=(.*?)\s(.*)`
removeRegexPattern = `([a-zA-Z0-9]+):\smessage-id=(.*)`
records = make(map[string]Record)
analyse = make(map[string]int)
)
type kv struct {
Key string
Value int
}
func main() {
db, err := geoip2.Open("GeoLite2-City.mmdb")
if err != nil {
log.Fatal(err)
}
defer db.Close()
clientRegex := regexp.MustCompile(smtpdPattern)
smtpRegex := regexp.MustCompile(smtpPattern)
removeRegex := regexp.MustCompile(removeRegexPattern)
file, err := os.Open("maillog")
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
var cnt = 0
for scanner.Scan() {
line := scanner.Text()
cnt++
if cnt%10000 == 0 {
log.Println(cnt)
}
switch {
case clientRegex.MatchString(line):
matches := clientRegex.FindAllStringSubmatch(line, -1)
clientInfoRegexPattern := regexp.MustCompile(`(.*?)\[(.*?)\]`)
clientMatches := clientInfoRegexPattern.FindAllStringSubmatch(matches[0][2], -1)
ID := matches[0][1]
IP := clientMatches[0][2]
FROM := clientMatches[0][1]
//overwrite if exists
records[ID] = Record{
From: FROM,
IP: IP,
}
break
case smtpRegex.MatchString(line):
matches := smtpRegex.FindAllStringSubmatch(line, -1)
ID := matches[0][1]
TO := matches[0][2]
clientIP := records[ID].IP
ip := net.ParseIP(clientIP)
record, err := db.City(ip)
if err != nil {
log.Fatal(err)
}
if (record.Country.IsoCode == "ZA") && matches[0][7] == "sent" {
analyse[TO]++
}
break
case removeRegex.MatchString(line):
break
}
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
var ss []kv
for k, v := range analyse {
ss = append(ss, kv{k, v})
}
sort.Slice(ss, func(i, j int) bool {
return ss[i].Value > ss[j].Value
})
for _, kv := range ss {
fmt.Printf("%s, %d\n", kv.Key, kv.Value)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment