|
1 #!/usr/bin/env python |
|
2 # -*- coding: utf-8 -*- |
|
3 # Copyright 2009 Pascal Volk |
|
4 |
|
5 __author__ = 'Pascal Volk' |
|
6 __version__ = '0.1' |
|
7 __date__ = '2009-06-07' |
|
8 |
|
9 import os |
|
10 import re |
|
11 |
|
12 class NiXSpamPlot: |
|
13 """Do sth ...""" |
|
14 |
|
15 """Regular expression pattern for mail logs from Postfix""" |
|
16 RE_PF = '''^[\w\s:-]{17,80}\spostfix\/smtpd\[[\d]{3,5}\]: NOQUEUE: reject:.*blocked using ix.dnsbl.manitu.net; Spam sent to the mailhost ((?:[a-z0-9-]{1,63}\.){1,}[a-z]{2,6}) was detected by NiX Spam.*$''' |
|
17 |
|
18 def __init__(self): |
|
19 self._doms = {} |
|
20 self._mxs = {} |
|
21 self._repo = None |
|
22 |
|
23 def setLogFormat(self, format='postfix'): |
|
24 if format == 'postfix': |
|
25 self._repo = re.compile(NiXSpamPlot.RE_PF) |
|
26 else: |
|
27 raise Exception('MTA/Logformat not supported yet.') |
|
28 |
|
29 def parseLog(self, filehandle): |
|
30 for l in filehandle: |
|
31 mo = self._repo.match(l) |
|
32 if mo: |
|
33 mx = mo.group(1) |
|
34 try: |
|
35 self._mxs[mx] += 1 |
|
36 except KeyError: |
|
37 self._mxs[mx] = 1 |
|
38 |
|
39 def countByDom(self): |
|
40 for mx in self._mxs.keys(): |
|
41 dom = '.'.join(mx.split('.')[-2:]) |
|
42 try: |
|
43 self._doms[dom] += self._mxs[mx] |
|
44 except KeyError: |
|
45 self._doms[dom] = self._mxs[mx] |
|
46 |
|
47 def getDomains(self): |
|
48 return self._doms |
|
49 |
|
50 def getMXs(self): |
|
51 return self._mxs |
|
52 |
|
53 def getTotal(self): |
|
54 return sum(self._mxs.values()) |
|
55 |
|
56 def getOptionParser(): |
|
57 from optparse import OptionParser |
|
58 usage = 'usage: %prog [options] maillog [maillog [...]]' |
|
59 parser = OptionParser(usage=usage, description='do something ...') |
|
60 parser.add_option('-d', action='store_true', dest='countByDom', |
|
61 default=False, help='summarize all MX by domain') |
|
62 parser.add_option('-m', action='store_false', dest='countByDom', |
|
63 help='count per MX host [default]') |
|
64 parser.add_option('-o', dest='oFormat', default='table',metavar='FORMAT', |
|
65 help='the output format: table or csv [default: %default]') |
|
66 parser.add_option('-p', action='store_true', dest='percent', default=False, |
|
67 help='show also percentages in table output [default: %default]') |
|
68 parser.add_option('-s', dest='order', default='name', metavar='SORTBY', |
|
69 help='arrange output by: name or count [default: %default]') |
|
70 parser.add_option('-t', dest='format', default='postfix',metavar='MTA', |
|
71 help='MTA that generated the maillog [default: %default]') |
|
72 return parser |
|
73 |
|
74 def openLogFile(fname): |
|
75 try: |
|
76 fh = open(fname) |
|
77 return fh |
|
78 except IOError, e: |
|
79 os.sys.stderr.write('Warning: %s\nskipped file: %s\n' % (e.strerror, |
|
80 fname)) |
|
81 |
|
82 def showResult(nixspamplot, options): |
|
83 if options.countByDom: |
|
84 nixspamplot.countByDom() |
|
85 domains = nixspamplot.getDomains() |
|
86 else: |
|
87 domains = nixspamplot.getMXs() |
|
88 if options.percent: |
|
89 total = nixspamplot.getTotal() |
|
90 k = 0 if options.order == 'name' else 1 |
|
91 doms = sorted(domains.items(), lambda d,c: cmp(d[k],c[k]), reverse=k) |
|
92 for d in doms: |
|
93 print "%s -> %d" % d |
|
94 |
|
95 def main(): |
|
96 parser = getOptionParser() |
|
97 opts, args = parser.parse_args() |
|
98 if len(args) < 1: |
|
99 parser.error('No logfiles specified') |
|
100 nsp = NiXSpamPlot() |
|
101 nsp.setLogFormat(opts.format) |
|
102 for fn in args: |
|
103 fh = openLogFile(fn) |
|
104 if fh is not None: |
|
105 nsp.parseLog(fh) |
|
106 fh.close() |
|
107 showResult(nsp, opts) |
|
108 |
|
109 if __name__ == '__main__': |
|
110 main() |