#!/usr/bin/perl -w # mailgraph -- detailed postfix mail traffic statistics # copyright (c) 2000-2007 ETH Zurich # copyright (c) 2000-2007 David Schweikert # modified 2011 for queuegraph by Ralf Hildebrandt # modified 2015 for mailgraph-ng by Django based on # patches from Sebastian van de Meer # released under the GNU General Public License use RRDs; use POSIX qw(uname); my $VERSION = "1.15"; my $host = (POSIX::uname())[1]; my $scriptname = $ENV{"SCRIPT_NAME"}; my $xpoints = 800; my $points_per_sample = 3; my $ypoints = 160; my $rrd = '/var/lib/mailgraph/mx14/mailgraph.rrd'; my $rrd_virus = '/var/lib/mailgraph/mx14/mailgraph_virus.rrd'; my $rrd_grey = '/var/lib/mailgraph/mx14/mailgraph_grey.rrd'; my $rrd_dane = '/var/lib/mailgraph/mx14/mailgraph_dane.rrd'; my $rrd_dmarc = '/var/lib/mailgraph/mx14/mailgraph_dmarc.rrd'; my $rrd_smtpd = '/var/lib/mailgraph/mx14/mailgraph_smtpd.rrd'; my $rrd_queue = '/var/lib/mailgraph/mx14/mailqueues.rrd'; my $rrd_post = '/var/lib/mailgraph/mx14/mailgraph_post.rrd'; my $tmp_dir = '/var/cache/mailgraph'; my @graphs = ( { title => 'Letzter Tag', seconds => 3600*24, }, { title => 'Letzte Woche', seconds => 3600*24*7, }, { title => 'Letzter Monat', seconds => 3600*24*31, }, { title => 'Letztes Jahr', seconds => 3600*24*365, }, ); my %color = ( # rrggbb in hex # n sent => '000099', received => '009900', bounced => '000000', virus => 'DDBB00', spam => '999999', rejected => 'AA0000', greylisted => 'CCCCCC', delayed => '006400', whitelist => '00D8FF', awl => 'FF7700', early => 'AA0000', pswl => 'E1FFC1', # psbl => 'EBBAD5', passold => 'BAFF70', # veto => 'EBEBD5', pregreet => 'EBA8D5', dnsbl => 'EB75D5', pipelining => 'B85BA7', nonsmtp => '793C6E', barenewline => '793C2E', command => '47231B', hangup => 'C12C0A', passnew => '468700', # new => 'FF77EE', reconnectok => '7700DD', active => 'EFEF00', deferred => 'DD8800', untrustedtls => 'ffebd1', anonymoustls => 'ffcf90', trustedtls => 'ffb24f', verifiedtls => 'ff5800', untrustedtlsin => 'ddd1ff', anonymoustlsin => 'a8a8ff', trustedtlsin => '6767ff', spfnone => '12FF0A', spffail => 'f80b6f', spfpass => '2E5fEC', dkimnone => 'E6E27A', dkimfail => 'FF6600', dkimpass => '3013EC', dmarcnone => 'F0B166', dmarcfail => 'f11717', dmarcpass => '00FFD5', ); my $url = "http://mailgraph-ng.nausch.org/mx/"; my $urlg = "http://mailgraph-ng.nausch.org/mx/#G"; my $url1 = "http://mailgraph-ng.nausch.org/mx11/"; my $url2 = "http://mailgraph-ng.nausch.org/mx12/"; my $url3 = "http://mailgraph-ng.nausch.org/mx13/"; my $url4 = "http://mailgraph-ng.nausch.org/mx14/"; my $url11 = "http://mailgraph-ng.nausch.org/mx11/#G"; my $url12 = "http://mailgraph-ng.nausch.org/mx12/#G"; my $url13 = "http://mailgraph-ng.nausch.org/mx13/#G"; my $url14 = "http://mailgraph-ng.nausch.org/mx14/#G"; sub rrd_graph(@) { my ($range, $file, $ypoints, @rrdargs) = @_; my $step = $range*$points_per_sample/$xpoints; my $end = time; $end -= $end % $step; my $date = localtime(time); $date =~ s|:|\\:|g unless $RRDs::VERSION < 1.199908; my ($graphret,$xs,$ys) = RRDs::graph($file, '--imgformat', 'PNG', '--width', $xpoints, '--height', $ypoints, '--start', "-$range", '--end', $end, '--vertical-label', 'msgs/min', '--lower-limit', 0, '--units-exponent', 0, # don't show milli-messages/s '--lazy', '--color', 'SHADEA#ffffff', '--color', 'SHADEB#ffffff', '--color', 'BACK#ffffff', $RRDs::VERSION < 1.2002 ? () : ( '--slope-mode'), @rrdargs, 'COMMENT:['.$date.']\r', ); my $ERR=RRDs::error; die "ERROR: $ERR\n" if $ERR; } sub graph($$) { my ($range, $file) = @_; my $step = $range*$points_per_sample/$xpoints; rrd_graph($range, $file, $ypoints, "DEF:sent=$rrd:sent:AVERAGE", "DEF:msent=$rrd:sent:MAX", "CDEF:rsent=sent,60,*", "CDEF:rmsent=msent,60,*", "CDEF:dsent=sent,UN,0,sent,IF,$step,*", "CDEF:ssent=PREV,UN,dsent,PREV,IF,dsent,+", "AREA:rsent#$color{sent}:Sent ", 'GPRINT:ssent:MAX:total\: %15.0lf msgs', 'GPRINT:rsent:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmsent:MAX:max\: %11.0lf msgs/min\l', "DEF:recv=$rrd:recv:AVERAGE", "DEF:mrecv=$rrd:recv:MAX", "CDEF:rrecv=recv,60,*", "CDEF:rmrecv=mrecv,60,*", "CDEF:drecv=recv,UN,0,recv,IF,$step,*", "CDEF:srecv=PREV,UN,drecv,PREV,IF,drecv,+", "LINE2:rrecv#$color{received}:Received ", 'GPRINT:srecv:MAX:total\: %15.0lf msgs', 'GPRINT:rrecv:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmrecv:MAX:max\: %11.0lf msgs/min\l', ); } sub graph_virus($$) { my ($range, $file) = @_; my $step = $range*$points_per_sample/$xpoints; rrd_graph($range, $file, $ypoints, "DEF:rejected=$rrd:rejected:AVERAGE", "DEF:mrejected=$rrd:rejected:MAX", "CDEF:rrejected=rejected,60,*", "CDEF:drejected=rejected,UN,0,rejected,IF,$step,*", "CDEF:srejected=PREV,UN,drejected,PREV,IF,drejected,+", "CDEF:rmrejected=mrejected,60,*", "AREA:rrejected#$color{rejected}:Rejected ", 'GPRINT:srejected:MAX:total\: %15.0lf msgs', 'GPRINT:rrejected:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmrejected:MAX:max\: %11.0lf msgs/min\l', "DEF:virus=$rrd_virus:virus:AVERAGE", "DEF:mvirus=$rrd_virus:virus:MAX", "CDEF:rvirus=virus,60,*", "CDEF:dvirus=virus,UN,0,virus,IF,$step,*", "CDEF:svirus=PREV,UN,dvirus,PREV,IF,dvirus,+", "CDEF:rmvirus=mvirus,60,*", "AREA:rvirus#$color{virus}:Viruses ", 'GPRINT:svirus:MAX:total\: %15.0lf msgs', 'GPRINT:rvirus:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmvirus:MAX:max\: %11.0lf msgs/min\l', "DEF:spam=$rrd_virus:spam:AVERAGE", "DEF:mspam=$rrd_virus:spam:MAX", "CDEF:rspam=spam,60,*", "CDEF:dspam=spam,UN,0,spam,IF,$step,*", "CDEF:sspam=PREV,UN,dspam,PREV,IF,dspam,+", "CDEF:rmspam=mspam,60,*", "STACK:rspam#$color{spam}:Spam ", 'GPRINT:sspam:MAX:total\: %15.0lf msgs', 'GPRINT:rspam:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmspam:MAX:max\: %11.0lf msgs/min\l', "DEF:bounced=$rrd:bounced:AVERAGE", "DEF:mbounced=$rrd:bounced:MAX", "CDEF:rbounced=bounced,60,*", "CDEF:dbounced=bounced,UN,0,bounced,IF,$step,*", "CDEF:sbounced=PREV,UN,dbounced,PREV,IF,dbounced,+", "CDEF:rmbounced=mbounced,60,*", "LINE2:rbounced#$color{bounced}:Bounced ", 'GPRINT:sbounced:MAX:total\: %15.0lf msgs', 'GPRINT:rbounced:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmbounced:MAX:max\: %11.0lf msgs/min\l', ); } sub graph_greylist($$) { my ($range, $file) = @_; my $step = $range*$points_per_sample/$xpoints; rrd_graph($range, $file, $ypoints, "DEF:new=$rrd_grey:new:AVERAGE", "DEF:mnew=$rrd_grey:new:MAX", "CDEF:rnew=new,60,*", "CDEF:rmnew=mnew,60,*", "CDEF:dnew=new,UN,0,new,IF,$step,*", "CDEF:snew=PREV,UN,dnew,PREV,IF,dnew,+", "AREA:rnew#$color{new}:New ", 'GPRINT:snew:MAX:total\: %15.0lf msgs', 'GPRINT:rnew:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmnew:MAX:max\: %11.0lf msgs/min\l', "DEF:reconnectok=$rrd_grey:reconnectok:AVERAGE", "DEF:mreconnectok=$rrd_grey:reconnectok:MAX", "CDEF:rreconnectok=reconnectok,60,*", "CDEF:dreconnectok=reconnectok,UN,0,reconnectok,IF,$step,*", "CDEF:sreconnectok=PREV,UN,dreconnectok,PREV,IF,dreconnectok,+", "CDEF:rmreconnectok=mreconnectok,60,*", "LINE2:rreconnectok#$color{reconnectok}:Reconnect O.K. ", 'GPRINT:sreconnectok:MAX:total\: %15.0lf msgs', 'GPRINT:rreconnectok:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmreconnectok:MAX:max\: %11.0lf msgs/min\l', ); } sub graph_greystats($$) { my ($range, $file) = @_; my $step = $range*$points_per_sample/$xpoints; rrd_graph($range, $file, $ypoints, "DEF:greylisted=$rrd_grey:greylisted:AVERAGE", "DEF:mgreylisted=$rrd_grey:greylisted:MAX", "CDEF:rgreylisted=greylisted,60,*", "CDEF:rmgreylisted=mgreylisted,60,*", "CDEF:dgreylisted=greylisted,UN,0,greylisted,IF,$step,*", "CDEF:sgreylisted=PREV,UN,dgreylisted,PREV,IF,dgreylisted,+", "AREA:rgreylisted#$color{greylisted}:Greylisted ", 'GPRINT:sgreylisted:MAX:total\: %15.0lf msgs', 'GPRINT:rgreylisted:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmgreylisted:MAX:max\: %11.0lf msgs/min\l', "DEF:delayed=$rrd_grey:delayed:AVERAGE", "DEF:mdelayed=$rrd_grey:delayed:MAX", "CDEF:rdelayed=delayed,60,*", "CDEF:rmdelayed=mdelayed,60,*", "CDEF:ddelayed=delayed,UN,0,delayed,IF,$step,*", "CDEF:sdelayed=PREV,UN,ddelayed,PREV,IF,ddelayed,+", "LINE2:rdelayed#$color{delayed}:Delayed ", 'GPRINT:sdelayed:MAX:total\: %15.0lf msgs', 'GPRINT:rdelayed:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmdelayed:MAX:max\: %11.0lf msgs/min\l', "DEF:whitelist=$rrd_grey:whitelist:AVERAGE", "DEF:mwhitelist=$rrd_grey:whitelist:MAX", "CDEF:rwhitelist=whitelist,60,*", "CDEF:rmwhitelist=mwhitelist,60,*", "CDEF:dwhitelist=whitelist,UN,0,whitelist,IF,$step,*", "CDEF:swhitelist=PREV,UN,dwhitelist,PREV,IF,dwhitelist,+", "AREA:rwhitelist#$color{whitelist}:Whitelist ", 'GPRINT:swhitelist:MAX:total\: %15.0lf msgs', 'GPRINT:rwhitelist:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmwhitelist:MAX:max\: %11.0lf msgs/min\l', "DEF:awl=$rrd_grey:awl:AVERAGE", "DEF:mawl=$rrd_grey:awl:MAX", "CDEF:rawl=awl,60,*", "CDEF:dawl=awl,UN,0,awl,IF,$step,*", "CDEF:sawl=PREV,UN,dawl,PREV,IF,dawl,+", "CDEF:rmawl=mawl,60,*", "LINE2:rawl#$color{awl}:Auto whitelist ", 'GPRINT:sawl:MAX:total\: %15.0lf msgs', 'GPRINT:rawl:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmawl:MAX:max\: %11.0lf msgs/min\l', "DEF:early=$rrd_grey:early:AVERAGE", "DEF:mearly=$rrd_grey:early:MAX", "CDEF:rearly=early,60,*", "CDEF:rmearly=mearly,60,*", "CDEF:dearly=early,UN,0,early,IF,$step,*", "CDEF:searly=PREV,UN,dearly,PREV,IF,dearly,+", "AREA:rearly#$color{early}:Early connect ", 'GPRINT:searly:MAX:total\: %15.0lf msgs', 'GPRINT:rearly:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmearly:MAX:max\: %11.0lf msgs/min\l', ); } sub graph_postscreen($$) { my ($range, $file) = @_; my $step = $range*$points_per_sample/$xpoints; rrd_graph($range, $file, $ypoints, "DEF:pswl=$rrd_post:pswl:AVERAGE", "DEF:mpswl=$rrd_post:pswl:MAX", "CDEF:rpswl=pswl,60,*", "CDEF:rmpswl=mpswl,60,*", "CDEF:dpswl=pswl,UN,0,pswl,IF,$step,*", "CDEF:spswl=PREV,UN,dpswl,PREV,IF,dpswl,+", "AREA:rpswl#$color{pswl}:WHITELISTED ", 'GPRINT:spswl:MAX:total\: %15.0lf msgs', 'GPRINT:rpswl:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmpswl:MAX:max\: %11.0lf msgs/min\l', "DEF:passold=$rrd_post:passold:AVERAGE", "DEF:mpassold=$rrd_post:passold:MAX", "CDEF:rpassold=passold,60,*", "CDEF:dpassold=passold,UN,0,passold,IF,$step,*", "CDEF:spassold=PREV,UN,dpassold,PREV,IF,dpassold,+", "CDEF:rmpassold=mpassold,60,*", "STACK:rpassold#$color{passold}:PASS OLD ", 'GPRINT:spassold:MAX:total\: %15.0lf msgs', 'GPRINT:rpassold:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmpassold:MAX:max\: %11.0lf msgs/min\l', "DEF:passnew=$rrd_post:passnew:AVERAGE", "DEF:mpassnew=$rrd_post:passnew:MAX", "CDEF:rpassnew=passnew,60,*", "CDEF:dpassnew=passnew,UN,0,passnew,IF,$step,*", "CDEF:spassnew=PREV,UN,dpassnew,PREV,IF,dpassnew,+", "CDEF:rmpassnew=mpassnew,60,*", "LINE2:rpassnew#$color{passnew}:PASS NEW ", 'GPRINT:spassnew:MAX:total\: %15.0lf msgs', 'GPRINT:rpassnew:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmpassnew:MAX:max\: %11.0lf msgs/min\l', ); } sub graph_postscreenstats($$) { my ($range, $file) = @_; my $step = $range*$points_per_sample/$xpoints; rrd_graph($range, $file, $ypoints, "DEF:psbl=$rrd_post:psbl:AVERAGE", "DEF:mpsbl=$rrd_post:psbl:MAX", "CDEF:rpsbl=psbl,60,*", "CDEF:dpsbl=psbl,UN,0,psbl,IF,$step,*", "CDEF:spsbl=PREV,UN,dpsbl,PREV,IF,dpsbl,+", "CDEF:rmpsbl=mpsbl,60,*", "AREA:rpsbl#$color{psbl}:BLACKLISTED ", 'GPRINT:spsbl:MAX:total\: %15.0lf msgs', 'GPRINT:rpsbl:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmpsbl:MAX:max\: %11.0lf msgs/min\l', "DEF:veto=$rrd_post:veto:AVERAGE", "DEF:mveto=$rrd_post:veto:MAX", "CDEF:rveto=veto,60,*", "CDEF:dveto=veto,UN,0,veto,IF,$step,*", "CDEF:sveto=PREV,UN,dveto,PREV,IF,dveto,+", "CDEF:rmveto=mveto,60,*", "STACK:rveto#$color{veto}:WHITELIST VETO ", 'GPRINT:sveto:MAX:total\: %15.0lf msgs', 'GPRINT:rveto:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmveto:MAX:max\: %11.0lf msgs/min\l', "DEF:pregreet=$rrd_post:pregreet:AVERAGE", "DEF:mpregreet=$rrd_post:pregreet:MAX", "CDEF:rpregreet=pregreet,60,*", "CDEF:dpregreet=pregreet,UN,0,pregreet,IF,$step,*", "CDEF:spregreet=PREV,UN,dpregreet,PREV,IF,dpregreet,+", "CDEF:rmpregreet=mpregreet,60,*", "STACK:rpregreet#$color{pregreet}:PREGREET ", 'GPRINT:spregreet:MAX:total\: %15.0lf msgs', 'GPRINT:rpregreet:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmpregreet:MAX:max\: %11.0lf msgs/min\l', "DEF:dnsbl=$rrd_post:dnsbl:AVERAGE", "DEF:mdnsbl=$rrd_post:dnsbl:MAX", "CDEF:rdnsbl=dnsbl,60,*", "CDEF:ddnsbl=dnsbl,UN,0,dnsbl,IF,$step,*", "CDEF:sdnsbl=PREV,UN,ddnsbl,PREV,IF,ddnsbl,+", "CDEF:rmdnsbl=mdnsbl,60,*", "STACK:rdnsbl#$color{dnsbl}:DNSBL ", 'GPRINT:sdnsbl:MAX:total\: %15.0lf msgs', 'GPRINT:rdnsbl:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmdnsbl:MAX:max\: %11.0lf msgs/min\l', "DEF:pipelining=$rrd_post:pipelining:AVERAGE", "DEF:mpipelining=$rrd_post:pipelining:MAX", "CDEF:rpipelining=pipelining,60,*", "CDEF:dpipelining=pipelining,UN,0,pipelining,IF,$step,*", "CDEF:spipelining=PREV,UN,dpipelining,PREV,IF,dpipelining,+", "CDEF:rmpipelining=mpipelining,60,*", "STACK:rpipelining#$color{pipelining}:PIPELINING ", 'GPRINT:spipelining:MAX:total\: %15.0lf msgs', 'GPRINT:rpipelining:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmpipelining:MAX:max\: %11.0lf msgs/min\l', "DEF:nonsmtp=$rrd_post:nonsmtp:AVERAGE", "DEF:mnonsmtp=$rrd_post:nonsmtp:MAX", "CDEF:rnonsmtp=nonsmtp,60,*", "CDEF:dnonsmtp=nonsmtp,UN,0,nonsmtp,IF,$step,*", "CDEF:snonsmtp=PREV,UN,dnonsmtp,PREV,IF,dnonsmtp,+", "CDEF:rmnonsmtp=mnonsmtp,60,*", "STACK:rnonsmtp#$color{nonsmtp}:NON SMTP COMMAND ", 'GPRINT:snonsmtp:MAX:total\: %15.0lf msgs', 'GPRINT:rnonsmtp:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmnonsmtp:MAX:max\: %11.0lf msgs/min\l', "DEF:barenewline=$rrd_post:barenewline:AVERAGE", "DEF:mbarenewline=$rrd_post:barenewline:MAX", "CDEF:rbarenewline=barenewline,60,*", "CDEF:dbarenewline=barenewline,UN,0,barenewline,IF,$step,*", "CDEF:sbarenewline=PREV,UN,dbarenewline,PREV,IF,dbarenewline,+", "CDEF:rmbarenewline=mbarenewline,60,*", "STACK:rbarenewline#$color{barenewline}:BARE NEWLINE ", 'GPRINT:sbarenewline:MAX:total\: %15.0lf msgs', 'GPRINT:rbarenewline:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmbarenewline:MAX:max\: %11.0lf msgs/min\l', "DEF:command=$rrd_post:command:AVERAGE", "DEF:mcommand=$rrd_post:command:MAX", "CDEF:rcommand=command,60,*", "CDEF:dcommand=command,UN,0,command,IF,$step,*", "CDEF:scommand=PREV,UN,dcommand,PREV,IF,dcommand,+", "CDEF:rmcommand=mcommand,60,*", "STACK:rcommand#$color{command}:COMMAND LIMITS ", 'GPRINT:scommand:MAX:total\: %15.0lf msgs', 'GPRINT:rcommand:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmcommand:MAX:max\: %11.0lf msgs/min\l', "DEF:hangup=$rrd_post:hangup:AVERAGE", "DEF:mhangup=$rrd_post:hangup:MAX", "CDEF:rhangup=hangup,60,*", "CDEF:dhangup=hangup,UN,0,hangup,IF,$step,*", "CDEF:shangup=PREV,UN,dhangup,PREV,IF,dhangup,+", "CDEF:rmhangup=mhangup,60,*", "STACK:rhangup#$color{hangup}:HUNGUP ", 'GPRINT:shangup:MAX:total\: %15.0lf msgs', 'GPRINT:rhangup:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmhangup:MAX:max\: %11.0lf msgs/min\l', ); } sub graph_dane($$) { my ($range, $file) = @_; my $step = $range*$points_per_sample/$xpoints; rrd_graph($range, $file, $ypoints, "DEF:untrustedtls=$rrd_dane:untrustedtls:AVERAGE", "DEF:muntrustedtls=$rrd_dane:untrustedtls:MAX", "CDEF:runtrustedtls=untrustedtls,60,*", "CDEF:duntrustedtls=untrustedtls,UN,0,untrustedtls,IF,$step,*", "CDEF:suntrustedtls=PREV,UN,duntrustedtls,PREV,IF,duntrustedtls,+", "CDEF:rmuntrustedtls=muntrustedtls,60,*", "AREA:runtrustedtls#$color{untrustedtls}:Out Untrusted TLS ", 'GPRINT:suntrustedtls:MAX:total\: %15.0lf msgs', 'GPRINT:runtrustedtls:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmuntrustedtls:MAX:max\: %11.0lf msgs/min\l', "DEF:anonymoustls=$rrd_dane:anonymoustls:AVERAGE", "DEF:manonymoustls=$rrd_dane:anonymoustls:MAX", "CDEF:ranonymoustls=anonymoustls,60,*", "CDEF:danonymoustls=anonymoustls,UN,0,anonymoustls,IF,$step,*", "CDEF:sanonymoustls=PREV,UN,danonymoustls,PREV,IF,danonymoustls,+", "CDEF:rmanonymoustls=manonymoustls,60,*", "STACK:ranonymoustls#$color{anonymoustls}:Out Anonymous TLS ", 'GPRINT:sanonymoustls:MAX:total\: %15.0lf msgs', 'GPRINT:ranonymoustls:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmanonymoustls:MAX:max\: %11.0lf msgs/min\l', "DEF:trustedtls=$rrd_dane:trustedtls:AVERAGE", "DEF:mtrustedtls=$rrd_dane:trustedtls:MAX", "CDEF:rtrustedtls=trustedtls,60,*", "CDEF:dtrustedtls=trustedtls,UN,0,trustedtls,IF,$step,*", "CDEF:strustedtls=PREV,UN,dtrustedtls,PREV,IF,dtrustedtls,+", "CDEF:rmtrustedtls=mtrustedtls,60,*", "STACK:rtrustedtls#$color{trustedtls}:Out Trusted TLS ", 'GPRINT:strustedtls:MAX:total\: %15.0lf msgs', 'GPRINT:rtrustedtls:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmtrustedtls:MAX:max\: %11.0lf msgs/min\l', "DEF:verifiedtls=$rrd_dane:verifiedtls:AVERAGE", "DEF:mverifiedtls=$rrd_dane:verifiedtls:MAX", "CDEF:rverifiedtls=verifiedtls,60,*", "CDEF:dverifiedtls=verifiedtls,UN,0,verifiedtls,IF,$step,*", "CDEF:sverifiedtls=PREV,UN,dverifiedtls,PREV,IF,dverifiedtls,+", "CDEF:rmverifiedtls=mverifiedtls,60,*", "LINE2:rverifiedtls#$color{verifiedtls}:Out Verified TLS ", 'GPRINT:sverifiedtls:MAX:total\: %15.0lf msgs', 'GPRINT:rverifiedtls:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmverifiedtls:MAX:max\: %11.0lf msgs/min\l', ); } sub graph_smtpd($$) { my ($range, $file) = @_; my $step = $range*$points_per_sample/$xpoints; rrd_graph($range, $file, $ypoints, "DEF:untrustedtlsin=$rrd_smtpd:untrustedtlsin:AVERAGE", "DEF:muntrustedtlsin=$rrd_smtpd:untrustedtlsin:MAX", "CDEF:runtrustedtlsin=untrustedtlsin,60,*", "CDEF:duntrustedtlsin=untrustedtlsin,UN,0,untrustedtlsin,IF,$step,*", "CDEF:suntrustedtlsin=PREV,UN,duntrustedtlsin,PREV,IF,duntrustedtlsin,+", "CDEF:rmuntrustedtlsin=muntrustedtlsin,60,*", "AREA:runtrustedtlsin#$color{untrustedtlsin}:IN Untrusted TLS ", 'GPRINT:suntrustedtlsin:MAX:total\: %15.0lf msgs', 'GPRINT:runtrustedtlsin:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmuntrustedtlsin:MAX:max\: %11.0lf msgs/min\l', "DEF:anonymoustlsin=$rrd_smtpd:anonymoustlsin:AVERAGE", "DEF:manonymoustlsin=$rrd_smtpd:anonymoustlsin:MAX", "CDEF:ranonymoustlsin=anonymoustlsin,60,*", "CDEF:danonymoustlsin=anonymoustlsin,UN,0,anonymoustlsin,IF,$step,*", "CDEF:sanonymoustlsin=PREV,UN,danonymoustlsin,PREV,IF,danonymoustlsin,+", "CDEF:rmanonymoustlsin=manonymoustlsin,60,*", "STACK:ranonymoustlsin#$color{anonymoustlsin}:IN Anonymous TLS ", 'GPRINT:sanonymoustlsin:MAX:total\: %15.0lf msgs', 'GPRINT:ranonymoustlsin:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmanonymoustlsin:MAX:max\: %11.0lf msgs/min\l', "DEF:trustedtlsin=$rrd_smtpd:trustedtlsin:AVERAGE", "DEF:mtrustedtlsin=$rrd_smtpd:trustedtlsin:MAX", "CDEF:rtrustedtlsin=trustedtlsin,60,*", "CDEF:dtrustedtlsin=trustedtlsin,UN,0,trustedtlsin,IF,$step,*", "CDEF:strustedtlsin=PREV,UN,dtrustedtlsin,PREV,IF,dtrustedtlsin,+", "CDEF:rmtrustedtlsin=mtrustedtlsin,60,*", "STACK:rtrustedtlsin#$color{trustedtlsin}:In Trusted TLS ", 'GPRINT:strustedtlsin:MAX:total\: %15.0lf msgs', 'GPRINT:rtrustedtlsin:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmtrustedtlsin:MAX:max\: %11.0lf msgs/min\l', ); } sub graph_spf($$) { my ($range, $file) = @_; my $step = $range*$points_per_sample/$xpoints; rrd_graph($range, $file, $ypoints, "DEF:spfpass=$rrd_dmarc:spfpass:AVERAGE", "DEF:mspfpass=$rrd_dmarc:spfpass:MAX", "CDEF:rspfpass=spfpass,60,*", "CDEF:dspfpass=spfpass,UN,0,spfpass,IF,$step,*", "CDEF:sspfpass=PREV,UN,dspfpass,PREV,IF,dspfpass,+", "CDEF:rmspfpass=mspfpass,60,*", "AREA:rspfpass#$color{spfpass}:SPF pass ", 'GPRINT:sspfpass:MAX:total\: %15.0lf msgs', 'GPRINT:rspfpass:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmspfpass:MAX:max\: %11.0lf msgs/min\l', "DEF:spfnone=$rrd_dmarc:spfnone:AVERAGE", "DEF:mspfnone=$rrd_dmarc:spfnone:MAX", "CDEF:rspfnone=spfnone,60,*", "CDEF:dspfnone=spfnone,UN,0,spfnone,IF,$step,*", "CDEF:sspfnone=PREV,UN,dspfnone,PREV,IF,dspfnone,+", "CDEF:rmspfnone=mspfnone,60,*", "LINE2:rspfnone#$color{spfnone}:SPF none ", 'GPRINT:sspfnone:MAX:total\: %15.0lf msgs', 'GPRINT:rspfnone:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmspfnone:MAX:max\: %11.0lf msgs/min\l', "DEF:spffail=$rrd_dmarc:spffail:AVERAGE", "DEF:mspffail=$rrd_dmarc:spffail:MAX", "CDEF:rspffail=spffail,60,*", "CDEF:dspffail=spffail,UN,0,spffail,IF,$step,*", "CDEF:sspffail=PREV,UN,dspffail,PREV,IF,dspffail,+", "CDEF:rmspffail=mspffail,60,*", "LINE2:rspffail#$color{spffail}:SPF fail ", 'GPRINT:sspffail:MAX:total\: %15.0lf msgs', 'GPRINT:rspffail:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmspffail:MAX:max\: %11.0lf msgs/min\l', ); } sub graph_dkim($$) { my ($range, $file) = @_; my $step = $range*$points_per_sample/$xpoints; rrd_graph($range, $file, $ypoints, "DEF:dkimpass=$rrd_dmarc:dkimpass:AVERAGE", "DEF:mdkimpass=$rrd_dmarc:dkimpass:MAX", "CDEF:rdkimpass=dkimpass,60,*", "CDEF:ddkimpass=dkimpass,UN,0,dkimpass,IF,$step,*", "CDEF:sdkimpass=PREV,UN,ddkimpass,PREV,IF,ddkimpass,+", "CDEF:rmdkimpass=mdkimpass,60,*", "AREA:rdkimpass#$color{dkimpass}:DKIM pass ", 'GPRINT:sdkimpass:MAX:total\: %15.0lf msgs', 'GPRINT:rdkimpass:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmdkimpass:MAX:max\: %11.0lf msgs/min\l', "DEF:dkimnone=$rrd_dmarc:dkimnone:AVERAGE", "DEF:mdkimnone=$rrd_dmarc:dkimnone:MAX", "CDEF:rdkimnone=dkimnone,60,*", "CDEF:ddkimnone=dkimnone,UN,0,dkimnone,IF,$step,*", "CDEF:sdkimnone=PREV,UN,ddkimnone,PREV,IF,ddkimnone,+", "CDEF:rmdkimnone=mdkimnone,60,*", "LINE2:rdkimnone#$color{dkimnone}:DKIM none ", 'GPRINT:sdkimnone:MAX:total\: %15.0lf msgs', 'GPRINT:rdkimnone:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmdkimnone:MAX:max\: %11.0lf msgs/min\l', "DEF:dkimfail=$rrd_dmarc:dkimfail:AVERAGE", "DEF:mdkimfail=$rrd_dmarc:dkimfail:MAX", "CDEF:rdkimfail=dkimfail,60,*", "CDEF:ddkimfail=dkimfail,UN,0,dkimfail,IF,$step,*", "CDEF:sdkimfail=PREV,UN,ddkimfail,PREV,IF,ddkimfail,+", "CDEF:rmdkimfail=mdkimfail,60,*", "LINE2:rdkimfail#$color{dkimfail}:DKIM fail ", 'GPRINT:sdkimfail:MAX:total\: %15.0lf msgs', 'GPRINT:rdkimfail:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmdkimfail:MAX:max\: %11.0lf msgs/min\l', ); } sub graph_dmarc($$) { my ($range, $file) = @_; my $step = $range*$points_per_sample/$xpoints; rrd_graph($range, $file, $ypoints, "DEF:dmarcpass=$rrd_dmarc:dmarcpass:AVERAGE", "DEF:mdmarcpass=$rrd_dmarc:dmarcpass:MAX", "CDEF:rdmarcpass=dmarcpass,60,*", "CDEF:ddmarcpass=dmarcpass,UN,0,dmarcpass,IF,$step,*", "CDEF:sdmarcpass=PREV,UN,ddmarcpass,PREV,IF,ddmarcpass,+", "CDEF:rmdmarcpass=mdmarcpass,60,*", "AREA:rdmarcpass#$color{dmarcpass}:DMARC pass ", 'GPRINT:sdmarcpass:MAX:total\: %15.0lf msgs', 'GPRINT:rdmarcpass:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmdmarcpass:MAX:max\: %11.0lf msgs/min\l', "DEF:dmarcnone=$rrd_dmarc:dmarcnone:AVERAGE", "DEF:mdmarcnone=$rrd_dmarc:dmarcnone:MAX", "CDEF:rdmarcnone=dmarcnone,60,*", "CDEF:ddmarcnone=dmarcnone,UN,0,dmarcnone,IF,$step,*", "CDEF:sdmarcnone=PREV,UN,ddmarcnone,PREV,IF,ddmarcnone,+", "CDEF:rmdmarcnone=mdmarcnone,60,*", "LINE2:rdmarcnone#$color{dmarcnone}:DMARC none ", 'GPRINT:sdmarcnone:MAX:total\: %15.0lf msgs', 'GPRINT:rdmarcnone:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmdmarcnone:MAX:max\: %11.0lf msgs/min\l', "DEF:dmarcfail=$rrd_dmarc:dmarcfail:AVERAGE", "DEF:mdmarcfail=$rrd_dmarc:dmarcfail:MAX", "CDEF:rdmarcfail=dmarcfail,60,*", "CDEF:ddmarcfail=dmarcfail,UN,0,dmarcfail,IF,$step,*", "CDEF:sdmarcfail=PREV,UN,ddmarcfail,PREV,IF,ddmarcfail,+", "CDEF:rmdmarcfail=mdmarcfail,60,*", "LINE2:rdmarcfail#$color{dmarcfail}:DMARC fail ", 'GPRINT:sdmarcfail:MAX:total\: %15.0lf msgs', 'GPRINT:rdmarcfail:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:rmdmarcfail:MAX:max\: %11.0lf msgs/min\l', ); } sub graph_queue($$) { my ($range, $file) = @_; my $step = $range*$points_per_sample/$xpoints; rrd_graph($range, $file, $ypoints, "DEF:deferred=$rrd_queue:deferred:AVERAGE", "AREA:deferred#$color{deferred}:Deferred ", 'GPRINT:deferred:MAX:total\: %15.0lf msgs', 'GPRINT:deferred:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:deferred:MAX:max\: %11.0lf msgs/min\l', "DEF:active=$rrd_queue:active:AVERAGE", "LINE2:active#$color{active}:Active+Incoming+Maildrop", 'GPRINT:active:MAX:total\: %15.0lf msgs', 'GPRINT:active:AVERAGE:avg\: %12.2lf msgs/min', 'GPRINT:active:MAX:max\: %11.0lf msgs/min\l', ); } sub print_html() { print "Content-Type: text/html\n\n"; print < Mailserver Statistiken auf $host HEADER print "

Mailserver Statistiken für mx14.dmz.nausch.org

\n"; print "

(Summen- und Einzelaufstellungen "; print "MX11, "; print "MX12 und "; print "MX13)

\n"; #print "MX14)\n"; print "\n"; for my $n (0..$#graphs) { print "

$graphs[$n]{title}

\n"; print "

Mail Ein und -Ausgang

\n"; print "
( Summe\n"; print "MX11\n"; print "MX12\n"; print "MX13 )
\n"; print "

\"mailgraph

\n"; print "

geblockte Nachrichten

\n"; print "
( Summe\n"; print "MX11\n"; print "MX12\n"; print "MX13 )
\n"; print "

\"mailgraph

\n"; print "

Greylisting Übersicht

\n"; print "
( Summe\n"; print "MX11\n"; print "MX12\n"; print "MX13 )
\n"; print "

\"mailgraph

\n"; print "

Greylisting Detailansicht

\n"; print "
( Summe\n"; print "MX11\n"; print "MX12\n"; print "MX13 )
\n"; print "

\"mailgraph

\n"; print "

Postscreen (positive) Übersicht

\n"; print "
( Summe\n"; print "MX11\n"; print "MX12\n"; print "MX13 )
\n"; print "

\"mailgraph

\n"; print "

Postscreen Detailansicht

\n"; print "
( Summe\n"; print "MX11\n"; print "MX12\n"; print "MX13 )
\n"; print "

\"mailgraph

\n"; print "

Übersicht Mail-Queues

\n"; print "
( Summe\n"; print "MX11\n"; print "MX12\n"; print "MX13 )
\n"; print "

\"mailgraph

\n"; print "

ausgehende DANE/TLSA-gesicherte Verbindungen

\n"; print "
( Summe\n"; print "MX11\n"; print "MX12\n"; print "MX13 )
\n"; print "

\"mailgraph

\n"; print "

ankommende TLS-gesicherte Verbindungen

\n"; print "
( Summe\n"; print "MX11\n"; print "MX12\n"; print "MX13 )
\n"; print "

\"mailgraph

\n"; print "

Sender policy Framework - SPF-Prüfungen

\n"; print "
( Summe\n"; print "MX11\n"; print "MX12\n"; print "MX13 )
\n"; print "

\"mailgraph

\n"; print "

DomainKeys Identified Mail - DKIM-Prüfungen

\n"; print "
( Summe\n"; print "MX11\n"; print "MX12\n"; print "MX13 )
\n"; print "

\"mailgraph

\n"; print "

Domain-based Message Authentication, Reporting & Conformance - DMARC-Prüfungen

\n"; print "
( Summe\n"; print "MX11\n"; print "MX12\n"; print "MX13 )
\n"; print "

\"mailgraph

\n"; } print <
Mailgraph(-ng) $VERSION by Django based on David Schweikert's Mailgraph, Markus Neubauer's Greygraph,
Ralf Hildebrandt's Queuegraph and Sebastian van de Meer's mailgraphpatch 1 and mailgraphpatch 2
FOOTER } sub send_image($) { my ($file)= @_; -r $file or do { print "Content-type: text/plain\n\nERROR: can't find $file\n"; exit 1; }; print "Content-type: image/png\n"; print "Content-length: ".((stat($file))[7])."\n"; print "\n"; open(IMG, $file) or die; my $data; print $data while read(IMG, $data, 16384)>0; } sub main() { my $uri = $ENV{REQUEST_URI} || ''; $uri =~ s/\/[^\/]+$//; $uri =~ s/\//,/g; $uri =~ s/(\~|\%7E)/tilde,/g; mkdir $tmp_dir, 0777 unless -d $tmp_dir; mkdir "$tmp_dir/$uri", 0777 unless -d "$tmp_dir/$uri"; my $img = $ENV{QUERY_STRING}; if(defined $img and $img =~ /\S/) { if($img =~ /^(\d+)-n$/) { my $file = "$tmp_dir/$uri/mailgraph_$1.png"; graph($graphs[$1]{seconds}, $file); send_image($file); } elsif($img =~ /^(\d+)-e$/) { my $file = "$tmp_dir/$uri/mailgraph_$1_err.png"; graph_virus($graphs[$1]{seconds}, $file); send_image($file); } elsif($img =~ /^(\d+)-g$/) { my $file = "$tmp_dir/$uri/mailgraph_$1_greylist.png"; graph_greylist($graphs[$1]{seconds}, $file); send_image($file); } elsif($img =~ /^(\d+)-d$/) { my $file = "$tmp_dir/$uri/mailgraph_$1_greystats.png"; graph_greystats($graphs[$1]{seconds}, $file); send_image($file); } elsif($img =~ /^(\d+)-v$/) { my $file = "$tmp_dir/$uri/mailgraph_$1_postscreen.png"; graph_postscreen($graphs[$1]{seconds}, $file); send_image($file); } elsif($img =~ /^(\d+)-w$/) { my $file = "$tmp_dir/$uri/mailgraph_$1_postscreenstats.png"; graph_postscreenstats($graphs[$1]{seconds}, $file); send_image($file); } elsif($img =~ /^(\d+)-q$/) { my $file = "$tmp_dir/$uri/mailgraph_$1_queue.png"; graph_queue($graphs[$1]{seconds}, $file); send_image($file); } elsif($img =~ /^(\d+)-t$/) { my $file = "$tmp_dir/$uri/mailgraph_$1_dane.png"; graph_dane($graphs[$1]{seconds}, $file); send_image($file); } elsif($img =~ /^(\d+)-i$/) { my $file = "$tmp_dir/$uri/mailgraph_$1_smtpd.png"; graph_smtpd($graphs[$1]{seconds}, $file); send_image($file); } elsif($img =~ /^(\d+)-f$/) { my $file = "$tmp_dir/$uri/mailgraph_$1_spf.png"; graph_spf($graphs[$1]{seconds}, $file); send_image($file); } elsif($img =~ /^(\d+)-m$/) { my $file = "$tmp_dir/$uri/mailgraph_$1_dkim.png"; graph_dkim($graphs[$1]{seconds}, $file); send_image($file); } elsif($img =~ /^(\d+)-c$/) { my $file = "$tmp_dir/$uri/mailgraph_$1_dmarc.png"; graph_dmarc($graphs[$1]{seconds}, $file); send_image($file); } else { die "ERROR: invalid argument\n"; } } else { print_html; } } main;