nixspamsum
changeset 11 a5f5a8f288da
parent 10 07b9fe5c6fcf
child 13 b0c05ce0f44c
equal deleted inserted replaced
10:07b9fe5c6fcf 11:a5f5a8f288da
     2 # -*- coding: utf-8 -*-
     2 # -*- coding: utf-8 -*-
     3 # Copyright 2009 - 2010 Pascal Volk
     3 # Copyright 2009 - 2010 Pascal Volk
     4 # See COPYING for distribution information.
     4 # See COPYING for distribution information.
     5 
     5 
     6 __author__ = 'Pascal Volk'
     6 __author__ = 'Pascal Volk'
     7 __version__ = '0.1.2'
     7 __version__ = '0.1.3'
     8 __date__ = '2009-07-03'
     8 __date__ = '2010-04-11'
     9 
     9 
    10 import os
    10 import os
    11 import re
    11 import re
    12 import fileinput
    12 import fileinput
       
    13 
    13 
    14 
    14 class NiXSapmSum(object):
    15 class NiXSapmSum(object):
    15     """
    16     """
    16     Small log parser class to parse and summarize NiX Spam DNSBL lookup
    17     Small log parser class to parse and summarize NiX Spam DNSBL lookup
    17     based rejects from a mail log file.
    18     based rejects from a mail log file.
    24     RE_PF = r'''^[\w\s:-]{17,80}\spostfix\/smtpd\[[\d]{1,5}\]:\sNOQUEUE:
    25     RE_PF = r'''^[\w\s:-]{17,80}\spostfix\/smtpd\[[\d]{1,5}\]:\sNOQUEUE:
    25                 \sreject:.*blocked\susing\six.dnsbl.manitu.net;
    26                 \sreject:.*blocked\susing\six.dnsbl.manitu.net;
    26                 \sSpam\ssent\sto\sthe\smailhost\s(%s|%s)
    27                 \sSpam\ssent\sto\sthe\smailhost\s(%s|%s)
    27                 \swas\sdetected\sby\sNiX\sSpam.*$''' % (RE_FQDN, RE_IPv4)
    28                 \swas\sdetected\sby\sNiX\sSpam.*$''' % (RE_FQDN, RE_IPv4)
    28 
    29 
    29 
       
    30     def __init__(self):
    30     def __init__(self):
    31         self._doms = {}
    31         self._doms = {}
    32         self._mxs  = {}
    32         self._mxs = {}
    33         self._repo = None
    33         self._repo = None
    34 
    34 
    35     def setLogFormat(self, format='postfix'):
    35     def setLogFormat(self, format='postfix'):
    36         if format == 'postfix':
    36         if format == 'postfix':
    37             self._repo = re.compile(NiXSapmSum.RE_PF, re.VERBOSE)
    37             self._repo = re.compile(NiXSapmSum.RE_PF, re.VERBOSE)
    44             if mo:
    44             if mo:
    45                 mx = mo.group(1)
    45                 mx = mo.group(1)
    46                 try:
    46                 try:
    47                     self._mxs[mx] += 1
    47                     self._mxs[mx] += 1
    48                 except KeyError:
    48                 except KeyError:
    49                     self._mxs[mx]  = 1
    49                     self._mxs[mx] = 1
    50 
    50 
    51     def countByDom(self):
    51     def countByDom(self):
    52         ipv4po = re.compile(NiXSapmSum.RE_IPv4)
    52         ipv4po = re.compile(NiXSapmSum.RE_IPv4)
    53         for mx in self._mxs.keys():
    53         for mx in self._mxs.keys():
    54             mo = ipv4po.match(mx)
    54             mo = ipv4po.match(mx)
    57             else:
    57             else:
    58                 dom = '.'.join(mx.split('.')[-2:])
    58                 dom = '.'.join(mx.split('.')[-2:])
    59             try:
    59             try:
    60                 self._doms[dom] += self._mxs[mx]
    60                 self._doms[dom] += self._mxs[mx]
    61             except KeyError:
    61             except KeyError:
    62                 self._doms[dom]  = self._mxs[mx]
    62                 self._doms[dom] = self._mxs[mx]
    63 
    63 
    64     def getDomains(self):
    64     def getDomains(self):
    65         return self._doms
    65         return self._doms
    66 
    66 
    67     def getMXs(self):
    67     def getMXs(self):
    69 
    69 
    70 
    70 
    71 def getOptionParser():
    71 def getOptionParser():
    72     from optparse import OptionParser
    72     from optparse import OptionParser
    73     description = 'NiX Spam DNSBL lookup based rejects summarizer'
    73     description = 'NiX Spam DNSBL lookup based rejects summarizer'
    74     usage  = 'usage: %prog [options] maillog [maillog [...]]'
    74     usage = 'usage: %prog [options] maillog [maillog [...]]'
    75     version = '%prog '+__version__
    75     version = '%prog ' + __version__
    76     parser = OptionParser(description=description,usage=usage,version=version)
    76     parser = OptionParser(description=description, usage=usage,
       
    77                           version=version)
    77     parser.add_option('-d', action='store_true', dest='countByDom',
    78     parser.add_option('-d', action='store_true', dest='countByDom',
    78             default=False, help='summarize all MX by domain')
    79             default=False, help='summarize all MX by domain')
    79     parser.add_option('-m', action='store_false', dest='countByDom',
    80     parser.add_option('-m', action='store_false', dest='countByDom',
    80             help='count per MX host [default]')
    81             help='count per MX host [default]')
    81     parser.add_option('-o', dest='oFormat', default='table',metavar='FORMAT',
    82     parser.add_option('-o', dest='oFormat', default='table', metavar='FORMAT',
    82             choices=('csv', 'table'),
    83             choices=('csv', 'table'),
    83             help='the output format: table or csv [default: %default]')
    84             help='the output format: table or csv [default: %default]')
    84     parser.add_option('-p', action='store_true', dest='percent', default=False,
    85     parser.add_option('-p', action='store_true', dest='percent', default=False,
    85             help='show also percentages in table output [default: %default]')
    86             help='show also percentages in table output [default: %default]')
    86     parser.add_option('-s', dest='order', default='name', metavar='SORTBY',
    87     parser.add_option('-s', dest='order', default='name', metavar='SORTBY',
    87             choices=('count', 'name'),
    88             choices=('count', 'name'),
    88             help='arrange output by: name or count [default: %default]')
    89             help='arrange output by: name or count [default: %default]')
    89     parser.add_option('-t', dest='format', default='postfix',metavar='MTA',
    90     parser.add_option('-t', dest='format', default='postfix', metavar='MTA',
    90             choices=('postfix',),
    91             choices=('postfix',),
    91             help='MTA that generated the maillog [default: %default]')
    92             help='MTA that generated the maillog [default: %default]')
    92     return parser
    93     return parser
    93 
    94 
    94 
    95 
   121     return False
   122     return False
   122 
   123 
   123 
   124 
   124 def buildTable(output, domains, percent, orderBy):
   125 def buildTable(output, domains, percent, orderBy):
   125     k = 0 if orderBy == 'name' else 1
   126     k = 0 if orderBy == 'name' else 1
   126     doms = sorted(domains.items(), lambda d,c: cmp(d[k],c[k]), reverse=k)
   127     doms = sorted(domains.items(), lambda d, c: cmp(d[k], c[k]), reverse=k)
   127     dlen = len(max(domains.iterkeys(), key=len)) + 1
   128     dlen = len(max(domains.iterkeys(), key=len)) + 1
   128     clen = len(str(max(domains.values())))
   129     clen = len(str(max(domains.values())))
   129     total = sum(domains.values())
   130     total = sum(domains.values())
   130     if percent:
   131     if percent:
   131         format = ' %%%ds  %%%dd  %%6.2f %%%%\n' % (-dlen, clen)
   132         format = ' %%%ds  %%%dd  %%6.2f %%%%\n' % (-dlen, clen)
   132         for d, c in doms:
   133         for d, c in doms:
   133             dfrac = 100./total*c
   134             dfrac = 100. / total * c
   134             output.write(format % (d, c, dfrac))
   135             output.write(format % (d, c, dfrac))
   135         output.write('%s\n' % ((clen+dlen+14)*'-'))
   136         output.write('%s\n' % ((clen + dlen + 14) * '-'))
   136         output.write(format % ('total', total, 100))
   137         output.write(format % ('total', total, 100))
   137     else:
   138     else:
   138         format = ' %%%ds  %%%dd\n' % (-dlen, clen)
   139         format = ' %%%ds  %%%dd\n' % (-dlen, clen)
   139         for d in doms:
   140         for d in doms:
   140             output.write(format % d)
   141             output.write(format % d)
   141         output.write('%s\n' % ((clen+dlen+4)*'-'))
   142         output.write('%s\n' % ((clen + dlen + 4) * '-'))
   142         output.write(format % ('total', total))
   143         output.write(format % ('total', total))
       
   144 
   143 
   145 
   144 def showResult(nixspamsum, options):
   146 def showResult(nixspamsum, options):
   145     if options.countByDom:
   147     if options.countByDom:
   146         nixspamsum.countByDom()
   148         nixspamsum.countByDom()
   147         domains = nixspamsum.getDomains()
   149         domains = nixspamsum.getDomains()
   166     else:
   168     else:
   167         print "Oops, error in function showResult() happend"
   169         print "Oops, error in function showResult() happend"
   168     # show the result
   170     # show the result
   169     print output.getvalue()
   171     print output.getvalue()
   170 
   172 
       
   173 
   171 def main():
   174 def main():
   172     parser = getOptionParser()
   175     parser = getOptionParser()
   173     opts, args = parser.parse_args()
   176     opts, args = parser.parse_args()
   174     if not args:
   177     if not args:
   175         parser.error('No log file specified')
   178         parser.error('No log file specified')
   187     nixss.parseLog(fi)
   190     nixss.parseLog(fi)
   188     fi.close()
   191     fi.close()
   189     showResult(nixss, opts)
   192     showResult(nixss, opts)
   190     return 0
   193     return 0
   191 
   194 
       
   195 
   192 if __name__ == '__main__':
   196 if __name__ == '__main__':
   193     os.sys.exit(main())
   197     os.sys.exit(main())