Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Vorhergehende Überarbeitung | |||
| — | centos:mail_c7:mta_13 [18.11.2024 19:00. ] (aktuell) – Externe Bearbeitung 127.0.0.1 | ||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| + | ====== Mailserver - Logfileauswertungen unter CentOS 7.x ====== | ||
| + | Oft werden vom Management hübsche bunte Auswertungsgraphiken gewünscht, um sich so mehr oder weniger ein Bild davon zu machen, ob und wie der/die Mailserver mit der anfallenden Menge an elektronischer Post umgehen können. | ||
| + | Auch als Postmaster und Admin können wir uns so einen kurzen Überblick verschaffen, | ||
| + | |||
| + | Im Detail wollen wir uns nun drei der Varianten genauer ansehen. | ||
| + | - **[[centos: | ||
| + | - **WEB-GUIs** Graphisch sehr ansprechende Logfile Zusammenfassung generieren und zum Abrufen via Browser anbieten | ||
| + | - **[[centos: | ||
| + | - **[[centos: | ||
| + | - **[[centos: | ||
| + | - **[[centos: | ||
| + | |||
| + | ===== pflogsumm ===== | ||
| + | Mit Hilfe dieses kleinen Perlscriptes können wir uns einen täglichen Statusbericht unseres Mailservers erstellen lassen und wissen so das was unserem MX widerfahren ist. :-) Das Perlscript **pflogsumm** wertet hierzu das Logfile // | ||
| + | |||
| + | ==== Installation ==== | ||
| + | Das Perlscript **pflogsumm** befindet sich unter CentOS 7.x im Paket **// | ||
| + | # yum install postfix-perl-scripts -y | ||
| + | |||
| + | Was uns bei der Installation dieses Paketes alles mitgebracht wurde, zeigt uns folgender Aufruf. | ||
| + | # rpm -qil postfix-perl-scripts | ||
| + | < | ||
| + | Epoch : 2 | ||
| + | Version | ||
| + | Release | ||
| + | Architecture: | ||
| + | Install Date: Thu 30 Oct 2014 01:35:54 PM CET | ||
| + | Group : Applications/ | ||
| + | Size : 111466 | ||
| + | License | ||
| + | Signature | ||
| + | Source RPM : postfix-2.11.3-1.el7.centos.src.rpm | ||
| + | Build Date : Thu 30 Oct 2014 12:57:01 PM CET | ||
| + | Build Host : vml000200.dmz.nausch.org | ||
| + | Relocations : (not relocatable) | ||
| + | Packager | ||
| + | Vendor | ||
| + | URL : http:// | ||
| + | Summary | ||
| + | Description : | ||
| + | This package contains perl scripts pflogsumm and qshape. | ||
| + | |||
| + | Pflogsumm is a log analyzer/ | ||
| + | designed to provide an over-view of Postfix activity. Pflogsumm | ||
| + | generates summaries and, in some cases, detailed reports of mail | ||
| + | server traffic volumes, rejected and bounced email, and server | ||
| + | warnings, errors and panics. | ||
| + | |||
| + | qshape prints Postfix queue domain and age distribution. | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | </ | ||
| + | |||
| + | ==== Optionen beim Programmaufruf==== | ||
| + | Hinweise zur Konfiguration oder besser gesagt über die Optionen beim Aufruf des Programms zeigt ein Blick in die Manpage von **pflogsumm**. | ||
| + | # man pflogsumm | ||
| + | |||
| + | < | ||
| + | |||
| + | NAME | ||
| + | | ||
| + | |||
| + | | ||
| + | |||
| + | SYNOPSIS | ||
| + | | ||
| + | | ||
| + | [-h < | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | [-u < | ||
| + | | ||
| + | |||
| + | | ||
| + | |||
| + | If no file(s) specified, reads from stdin. | ||
| + | |||
| + | DESCRIPTION | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | | ||
| + | mail server traffic volumes, rejected and bounced email, and server | ||
| + | | ||
| + | |||
| + | OPTIONS | ||
| + | | ||
| + | |||
| + | Limit detailed bounce reports to the top < | ||
| + | to suppress entirely. | ||
| + | |||
| + | -d today | ||
| + | -d yesterday | ||
| + | |||
| + | | ||
| + | |||
| + | Limit detailed deferral reports to the top < | ||
| + | to suppress entirely. | ||
| + | |||
| + | | ||
| + | |||
| + | Sets all --*_detail, -h and -u to < | ||
| + | over-ridden by individual settings. | ||
| + | suppresses *all* detail. | ||
| + | |||
| + | | ||
| + | |||
| + | Emit detailed reports. | ||
| + | only a per-message report, sorted by sender domain, | ||
| + | then user-in-domain, | ||
| + | |||
| + | WARNING: the data built to generate this report can | ||
| + | quickly consume very large amounts of memory if a | ||
| + | lot of log entries are processed! | ||
| + | |||
| + | -h < | ||
| + | |||
| + | 0 = none. | ||
| + | |||
| + | See also: " | ||
| + | report-limiting options. | ||
| + | |||
| + | | ||
| + | |||
| + | (By happy coincidence, | ||
| + | being as it requires a numeric argument :-). Yeah, I | ||
| + | know: lame.) | ||
| + | |||
| + | -i | ||
| + | | ||
| + | manner. | ||
| + | |||
| + | Normally pflogsumm lower-cases only the host and | ||
| + | domain parts, leaving the user part alone. | ||
| + | option causes the entire email address to be lower- | ||
| + | cased. | ||
| + | |||
| + | | ||
| + | |||
| + | For summaries that contain date or time information, | ||
| + | use ISO 8601 standard formats (CCYY-MM-DD and HH:MM), | ||
| + | rather than "Mon DD CCYY" and " | ||
| + | |||
| + | | ||
| + | | ||
| + | |||
| + | This is for use when you have a mix of Internet-style | ||
| + | domain addresses and UUCP-style bang-paths in the log. | ||
| + | Upstream UUCP feeds sometimes mung Internet domain | ||
| + | style address into bang-paths. | ||
| + | sometimes undo the " | ||
| + | " | ||
| + | host upstream and " | ||
| + | originated) will get converted to | ||
| + | " | ||
| + | extended detail report (-e), to help ensure that by- | ||
| + | | ||
| + | |||
| + | | ||
| + | |||
| + | Merely a convenience feature. | ||
| + | is in $PATH. | ||
| + | if desired.) | ||
| + | |||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | These switches are depreciated in favour of | ||
| + | --bounce_detail, | ||
| + | --reject_detail, | ||
| + | |||
| + | Suppresses the printing of the following detailed | ||
| + | reports, respectively: | ||
| + | |||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | See also: " | ||
| + | options. | ||
| + | |||
| + | | ||
| + | |||
| + | Do not emit report on " | ||
| + | |||
| + | | ||
| + | The message may be delivered long-enough after the | ||
| + | | ||
| + | the log(s) processed by a particular run of | ||
| + | | ||
| + | | ||
| + | | ||
| + | size data." | ||
| + | |||
| + | | ||
| + | |||
| + | This switch is depreciated in favour of | ||
| + | smtpd_warning_detail | ||
| + | |||
| + | On a busy mail server, say at an ISP, SMTPD warnings | ||
| + | can result in a rather sizeable report. | ||
| + | turns reporting them off. | ||
| + | |||
| + | | ||
| + | |||
| + | Emit " | ||
| + | etc.) before " | ||
| + | |||
| + | | ||
| + | For those reject reports that list IP addresses or | ||
| + | host/domain names: append the email from address to | ||
| + | each listing. | ||
| + | SMTP command pipelining" | ||
| + | |||
| + | | ||
| + | |||
| + | note: headings for warning, fatal, and " | ||
| + | messages will always be printed. | ||
| + | |||
| + | | ||
| + | |||
| + | Limit detailed smtpd reject, warn, hold and discard | ||
| + | reports to the top < | ||
| + | |||
| + | | ||
| + | |||
| + | Limit detailed smtp delivery reports to the top < | ||
| + | 0 to suppress entirely. | ||
| + | |||
| + | | ||
| + | |||
| + | Generate smtpd connection statistics. | ||
| + | |||
| + | The " | ||
| + | reports. | ||
| + | are daily averages (reflected in the report heading). | ||
| + | |||
| + | | ||
| + | |||
| + | Limit detailed smtpd warnings reports to the top < | ||
| + | 0 to suppress entirely. | ||
| + | |||
| + | | ||
| + | |||
| + | Set syslog_name to look for for Postfix log entries. | ||
| + | |||
| + | By default, pflogsumm looks for entries in logfiles | ||
| + | with a syslog name of " | ||
| + | If you've set a non-default " | ||
| + | in your Postfix configuration, | ||
| + | tell pflogsumm what that is. | ||
| + | |||
| + | See the discussion about the use of this option under | ||
| + | " | ||
| + | |||
| + | -u < | ||
| + | |||
| + | See also: " | ||
| + | report-limiting options. | ||
| + | |||
| + | | ||
| + | |||
| + | For the message deferral, bounce and reject summaries: | ||
| + | display the full " | ||
| + | |||
| + | Note: this can result in quite long lines in the report. | ||
| + | |||
| + | | ||
| + | | ||
| + | " | ||
| + | to | ||
| + | " | ||
| + | |||
| + | In other words: replace the numeric value with " | ||
| + | |||
| + | By specifying the optional " | ||
| + | munging is more " | ||
| + | to something like: | ||
| + | |||
| + | " | ||
| + | |||
| + | Actually: specifying anything less than 2 does the | ||
| + | " | ||
| + | in the more " | ||
| + | |||
| + | See " | ||
| + | |||
| + | | ||
| + | |||
| + | | ||
| + | data in columns that that might otherwise be blank. | ||
| + | |||
| + | RETURN VALUE | ||
| + | | ||
| + | |||
| + | ERRORS | ||
| + | Error messages are emitted to stderr. | ||
| + | |||
| + | EXAMPLES | ||
| + | | ||
| + | |||
| + | | ||
| + | |||
| + | A report of prior week's activities (after logs rotated): | ||
| + | |||
| + | | ||
| + | |||
| + | | ||
| + | |||
| + | | ||
| + | |||
| + | | ||
| + | at 10 minutes after midnight. | ||
| + | |||
| + | 10 0 * * * / | ||
| + | | ||
| + | |||
| + | | ||
| + | (This example assumes one rotates ones mail logs weekly, some time | ||
| + | | ||
| + | |||
| + | 10 4 * * 0 / | ||
| + | | ||
| + | |||
| + | The two crontab examples, above, must actually be a single line | ||
| + | | ||
| + | | ||
| + | |||
| + | SEE ALSO | ||
| + | The pflogsumm FAQ: pflogsumm-faq.txt. | ||
| + | |||
| + | NOTES | ||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | For display purposes: integer values are munged into " | ||
| + | " | ||
| + | | ||
| + | which to do this--my thinking being 512x was the largest number | ||
| + | (of digits) that most folks can comfortably grok at-a-glance. | ||
| + | These are " | ||
| + | can easily change all of this with some constants near the | ||
| + | | ||
| + | |||
| + | " | ||
| + | | ||
| + | daily averages (reflected in the report headings). | ||
| + | |||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | Verp munging may not always result in correct address and | ||
| + | | ||
| + | |||
| + | Verp munging is always in a state of experimentation. | ||
| + | of this option may result in inaccurate statistics with regards | ||
| + | to the " | ||
| + | |||
| + | | ||
| + | | ||
| + | run with " | ||
| + | may not be sorted correctly by-domain-by-user. | ||
| + | | ||
| + | |||
| + | The " | ||
| + | | ||
| + | " | ||
| + | |||
| + | | ||
| + | |||
| + | | ||
| + | |||
| + | There are some issues with the use of --syslog_name. | ||
| + | that, even with $syslog_name set, Postfix will sometimes still log | ||
| + | | ||
| + | / | ||
| + | |||
| + | # Beware: a non-default syslog_name setting takes effect only | ||
| + | # after process initialization. Some initialization errors will be | ||
| + | # logged with the default name, especially errors while parsing | ||
| + | # the command line and errors while accessing the Postfix main.cf | ||
| + | # configuration file. | ||
| + | |||
| + | As a consequence, | ||
| + | as well as whatever is supplied for syslog_name. | ||
| + | |||
| + | Where this becomes an issue is where people are running two or more | ||
| + | | ||
| + | |||
| + | . Neither instance may use the default " | ||
| + | | ||
| + | |||
| + | . Log entries that fall victim to what's described in | ||
| + | | ||
| + | | ||
| + | log entries will show up in each report. | ||
| + | |||
| + | The Pflogsumm Home Page is at: | ||
| + | |||
| + | | ||
| + | |||
| + | REQUIREMENTS | ||
| + | For certain options (e.g.: --smtpd_stats), | ||
| + | | ||
| + | | ||
| + | |||
| + | | ||
| + | As of version 19990413-02, | ||
| + | | ||
| + | |||
| + | LICENSE | ||
| + | This program is free software; you can redistribute it and/or | ||
| + | | ||
| + | as published by the Free Software Foundation; either version 2 | ||
| + | of the License, or (at your option) any later version. | ||
| + | |||
| + | This program is distributed in the hope that it will be useful, | ||
| + | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| + | | ||
| + | GNU General Public License for more details. | ||
| + | |||
| + | You may have received a copy of the GNU General Public License | ||
| + | along with this program; if not, write to the Free Software | ||
| + | | ||
| + | USA. | ||
| + | |||
| + | An on-line copy of the GNU General Public License can be found | ||
| + | | ||
| + | |||
| + | 1.1.3 2010-03-20 | ||
| + | </ | ||
| + | |||
| + | Mit der Option **-help** werden die entsprechenden Optionen ebenfalls in Kurzform angezeigt. | ||
| + | # pflogsumm -help | ||
| + | < | ||
| + | [--bounce_detail < | ||
| + | [-h < | ||
| + | [-m|--uucp_mung] [--no_bounce_detail] [--no_deferral_detail] | ||
| + | [--no_no_msg_size] [--no_reject_detail] [--no_smtpd_warnings] | ||
| + | [--problems_first] [--rej_add_from] [--reject_detail < | ||
| + | [--smtp_detail < | ||
| + | [--smtpd_warning_detail < | ||
| + | [-u < | ||
| + | [--zero_fill] [file1 [filen]] | ||
| + | |||
| + | | ||
| + | </ | ||
| + | |||
| + | ==== manueller Programmaufruf ==== | ||
| + | Wollen wir uns einen Bericht des heutigen Tages ansehen, so generieren wir diesen on-the-fly mit: | ||
| + | # / | ||
| + | |||
| + | Interessiert uns was gestern los war, so lautet der Aufgruf ganz einfach: | ||
| + | # / | ||
| + | |||
| + | ==== automatischer Programmaufruf ==== | ||
| + | Für die tägliche Erstellung unserer Mailserverstatistik bemühen wir nun ganz einfach unseres cron-deamon. | ||
| + | |||
| + | Hierzu legen wir mit dem Editor unserer Wahl eine betreffende Konfigurationsdatei an, bzw. ergänzen die bereits vorhandene Datei. | ||
| + | # vim / | ||
| + | |||
| + | < | ||
| + | #täglicher Statusbericht unseres Mailservers postfix | ||
| + | 10 0 * * * root / | ||
| + | </ | ||
| + | |||
| + | Täglich um 00:10 Uhr wird die Statistik des letzten Tages erstellt und mittels **mailx** als eMail an den postmaster verschickt. | ||
| + | Das Paket mailx muss dazu natürlich installiert sein, falls (noch) nicht, holen wir dies kurz noch nach. | ||
| + | # yum install mailx -y | ||
| + | |||
| + | < | ||
| + | From: root < | ||
| + | To: postmaster@nausch.org | ||
| + | Subject: mx-test.dmz.nausch.org daily mail stats | ||
| + | |||
| + | Postfix log summaries for Feb 01 | ||
| + | |||
| + | Grand Totals | ||
| + | ------------ | ||
| + | messages | ||
| + | |||
| + | | ||
| + | | ||
| + | 0 | ||
| + | 0 | ||
| + | 0 | ||
| + | 339 | ||
| + | 0 | ||
| + | 0 held | ||
| + | 0 | ||
| + | |||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | 4 | ||
| + | 1 | ||
| + | |||
| + | |||
| + | Per-Hour Traffic Summary | ||
| + | time received | ||
| + | -------------------------------------------------------------------- | ||
| + | 0000-0100 | ||
| + | 0100-0200 | ||
| + | 0200-0300 | ||
| + | 0300-0400 | ||
| + | 0400-0500 | ||
| + | 0500-0600 | ||
| + | 0600-0700 | ||
| + | 0700-0800 | ||
| + | 0800-0900 | ||
| + | 0900-1000 | ||
| + | 1000-1100 | ||
| + | 1100-1200 | ||
| + | 1200-1300 | ||
| + | 1300-1400 | ||
| + | 1400-1500 | ||
| + | 1500-1600 | ||
| + | 1600-1700 | ||
| + | 1700-1800 | ||
| + | 1800-1900 | ||
| + | 1900-2000 | ||
| + | 2000-2100 | ||
| + | 2100-2200 | ||
| + | 2200-2300 | ||
| + | 2300-2400 | ||
| + | |||
| + | Host/Domain Summary: Message Delivery | ||
| + | sent cnt bytes | ||
| + | | ||
| + | 872 | ||
| + | ... | ||
| + | |||
| + | ... | ||
| + | |||
| + | Fatal Errors: none | ||
| + | |||
| + | Panics: none | ||
| + | |||
| + | Master daemon messages | ||
| + | ---------------------- | ||
| + | 1 | ||
| + | </ | ||
| + | |||
| + | ===== mailgraph ===== | ||
| + | Eine ansprechende graphische Übersicht kann mittels [[http:// | ||
| + | |||
| + | Mailgraph besteht im wesentlichen aus zwei Teilen. Das eine perl-Script ist zuständig für das Durchsuchen und Analysieren des Mailserver-Logdatei. Die gewonnenen Daten werden in **rrd**-Datendateien geschrieben. Ein zweites Perl **cgi**-Script generiert dann beim Aufrufen der zugehörigen Webseite Graphiken mit den Daten der **rrd**-Dateien. | ||
| + | |||
| + | |||
| + | ==== Installation ==== | ||
| + | Mit Hilfe von **yum** holen wir uns als erstes das benötigte Paket auf unser System. | ||
| + | # yum install mailgraph -y | ||
| + | Den Inhalt des Paketes inspizieren wir bei Bedarf mit folgendem Aufruf. | ||
| + | # rpm -qil mailgraph | ||
| + | |||
| + | < | ||
| + | Version | ||
| + | Release | ||
| + | Architecture: | ||
| + | Install Date: Fri 30 Jan 2015 03:21:39 PM CET | ||
| + | Group : System Environment/ | ||
| + | Size : 66890 | ||
| + | License | ||
| + | Signature | ||
| + | Source RPM : mailgraph-1.14-1.el7.centos.src.rpm | ||
| + | Build Date : Fri 30 Jan 2015 09:57:42 AM CET | ||
| + | Build Host : vml000200.dmz.nausch.org | ||
| + | Relocations : (not relocatable) | ||
| + | Packager | ||
| + | URL : http:// | ||
| + | Summary | ||
| + | Description : | ||
| + | Mailgraph is a very simple mail statistics RRDtool frontend for Postfix and | ||
| + | Sendmail that produces daily, weekly, monthly and yearly graphs of | ||
| + | received/ | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | </ | ||
| + | |||
| + | ==== Konfiguration ==== | ||
| + | Die Konfiguration von mailgraph selbst gestaltet sich sehr einfach. Über die Konfigurationsdatei // | ||
| + | # vim / | ||
| + | |||
| + | <file hash / | ||
| + | PRIORITY=-19 | ||
| + | OPTIONS=--ignore-localhost | ||
| + | </ | ||
| + | |||
| + | Will man die Sprache bei der Webseite, oder die Farben der Grafiken anpassen, schreibt man einfach seine Änderungen direkt in das übersichtliche CGI-Script. | ||
| + | # cat / | ||
| + | |||
| + | <file perl / | ||
| + | |||
| + | # mailgraph -- postfix mail traffic statistics | ||
| + | # copyright (c) 2000-2007 ETH Zurich | ||
| + | # copyright (c) 2000-2007 David Schweikert < | ||
| + | # released under the GNU General Public License | ||
| + | |||
| + | use RRDs; | ||
| + | use POSIX qw(uname); | ||
| + | |||
| + | my $VERSION = " | ||
| + | |||
| + | my $host = (POSIX:: | ||
| + | my $scriptname = ' | ||
| + | my $xpoints = 540; | ||
| + | my $points_per_sample = 3; | ||
| + | my $ypoints = 160; | ||
| + | my $ypoints_err = 96; | ||
| + | my $rrd = '/ | ||
| + | my $rrd_virus = '/ | ||
| + | my $tmp_dir = '/ | ||
| + | |||
| + | my @graphs = ( | ||
| + | { title => 'Last Day', | ||
| + | { title => 'Last Week', | ||
| + | { title => 'Last Month', | ||
| + | { title => 'Last Year', | ||
| + | ); | ||
| + | |||
| + | my %color = ( | ||
| + | sent => ' | ||
| + | received => ' | ||
| + | rejected => ' | ||
| + | bounced | ||
| + | virus => ' | ||
| + | spam => ' | ||
| + | ); | ||
| + | |||
| + | sub rrd_graph(@) | ||
| + | { | ||
| + | my ($range, $file, $ypoints, @rrdargs) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | # choose carefully the end otherwise rrd will maybe pick the wrong RRA: | ||
| + | my $end = time; $end -= $end % $step; | ||
| + | my $date = localtime(time); | ||
| + | $date =~ s|:|\\:|g unless $RRDs:: | ||
| + | |||
| + | my ($graphret, | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | $RRDs:: | ||
| + | |||
| + | @rrdargs, | ||
| + | |||
| + | ' | ||
| + | ); | ||
| + | |||
| + | my $ERR=RRDs:: | ||
| + | die " | ||
| + | } | ||
| + | |||
| + | sub graph($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_err($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub print_html() | ||
| + | { | ||
| + | print " | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | <meta http-equiv=" | ||
| + | <link rel=" | ||
| + | </ | ||
| + | < | ||
| + | HEADER | ||
| + | |||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | for my $n (0..$# | ||
| + | print " | ||
| + | } | ||
| + | print "</ | ||
| + | |||
| + | for my $n (0..$# | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | } | ||
| + | |||
| + | print << | ||
| + | <hr/> | ||
| + | < | ||
| + | <a href=" | ||
| + | by <a href=" | ||
| + | <td align=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | </ | ||
| + | FOOTER | ||
| + | } | ||
| + | |||
| + | sub send_image($) | ||
| + | { | ||
| + | my ($file)= @_; | ||
| + | |||
| + | -r $file or do { | ||
| + | print " | ||
| + | exit 1; | ||
| + | }; | ||
| + | |||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | open(IMG, $file) or die; | ||
| + | my $data; | ||
| + | print $data while read(IMG, $data, 16384)> | ||
| + | } | ||
| + | |||
| + | sub main() | ||
| + | { | ||
| + | my $uri = $ENV{REQUEST_URI} || ''; | ||
| + | $uri =~ s/ | ||
| + | $uri =~ s/\//,/g; | ||
| + | $uri =~ s/ | ||
| + | mkdir $tmp_dir, 0777 unless -d $tmp_dir; | ||
| + | mkdir " | ||
| + | |||
| + | my $img = $ENV{QUERY_STRING}; | ||
| + | if(defined $img and $img =~ /\S/) { | ||
| + | if($img =~ / | ||
| + | my $file = " | ||
| + | graph($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_err($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | else { | ||
| + | die " | ||
| + | } | ||
| + | } | ||
| + | else { | ||
| + | print_html; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | main; | ||
| + | </ | ||
| + | |||
| + | ==== Apache VHost anlegen ==== | ||
| + | Damit wir bequem von unserem Browser aus, die aktuellen Graphiken abfragen können, bearbeiten wir entweder die aus dem RPM stammende Konfigurationsdatei oder legen wir nun einen passenden VHost an. | ||
| + | # vim / | ||
| + | <file apache / | ||
| + | # | ||
| + | # mailgraph.nausch.org | ||
| + | # | ||
| + | < | ||
| + | ServerAdmin webmaster@nausch.org | ||
| + | ServerName mailgraph.nausch.org | ||
| + | ServerAlias www.mailgraph.nausch.org | ||
| + | ServerPath / | ||
| + | DocumentRoot "/ | ||
| + | AddHandler cgi-script .cgi | ||
| + | |||
| + | < | ||
| + | AllowOverride None | ||
| + | Options +ExecCGI | ||
| + | DirectoryIndex mailgraph.cgi | ||
| + | Order deny,allow | ||
| + | require IP 10.0. | ||
| + | </ | ||
| + | ErrorLog logs/ | ||
| + | CustomLog logs/ | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | |||
| + | Bevor wir bei unserem Webserver eine Reload der Konfiguration vornehmen, testen wir unsere neue Konfigurationsdatei auf syntaktische Fehler. | ||
| + | # apachectl -t | ||
| + | |||
| + | | ||
| + | |||
| + | Da keine Fehler aufgetreten sind, aktivieren wir die neue Konfiguration durch einen Reload des Webserver-Daemon. | ||
| + | # systemctl reload postfix | ||
| + | |||
| + | ==== NGiNX VHost anlegen ==== | ||
| + | Nutzen wir als Webserver **[[centos: | ||
| + | # vim / | ||
| + | <file http / | ||
| + | listen | ||
| + | server_name | ||
| + | access_log | ||
| + | error_log | ||
| + | |||
| + | root / | ||
| + | index mailgraph.cgi; | ||
| + | |||
| + | | ||
| + | fastcgi_split_path_info ^(.+\.cgi)(/ | ||
| + | fastcgi_index mailgraph.cgi; | ||
| + | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; | ||
| + | include fastcgi_params; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Den Parameter **fastcgi_pass** setzen wir im übrigen auf den Wert aus der Konfigurationsdatei // | ||
| + | |||
| + | Haben wir die Konfigurationsdatei vervollständigt, | ||
| + | # nginx -t | ||
| + | |||
| + | | ||
| + | | ||
| + | |||
| + | Somit können wir unsere Konfiguration nun noch aktivieren. | ||
| + | # systemctl reload nginx | ||
| + | |||
| + | ==== Programmaufruf ==== | ||
| + | === erster manueller Start des Dämon === | ||
| + | Damit das Mail-Logfile forlaufend ausgelesen wird, starten wir nun noch den Dämon mit Hilfe des mitgelieferten systemd-Start-Scriptes // | ||
| + | # systemctl start mailgraph | ||
| + | |||
| + | Im syslog wurde der Start des Daemon entsprechend dokumentiert. | ||
| + | # tail -n2 / | ||
| + | |||
| + | | ||
| + | | ||
| + | |||
| + | Ebenso kann man den Status des Webservers mit Hilfe des Befehls **systemctl** abfragen. | ||
| + | # systemctl status mailgraph | ||
| + | |||
| + | < | ||
| + | | ||
| + | | ||
| + | Process: 2362 ExecStart=/ | ||
| + | Main PID: 2367 (mailgraph) | ||
| + | | ||
| + | | ||
| + | |||
| + | Feb 02 21:17:37 vml000097.dmz.nausch.org systemd[1]: Started mailgraph mail log file analyzer. | ||
| + | </ | ||
| + | |||
| + | ==== automatischer Start beim Systemstart ==== | ||
| + | Wollen wir den Daemon beim Hochfahren des Systems automatisch starten, greifen wir auf den Befehl **systemctl** zurück. | ||
| + | # systemctl enable mailgraph.service | ||
| + | |||
| + | ln -s '/ | ||
| + | |||
| + | Möchten wir uns vergewissern, | ||
| + | # systemctl is-enabled mailgraph.service | ||
| + | |||
| + | | ||
| + | |||
| + | Startet der Server nicht automatisch, | ||
| + | |||
| + | ==== Webaufruf ==== | ||
| + | Über unseren [[https:// | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | |||
| + | ===== queuegraph ===== | ||
| + | Möchte man einen graphischen Überblick über die Queues haben, so liefert uns das gerade vorgestellte und installierte **Mailgraph** leider keine grafischen werte. Hierzu greifen wir auf das Programm **[[http:// | ||
| + | |||
| + | Das passende Programmpaket **queuegraph** installieren am einfachsten aus dem Repository **[[centos: | ||
| + | |||
| + | ==== Installation ==== | ||
| + | Mit Hilfe von **yum** holen wir uns als erstes das benötigte Paket auf unser System. | ||
| + | # yum install queuegraph -y | ||
| + | Den Inhalt des Paketes inspizieren wir bei Bedarf mit folgendem Aufruf. | ||
| + | # rpm -qil queuegraph | ||
| + | |||
| + | < | ||
| + | Version | ||
| + | Release | ||
| + | Architecture: | ||
| + | Install Date: Mon 02 Feb 2015 09:29:25 PM CET | ||
| + | Group : System Environment/ | ||
| + | Size : 6271 | ||
| + | License | ||
| + | Signature | ||
| + | Source RPM : queuegraph-1.1-1.el7.centos.src.rpm | ||
| + | Build Date : Fri 30 Jan 2015 09:21:46 PM CET | ||
| + | Build Host : vml000200.dmz.nausch.org | ||
| + | Relocations : (not relocatable) | ||
| + | Packager | ||
| + | URL : http:// | ||
| + | Summary | ||
| + | Description : | ||
| + | Queuegraph is a very simple mail statistics RRDtool frontend for Postfix that | ||
| + | produces daily, weekly, monthly and yearly graphs of Postfix' | ||
| + | deferred, incoming and bounce queues. | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | </ | ||
| + | |||
| + | ==== Konfiguration ==== | ||
| + | Die Konfiguration von queuegraph selbst gestaltet sich sehr einfach, da es gar nichts großartrig zu konfigurieren gibt! | ||
| + | |||
| + | Will man die Sprache bei der Webseite, oder die Farben anpassen, so nimmt man die Änderungen direkt im CGI-Script vor. | ||
| + | # vim / | ||
| + | <file perl / | ||
| + | |||
| + | # queuegraph -- a postfix queue statistics rrdtool frontend | ||
| + | # based on mailgraph, which is | ||
| + | # copyright (c) 2000-2002 David Schweikert < | ||
| + | # released under the GNU General Public License | ||
| + | |||
| + | use RRDs; | ||
| + | use POSIX qw(uname); | ||
| + | |||
| + | my $VERSION = " | ||
| + | |||
| + | my $host = (POSIX:: | ||
| + | my $scriptname = ' | ||
| + | my $xpoints = 800; | ||
| + | my $points_per_sample = 3; | ||
| + | my $ypoints = 160; | ||
| + | my $ypoints_err = 80; | ||
| + | my $rrd = '/ | ||
| + | my $tmp_dir = '/ | ||
| + | my $rrdtool_1_0 = ($RRDs:: | ||
| + | |||
| + | my @graphs = ( | ||
| + | { title => 'Day Graph', | ||
| + | { title => 'Week Graph', | ||
| + | { title => 'Month Graph', | ||
| + | { title => 'Year Graph', | ||
| + | ); | ||
| + | |||
| + | my %color = ( | ||
| + | sent => ' | ||
| + | received => ' | ||
| + | rejected => ' | ||
| + | bounced | ||
| + | virus => ' | ||
| + | spam => ' | ||
| + | ); | ||
| + | |||
| + | sub graph($$$) | ||
| + | { | ||
| + | my $range = shift; | ||
| + | my $file = shift; | ||
| + | my $title = shift; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | my $date = localtime(time); | ||
| + | $date =~ s|:|\\:|g unless $rrdtool_1_0; | ||
| + | |||
| + | my ($graphret, | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | $rrdtool_1_0 ? () : ( | ||
| + | ' | ||
| + | ), | ||
| + | |||
| + | " | ||
| + | " | ||
| + | |||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | my $ERR=RRDs:: | ||
| + | die " | ||
| + | } | ||
| + | |||
| + | sub print_html() | ||
| + | { | ||
| + | print " | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | <BODY BGCOLOR="# | ||
| + | HEADER | ||
| + | |||
| + | print "< | ||
| + | for my $n (0..$# | ||
| + | print "< | ||
| + | print "< | ||
| + | } | ||
| + | |||
| + | print << | ||
| + | <table border=" | ||
| + | <A href=" | ||
| + | by <A href=" | ||
| + | based on <A href=" | ||
| + | by <A href=" | ||
| + | <td ALIGN=" | ||
| + | <a HREF=" | ||
| + | </ | ||
| + | </ | ||
| + | FOOTER | ||
| + | } | ||
| + | |||
| + | sub send_image($) | ||
| + | { | ||
| + | my $file = shift; | ||
| + | -r $file or do { | ||
| + | print " | ||
| + | exit 1; | ||
| + | }; | ||
| + | |||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | open(IMG, $file) or die; | ||
| + | my $data; | ||
| + | print $data while read IMG, $data, 1; | ||
| + | } | ||
| + | |||
| + | sub main() | ||
| + | { | ||
| + | if($ENV{PATH_INFO}) { | ||
| + | my $uri = $ENV{REQUEST_URI}; | ||
| + | $uri =~ s/ | ||
| + | $uri =~ s/\//,/g; | ||
| + | $uri =~ s/ | ||
| + | mkdir " | ||
| + | my $file = " | ||
| + | if($ENV{PATH_INFO} =~ / | ||
| + | graph($graphs[$1]{seconds}, | ||
| + | } | ||
| + | else { | ||
| + | print " | ||
| + | exit 1; | ||
| + | } | ||
| + | send_image($file); | ||
| + | } | ||
| + | else { | ||
| + | print_html; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | main; | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ==== Optionen beim Programmaufruf==== | ||
| + | Hinweise zur Konfiguration oder besser gesagt über die Optionen beim Aufruf des Programms zeigt ein Blick in die Datei // | ||
| + | # cat / | ||
| + | |||
| + | <file bash / | ||
| + | |||
| + | Dependencies: | ||
| + | |||
| + | To install, adjust the path to your rrdtools binaries in queuegraph-rrd.sh | ||
| + | |||
| + | Create a cronjob that runs queuegraph-rrd.sh every minute -- this | ||
| + | populates the *.rrd database: | ||
| + | |||
| + | * * * * * / | ||
| + | |||
| + | Now put queuegraph.cgi into the cgi-bin directory of your webserver. | ||
| + | chmod 755 queuegraph.cgi | ||
| + | </ | ||
| + | |||
| + | ==== Apache VHost anlegen ==== | ||
| + | Damit wir bequem von unserem Browser aus, die aktuellen Graphiken abfragen können, bearbeiten wir entweder die aus dem RPM stammende Konfigurationsdatei oder legen wir nun einen passenden VHost an. | ||
| + | # vim / | ||
| + | <file apache / | ||
| + | # | ||
| + | # queuegraph.nausch.org | ||
| + | # | ||
| + | < | ||
| + | ServerAdmin webmaster@nausch.org | ||
| + | ServerName queue.nausch.org | ||
| + | ServerAlias www.queue.nausch.org | ||
| + | ServerPath / | ||
| + | DocumentRoot "/ | ||
| + | AddHandler cgi-script .cgi | ||
| + | |||
| + | < | ||
| + | AllowOverride None | ||
| + | Options +ExecCGI | ||
| + | DirectoryIndex queuegraph.cgi | ||
| + | Order deny,allow | ||
| + | require IP 10.0. | ||
| + | </ | ||
| + | ErrorLog logs/ | ||
| + | CustomLog logs/ | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | |||
| + | Bevor wir bei unserem Webserver eine Reload der Konfiguration vornehmen, testen wir unsere neue Konfigurationsdatei auf syntaktische Fehler. | ||
| + | # apachectl -t | ||
| + | |||
| + | | ||
| + | |||
| + | Da keine Fehler aufgetreten sind, aktivieren wir die neue Konfiguration durch einen Reload des Webserver-Daemon. | ||
| + | # systemctl reload postfix | ||
| + | |||
| + | ==== NGiNX VHost anlegen ==== | ||
| + | Nutzen wir als Webserver **[[centos: | ||
| + | # vim / | ||
| + | <file http / | ||
| + | listen | ||
| + | server_name | ||
| + | access_log | ||
| + | error_log | ||
| + | |||
| + | root / | ||
| + | index queuegraph.cgi; | ||
| + | |||
| + | | ||
| + | fastcgi_split_path_info ^(.+\.cgi)(/ | ||
| + | fastcgi_index queuegraph.cgi; | ||
| + | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; | ||
| + | include fastcgi_params; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Den Parameter **fastcgi_pass** setzen wir im übrigen auf den Wert aus der Konfigurationsdatei // | ||
| + | |||
| + | Haben wir die Konfigurationsdatei vervollständigt, | ||
| + | # nginx -t | ||
| + | |||
| + | | ||
| + | | ||
| + | |||
| + | Somit können wir unsere Konfiguration nun noch aktivieren. | ||
| + | # systemctl reload nginx | ||
| + | |||
| + | ==== Programmaufruf ==== | ||
| + | Die automatische Befüllung der **rrd**-files übernimmt ein cronjob, der jede Minute das Script **queuegraph-rrd.sh** startet. | ||
| + | # cat / | ||
| + | |||
| + | <file bash / | ||
| + | # | ||
| + | # This will run every one minute | ||
| + | * * * * * root / | ||
| + | </ | ||
| + | |||
| + | # less / | ||
| + | <file bash / | ||
| + | |||
| + | # output the number of messages in the incoming, active, and deferred | ||
| + | # queues of postfix one per line suitable for use with snmpd/ | ||
| + | # | ||
| + | # 2003/01/24 Mike Saunders <method at method DOT cx> | ||
| + | # mailqsize was originally written by Vivek Khera. | ||
| + | # make it update an rrd. | ||
| + | # 2003/04/14 Ralf Hildebrandt < | ||
| + | # I bundled this with a modified mailgraph | ||
| + | # 2007/07/28 Ralf Hildebrandt < | ||
| + | # find rrdtool using " | ||
| + | |||
| + | # change this to the location of rrdtool | ||
| + | RRDTOOL=`which rrdtool` | ||
| + | |||
| + | # change this to the location you want to store the rrd | ||
| + | RRDFILE=/ | ||
| + | |||
| + | if test ! -x $RRDTOOL ; then | ||
| + | echo " | ||
| + | exit | ||
| + | fi | ||
| + | |||
| + | if test ! -f $RRDFILE ; then | ||
| + | echo " | ||
| + | |||
| + | $RRDTOOL create $RRDFILE --step 60 \ | ||
| + | DS: | ||
| + | DS: | ||
| + | RRA: | ||
| + | RRA: | ||
| + | RRA: | ||
| + | RRA: | ||
| + | RRA: | ||
| + | RRA: | ||
| + | fi | ||
| + | |||
| + | #set -x | ||
| + | qdir=`/ | ||
| + | active=`find $qdir/ | ||
| + | deferred=`find $qdir/ | ||
| + | #printf " | ||
| + | |||
| + | $RRDTOOL update $RRDFILE " | ||
| + | </ | ||
| + | |||
| + | ==== Webaufruf ==== | ||
| + | Über unseren [[https:// | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | ===== Mailgraph NextGeneration ===== | ||
| + | Wem all die vorgenannten graphischen Aufbereitungen noch nicht ausführlich genug sind, dem bietet der Fork von [[http:// | ||
| + | * **Mail Ein und -Ausgang** | ||
| + | * **geblockte Nachrichten** | ||
| + | * **Greylisting Übersicht** | ||
| + | * **Greylisting Detailansicht** | ||
| + | * **Postscreen Übersicht** | ||
| + | * **Postscreen Detailansicht** | ||
| + | * **Übersicht Mail-Queues** | ||
| + | * **DANE / TLSA Verbindungen** | ||
| + | * **Sender policy Framework - SPF-Prüfungen** | ||
| + | * **DomainKeys Identified Mail - DKIM-Prüfungen** | ||
| + | * **Domain-based Message Authentication, | ||
| + | |||
| + | <WRAP center round info 80%> | ||
| + | Das Ganze ist aber zugegebener Maßen keine großartige Neuprogrammierung, | ||
| + | |||
| + | __**Besonderer Dank**__ geht daher an: | ||
| + | * **[[http:// | ||
| + | * **[[http:// | ||
| + | * **[[http:// | ||
| + | * **[[https:// | ||
| + | |||
| + | </ | ||
| + | |||
| + | Doch genug der Vorrede, einen Blick auf die Ausgabe des Webfrontends von **Mailgraph-ng** sagt mehr als 1.000 Worte. Die Ausgabe zeigt exemplarisch alle möglichen Graphen an, die auf einem Testsystem generiert wurden. | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Im Realbetrieb wird man entweder **Greylisting** oder **Postscreen** einsetzen, somit werden sicher zwei der gezeigten Graphen wegfallen. Wie das geht, wird [[/ | ||
| + | |||
| + | |||
| + | |||
| + | ==== Installation ==== | ||
| + | Bei der Installation der NextGeneration Version von Mailgraph gibt es mehrere Möglichkeiten. | ||
| + | * **RPM**-basiert | ||
| + | * **Update** mit Hilfe eines **tar.gz**-Archives | ||
| + | * **manuelle Installation/ | ||
| + | |||
| + | Auf die einzelnen Installationsarten gehen wir nun entsprechend ein. | ||
| + | |||
| + | === RPM-Installation === | ||
| + | Die wohl einfachste Art ist die der RPM-basierten Installation. Das passende Paket **mailgraph** installieren wir aus dem Repository **[[centos: | ||
| + | Haben wir das Repository **[[centos: | ||
| + | # yum install mailgraph | ||
| + | |||
| + | Das abhängige Paket **[[http:// | ||
| + | |||
| + | Will man die beiden Pakete "nur lokal" installieren verwendet man folgenden Aufruf. | ||
| + | # yum localinstall http:// | ||
| + | http:// | ||
| + | |||
| + | === manuelle Installation === | ||
| + | Hat man bereits Mailgraph in einer früheren Version (manuell) installiert und möchte diese Installation erweitern, so kann man natürlich Mailgraph auch manuell installieren. | ||
| + | |||
| + | Hierzu laden wir uns erst einmal das betreffende Paket auf unseren Server. Zuerst wechseln wir in unseren lokalen Paketspeicher. | ||
| + | # cd / | ||
| + | |||
| + | # wget http:// | ||
| + | |||
| + | Anschließend entpacken wir das Archiv. | ||
| + | # tar xzfv mailgraph-1.15.2.tar.gz -C /tmp/ | ||
| + | |||
| + | Dann erstellen wir, falls noch nicht im System vorhanden, die einzelnen Zielordner. | ||
| + | - **RRD-Speicherverzeichnis** \\ < | ||
| + | - **Cachingverzeichnis für die Graphen** \\ < | ||
| + | - **WEB Root Verzeichnis für die Webseite** \\ < | ||
| + | |||
| + | Nun kopieren wir die Dateien aus unserem temporären Verzeichnis an die richtige Stelle im System. | ||
| + | # cp / | ||
| + | |||
| + | # cp / | ||
| + | |||
| + | Das Script zur Datengenerierung kopieren wir dann noch in das Verzeichnis // | ||
| + | # systemctl stop mailgraph | ||
| + | |||
| + | # cp / | ||
| + | |||
| + | ==== Konfiguration ==== | ||
| + | === / | ||
| + | Die Konfiguration von mailgraph selbst gestaltet sich sehr einfach. Über die Konfigurationsdatei // | ||
| + | # vim / | ||
| + | |||
| + | <file hash / | ||
| + | PRIORITY=-19 | ||
| + | OPTIONS=--ignore-localhost | ||
| + | </ | ||
| + | |||
| + | === / | ||
| + | Will man die Sprache bei der Webseite, oder die Farben der Grafiken anpassen, schreibt man einfach seine Änderungen direkt in das übersichtliche CGI-Script. | ||
| + | # vim / | ||
| + | |||
| + | <file perl / | ||
| + | |||
| + | # 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 < | ||
| + | # patches from Sebastian van de Meer < | ||
| + | # released under the GNU General Public License | ||
| + | |||
| + | use RRDs; | ||
| + | use POSIX qw(uname); | ||
| + | |||
| + | my $VERSION = " | ||
| + | |||
| + | my $host = (POSIX:: | ||
| + | my $scriptname = $ENV{" | ||
| + | my $xpoints = 800; | ||
| + | my $points_per_sample = 3; | ||
| + | my $ypoints = 160; | ||
| + | my $rrd = '/ | ||
| + | my $rrd_virus = '/ | ||
| + | my $rrd_grey = '/ | ||
| + | my $rrd_dane = '/ | ||
| + | my $rrd_dmarc = '/ | ||
| + | my $rrd_queue = '/ | ||
| + | my $rrd_post = '/ | ||
| + | |||
| + | my $tmp_dir = '/ | ||
| + | my @graphs = ( | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | ); | ||
| + | |||
| + | my %color = ( # rrggbb in hex | ||
| + | # n | ||
| + | sent => ' | ||
| + | received | ||
| + | |||
| + | bounced | ||
| + | virus => ' | ||
| + | spam => ' | ||
| + | rejected | ||
| + | |||
| + | greylisted | ||
| + | delayed | ||
| + | whitelist | ||
| + | awl => ' | ||
| + | early => ' | ||
| + | |||
| + | pswl => ' | ||
| + | psbl => ' | ||
| + | passold | ||
| + | veto => ' | ||
| + | pregreet | ||
| + | dnsbl => ' | ||
| + | pipelining | ||
| + | nonsmtp | ||
| + | barenewline | ||
| + | command | ||
| + | hangup | ||
| + | passnew | ||
| + | |||
| + | new => ' | ||
| + | reconnectok | ||
| + | |||
| + | active | ||
| + | deferred | ||
| + | |||
| + | anonymoustls | ||
| + | trustedtls | ||
| + | untrustedtls | ||
| + | verifiedtls | ||
| + | |||
| + | spfnone | ||
| + | spffail | ||
| + | spfpass | ||
| + | |||
| + | dkimnone | ||
| + | dkimfail | ||
| + | dkimpass | ||
| + | |||
| + | dmarcnone | ||
| + | dmarcfail | ||
| + | dmarcpass | ||
| + | ); | ||
| + | |||
| + | sub rrd_graph(@) | ||
| + | { | ||
| + | my ($range, $file, $ypoints, @rrdargs) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | my $end = time; $end -= $end % $step; | ||
| + | my $date = localtime(time); | ||
| + | $date =~ s|:|\\:|g unless $RRDs:: | ||
| + | |||
| + | my ($graphret, | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | $RRDs:: | ||
| + | |||
| + | @rrdargs, | ||
| + | |||
| + | ' | ||
| + | ); | ||
| + | |||
| + | my $ERR=RRDs:: | ||
| + | die " | ||
| + | } | ||
| + | |||
| + | sub graph($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_virus($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | sub graph_greylist($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | sub graph_greystats($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_postscreen($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_postscreenstats($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_dane($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_spf($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_dkim($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_dmarc($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_queue($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | sub print_html() | ||
| + | { | ||
| + | print " | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | <meta http-equiv=" | ||
| + | <link rel=" | ||
| + | </ | ||
| + | < | ||
| + | HEADER | ||
| + | |||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | for my $n (0..$# | ||
| + | print " | ||
| + | } | ||
| + | print "</ | ||
| + | |||
| + | for my $n (0..$# | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | } | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | <table border=" | ||
| + | < | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </td> | ||
| + | <td> | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </td> | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | </td> | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | </td> | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </td> | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | FOOTER | ||
| + | } | ||
| + | |||
| + | sub send_image($) | ||
| + | { | ||
| + | my ($file)= @_; | ||
| + | |||
| + | -r $file or do { | ||
| + | print " | ||
| + | exit 1; | ||
| + | }; | ||
| + | |||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | open(IMG, $file) or die; | ||
| + | my $data; | ||
| + | print $data while read(IMG, $data, 16384)> | ||
| + | } | ||
| + | |||
| + | sub main() | ||
| + | { | ||
| + | my $uri = $ENV{REQUEST_URI} || ''; | ||
| + | $uri =~ s/ | ||
| + | $uri =~ s/\//,/g; | ||
| + | $uri =~ s/ | ||
| + | mkdir $tmp_dir, 0777 unless -d $tmp_dir; | ||
| + | mkdir " | ||
| + | |||
| + | my $img = $ENV{QUERY_STRING}; | ||
| + | if(defined $img and $img =~ /\S/) { | ||
| + | if($img =~ / | ||
| + | my $file = " | ||
| + | graph($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_virus($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_greylist($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_greystats($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_postscreen($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_postscreenstats($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_queue($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dane($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_spf($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dkim($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dmarc($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | else { | ||
| + | die " | ||
| + | } | ||
| + | } | ||
| + | else { | ||
| + | print_html; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | main; | ||
| + | </ | ||
| + | |||
| + | |||
| + | === / | ||
| + | Änderungen am Aussehen im Punkto Schriften und Farben der Webseite können auch mit Hilfe der CSS-Datei vorgenommen werden. | ||
| + | # vim / | ||
| + | |||
| + | <file css / | ||
| + | body { width: 900px; background-color: | ||
| + | font-family: | ||
| + | font-size: 12pt; | ||
| + | margin: 5px } | ||
| + | h1 { margin-top: 20px; margin-bottom: | ||
| + | text-align: center } | ||
| + | h2 { background-color: | ||
| + | padding: 2px 0 2px 4px } | ||
| + | hr { height: 1px; | ||
| + | border: 0; | ||
| + | border-top: 1px solid #aaa } | ||
| + | table { border: 0px; width: 100% } | ||
| + | img { border: 0 } | ||
| + | a { text-decoration: | ||
| + | a: | ||
| + | #jump { margin: 0 0 10px 4px } | ||
| + | #jump li { list-style: none; display: inline; | ||
| + | | ||
| + | #jump li: | ||
| + | #jump li: | ||
| + | </ | ||
| + | |||
| + | === / | ||
| + | Der Vollständigkeit halber ist nachfolgend das Perl-Script zum erstellen und Befüllen der **RRD**-Datenbankfiles aufgeführt. Eine Konfiguration des scriptes ist aber __nicht__ vorgesehen und notwendig! | ||
| + | # less / | ||
| + | |||
| + | <file perl / | ||
| + | |||
| + | # mailgraph -- an rrdtool frontend for mail statistics | ||
| + | # copyright (c) 2000-2007 ETH Zurich | ||
| + | # copyright (c) 2000-2007 David Schweikert < | ||
| + | # copyright (c) 2011 Markus Neubauer < | ||
| + | # copyright (c) 2014-2015 Django < | ||
| + | # released under the GNU General Public License | ||
| + | # with spf-, dkim-, dmarc, and dane-patch Sebastian van de Meer < | ||
| + | |||
| + | ######## Parse:: | ||
| + | package Parse:: | ||
| + | use Carp; | ||
| + | use Symbol; | ||
| + | use Time:: | ||
| + | use IO::File; | ||
| + | use strict; | ||
| + | use vars qw($VERSION); | ||
| + | my %months_map = ( | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | sub is_dst_switch($$$) | ||
| + | { | ||
| + | my ($self, $t, $time) = @_; | ||
| + | # calculate the time in one hour and see if the difference is 3600 seconds. | ||
| + | # if not, we are in a dst-switch hour | ||
| + | # note that right now we only support 1-hour dst offsets | ||
| + | # cache the result | ||
| + | if(defined $self-> | ||
| + | $self-> | ||
| + | return @{$self-> | ||
| + | } | ||
| + | # calculate a number out of the day and hour to identify the hour | ||
| + | $self-> | ||
| + | # calculating hour+1 (below) is a problem if the hour is 23. as far as I | ||
| + | # know, nobody does the DST switch at this time, so just assume it isn't | ||
| + | # DST switch if the hour is 23. | ||
| + | if($t-> | ||
| + | @{$self-> | ||
| + | return @{$self-> | ||
| + | } | ||
| + | # let's see the timestamp in one hour | ||
| + | # 0: sec, 1: min, 2: h, 3: day, 4: month, 5: year | ||
| + | my $time_plus_1h = timelocal($t-> | ||
| + | if($time_plus_1h - $time > 4000) { | ||
| + | @{$self-> | ||
| + | } | ||
| + | else { | ||
| + | @{$self-> | ||
| + | } | ||
| + | return @{$self-> | ||
| + | } | ||
| + | # fast timelocal, cache minute' | ||
| + | # don't cache more than minute because of daylight saving time switch | ||
| + | # 0: sec, 1: min, 2: h, 3: day, 4: month, 5: year | ||
| + | sub str2time($$$$$$$$) | ||
| + | { | ||
| + | my $self = shift @_; | ||
| + | my $GMT = pop @_; | ||
| + | my $lastmin = $self-> | ||
| + | if(defined $lastmin and | ||
| + | $lastmin-> | ||
| + | $lastmin-> | ||
| + | $lastmin-> | ||
| + | $lastmin-> | ||
| + | $lastmin-> | ||
| + | { | ||
| + | $self-> | ||
| + | return $self-> | ||
| + | } | ||
| + | my $time; | ||
| + | if($GMT) { | ||
| + | $time = timegm(@_); | ||
| + | } | ||
| + | else { | ||
| + | $time = timelocal(@_); | ||
| + | } | ||
| + | # compensate for DST-switch | ||
| + | # - if a timewarp is detected (1:00 -> 1:30 -> 1:00): | ||
| + | # - test if we are in a DST-switch-hour | ||
| + | # - compensate if yes | ||
| + | # note that we assume that the DST-switch goes like this: | ||
| + | # time | ||
| + | # stamp | ||
| + | # comp. | ||
| + | # result | ||
| + | # old Time::Local versions behave differently (1 2 5 6 5 6 7 8) | ||
| + | if(!$GMT and !defined $self-> | ||
| + | defined $self-> | ||
| + | $self-> | ||
| + | $self-> | ||
| + | { | ||
| + | my ($off, $until) = $self-> | ||
| + | if($off) { | ||
| + | $self-> | ||
| + | $self-> | ||
| + | } | ||
| + | } | ||
| + | if(defined $self-> | ||
| + | delete $self-> | ||
| + | delete $self-> | ||
| + | } | ||
| + | $self-> | ||
| + | $self-> | ||
| + | $self-> | ||
| + | return $time+($self-> | ||
| + | } | ||
| + | sub _use_locale($) | ||
| + | { | ||
| + | use POSIX qw(locale_h strftime); | ||
| + | my $old_locale = setlocale(LC_TIME); | ||
| + | for my $locale (@_) { | ||
| + | croak " | ||
| + | for my $month (0..11) { | ||
| + | $months_map{strftime(" | ||
| + | } | ||
| + | } | ||
| + | setlocale(LC_TIME, | ||
| + | } | ||
| + | sub new($$;%) | ||
| + | { | ||
| + | my ($class, $file, %data) = @_; | ||
| + | croak "new() requires one argument: file" unless defined $file; | ||
| + | %data = () unless %data; | ||
| + | if(not defined $data{year}) { | ||
| + | $data{year} = (localtime(time))[5]+1900; | ||
| + | } | ||
| + | $data{type} = ' | ||
| + | $data{_repeat}=0; | ||
| + | if(UNIVERSAL:: | ||
| + | $data{file} = $file; | ||
| + | } | ||
| + | elsif(UNIVERSAL:: | ||
| + | $data{file} = $file; | ||
| + | $data{filetail}=1; | ||
| + | } | ||
| + | elsif(! ref $file) { | ||
| + | if($file eq ' | ||
| + | my $io = new IO::Handle; | ||
| + | $data{file} = $io-> | ||
| + | } | ||
| + | else { | ||
| + | $data{file} = new IO:: | ||
| + | defined $data{file} or croak " | ||
| + | } | ||
| + | } | ||
| + | else { | ||
| + | croak " | ||
| + | } | ||
| + | if(defined $data{locale}) { | ||
| + | if(ref $data{locale} eq ' | ||
| + | _use_locale @{$data{locale}}; | ||
| + | } | ||
| + | elsif(ref $data{locale} eq '' | ||
| + | _use_locale $data{locale}; | ||
| + | } | ||
| + | else { | ||
| + | croak "' | ||
| + | } | ||
| + | } | ||
| + | return bless \%data, $class; | ||
| + | } | ||
| + | sub _year_increment($$) | ||
| + | { | ||
| + | my ($self, $mon) = @_; | ||
| + | # year change | ||
| + | if($mon==0) { | ||
| + | $self-> | ||
| + | $self-> | ||
| + | } | ||
| + | elsif($mon == 11) { | ||
| + | if($self-> | ||
| + | $self-> | ||
| + | } | ||
| + | } | ||
| + | else { | ||
| + | $self-> | ||
| + | } | ||
| + | $self-> | ||
| + | } | ||
| + | sub _next_line($) | ||
| + | { | ||
| + | my $self = shift; | ||
| + | my $f = $self-> | ||
| + | if(defined $self-> | ||
| + | return $f-> | ||
| + | } | ||
| + | else { | ||
| + | return $f-> | ||
| + | } | ||
| + | } | ||
| + | sub _next_syslog($) | ||
| + | { | ||
| + | my ($self) = @_; | ||
| + | while($self-> | ||
| + | $self-> | ||
| + | return $self-> | ||
| + | } | ||
| + | my $file = $self-> | ||
| + | line: while(defined (my $str = $self-> | ||
| + | # date, time and host | ||
| + | $str =~ /^ | ||
| + | (\S{3})\s+(\d+) | ||
| + | \s | ||
| + | (\d+): | ||
| + | (?: | ||
| + | \s | ||
| + | ([-\w\.\@: | ||
| + | \s+ | ||
| + | (?: | ||
| + | (.*) # text -- 7 | ||
| + | $/x or do | ||
| + | { | ||
| + | warn " | ||
| + | next line; | ||
| + | }; | ||
| + | my $mon = $months_map{$1}; | ||
| + | defined $mon or croak " | ||
| + | $self-> | ||
| + | # convert to unix time | ||
| + | my $time = $self-> | ||
| + | if(not $self-> | ||
| + | # accept maximum one day in the present future | ||
| + | if($time - time > 86400) { | ||
| + | warn " | ||
| + | next line; | ||
| + | } | ||
| + | } | ||
| + | my ($host, $text) = ($6, $7); | ||
| + | # last message repeated ... times | ||
| + | if($text =~ /^(?:last message repeated|above message repeats) (\d+) time/) { | ||
| + | next line if defined $self-> | ||
| + | next line if not defined $self-> | ||
| + | $1 > 0 or do { | ||
| + | warn " | ||
| + | next line; | ||
| + | }; | ||
| + | $self-> | ||
| + | $self-> | ||
| + | return $self-> | ||
| + | } | ||
| + | # marks | ||
| + | next if $text eq '-- MARK --'; | ||
| + | # some systems send over the network their | ||
| + | # hostname prefixed to the text. strip that. | ||
| + | $text =~ s/ | ||
| + | # discard ':' | ||
| + | # Apr 24 19:09:40 remedy : su : + tty?? root-oracle | ||
| + | $text =~ s/^:\s+//; | ||
| + | $text =~ /^ | ||
| + | ([^: | ||
| + | (?: | ||
| + | :\s+ | ||
| + | (?:\[ID\ (\d+)\ ([a-z0-9]+)\.([a-z]+)\]\ )? # Solaris 8 " | ||
| + | (.*) # text -- 6 | ||
| + | $/x or do | ||
| + | { | ||
| + | warn " | ||
| + | next line; | ||
| + | }; | ||
| + | if($self-> | ||
| + | $self-> | ||
| + | $time, | ||
| + | $host, | ||
| + | $1, # 2: program | ||
| + | $2, # 3: pid | ||
| + | $6, # 4: text | ||
| + | ]; | ||
| + | } | ||
| + | else { | ||
| + | $self-> | ||
| + | timestamp => $time, | ||
| + | host => $host, | ||
| + | program | ||
| + | pid => $2, | ||
| + | msgid => $3, | ||
| + | facility | ||
| + | level => $5, | ||
| + | text => $6, | ||
| + | }; | ||
| + | } | ||
| + | return $self-> | ||
| + | } | ||
| + | return undef; | ||
| + | } | ||
| + | sub _next_metalog($) | ||
| + | { | ||
| + | my ($self) = @_; | ||
| + | my $file = $self-> | ||
| + | line: while(my $str = $self-> | ||
| + | # date, time and host | ||
| + | $str =~ /^ | ||
| + | (\S{3})\s+(\d+) | ||
| + | \s | ||
| + | (\d+): | ||
| + | # host is not logged | ||
| + | \s+ | ||
| + | (.*) # text -- 6 | ||
| + | $/x or do | ||
| + | { | ||
| + | warn " | ||
| + | next line; | ||
| + | }; | ||
| + | my $mon = $months_map{$1}; | ||
| + | defined $mon or croak " | ||
| + | $self-> | ||
| + | # convert to unix time | ||
| + | my $time = $self-> | ||
| + | my $text = $6; | ||
| + | $text =~ /^ | ||
| + | \[(.*? | ||
| + | # no PID | ||
| + | \s+ | ||
| + | (.*) # text -- 2 | ||
| + | $/x or do | ||
| + | { | ||
| + | warn " | ||
| + | next line; | ||
| + | }; | ||
| + | if($self-> | ||
| + | return [ | ||
| + | $time, | ||
| + | ' | ||
| + | $1, # 2: program | ||
| + | undef, | ||
| + | $2, # 4: text | ||
| + | ]; | ||
| + | } | ||
| + | else { | ||
| + | return { | ||
| + | timestamp => $time, | ||
| + | host => ' | ||
| + | program | ||
| + | text => $2, | ||
| + | }; | ||
| + | } | ||
| + | } | ||
| + | return undef; | ||
| + | } | ||
| + | sub next($) | ||
| + | { | ||
| + | my ($self) = @_; | ||
| + | if($self-> | ||
| + | return $self-> | ||
| + | } | ||
| + | elsif($self-> | ||
| + | return $self-> | ||
| + | } | ||
| + | croak " | ||
| + | } | ||
| + | |||
| + | ##################################################################### | ||
| + | ##################################################################### | ||
| + | ##################################################################### | ||
| + | |||
| + | use RRDs; | ||
| + | |||
| + | use strict; | ||
| + | use File::Tail; | ||
| + | use Getopt:: | ||
| + | use POSIX ' | ||
| + | |||
| + | my $VERSION = " | ||
| + | |||
| + | # config | ||
| + | my $rrdstep | ||
| + | my $xpoints | ||
| + | my $points_per_sample = 3; | ||
| + | |||
| + | my $daemon_logfile = '/ | ||
| + | my $daemon_pidfile = '/ | ||
| + | my $daemon_rrd_dir = '/ | ||
| + | |||
| + | # global variables | ||
| + | my $logfile; | ||
| + | my $rrd = " | ||
| + | my $rrd_virus | ||
| + | my $rrd_grey | ||
| + | my $rrd_dane | ||
| + | my $rrd_dmarc | ||
| + | my $rrd_post | ||
| + | my $year; | ||
| + | my $this_minute; | ||
| + | my %sum = ( sent => 0, received => 0, bounced => 0, rejected => 0, virus => 0, spam => 0, greylisted => 0, delayed => 0,whitelist => 0, new => 0, awl => 0, early => 0, reconnectok => 0, anonymoustls => 0, trustedtls => 0, untrustedtls => 0, verifiedtls => 0, spfnone => 0, spffail => 0, spfpass => 0, dmarcnone => 0, dmarcfail => 0, dmarcpass => 0, dkimnone => 0, dkimfail => 0, dkimpass => 0, pswl => 0, psbl => 0, passold => 0, veto => 0, pregreet => 0, dnsbl => 0, pipelining =>, nonsmtp => 0, barenewline => 0, command => 0, hangup =>, passnew => 0); | ||
| + | my $rrd_inited=0; | ||
| + | |||
| + | my %opt = (); | ||
| + | |||
| + | # prototypes | ||
| + | sub daemonize(); | ||
| + | sub process_line($); | ||
| + | #4 | ||
| + | sub event_sent($); | ||
| + | sub event_received($); | ||
| + | sub event_bounced($); | ||
| + | sub event_rejected($); | ||
| + | #2 | ||
| + | sub event_virus($); | ||
| + | sub event_spam($); | ||
| + | #7 | ||
| + | sub event_greylisted($); | ||
| + | sub event_delayed($); | ||
| + | sub event_whitelist($); | ||
| + | sub event_new($); | ||
| + | sub event_awl($); | ||
| + | sub event_early($); | ||
| + | sub event_reconnectok($); | ||
| + | #4 | ||
| + | sub event_anonymoustls($); | ||
| + | sub event_trustedtls($); | ||
| + | sub event_untrustedtls($); | ||
| + | sub event_verifiedtls($); | ||
| + | #9 | ||
| + | sub event_spfnone($); | ||
| + | sub event_spffail($); | ||
| + | sub event_spfpass($); | ||
| + | sub event_dmarcnone($); | ||
| + | sub event_dmarcfail($); | ||
| + | sub event_dmarcpass($); | ||
| + | sub event_dkimnone($); | ||
| + | sub event_dkimfail($); | ||
| + | sub event_dkimpass($); | ||
| + | #12 | ||
| + | sub event_pswl($); | ||
| + | sub event_psbl($); | ||
| + | sub event_passold($); | ||
| + | sub event_veto($); | ||
| + | sub event_pregreet($); | ||
| + | sub event_dnsbl($); | ||
| + | sub event_pipelining($); | ||
| + | sub event_nonsmtp($); | ||
| + | sub event_barenewline($); | ||
| + | sub event_command($); | ||
| + | sub event_hangup($); | ||
| + | sub event_passnew($); | ||
| + | # | ||
| + | sub init_rrd($); | ||
| + | sub update($); | ||
| + | |||
| + | sub usage | ||
| + | { | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | |||
| + | exit; | ||
| + | } | ||
| + | |||
| + | sub main | ||
| + | { | ||
| + | Getopt:: | ||
| + | GetOptions(\%opt, | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ) or exit(1); | ||
| + | usage if $opt{help}; | ||
| + | |||
| + | if($opt{version}) { | ||
| + | print " | ||
| + | exit; | ||
| + | } | ||
| + | |||
| + | $daemon_pidfile = $opt{daemon_pid} if defined $opt{daemon_pid}; | ||
| + | $daemon_logfile = $opt{daemon_log} if defined $opt{daemon_log}; | ||
| + | $daemon_rrd_dir = $opt{daemon_rrd} if defined $opt{daemon_rrd}; | ||
| + | $rrd = $opt{rrd_name}." | ||
| + | $rrd_virus | ||
| + | $rrd_grey | ||
| + | $rrd_dane | ||
| + | $rrd_dmarc | ||
| + | $rrd_post | ||
| + | |||
| + | |||
| + | # compile --ignore-host regexps | ||
| + | if(defined $opt{' | ||
| + | for my $ih (@{$opt{' | ||
| + | push @{$opt{' | ||
| + | } | ||
| + | } | ||
| + | |||
| + | if($opt{daemon} or $opt{daemon_rrd}) { | ||
| + | chdir $daemon_rrd_dir or die " | ||
| + | -w $daemon_rrd_dir or die " | ||
| + | } | ||
| + | |||
| + | daemonize if $opt{daemon}; | ||
| + | |||
| + | my $logfile = defined $opt{logfile} ? $opt{logfile} : '/ | ||
| + | my $file; | ||
| + | if($opt{cat}) { | ||
| + | $file = $logfile; | ||
| + | } | ||
| + | else { | ||
| + | $file = File:: | ||
| + | } | ||
| + | my $parser = new Parse:: | ||
| + | type => defined $opt{logtype} ? $opt{logtype} : ' | ||
| + | |||
| + | if(not defined $opt{host}) { | ||
| + | while(my $sl = $parser-> | ||
| + | process_line($sl); | ||
| + | } | ||
| + | } | ||
| + | else { | ||
| + | my $host = qr/ | ||
| + | while(my $sl = $parser-> | ||
| + | process_line($sl) if $sl->[1] =~ $host; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | sub daemonize() | ||
| + | { | ||
| + | open STDIN, '/ | ||
| + | if($opt{verbose}) { | ||
| + | open STDOUT, ">> | ||
| + | or die " | ||
| + | } | ||
| + | else { | ||
| + | open STDOUT, '>/ | ||
| + | or die " | ||
| + | } | ||
| + | defined(my $pid = fork) or die " | ||
| + | if($pid) { | ||
| + | # parent | ||
| + | open PIDFILE, "> | ||
| + | or die " | ||
| + | print PIDFILE " | ||
| + | close(PIDFILE); | ||
| + | exit; | ||
| + | } | ||
| + | # child | ||
| + | setsid | ||
| + | open STDERR, '>& | ||
| + | } | ||
| + | |||
| + | sub init_rrd($) | ||
| + | { | ||
| + | my $m = shift; | ||
| + | my $rows = $xpoints/ | ||
| + | my $realrows = int($rows*1.1); | ||
| + | my $day_steps = int(3600*24 / ($rrdstep*$rows)); | ||
| + | # use multiples, otherwise rrdtool could choose the wrong RRA | ||
| + | my $week_steps = $day_steps*7; | ||
| + | my $month_steps = $week_steps*5; | ||
| + | my $year_steps = $month_steps*12; | ||
| + | |||
| + | # mail rrd | ||
| + | if(! -f $rrd and ! $opt{' | ||
| + | RRDs:: | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ); | ||
| + | $this_minute = $m; | ||
| + | } | ||
| + | elsif(-f $rrd) { | ||
| + | $this_minute = RRDs:: | ||
| + | } | ||
| + | |||
| + | # virus rrd | ||
| + | if(! -f $rrd_virus and ! $opt{' | ||
| + | RRDs:: | ||
| + | ' | ||
| + | ' | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ); | ||
| + | } | ||
| + | elsif(-f $rrd_virus and ! defined $rrd_virus) { | ||
| + | $this_minute = RRDs:: | ||
| + | } | ||
| + | |||
| + | # grey rrd | ||
| + | if(! -f $rrd_grey and ! $opt{' | ||
| + | RRDs:: | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ); | ||
| + | $this_minute = $m; | ||
| + | } | ||
| + | elsif(-f $rrd_grey and ! defined $rrd_grey) { | ||
| + | $this_minute = RRDs:: | ||
| + | } | ||
| + | |||
| + | # dane rrd | ||
| + | if(! -f $rrd_dane and ! $opt{' | ||
| + | RRDs:: | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ); | ||
| + | $this_minute = $m; | ||
| + | } | ||
| + | elsif(-f $rrd_dane and ! defined $rrd_dane) { | ||
| + | $this_minute = RRDs:: | ||
| + | } | ||
| + | |||
| + | # dmarc rrd | ||
| + | if(! -f $rrd_dmarc and ! $opt{' | ||
| + | RRDs:: | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ); | ||
| + | $this_minute = $m; | ||
| + | } | ||
| + | elsif(-f $rrd_dmarc and ! defined $rrd_dmarc) { | ||
| + | $this_minute = RRDs:: | ||
| + | } | ||
| + | |||
| + | # post rrd | ||
| + | if(! -f $rrd_post and ! $opt{' | ||
| + | RRDs:: | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ); | ||
| + | $this_minute = $m; | ||
| + | } | ||
| + | elsif(-f $rrd_post and ! defined $rrd_post) { | ||
| + | $this_minute = RRDs:: | ||
| + | } | ||
| + | |||
| + | $rrd_inited=1; | ||
| + | } | ||
| + | |||
| + | sub process_line($) | ||
| + | { | ||
| + | my $sl = shift; | ||
| + | my $time = $sl-> | ||
| + | my $prog = $sl-> | ||
| + | my $text = $sl-> | ||
| + | |||
| + | if($prog =~ / | ||
| + | my $prog = $1; | ||
| + | if($prog eq ' | ||
| + | if($text =~ / | ||
| + | return if $opt{' | ||
| + | $text =~ / | ||
| + | if(defined $opt{' | ||
| + | for my $ih (@{$opt{' | ||
| + | warn " | ||
| + | return if $text =~ $ih; | ||
| + | } | ||
| + | } | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /Anonymous TLS connection established to/) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /Trusted TLS connection established to/) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /Untrusted TLS connection established to/) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /Verified TLS connection established to/) { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ / | ||
| + | my $client = $1; | ||
| + | return if $opt{' | ||
| + | $client =~ / | ||
| + | return if $opt{' | ||
| + | $client =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($opt{' | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($opt{' | ||
| + | event($time, | ||
| + | } | ||
| + | # | ||
| + | # | ||
| + | #} | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | if($text =~ /Blocked by SpamAssassin/ | ||
| + | event($time, | ||
| + | } | ||
| + | else { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /PASS OLD/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /WHITELIST VETO/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /WHITELIST VETO/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /PREGREET/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /PREGREET/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /DNSBL/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /DNSBL/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /COMMAND PIPELINING/ | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /COMMAND PIPELINING/ | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /NON-SMTP COMMAND/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /NON-SMTP COMMAND/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /BARE NEWLINE/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /BARE NEWLINE/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /COMMAND TIME LIMIT/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /COMMAND TIME LIMIT/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /COMMAND COUNT LIMIT/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /COMMAND COUNT LIMIT/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /COMMAND LENGTH LIMIT/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /COMMAND LENGTH LIMIT/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /HANGUP/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /HANGUP/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ /PASS NEW/) { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /\blost input channel\b/ ) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | if (($opt{' | ||
| + | event($time, | ||
| + | } elsif ($opt{' | ||
| + | event($time, | ||
| + | } else { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($text =~ /\bsender blocked\b/ ) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /\bsender denied\b/ ) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /\bUser unknown$/i ) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / rejected because \S+ is in a black list at \S+/) { | ||
| + | if($opt{' | ||
| + | event($time, | ||
| + | } else { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($text =~ / rejected RCPT \S+: (Sender verify failed|Unknown user)/) { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if( $text =~ / | ||
| + | if($text !~ /\btag2=/) { # ignore new per-recipient log entry (2.2.0) | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | if($text !~ /\btag2=/) { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | if($text !~ /\btag2=/) { | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | elsif($text =~ /^Virus found\b/) { | ||
| + | event($time, | ||
| + | } | ||
| + | # | ||
| + | # event($time, | ||
| + | # } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | # Vexira antivirus (old) | ||
| + | if($text =~ /^VIRUS/) { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | # Vexira antivirus | ||
| + | if($text =~ /^\*+ Virus\b/) { | ||
| + | event($time, | ||
| + | } | ||
| + | # Vexira antispam | ||
| + | elsif($text =~ /\bcontains spam\b/) { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | # AntiVir MailGate | ||
| + | if($text =~ /^Alert!/) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | # avcheck | ||
| + | if($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ /^(?:spamd: )? | ||
| + | event($time, | ||
| + | } | ||
| + | # ClamAV SpamAssassin-plugin | ||
| + | elsif($text =~ /(?:result: )?CLAMAV/) { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ /spam detected from/) { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ /^\s*SPAM/ or $text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | # DrWeb | ||
| + | if($text =~ /infected/) { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ /Virus/) { | ||
| + | event($time, | ||
| + | } | ||
| + | if($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ /(Virus Scanning: Found)/ ) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /Bounce to/ ) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /^Spam Checks: Found ([0-9]+) spam messages/) { | ||
| + | my $cnt = $1; | ||
| + | for (my $i=0; $i<$cnt; $i++) { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | # uncommment for clamassassin: | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # } | ||
| + | #} | ||
| + | elsif ($prog eq ' | ||
| + | if ($text =~ /clamd: found/) { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | # AntiVir Milter | ||
| + | if($text =~ /^Alert!/) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ /Spam/) { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif($prog eq ' | ||
| + | if($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | ## Old versions (up to 1.27) | ||
| + | #if($text =~ /delayed [0-9]+ seconds: client/) { | ||
| + | # | ||
| + | #} | ||
| + | # New versions (from 1.28) | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ / | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /triplet found/) { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif ($prog eq ' | ||
| + | if ($text =~ /SPF pass:/) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /SPF none:/) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /fail:/) { | ||
| + | event($time, | ||
| + | } | ||
| + | # elsif($text =~ /SPF fail:\b/) { | ||
| + | # event($time, | ||
| + | # } | ||
| + | # elsif($text =~ /SPF softfail: | ||
| + | # event($time, | ||
| + | # } | ||
| + | } | ||
| + | elsif ($prog eq ' | ||
| + | if ($text =~ /DKIM verification successful/ | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /no signature data/) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /bad signature data/) { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | elsif ($prog eq ' | ||
| + | if ($text =~ /pass/) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /none/) { | ||
| + | event($time, | ||
| + | } | ||
| + | elsif($text =~ /fail/) { | ||
| + | event($time, | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | sub event($$) | ||
| + | { | ||
| + | my ($t, $type) = @_; | ||
| + | update($t) and $sum{$type}++; | ||
| + | } | ||
| + | |||
| + | # returns 1 if $sum should be updated | ||
| + | sub update($) | ||
| + | { | ||
| + | my $t = shift; | ||
| + | my $m = $t - $t%$rrdstep; | ||
| + | init_rrd($m) unless $rrd_inited; | ||
| + | return 1 if $m == $this_minute; | ||
| + | return 0 if $m < $this_minute; | ||
| + | |||
| + | print " | ||
| + | #4 | ||
| + | RRDs:: | ||
| + | #2 | ||
| + | RRDs:: | ||
| + | #7 | ||
| + | RRDs:: | ||
| + | #4 | ||
| + | RRDs:: | ||
| + | #9 | ||
| + | RRDs:: | ||
| + | #12 | ||
| + | RRDs:: | ||
| + | |||
| + | |||
| + | if($m > $this_minute+$rrdstep) { | ||
| + | for(my $sm=$this_minute+$rrdstep; | ||
| + | print " | ||
| + | #4 | ||
| + | RRDs:: | ||
| + | #2 | ||
| + | RRDs:: | ||
| + | #7 | ||
| + | RRDs:: | ||
| + | #4 | ||
| + | RRDs:: | ||
| + | #9 | ||
| + | RRDs:: | ||
| + | #12 | ||
| + | RRDs:: | ||
| + | } | ||
| + | } | ||
| + | $this_minute = $m; | ||
| + | #4 | ||
| + | $sum{sent}=0; | ||
| + | $sum{received}=0; | ||
| + | $sum{bounced}=0; | ||
| + | $sum{rejected}=0; | ||
| + | #2 | ||
| + | $sum{virus}=0; | ||
| + | $sum{spam}=0; | ||
| + | #7 | ||
| + | $sum{greylisted}=0; | ||
| + | $sum{delayed}=0; | ||
| + | $sum{whitelist}=0; | ||
| + | $sum{new}=0; | ||
| + | $sum{awl}=0; | ||
| + | $sum{early}=0; | ||
| + | $sum{reconnectok}=0; | ||
| + | #4 | ||
| + | $sum{anonymoustls}=0; | ||
| + | $sum{trustedtls}=0; | ||
| + | $sum{untrustedtls}=0; | ||
| + | $sum{verifiedtls}=0; | ||
| + | #9 | ||
| + | $sum{spfnone}=0; | ||
| + | $sum{spffail}=0; | ||
| + | $sum{spfpass}=0; | ||
| + | $sum{dmarcnone}=0; | ||
| + | $sum{dmarcfail}=0; | ||
| + | $sum{dmarcpass}=0; | ||
| + | $sum{dkimnone}=0; | ||
| + | $sum{dkimfail}=0; | ||
| + | $sum{dkimpass}=0; | ||
| + | # 12 | ||
| + | $sum{pswl}=0; | ||
| + | $sum{psbl}=0; | ||
| + | $sum{passold}=0; | ||
| + | $sum{veto}=0; | ||
| + | $sum{pregreet}=0; | ||
| + | $sum{dnsbl}=0; | ||
| + | $sum{pipelining}=0; | ||
| + | $sum{nonsmtp}=0; | ||
| + | $sum{barenewline}=0; | ||
| + | $sum{command}=0; | ||
| + | $sum{hangup}=0; | ||
| + | $sum{passnew}=0; | ||
| + | return 1; | ||
| + | } | ||
| + | |||
| + | main; | ||
| + | |||
| + | __END__ | ||
| + | |||
| + | =head1 NAME | ||
| + | |||
| + | mailgraph.pl - rrdtool frontend for mail statistics | ||
| + | |||
| + | =head1 SYNOPSIS | ||
| + | |||
| + | B< | ||
| + | |||
| + | | ||
| + | -h, --help | ||
| + | | ||
| + | -h, --help | ||
| + | -v, --verbose | ||
| + | -V, --version | ||
| + | -c, --cat causes the logfile to be only read and not monitored | ||
| + | -l, --logfile f monitor logfile f instead of / | ||
| + | -t, --logtype t set logfile' | ||
| + | -y, --year | ||
| + | | ||
| + | -d, --daemon | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | =head1 DESCRIPTION | ||
| + | |||
| + | This script does parse syslog and updates the RRD database (mailgraph.rrd) in | ||
| + | the current directory. | ||
| + | |||
| + | =head2 Log-Types | ||
| + | |||
| + | The following types can be given to --logtype: | ||
| + | |||
| + | =over 10 | ||
| + | |||
| + | =item syslog | ||
| + | |||
| + | Traditional " | ||
| + | |||
| + | =item metalog | ||
| + | |||
| + | Metalog (see http:// | ||
| + | |||
| + | =back | ||
| + | |||
| + | =head1 COPYRIGHT | ||
| + | |||
| + | Copyright (c) 2000-2007 by ETH Zurich | ||
| + | Copyright (c) 2000-2007 by David Schweikert | ||
| + | Copyright (c) 2011 Markus Neubauer | ||
| + | Copyright (c) 2014-2015 by Django | ||
| + | |||
| + | =head1 LICENSE | ||
| + | |||
| + | This program is free software; you can redistribute it and/or modify | ||
| + | it under the terms of the GNU General Public License as published by | ||
| + | the Free Software Foundation; either version 2 of the License, or | ||
| + | (at your option) any later version. | ||
| + | |||
| + | This program is distributed in the hope that it will be useful, | ||
| + | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| + | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| + | GNU General Public License for more details. | ||
| + | |||
| + | You should have received a copy of the GNU General Public License | ||
| + | along with this program; if not, write to the Free Software | ||
| + | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| + | |||
| + | =head1 AUTHOR | ||
| + | |||
| + | S<David Schweikert E< | ||
| + | |||
| + | =cut | ||
| + | |||
| + | # vi: sw=8 | ||
| + | </ | ||
| + | ==== Apache VHost anlegen ==== | ||
| + | Damit wir bequem von unserem Browser aus, die aktuellen Graphiken abfragen können, bearbeiten wir entweder die aus dem RPM stammende Konfigurationsdatei oder legen wir nun einen passenden VHost an. | ||
| + | # vim / | ||
| + | <file apache / | ||
| + | # | ||
| + | # mailgraph.nausch.org | ||
| + | # | ||
| + | < | ||
| + | ServerAdmin webmaster@nausch.org | ||
| + | ServerName mailgraph.nausch.org | ||
| + | ServerAlias www.mailgraph.nausch.org | ||
| + | ServerPath / | ||
| + | DocumentRoot "/ | ||
| + | AddHandler cgi-script .cgi | ||
| + | |||
| + | < | ||
| + | AllowOverride None | ||
| + | Options +ExecCGI | ||
| + | DirectoryIndex mailgraph.cgi | ||
| + | Order deny,allow | ||
| + | require IP 10.0. | ||
| + | </ | ||
| + | ErrorLog logs/ | ||
| + | CustomLog logs/ | ||
| + | </ | ||
| + | |||
| + | </ | ||
| + | |||
| + | Bevor wir bei unserem Webserver eine Reload der Konfiguration vornehmen, testen wir unsere neue Konfigurationsdatei auf syntaktische Fehler. | ||
| + | # apachectl -t | ||
| + | |||
| + | | ||
| + | |||
| + | Da keine Fehler aufgetreten sind, aktivieren wir die neue Konfiguration durch einen Reload des Webserver-Daemon. | ||
| + | # systemctl reload postfix | ||
| + | |||
| + | ==== NGiNX VHost anlegen ==== | ||
| + | Nutzen wir als Webserver **[[centos: | ||
| + | # vim / | ||
| + | <file http / | ||
| + | listen | ||
| + | server_name | ||
| + | access_log | ||
| + | error_log | ||
| + | |||
| + | root / | ||
| + | index queuegraph.cgi; | ||
| + | |||
| + | | ||
| + | fastcgi_split_path_info ^(.+\.cgi)(/ | ||
| + | fastcgi_index queuegraph.cgi; | ||
| + | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; | ||
| + | include fastcgi_params; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Den Parameter **fastcgi_pass** setzen wir im übrigen auf den Wert aus der Konfigurationsdatei // | ||
| + | |||
| + | Haben wir die Konfigurationsdatei vervollständigt, | ||
| + | # nginx -t | ||
| + | |||
| + | | ||
| + | | ||
| + | |||
| + | Somit können wir unsere Konfiguration nun noch aktivieren. | ||
| + | # systemctl reload nginx | ||
| + | |||
| + | ==== Programmaufruf ==== | ||
| + | === erster manueller Start des Dämon === | ||
| + | Damit das Mail-Logfile forlaufend ausgelesen wird, starten wir nun noch den Dämon mit Hilfe des mitgelieferten systemd-Start-Scriptes // | ||
| + | # systemctl start mailgraph | ||
| + | |||
| + | Im syslog wurde der Start des Daemon entsprechend dokumentiert. | ||
| + | # tail -n2 / | ||
| + | |||
| + | | ||
| + | | ||
| + | |||
| + | Ebenso kann man den Status des Webservers mit Hilfe des Befehls **systemctl** abfragen. | ||
| + | # systemctl status mailgraph | ||
| + | |||
| + | < | ||
| + | | ||
| + | | ||
| + | Process: 2362 ExecStart=/ | ||
| + | Main PID: 2367 (mailgraph) | ||
| + | | ||
| + | | ||
| + | |||
| + | Feb 02 21:17:37 vml000097.dmz.nausch.org systemd[1]: Started mailgraph mail log file analyzer. | ||
| + | </ | ||
| + | |||
| + | ==== automatischer Start beim Systemstart ==== | ||
| + | Wollen wir den Daemon beim Hochfahren des Systems automatisch starten, greifen wir auf den Befehl **systemctl** zurück. | ||
| + | # systemctl enable mailgraph.service | ||
| + | |||
| + | ln -s '/ | ||
| + | |||
| + | Möchten wir uns vergewissern, | ||
| + | # systemctl is-enabled mailgraph.service | ||
| + | |||
| + | | ||
| + | |||
| + | Startet der Server nicht automatisch, | ||
| + | |||
| + | ==== Webaufruf ==== | ||
| + | Über unseren [[https:// | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | ==== Ausgabe individualisieren ==== | ||
| + | Der zeitgleiche Einsatz von **Postgrey** und **Postscreen** macht i.d.R. keinen besonderen Sinn und ist auch nicht zu empfehlen. In der **CGI**-Datei, | ||
| + | |||
| + | <WRAP center round tip 80%> | ||
| + | Einzelne Graphen lassen sich sehr leicht und einfach ausblenden, in dem man die zugehörigen Zeilen einfach auskommentiert, | ||
| + | </ | ||
| + | |||
| + | Im folgendem Beispiel wollen wir die Greylisting-Graphen nicht mehr ausgeben lassen. Mit dem Editor unserer Wahl bearbeiten wir das **cgi**-script. | ||
| + | # vim / | ||
| + | |||
| + | <code perl>... | ||
| + | |||
| + | for my $n (0..$# | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | #print "< | ||
| + | #print "< | ||
| + | #print "< | ||
| + | #print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | } | ||
| + | |||
| + | ... | ||
| + | </ | ||
| + | |||
| + | So lassen sich z.B. auch die Reports zu **SPF**, **DKIM** und **DMARC** ausblenden, wenn man diese (aktuell noch) nicht haben möchte. Will man später die Graphen wieder sehen, reicht das Entfernen des Kommentarzeichens **#** am Anfang der betreffenden Zeilen. | ||
| + | |||
| + | ===== Mailgraph-NG für mehrere Mailserver ===== | ||
| + | Betreibt man mehrere Mailserver will man neben den Einzelstatistiken der einzelnen Mailserver oft auch einen Überblick über den gesamten Mail-Server-Verkehr haben. | ||
| + | Auch das lässt sich mit einem überschaubaren Aufwand realisieren. Hierzu gehen wir wie folgt vor. | ||
| + | |||
| + | - Von den einzelnen Mailservern holen wir die RRD-Dateien ab. | ||
| + | - Diese kopieren wir dann auf ein zentrales Verzeichnis auf unserem WEB-Server. | ||
| + | - Wir passen unser CGI-Script, welches für die dynamische Generierung der WEB-Seite benutzt wird, soweit an, dass beim Erstellen eines Graphen nicht nur eine Datenquelle herangezogen wird, sondern die Summe unserer einzelnen Mailserver verwendet werden soll. | ||
| + | |||
| + | Auf diese drei Schritte gehen wir nun im Detail noch ein. | ||
| + | |||
| + | ==== RRD-Dateien einsammeln ==== | ||
| + | Die einzelnen RRD-Dateien unserer Mailserver kopieren wir mit scp in ein temporäres Arbeitsverzeichnis unseres WEB-Servers. Hierzu legen wir uns erst einmal einen eigenen User an. | ||
| + | # groupadd -g 1100 mx-transfer && useradd -c "MX Transfer User" -d / | ||
| + | |||
| + | <WRAP center round tip 80%> | ||
| + | Das Gleiche machen wir auf jedem der MX-Hosts, von denen wir später die Dateien einsammeln möchten. | ||
| + | </ | ||
| + | |||
| + | |||
| + | Anschließend generieren wir uns einen ssh-key für diesen transfer-User. Hierzu schlüpfen wir erst in die Rolle dieses speziellen Users. | ||
| + | # su - mx-transfer | ||
| + | |||
| + | Anschließend legen wir das Unterverzeichnis für den SSH-Schlüssel an und passen dessen Verzeichnisrechte an. | ||
| + | $ mkdir ~/.ssh | ||
| + | $ chmod 700 ~/.ssh | ||
| + | |||
| + | <WRAP center round tip 80%> | ||
| + | Auch hier legen wir auf jedem der MX-Hosts, von denen wir später die Dateien einsammeln möchten, das Verzeichnis mit den nötigen Berechtigungen an. | ||
| + | </ | ||
| + | |||
| + | Nun legen wir uns einen ssh-key ohne Passphrase an, in dem wir bei der Frage nach der Passphrase einfach keine angeben. | ||
| + | $ ssh-keygen -b 4096 -t rsa -C "MX Transfer User" | ||
| + | |||
| + | < | ||
| + | Enter file in which to save the key (/ | ||
| + | Enter passphrase (empty for no passphrase): | ||
| + | Enter same passphrase again: | ||
| + | Your identification has been saved in / | ||
| + | Your public key has been saved in / | ||
| + | The key fingerprint is: | ||
| + | 30: | ||
| + | The key's randomart image is: | ||
| + | +--[ RSA 4096]----+ | ||
| + | | | | ||
| + | | . . | | ||
| + | | o o | | ||
| + | |. = o . | | ||
| + | | = + S | | ||
| + | |o + o . | | ||
| + | |o* * . | | ||
| + | |oE@ o | | ||
| + | | = .. . | | ||
| + | +-----------------+ | ||
| + | </ | ||
| + | |||
| + | Den public-key kopieren wir nun anschließend auf jeden unserer MX-Hosts. | ||
| + | $ ssh-copy-id -i ~/ | ||
| + | |||
| + | $ ssh-copy-id -i ~/ | ||
| + | |||
| + | $ ssh-copy-id -i ~/ | ||
| + | |||
| + | $ ssh-copy-id -i ~/ | ||
| + | |||
| + | Als nächstes legen wir uns die temporären Zielverzeichnisse auf unserem Webserver an, in die wir später via scp die RRD-Dateien kopieren. | ||
| + | $ mkdir -p ~/ | ||
| + | |||
| + | Somit haben wir folgende Verzeichnisstruktur auf unserem Server. | ||
| + | < | ||
| + | └── mailgraph | ||
| + | ├── mx11 | ||
| + | ├── mx12 | ||
| + | ├── mx13 | ||
| + | └── mx14 | ||
| + | </ | ||
| + | |||
| + | Für das Einsammeln der RRD-Dateien legen wir uns ein passendes Script im Verzeichnis // | ||
| + | $ mkdir ~/bin | ||
| + | |||
| + | $ vim ~/ | ||
| + | |||
| + | <file bash ~/ | ||
| + | # Django : 2015-02-26 | ||
| + | # Einsammeln der RRD-Files von den einzelnen Mailservern | ||
| + | |||
| + | cd / | ||
| + | scp 10.100.0.87:/ | ||
| + | scp 10.100.0.87:/ | ||
| + | |||
| + | cd / | ||
| + | scp 10.200.0.87:/ | ||
| + | scp 10.200.0.87:/ | ||
| + | |||
| + | cd / | ||
| + | scp 10.300.0.87:/ | ||
| + | scp 10.300.0.87:/ | ||
| + | |||
| + | cd / | ||
| + | scp 10.400.0.87:/ | ||
| + | scp 10.400.0.87:/ | ||
| + | </ | ||
| + | |||
| + | Damit das Script auch ausgeführt werden kann, geben wir ihm noch das entsprechende **x**-Recht. | ||
| + | $ chmod +x ~/ | ||
| + | |||
| + | Im 5-minütigen Abstand holen wird dann die Daten von den Mailservern ab. Hierzu nutzen wir die benutzerindividuelle **crontab** unseres Transfer-Users. | ||
| + | $ crontab -e | ||
| + | |||
| + | < | ||
| + | # alles 5 Minuten die RRD-Files von den einzelnen Mailservern einsammeln | ||
| + | 2, | ||
| + | </ | ||
| + | |||
| + | Nach kurzer Zeit haben wir nunmehr von den einzelnen Mailservern die Statistikdaten mit einer Aktualität von 5 Minuten vorliegen. | ||
| + | < | ||
| + | ├── mx11 | ||
| + | │ ├── mailgraph_dane.rrd | ||
| + | │ ├── mailgraph_dmarc.rrd | ||
| + | │ ├── mailgraph_grey.rrd | ||
| + | │ ├── mailgraph_post.rrd | ||
| + | │ ├── mailgraph.rrd | ||
| + | │ ├── mailgraph_smtpd.rrd | ||
| + | │ ├── mailgraph_virus.rrd | ||
| + | │ └── mailqueues.rrd | ||
| + | ├── mx12 | ||
| + | │ ├── mailgraph_dane.rrd | ||
| + | │ ├── mailgraph_dmarc.rrd | ||
| + | │ ├── mailgraph_grey.rrd | ||
| + | │ ├── mailgraph_post.rrd | ||
| + | │ ├── mailgraph.rrd | ||
| + | │ ├── mailgraph_smtpd.rrd | ||
| + | │ ├── mailgraph_virus.rrd | ||
| + | │ └── mailqueues.rrd | ||
| + | ├── mx13 | ||
| + | │ ├── mailgraph_dane.rrd | ||
| + | │ ├── mailgraph_dmarc.rrd | ||
| + | │ ├── mailgraph_grey.rrd | ||
| + | │ ├── mailgraph_post.rrd | ||
| + | │ ├── mailgraph.rrd | ||
| + | │ ├── mailgraph_smtpd.rrd | ||
| + | │ ├── mailgraph_virus.rrd | ||
| + | │ └── mailqueues.rrd | ||
| + | └── mx14 | ||
| + | ├── mailgraph_dane.rrd | ||
| + | ├── mailgraph_dmarc.rrd | ||
| + | ├── mailgraph_grey.rrd | ||
| + | ├── mailgraph_post.rrd | ||
| + | ├── mailgraph.rrd | ||
| + | ├── mailgraph_smtpd.rrd | ||
| + | ├── mailgraph_virus.rrd | ||
| + | └── mailqueues.rrd | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== Datenbereitstellung ==== | ||
| + | Das CGI-Script, welches wir zum dynamischen Generieren der Statistikgraphen verwenden, bekommt im Verzeichnis // | ||
| + | # mkdir -p / | ||
| + | |||
| + | Die Befüllung dieser Zeilverzeichnisse nehmen wir jeweils mit Hilfe eines **rsync**-Aufrufs vor, den wir via cronjob ausführen lassen. | ||
| + | # vim / | ||
| + | |||
| + | <file bash / | ||
| + | PATH=/ | ||
| + | MAILTO=root | ||
| + | HOME=/ | ||
| + | |||
| + | # For details see man 4 crontabs | ||
| + | |||
| + | # Example of job definition: | ||
| + | # .---------------- minute (0 - 59) | ||
| + | # | .------------- hour (0 - 23) | ||
| + | # | | .---------- day of month (1 - 31) | ||
| + | # | | | .------- month (1 - 12) OR jan, | ||
| + | # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun, | ||
| + | # | | | | | | ||
| + | # * * * * * user-name command to be executed | ||
| + | |||
| + | # Django : 2015-02-26 | ||
| + | # alles 5 Minuten die RRD-Files vom Transfer-Verzeichnis abholen und in den Zielverzeichnissen ablegen | ||
| + | */5 * * * * root / | ||
| + | */5 * * * * root / | ||
| + | */5 * * * * root / | ||
| + | */5 * * * * root / | ||
| + | </ | ||
| + | |||
| + | Nach wenigen Minuten stehen die Statistikdaten, | ||
| + | |||
| + | ==== Generierung Statistikgraphen und Webseite(n) ==== | ||
| + | Zur Präsentation unserer Statistikdaten benötigen wir nun noch einen Webserver, der die aufbereiteten Daten bereitstellt. Hierzu legen wir uns folgende Verzeichnisstruktur an. | ||
| + | < | ||
| + | ├── mx | ||
| + | ├── mx11 | ||
| + | ├── mx12 | ||
| + | ├── mx13 | ||
| + | └── mx14 | ||
| + | </ | ||
| + | |||
| + | # mkdir -p / | ||
| + | |||
| + | Bei der **[[centos: | ||
| + | {{ : | ||
| + | body { width: 900px; background-color: | ||
| + | font-family: | ||
| + | font-size: 12pt; | ||
| + | margin: 5px } | ||
| + | h1 { margin-top: 20px; margin-bottom: | ||
| + | text-align: center } | ||
| + | h2 { background-color: | ||
| + | padding: 2px 0 2px 4px } | ||
| + | h3 { margin-top: 10px; margin-bottom: | ||
| + | text-align: center } | ||
| + | hr { height: 1px; | ||
| + | border: 0; | ||
| + | border-top: 1px solid #aaa } | ||
| + | table { border: 0px; width: 100% } | ||
| + | img { border: 0 } | ||
| + | a { text-decoration: | ||
| + | a: | ||
| + | #jump { margin: 0 0 10px 4px } | ||
| + | #jump li { list-style: none; display: inline; | ||
| + | | ||
| + | #jump li: | ||
| + | #jump li: | ||
| + | </ | ||
| + | |||
| + | Das Logo und die CSS-Date kopieren wir nun die die einzelnen Unterverzeichnisse. | ||
| + | # cp / | ||
| + | # cp / | ||
| + | # cp / | ||
| + | # cp / | ||
| + | # cp / | ||
| + | |||
| + | # cp / | ||
| + | # cp / | ||
| + | # cp / | ||
| + | # cp / | ||
| + | # cp / | ||
| + | |||
| + | In den Unterverzeichnissen **mx11** bis **mx14** legen wir jeweils ein CGI-Script ab. Damit wir später zwischen den Einzelanzeigen der Mailserver und der kumulierten Übersicht jeweils wechseln können, versehen wir das Originalscript aus dem RPM **[[http:// | ||
| + | |||
| + | Die wesentlichen Änderungen/ | ||
| + | * Änderungen des Verzeichnisses der Datenquellen (RRD-Dateien). \\ **Bsp. MX11:** <code perl>... | ||
| + | |||
| + | my $rrd = '/ | ||
| + | my $rrd_virus = '/ | ||
| + | my $rrd_grey | ||
| + | my $rrd_dane | ||
| + | my $rrd_dmarc = '/ | ||
| + | my $rrd_smtpd = '/ | ||
| + | my $rrd_queue = '/ | ||
| + | my $rrd_post | ||
| + | |||
| + | ... | ||
| + | </ | ||
| + | * Einfügen der Variablen **url** für die Verweise zu den jeweils anderen Statistikseiten. | ||
| + | |||
| + | my $url = " | ||
| + | my $urlg = " | ||
| + | my $url1 = " | ||
| + | my $url2 = " | ||
| + | my $url3 = " | ||
| + | my $url4 = " | ||
| + | my $url11 = " | ||
| + | my $url12 = " | ||
| + | my $url13 = " | ||
| + | my $url14 = " | ||
| + | |||
| + | |||
| + | ... | ||
| + | </ | ||
| + | * Erweiterung des Unterprogramms **print_html** um die links zu den verweisenden Statistikseiten.< | ||
| + | |||
| + | sub print_html() | ||
| + | { | ||
| + | print " | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | <meta http-equiv=" | ||
| + | <link rel=" | ||
| + | </ | ||
| + | < | ||
| + | HEADER | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | #print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | |||
| + | print "< | ||
| + | for my $n (0..$# | ||
| + | print " | ||
| + | } | ||
| + | print "</ | ||
| + | |||
| + | for my $n (0..$# | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | } | ||
| + | |||
| + | print << | ||
| + | <hr/> | ||
| + | <table border=" | ||
| + | < | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </td> | ||
| + | <td> | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </td> | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | </td> | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | </td> | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </td> | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | FOOTER | ||
| + | } | ||
| + | |||
| + | ... | ||
| + | </ | ||
| + | |||
| + | ==== CGI-Scripte für die Einzelsysteme ==== | ||
| + | Für die vier Mailserver ergeben sich folgende CGI-Scripte. | ||
| + | |||
| + | === / | ||
| + | |||
| + | # vim / | ||
| + | <file perl / | ||
| + | |||
| + | # 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 < | ||
| + | # patches from Sebastian van de Meer < | ||
| + | # released under the GNU General Public License | ||
| + | |||
| + | use RRDs; | ||
| + | use POSIX qw(uname); | ||
| + | |||
| + | my $VERSION = " | ||
| + | |||
| + | my $host = (POSIX:: | ||
| + | my $scriptname = $ENV{" | ||
| + | my $xpoints = 800; | ||
| + | my $points_per_sample = 3; | ||
| + | my $ypoints = 160; | ||
| + | my $rrd = '/ | ||
| + | my $rrd_virus = '/ | ||
| + | my $rrd_grey = '/ | ||
| + | my $rrd_dane = '/ | ||
| + | my $rrd_dmarc = '/ | ||
| + | my $rrd_smtpd = '/ | ||
| + | my $rrd_queue = '/ | ||
| + | my $rrd_post = '/ | ||
| + | |||
| + | my $tmp_dir = '/ | ||
| + | my @graphs = ( | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | ); | ||
| + | |||
| + | my %color = ( # rrggbb in hex | ||
| + | # n | ||
| + | sent => ' | ||
| + | received | ||
| + | |||
| + | bounced | ||
| + | virus => ' | ||
| + | spam => ' | ||
| + | rejected | ||
| + | |||
| + | greylisted | ||
| + | delayed | ||
| + | whitelist | ||
| + | awl => ' | ||
| + | early => ' | ||
| + | |||
| + | pswl => ' | ||
| + | psbl => ' | ||
| + | passold | ||
| + | veto => ' | ||
| + | pregreet | ||
| + | dnsbl => ' | ||
| + | pipelining | ||
| + | nonsmtp | ||
| + | barenewline | ||
| + | command | ||
| + | hangup | ||
| + | passnew | ||
| + | |||
| + | new => ' | ||
| + | reconnectok | ||
| + | |||
| + | active | ||
| + | deferred | ||
| + | |||
| + | untrustedtls | ||
| + | anonymoustls | ||
| + | trustedtls | ||
| + | verifiedtls | ||
| + | |||
| + | untrustedtlsin | ||
| + | anonymoustlsin | ||
| + | trustedtlsin | ||
| + | |||
| + | spfnone | ||
| + | spffail | ||
| + | spfpass | ||
| + | |||
| + | dkimnone | ||
| + | dkimfail | ||
| + | dkimpass | ||
| + | |||
| + | dmarcnone | ||
| + | dmarcfail | ||
| + | dmarcpass | ||
| + | ); | ||
| + | |||
| + | my $url = " | ||
| + | my $urlg = " | ||
| + | my $url1 = " | ||
| + | my $url2 = " | ||
| + | my $url3 = " | ||
| + | my $url4 = " | ||
| + | my $url11 = " | ||
| + | my $url12 = " | ||
| + | my $url13 = " | ||
| + | my $url14 = " | ||
| + | |||
| + | sub rrd_graph(@) | ||
| + | { | ||
| + | my ($range, $file, $ypoints, @rrdargs) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | my $end = time; $end -= $end % $step; | ||
| + | my $date = localtime(time); | ||
| + | $date =~ s|:|\\:|g unless $RRDs:: | ||
| + | |||
| + | my ($graphret, | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | $RRDs:: | ||
| + | |||
| + | @rrdargs, | ||
| + | |||
| + | ' | ||
| + | ); | ||
| + | |||
| + | my $ERR=RRDs:: | ||
| + | die " | ||
| + | } | ||
| + | |||
| + | sub graph($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_virus($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | sub graph_greylist($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | sub graph_greystats($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_postscreen($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_postscreenstats($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_dane($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_smtpd($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_spf($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_dkim($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_dmarc($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_queue($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | sub print_html() | ||
| + | { | ||
| + | print " | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | <meta http-equiv=" | ||
| + | <link rel=" | ||
| + | </ | ||
| + | < | ||
| + | HEADER | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | #print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | |||
| + | print "< | ||
| + | for my $n (0..$# | ||
| + | print " | ||
| + | } | ||
| + | print "</ | ||
| + | |||
| + | for my $n (0..$# | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | rint "<a href=' | ||
| + | print "< | ||
| + | |||
| + | } | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | <table border=" | ||
| + | < | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | < | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | </ | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | FOOTER | ||
| + | } | ||
| + | |||
| + | sub send_image($) | ||
| + | { | ||
| + | my ($file)= @_; | ||
| + | |||
| + | -r $file or do { | ||
| + | print " | ||
| + | exit 1; | ||
| + | }; | ||
| + | |||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | open(IMG, $file) or die; | ||
| + | my $data; | ||
| + | print $data while read(IMG, $data, 16384)> | ||
| + | } | ||
| + | |||
| + | sub main() | ||
| + | { | ||
| + | my $uri = $ENV{REQUEST_URI} || ''; | ||
| + | $uri =~ s/ | ||
| + | $uri =~ s/ | ||
| + | $uri =~ s/ | ||
| + | mkdir $tmp_dir, 0777 unless -d $tmp_dir; | ||
| + | mkdir " | ||
| + | |||
| + | my $img = $ENV{QUERY_STRING}; | ||
| + | if(defined $img and $img =~ /\S/) { | ||
| + | if($img =~ / | ||
| + | my $file = " | ||
| + | graph($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_virus($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_greylist($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_greystats($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_postscreen($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_postscreenstats($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_queue($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dane($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_smtpd($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_spf($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dkim($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dmarc($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | else { | ||
| + | die " | ||
| + | } | ||
| + | } | ||
| + | else { | ||
| + | print_html; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | main; | ||
| + | </ | ||
| + | |||
| + | === / | ||
| + | |||
| + | # vim / | ||
| + | <file perl / | ||
| + | |||
| + | # 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 < | ||
| + | # patches from Sebastian van de Meer < | ||
| + | # released under the GNU General Public License | ||
| + | |||
| + | use RRDs; | ||
| + | use POSIX qw(uname); | ||
| + | |||
| + | my $VERSION = " | ||
| + | |||
| + | my $host = (POSIX:: | ||
| + | my $scriptname = $ENV{" | ||
| + | my $xpoints = 800; | ||
| + | my $points_per_sample = 3; | ||
| + | my $ypoints = 160; | ||
| + | my $rrd = '/ | ||
| + | my $rrd_virus = '/ | ||
| + | my $rrd_grey | ||
| + | my $rrd_dane | ||
| + | my $rrd_dmarc = '/ | ||
| + | my $rrd_smtpd = '/ | ||
| + | my $rrd_queue = '/ | ||
| + | my $rrd_post | ||
| + | |||
| + | my $tmp_dir = '/ | ||
| + | my @graphs = ( | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | ); | ||
| + | |||
| + | my %color = ( # rrggbb in hex | ||
| + | # n | ||
| + | sent => ' | ||
| + | received | ||
| + | |||
| + | bounced | ||
| + | virus => ' | ||
| + | spam => ' | ||
| + | rejected | ||
| + | |||
| + | greylisted | ||
| + | delayed | ||
| + | whitelist | ||
| + | awl => ' | ||
| + | early => ' | ||
| + | |||
| + | pswl => ' | ||
| + | psbl => ' | ||
| + | passold | ||
| + | veto => ' | ||
| + | pregreet | ||
| + | dnsbl => ' | ||
| + | pipelining | ||
| + | nonsmtp | ||
| + | barenewline | ||
| + | command | ||
| + | hangup | ||
| + | passnew | ||
| + | |||
| + | new => ' | ||
| + | reconnectok | ||
| + | |||
| + | active | ||
| + | deferred | ||
| + | |||
| + | untrustedtls | ||
| + | anonymoustls | ||
| + | trustedtls | ||
| + | verifiedtls | ||
| + | |||
| + | untrustedtlsin | ||
| + | anonymoustlsin | ||
| + | trustedtlsin | ||
| + | |||
| + | spfnone | ||
| + | spffail | ||
| + | spfpass | ||
| + | |||
| + | dkimnone | ||
| + | dkimfail | ||
| + | dkimpass | ||
| + | |||
| + | dmarcnone | ||
| + | dmarcfail | ||
| + | dmarcpass | ||
| + | ); | ||
| + | |||
| + | my $url = " | ||
| + | my $urlg = " | ||
| + | my $url1 = " | ||
| + | my $url2 = " | ||
| + | my $url3 = " | ||
| + | my $url4 = " | ||
| + | my $url11 = " | ||
| + | my $url12 = " | ||
| + | my $url13 = " | ||
| + | my $url14 = " | ||
| + | |||
| + | sub rrd_graph(@) | ||
| + | { | ||
| + | my ($range, $file, $ypoints, @rrdargs) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | my $end = time; $end -= $end % $step; | ||
| + | my $date = localtime(time); | ||
| + | $date =~ s|:|\\:|g unless $RRDs:: | ||
| + | |||
| + | my ($graphret, | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | $RRDs:: | ||
| + | |||
| + | @rrdargs, | ||
| + | |||
| + | ' | ||
| + | ); | ||
| + | |||
| + | my $ERR=RRDs:: | ||
| + | die " | ||
| + | } | ||
| + | |||
| + | sub graph($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_virus($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | sub graph_greylist($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | sub graph_greystats($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_postscreen($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_postscreenstats($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_dane($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_smtpd($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_spf($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_dkim($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_dmarc($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_queue($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | sub print_html() | ||
| + | { | ||
| + | print " | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | <meta http-equiv=" | ||
| + | <link rel=" | ||
| + | </ | ||
| + | < | ||
| + | HEADER | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | #print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | |||
| + | print "< | ||
| + | for my $n (0..$# | ||
| + | print " | ||
| + | } | ||
| + | print "</ | ||
| + | |||
| + | for my $n (0..$# | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | } | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | <table border=" | ||
| + | < | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | < | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | </ | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | FOOTER | ||
| + | } | ||
| + | |||
| + | sub send_image($) | ||
| + | { | ||
| + | my ($file)= @_; | ||
| + | |||
| + | -r $file or do { | ||
| + | print " | ||
| + | exit 1; | ||
| + | }; | ||
| + | |||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | open(IMG, $file) or die; | ||
| + | my $data; | ||
| + | print $data while read(IMG, $data, 16384)> | ||
| + | } | ||
| + | |||
| + | sub main() | ||
| + | { | ||
| + | my $uri = $ENV{REQUEST_URI} || ''; | ||
| + | $uri =~ s/ | ||
| + | $uri =~ s/ | ||
| + | $uri =~ s/ | ||
| + | mkdir $tmp_dir, 0777 unless -d $tmp_dir; | ||
| + | mkdir " | ||
| + | |||
| + | my $img = $ENV{QUERY_STRING}; | ||
| + | if(defined $img and $img =~ /\S/) { | ||
| + | if($img =~ / | ||
| + | my $file = " | ||
| + | graph($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_virus($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_greylist($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_greystats($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_postscreen($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_postscreenstats($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_queue($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dane($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_smtpd($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_spf($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dkim($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dmarc($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | else { | ||
| + | die " | ||
| + | } | ||
| + | } | ||
| + | else { | ||
| + | print_html; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | main; | ||
| + | </ | ||
| + | |||
| + | === / | ||
| + | |||
| + | # vim / | ||
| + | <file perl / | ||
| + | |||
| + | # 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 < | ||
| + | # patches from Sebastian van de Meer < | ||
| + | # released under the GNU General Public License | ||
| + | |||
| + | use RRDs; | ||
| + | use POSIX qw(uname); | ||
| + | |||
| + | my $VERSION = " | ||
| + | |||
| + | my $host = (POSIX:: | ||
| + | my $scriptname = $ENV{" | ||
| + | my $xpoints = 800; | ||
| + | my $points_per_sample = 3; | ||
| + | my $ypoints = 160; | ||
| + | my $rrd = '/ | ||
| + | my $rrd_virus = '/ | ||
| + | my $rrd_grey | ||
| + | my $rrd_dane | ||
| + | my $rrd_dmarc = '/ | ||
| + | my $rrd_smtpd = '/ | ||
| + | my $rrd_queue = '/ | ||
| + | my $rrd_post | ||
| + | |||
| + | my $tmp_dir = '/ | ||
| + | my @graphs = ( | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | ); | ||
| + | |||
| + | my %color = ( # rrggbb in hex | ||
| + | # n | ||
| + | sent => ' | ||
| + | received | ||
| + | |||
| + | bounced | ||
| + | virus => ' | ||
| + | spam => ' | ||
| + | rejected | ||
| + | |||
| + | greylisted | ||
| + | delayed | ||
| + | whitelist | ||
| + | awl => ' | ||
| + | early => ' | ||
| + | |||
| + | pswl => ' | ||
| + | psbl => ' | ||
| + | passold | ||
| + | veto => ' | ||
| + | pregreet | ||
| + | dnsbl => ' | ||
| + | pipelining | ||
| + | nonsmtp | ||
| + | barenewline | ||
| + | command | ||
| + | hangup | ||
| + | passnew | ||
| + | |||
| + | new => ' | ||
| + | reconnectok | ||
| + | |||
| + | active | ||
| + | deferred | ||
| + | |||
| + | untrustedtls | ||
| + | anonymoustls | ||
| + | trustedtls | ||
| + | verifiedtls | ||
| + | |||
| + | untrustedtlsin | ||
| + | anonymoustlsin | ||
| + | trustedtlsin | ||
| + | |||
| + | spfnone | ||
| + | spffail | ||
| + | spfpass | ||
| + | |||
| + | dkimnone | ||
| + | dkimfail | ||
| + | dkimpass | ||
| + | |||
| + | dmarcnone | ||
| + | dmarcfail | ||
| + | dmarcpass | ||
| + | ); | ||
| + | |||
| + | my $url = " | ||
| + | my $urlg = " | ||
| + | my $url1 = " | ||
| + | my $url2 = " | ||
| + | my $url3 = " | ||
| + | my $url4 = " | ||
| + | my $url11 = " | ||
| + | my $url12 = " | ||
| + | my $url13 = " | ||
| + | my $url14 = " | ||
| + | |||
| + | sub rrd_graph(@) | ||
| + | { | ||
| + | my ($range, $file, $ypoints, @rrdargs) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | my $end = time; $end -= $end % $step; | ||
| + | my $date = localtime(time); | ||
| + | $date =~ s|:|\\:|g unless $RRDs:: | ||
| + | |||
| + | my ($graphret, | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | $RRDs:: | ||
| + | |||
| + | @rrdargs, | ||
| + | |||
| + | ' | ||
| + | ); | ||
| + | |||
| + | my $ERR=RRDs:: | ||
| + | die " | ||
| + | } | ||
| + | |||
| + | sub graph($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_virus($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | sub graph_greylist($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | sub graph_greystats($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_postscreen($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_postscreenstats($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_dane($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_smtpd($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_spf($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_dkim($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_dmarc($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_queue($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | sub print_html() | ||
| + | { | ||
| + | print " | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | <meta http-equiv=" | ||
| + | <link rel=" | ||
| + | </ | ||
| + | < | ||
| + | HEADER | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | #print "<a href=' | ||
| + | print "<a href=' | ||
| + | |||
| + | print "< | ||
| + | for my $n (0..$# | ||
| + | print " | ||
| + | } | ||
| + | print "</ | ||
| + | |||
| + | for my $n (0..$# | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | } | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | <table border=" | ||
| + | < | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | < | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | </ | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | FOOTER | ||
| + | } | ||
| + | |||
| + | sub send_image($) | ||
| + | { | ||
| + | my ($file)= @_; | ||
| + | |||
| + | -r $file or do { | ||
| + | print " | ||
| + | exit 1; | ||
| + | }; | ||
| + | |||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | open(IMG, $file) or die; | ||
| + | my $data; | ||
| + | print $data while read(IMG, $data, 16384)> | ||
| + | } | ||
| + | |||
| + | sub main() | ||
| + | { | ||
| + | my $uri = $ENV{REQUEST_URI} || ''; | ||
| + | $uri =~ s/ | ||
| + | $uri =~ s/ | ||
| + | $uri =~ s/ | ||
| + | mkdir $tmp_dir, 0777 unless -d $tmp_dir; | ||
| + | mkdir " | ||
| + | |||
| + | my $img = $ENV{QUERY_STRING}; | ||
| + | if(defined $img and $img =~ /\S/) { | ||
| + | if($img =~ / | ||
| + | my $file = " | ||
| + | graph($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_virus($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_greylist($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_greystats($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_postscreen($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_postscreenstats($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_queue($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dane($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_smtpd($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_spf($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dkim($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dmarc($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | else { | ||
| + | die " | ||
| + | } | ||
| + | } | ||
| + | else { | ||
| + | print_html; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | main; | ||
| + | </ | ||
| + | |||
| + | === / | ||
| + | # vim / | ||
| + | <file perl / | ||
| + | |||
| + | # 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 < | ||
| + | # patches from Sebastian van de Meer < | ||
| + | # released under the GNU General Public License | ||
| + | |||
| + | use RRDs; | ||
| + | use POSIX qw(uname); | ||
| + | |||
| + | my $VERSION = " | ||
| + | |||
| + | my $host = (POSIX:: | ||
| + | my $scriptname = $ENV{" | ||
| + | my $xpoints = 800; | ||
| + | my $points_per_sample = 3; | ||
| + | my $ypoints = 160; | ||
| + | my $rrd = '/ | ||
| + | my $rrd_virus = '/ | ||
| + | my $rrd_grey | ||
| + | my $rrd_dane | ||
| + | my $rrd_dmarc = '/ | ||
| + | my $rrd_smtpd = '/ | ||
| + | my $rrd_queue = '/ | ||
| + | my $rrd_post | ||
| + | |||
| + | my $tmp_dir = '/ | ||
| + | my @graphs = ( | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | ); | ||
| + | |||
| + | my %color = ( # rrggbb in hex | ||
| + | # n | ||
| + | sent => ' | ||
| + | received | ||
| + | |||
| + | bounced | ||
| + | virus => ' | ||
| + | spam => ' | ||
| + | rejected | ||
| + | |||
| + | greylisted | ||
| + | delayed | ||
| + | whitelist | ||
| + | awl => ' | ||
| + | early => ' | ||
| + | |||
| + | pswl => ' | ||
| + | psbl => ' | ||
| + | passold | ||
| + | veto => ' | ||
| + | pregreet | ||
| + | dnsbl => ' | ||
| + | pipelining | ||
| + | nonsmtp | ||
| + | barenewline | ||
| + | command | ||
| + | hangup | ||
| + | passnew | ||
| + | |||
| + | new => ' | ||
| + | reconnectok | ||
| + | |||
| + | active | ||
| + | deferred | ||
| + | |||
| + | untrustedtls | ||
| + | anonymoustls | ||
| + | trustedtls | ||
| + | verifiedtls | ||
| + | |||
| + | untrustedtlsin | ||
| + | anonymoustlsin | ||
| + | trustedtlsin | ||
| + | |||
| + | spfnone | ||
| + | spffail | ||
| + | spfpass | ||
| + | |||
| + | dkimnone | ||
| + | dkimfail | ||
| + | dkimpass | ||
| + | |||
| + | dmarcnone | ||
| + | dmarcfail | ||
| + | dmarcpass | ||
| + | ); | ||
| + | |||
| + | my $url = " | ||
| + | my $urlg = " | ||
| + | my $url1 = " | ||
| + | my $url2 = " | ||
| + | my $url3 = " | ||
| + | my $url4 = " | ||
| + | my $url11 = " | ||
| + | my $url12 = " | ||
| + | my $url13 = " | ||
| + | my $url14 = " | ||
| + | |||
| + | sub rrd_graph(@) | ||
| + | { | ||
| + | my ($range, $file, $ypoints, @rrdargs) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | my $end = time; $end -= $end % $step; | ||
| + | my $date = localtime(time); | ||
| + | $date =~ s|:|\\:|g unless $RRDs:: | ||
| + | |||
| + | my ($graphret, | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | $RRDs:: | ||
| + | |||
| + | @rrdargs, | ||
| + | |||
| + | ' | ||
| + | ); | ||
| + | |||
| + | my $ERR=RRDs:: | ||
| + | die " | ||
| + | } | ||
| + | |||
| + | sub graph($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_virus($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | sub graph_greylist($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | sub graph_greystats($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_postscreen($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_postscreenstats($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_dane($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_smtpd($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_spf($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_dkim($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_dmarc($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_queue($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | sub print_html() | ||
| + | { | ||
| + | print " | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | <meta http-equiv=" | ||
| + | <link rel=" | ||
| + | </ | ||
| + | < | ||
| + | HEADER | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | #print "<a href=' | ||
| + | |||
| + | print "< | ||
| + | for my $n (0..$# | ||
| + | print " | ||
| + | } | ||
| + | print "</ | ||
| + | |||
| + | for my $n (0..$# | ||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | } | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | <table border=" | ||
| + | < | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | < | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | </ | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | FOOTER | ||
| + | } | ||
| + | |||
| + | sub send_image($) | ||
| + | { | ||
| + | my ($file)= @_; | ||
| + | |||
| + | -r $file or do { | ||
| + | print " | ||
| + | exit 1; | ||
| + | }; | ||
| + | |||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | open(IMG, $file) or die; | ||
| + | my $data; | ||
| + | print $data while read(IMG, $data, 16384)> | ||
| + | } | ||
| + | |||
| + | sub main() | ||
| + | { | ||
| + | my $uri = $ENV{REQUEST_URI} || ''; | ||
| + | $uri =~ s/ | ||
| + | $uri =~ s/ | ||
| + | $uri =~ s/ | ||
| + | mkdir $tmp_dir, 0777 unless -d $tmp_dir; | ||
| + | mkdir " | ||
| + | |||
| + | my $img = $ENV{QUERY_STRING}; | ||
| + | if(defined $img and $img =~ /\S/) { | ||
| + | if($img =~ / | ||
| + | my $file = " | ||
| + | graph($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_virus($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_greylist($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_greystats($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_postscreen($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_postscreenstats($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_queue($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dane($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_smtpd($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_spf($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dkim($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dmarc($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | else { | ||
| + | die " | ||
| + | } | ||
| + | } | ||
| + | else { | ||
| + | print_html; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | main; | ||
| + | </ | ||
| + | |||
| + | ==== CGI-Erweiterung für die Σ-Seite ==== | ||
| + | Wie auch schon bei den Einzelstatistiken sind bei der Σ-Seite, die die kumulierten Einzelgraphen enthält, umfangreichere Änderungen/ | ||
| + | |||
| + | === Datenquellen === | ||
| + | Da wir bei der Gesamtstatistik die Summe der einzelnen Mailserver zur Anzeige bringen wollen, benötigen wir daher auch alle Datenquellen. Die Anzahl der Variablen **$rrd_* ** erhöht sich daher entsprechend! | ||
| + | <code perl>... | ||
| + | |||
| + | my $rrd_11 | ||
| + | my $rrd_12 | ||
| + | my $rrd_13 | ||
| + | my $rrd_14 | ||
| + | my $rrd_virus_11 | ||
| + | my $rrd_virus_12 | ||
| + | my $rrd_virus_13 | ||
| + | my $rrd_virus_14 | ||
| + | my $rrd_grey_11 | ||
| + | my $rrd_grey_12 | ||
| + | my $rrd_grey_13 | ||
| + | my $rrd_grey_14 | ||
| + | my $rrd_dane_11 | ||
| + | my $rrd_dane_12 | ||
| + | my $rrd_dane_13 | ||
| + | my $rrd_dane_14 | ||
| + | my $rrd_dmarc_11 | ||
| + | my $rrd_dmarc_12 | ||
| + | my $rrd_dmarc_13 | ||
| + | my $rrd_dmarc_14 | ||
| + | my $rrd_smtpd_11 | ||
| + | my $rrd_smtpd_12 | ||
| + | my $rrd_smtpd_13 | ||
| + | my $rrd_smtpd_14 | ||
| + | my $rrd_queue_11 | ||
| + | my $rrd_queue_12 | ||
| + | my $rrd_queue_13 | ||
| + | my $rrd_queue_14 | ||
| + | my $rrd_post_11 | ||
| + | my $rrd_post_12 | ||
| + | my $rrd_post_13 | ||
| + | my $rrd_post_14 | ||
| + | |||
| + | ... | ||
| + | </ | ||
| + | |||
| + | === URL-Definitionen === | ||
| + | Damit die Seite bei Portierungen ohne große Änderungen im Code realisiert werden können, wird für die Querverweise jeweils zugehörige URL's definiert. | ||
| + | |||
| + | <code perl>... | ||
| + | |||
| + | my $url = " | ||
| + | my $urlg = " | ||
| + | my $url1 = " | ||
| + | my $url2 = " | ||
| + | my $url3 = " | ||
| + | my $url4 = " | ||
| + | my $url11 = " | ||
| + | my $url12 = " | ||
| + | my $url13 = " | ||
| + | my $url14 = " | ||
| + | |||
| + | |||
| + | ... | ||
| + | </ | ||
| + | |||
| + | === Unterprogramme graph_xxx - kumulierte Werte für die Generierung der RRD-Graphiken === | ||
| + | Bei der Generierung der kumulierten Graphiken stellt sich grundsätzlich die Frage, wie führt man den Inhalt mehrerer RRD-Dateien zusammen um einen Summengraph zu erstellen. Anstatt nun einen neue RRD-Datei mit dem Inhalt der vier einzelnen RRD-Dateien zu erstellen um daraus dann den Graphen zu generieren, wählen wir einen anderen Weg. Bei der Erstellung eines Summengraphen mit Hilfe von **RRD_GRAPH** bedienen wir uns nicht nur einer Quelle (RRD-Datei), | ||
| + | |||
| + | Dazu müssen wir im ersten Schritt **alle Datenquellen** beim RRD_GRAPH Parameter **DEF** benennen. Somit wird z.B. beim Graphen mit den nicht angenommenen Nachrichten **Rejected** statt der **beiden Zeilen** < | ||
| + | " | ||
| + | " | ||
| + | </ | ||
| + | entsprechend **acht Zeilen** | ||
| + | < | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | </ | ||
| + | |||
| + | Bei der Generierung der eigentlichen Graphen ziehen wir die **Summe der vier RRD-Dateien** heran, egal ob eine einfache Fläche, ein gestapelter Bereich oder ein Liniengraph erzeugt werden soll. Beim RRD_GRAPH Parameter **CDEF** lassen wir daher die Summe aus den Variablen // | ||
| + | |||
| + | Hierzu verwenden wir die //RRD_GRAPH eigene Berechnungssyntax// | ||
| + | |||
| + | Im Falle unseres Graphen über die Abgelehneten Nachrichten (**rejected**) berechnet sich die Gesamtsumme also wie folgt: \\ < | ||
| + | |||
| + | Daraus wird dann in der //RRD_GRAPH eigenen Berechnungssyntax//: | ||
| + | | ||
| + | |||
| + | Anstatt der ursprünglichen **CDEF**-Definitionen | ||
| + | < | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | </ | ||
| + | verwenden wir also nachfolgende **CDEF**-Definitionen: | ||
| + | |||
| + | < | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | </ | ||
| + | |||
| + | Diese Änderungen tragen wir nun bei den Unterprogrammen **graph_xxx** nach. | ||
| + | |||
| + | === Unterprogramm print_html | ||
| + | Wie auch schon bei den [[centos: | ||
| + | <code perl> | ||
| + | |||
| + | sub print_html() | ||
| + | { | ||
| + | print " | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | <meta http-equiv=" | ||
| + | <link rel=" | ||
| + | </ | ||
| + | < | ||
| + | HEADER | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | for my $n (0..$# | ||
| + | print " | ||
| + | } | ||
| + | print "</ | ||
| + | |||
| + | for my $n (0..$# | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | } | ||
| + | |||
| + | print << | ||
| + | <hr/> | ||
| + | <table border=" | ||
| + | < | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </td> | ||
| + | <td> | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </td> | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | </td> | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | </td> | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </td> | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | FOOTER | ||
| + | } | ||
| + | |||
| + | ... | ||
| + | </ | ||
| + | |||
| + | |||
| + | === CGI-Script für die ∑-Auswertung === | ||
| + | Mit allen Änderungen und Erweiterungen ergibt sich dann folgendes Gesamt-CGI-Script: | ||
| + | # vim / | ||
| + | |||
| + | <file perl / | ||
| + | |||
| + | # 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 < | ||
| + | # patches from Sebastian van de Meer < | ||
| + | # released under the GNU General Public License | ||
| + | |||
| + | use RRDs; | ||
| + | use POSIX qw(uname); | ||
| + | |||
| + | my $VERSION = " | ||
| + | |||
| + | my $host = (POSIX:: | ||
| + | my $scriptname = $ENV{" | ||
| + | my $xpoints | ||
| + | my $points_per_sample = 3; | ||
| + | my $ypoints | ||
| + | my $rrd_11 | ||
| + | my $rrd_12 | ||
| + | my $rrd_13 | ||
| + | my $rrd_14 | ||
| + | my $rrd_virus_11 | ||
| + | my $rrd_virus_12 | ||
| + | my $rrd_virus_13 | ||
| + | my $rrd_virus_14 | ||
| + | my $rrd_grey_11 | ||
| + | my $rrd_grey_12 | ||
| + | my $rrd_grey_13 | ||
| + | my $rrd_grey_14 | ||
| + | my $rrd_dane_11 | ||
| + | my $rrd_dane_12 | ||
| + | my $rrd_dane_13 | ||
| + | my $rrd_dane_14 | ||
| + | my $rrd_dmarc_11 | ||
| + | my $rrd_dmarc_12 | ||
| + | my $rrd_dmarc_13 | ||
| + | my $rrd_dmarc_14 | ||
| + | my $rrd_smtpd_11 | ||
| + | my $rrd_smtpd_12 | ||
| + | my $rrd_smtpd_13 | ||
| + | my $rrd_smtpd_14 | ||
| + | my $rrd_queue_11 | ||
| + | my $rrd_queue_12 | ||
| + | my $rrd_queue_13 | ||
| + | my $rrd_queue_14 | ||
| + | my $rrd_post_11 | ||
| + | my $rrd_post_12 | ||
| + | my $rrd_post_13 | ||
| + | my $rrd_post_14 | ||
| + | |||
| + | my $tmp_dir = '/ | ||
| + | my @graphs = ( | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | { title => ' | ||
| + | ); | ||
| + | |||
| + | my %color = ( # rrggbb in hex | ||
| + | # n | ||
| + | sent => ' | ||
| + | received | ||
| + | |||
| + | bounced | ||
| + | virus => ' | ||
| + | spam => ' | ||
| + | rejected | ||
| + | |||
| + | greylisted | ||
| + | delayed | ||
| + | whitelist | ||
| + | awl => ' | ||
| + | early => ' | ||
| + | |||
| + | pswl => ' | ||
| + | psbl => ' | ||
| + | passold | ||
| + | veto => ' | ||
| + | pregreet | ||
| + | dnsbl => ' | ||
| + | pipelining | ||
| + | nonsmtp | ||
| + | barenewline | ||
| + | command | ||
| + | hangup | ||
| + | passnew | ||
| + | |||
| + | new => ' | ||
| + | reconnectok | ||
| + | |||
| + | active | ||
| + | deferred | ||
| + | |||
| + | untrustedtls | ||
| + | anonymoustls | ||
| + | trustedtls | ||
| + | verifiedtls | ||
| + | |||
| + | untrustedtlsin | ||
| + | anonymoustlsin | ||
| + | trustedtlsin | ||
| + | |||
| + | spfnone | ||
| + | spffail | ||
| + | spfpass | ||
| + | |||
| + | dkimnone | ||
| + | dkimfail | ||
| + | dkimpass | ||
| + | |||
| + | dmarcnone | ||
| + | dmarcfail | ||
| + | dmarcpass | ||
| + | ); | ||
| + | |||
| + | my $url = " | ||
| + | my $url1 = " | ||
| + | my $url2 = " | ||
| + | my $url3 = " | ||
| + | my $url4 = " | ||
| + | my $url11 | ||
| + | my $url12 | ||
| + | my $url13 | ||
| + | my $url14 | ||
| + | |||
| + | sub rrd_graph(@) | ||
| + | { | ||
| + | my ($range, $file, $ypoints, @rrdargs) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | my $end = time; $end -= $end % $step; | ||
| + | my $date = localtime(time); | ||
| + | $date =~ s|:|\\:|g unless $RRDs:: | ||
| + | |||
| + | my ($graphret, | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | $RRDs:: | ||
| + | |||
| + | @rrdargs, | ||
| + | |||
| + | ' | ||
| + | ); | ||
| + | |||
| + | my $ERR=RRDs:: | ||
| + | die " | ||
| + | } | ||
| + | |||
| + | sub graph($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_virus($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | sub graph_greylist($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | sub graph_greystats($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | |||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_postscreen($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_postscreenstats($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_dane($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_smtpd($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_spf($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_dkim($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | sub graph_dmarc($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | sub graph_queue($$) | ||
| + | { | ||
| + | my ($range, $file) = @_; | ||
| + | my $step = $range*$points_per_sample/ | ||
| + | rrd_graph($range, | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | |||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ' | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | sub print_html() | ||
| + | { | ||
| + | print " | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | < | ||
| + | <meta http-equiv=" | ||
| + | <meta http-equiv=" | ||
| + | <link rel=" | ||
| + | </ | ||
| + | < | ||
| + | HEADER | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | for my $n (0..$# | ||
| + | print " | ||
| + | } | ||
| + | print "</ | ||
| + | |||
| + | for my $n (0..$# | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | | ||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | |||
| + | print "< | ||
| + | print "< | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "<a href=' | ||
| + | print "< | ||
| + | } | ||
| + | |||
| + | print << | ||
| + | < | ||
| + | <table border=" | ||
| + | < | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | <col width=" | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | < | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | </ | ||
| + | < | ||
| + | <td class=" | ||
| + | </ | ||
| + | <td class=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | <a href=" | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | FOOTER | ||
| + | } | ||
| + | |||
| + | sub send_image($) | ||
| + | { | ||
| + | my ($file)= @_; | ||
| + | |||
| + | -r $file or do { | ||
| + | print " | ||
| + | exit 1; | ||
| + | }; | ||
| + | |||
| + | print " | ||
| + | print " | ||
| + | print " | ||
| + | open(IMG, $file) or die; | ||
| + | my $data; | ||
| + | print $data while read(IMG, $data, 16384)> | ||
| + | } | ||
| + | |||
| + | sub main() | ||
| + | { | ||
| + | my $uri = $ENV{REQUEST_URI} || ''; | ||
| + | $uri =~ s/ | ||
| + | $uri =~ s/ | ||
| + | $uri =~ s/ | ||
| + | mkdir $tmp_dir, 0777 unless -d $tmp_dir; | ||
| + | mkdir " | ||
| + | |||
| + | my $img = $ENV{QUERY_STRING}; | ||
| + | if(defined $img and $img =~ /\S/) { | ||
| + | if($img =~ / | ||
| + | my $file = " | ||
| + | graph($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_virus($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_greylist($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_greystats($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_postscreen($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_postscreenstats($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_queue($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dane($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_smtpd($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_spf($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dkim($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | elsif($img =~ / | ||
| + | my $file = " | ||
| + | graph_dmarc($graphs[$1]{seconds}, | ||
| + | send_image($file); | ||
| + | } | ||
| + | else { | ||
| + | die " | ||
| + | } | ||
| + | } | ||
| + | else { | ||
| + | print_html; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | main; | ||
| + | </ | ||
| + | |||
| + | ==== Apache VHost anlegen ==== | ||
| + | Damit wir bequem von unserem Browser aus, die aktuellen Graphiken abfragen können, bearbeiten wir entweder die aus dem RPM stammende Konfigurationsdatei oder legen wir nun einen passenden VHost an. | ||
| + | # vim / | ||
| + | <file apache / | ||
| + | # | ||
| + | # mailgraph.nausch.org | ||
| + | # | ||
| + | < | ||
| + | ServerAdmin webmaster@nausch.org | ||
| + | ServerName mailgraph.nausch.org | ||
| + | ServerAlias www.mailgraph.nausch.org | ||
| + | ServerPath / | ||
| + | DocumentRoot "/ | ||
| + | AddHandler cgi-script .cgi | ||
| + | |||
| + | < | ||
| + | AllowOverride None | ||
| + | Options +ExecCGI | ||
| + | DirectoryIndex mailgraph.cgi | ||
| + | require IP 10.0. | ||
| + | </ | ||
| + | < | ||
| + | AllowOverride None | ||
| + | Options +ExecCGI | ||
| + | DirectoryIndex mailgraph.cgi | ||
| + | require IP 10.0. | ||
| + | </ | ||
| + | < | ||
| + | AllowOverride None | ||
| + | Options +ExecCGI | ||
| + | DirectoryIndex mailgraph.cgi | ||
| + | require IP 10.0. | ||
| + | </ | ||
| + | < | ||
| + | AllowOverride None | ||
| + | Options +ExecCGI | ||
| + | DirectoryIndex mailgraph.cgi | ||
| + | require IP 10.0. | ||
| + | </ | ||
| + | < | ||
| + | AllowOverride None | ||
| + | Options +ExecCGI | ||
| + | DirectoryIndex mailgraph.cgi | ||
| + | require IP 10.0. | ||
| + | </ | ||
| + | |||
| + | ErrorLog logs/ | ||
| + | CustomLog logs/ | ||
| + | </ | ||
| + | |||
| + | |||
| + | </ | ||
| + | |||
| + | Bevor wir bei unserem Webserver eine Reload der Konfiguration vornehmen, testen wir unsere neue Konfigurationsdatei auf syntaktische Fehler. | ||
| + | # apachectl -t | ||
| + | |||
| + | | ||
| + | |||
| + | Da keine Fehler aufgetreten sind, aktivieren wir die neue Konfiguration durch einen Reload des Webserver-Daemon. | ||
| + | # systemctl reload postfix | ||
| + | |||
| + | ==== NGiNX vHost anlegen ==== | ||
| + | Nutzen wir als Webserver **[[centos: | ||
| + | # vim / | ||
| + | <file http / | ||
| + | listen | ||
| + | server_name | ||
| + | access_log | ||
| + | error_log | ||
| + | |||
| + | root / | ||
| + | index mailgraph.cgi; | ||
| + | |||
| + | | ||
| + | fastcgi_split_path_info ^(.+\.cgi)(/ | ||
| + | fastcgi_index mailgraph.cgi; | ||
| + | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; | ||
| + | include fastcgi_params; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Den Parameter **fastcgi_pass** setzen wir im übrigen auf den Wert aus der Konfigurationsdatei // | ||
| + | |||
| + | Haben wir die Konfigurationsdatei vervollständigt, | ||
| + | # nginx -t | ||
| + | |||
| + | | ||
| + | | ||
| + | |||
| + | Somit können wir unsere Konfiguration nun noch aktivieren. | ||
| + | # systemctl reload nginx | ||
| + | |||
| + | ==== Webaufruf ==== | ||
| + | Rufen wir nun die definierte Webseite unserer Gesamtstatistikübersicht auf, erhalten wir nachfolgende Ansicht. | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | Hier können wir nun gezielt einzelne Systeme auswählen, bzw. bei einer ausgewählten Detailstatistikseite zur Summenseite hin und her wechseln. | ||
| + | ===== AWStats ===== | ||
| + | Auch mit Hilfe des Projektes/ | ||
| + | |||
| + | ==== Installation ==== | ||
| + | Die Grundinstallation von **// | ||
| + | |||
| + | ==== Konfiguration ==== | ||
| + | Zur eigentlichen Logfileauswertung legen wir uns nun eine eigene Konfigurationdatei für // | ||
| + | # cp / | ||
| + | |||
| + | Darin passen wir nun alle Konfigurationsoptionen, | ||
| + | # vim / | ||
| + | <file bash / | ||
| + | # | ||
| + | # Copy this file into awstats.www.mydomain.conf and edit this new config file | ||
| + | # to setup AWStats (See documentation in docs/ directory). | ||
| + | # The config file must be in / | ||
| + | # Unix/Linux) or same directory than awstats.pl (Windows, Mac, Unix/ | ||
| + | # To include an environment variable in any parameter (AWStats will replace | ||
| + | # it with its value when reading it), follow the example: | ||
| + | # Parameter=" | ||
| + | # Note that environment variable AWSTATS_CURRENT_CONFIG is always defined with | ||
| + | # the config value in an AWStats running session and can be used like others. | ||
| + | # | ||
| + | # $Revision: 1.350 $ - $Author: eldy $ - $Date: 2010/09/29 19:16:21 $ | ||
| + | |||
| + | |||
| + | |||
| + | # | ||
| + | # MAIN SETUP SECTION (Required to make AWStats work) | ||
| + | # | ||
| + | |||
| + | # " | ||
| + | # Possible values: A full path, or a relative path from awstats.pl directory. | ||
| + | # Example: "/ | ||
| + | # Example: " | ||
| + | # You can also use tags in this filename if you need a dynamic file name | ||
| + | # depending on date or time (Replacement is made by AWStats at the beginning | ||
| + | # of its execution). This is available tags : | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # use n=24 if you need (1-7, 1=monday) | ||
| + | # | ||
| + | # use n=24 if you need (0-6, 0=monday) | ||
| + | # Use 0 for n if you need current year, month, day, hour... | ||
| + | # Example: "/ | ||
| + | # Example: " | ||
| + | # You can also use a pipe if log file come from a pipe : | ||
| + | # Example: "gzip -d </ | ||
| + | # If there are several log files from load balancing servers : | ||
| + | # Example: "/ | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: LogFile="/ | ||
| + | LogFile=" | ||
| + | |||
| + | # Enter the log file type you want to analyze. | ||
| + | # Possible values: | ||
| + | # W - For a web log file | ||
| + | # S - For a streaming log file | ||
| + | # M - For a mail log file | ||
| + | # F - For a ftp log file | ||
| + | # Example: W | ||
| + | # Default: W | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: LogType=W | ||
| + | LogType=M | ||
| + | |||
| + | # Enter here your log format (Must match your web server config. See setup | ||
| + | # instructions in documentation to know how to configure your web server to | ||
| + | # have the required log format). | ||
| + | # Possible values: 1,2,3,4 or " | ||
| + | # 1 - Apache or Lotus Notes/ | ||
| + | # 2 - IIS or ISA format (IIS W3C log format). See FAQ-COM115 For ISA. | ||
| + | # 3 - Webstar native log format. | ||
| + | # 4 - Apache or Squid native common log format (NCSA common/CLF log format) | ||
| + | # With LogFormat=4, | ||
| + | # " | ||
| + | # you must use following keys to define the log format string (See FAQ for | ||
| + | # ftp, mail or exotic web log format examples): | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # will discard records not in SiteDomain nor HostAliases | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # If your log format has some fields not included in this list, use: | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # Examples for Apache combined logs (following two examples are equivalent): | ||
| + | # LogFormat = 1 | ||
| + | # LogFormat = "%host %other %logname %time1 %methodurl %code %bytesd %refererquot %uaquot" | ||
| + | # | ||
| + | # Example for IIS: | ||
| + | # LogFormat = 2 | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: LogFormat=1 | ||
| + | LogFormat=" | ||
| + | |||
| + | |||
| + | # If your log field' | ||
| + | # This parameter is not used if LogFormat is a predefined value (1,2,3,4) | ||
| + | # Backslash can be used as escape character. | ||
| + | # Example: " " | ||
| + | # Example: " | ||
| + | # Example: " | ||
| + | # Example: "," | ||
| + | # Default: " " | ||
| + | # | ||
| + | LogSeparator=" | ||
| + | |||
| + | |||
| + | # " | ||
| + | # server name, used to reach the web site. | ||
| + | # If you share the same log file for several virtual web servers, this | ||
| + | # parameter is used to tell AWStats to filter record that contains records for | ||
| + | # this virtual host name only (So check that this virtual hostname can be | ||
| + | # found in your log file and use a personalized log format that include the | ||
| + | # %virtualname tag). | ||
| + | # But for multi hosting a better solution is to have one log file for each | ||
| + | # virtual web server. In this case, this parameter is only used to generate | ||
| + | # full URL's links when ShowLinksOnUrl option is set to 1. | ||
| + | # If analyzing mail log, enter here the domain name of mail server. | ||
| + | # Example: " | ||
| + | # Example: " | ||
| + | # Example: " | ||
| + | # Example: " | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: SiteDomain=" | ||
| + | SiteDomain=" | ||
| + | |||
| + | # Enter here all other possible domain names, addresses or virtual host | ||
| + | # aliases someone can use to access your site. Try to keep only the minimum | ||
| + | # number of possible names/ | ||
| + | # You can repeat the " | ||
| + | # This parameter is used to analyze referer field in log file and to help | ||
| + | # AWStats to know if a referer URL is a local URL of same site or an URL of | ||
| + | # another site. | ||
| + | # Note: Use space between each value. | ||
| + | # Note: You can use regular expression values writing value with REGEX[value]. | ||
| + | # Note: You can also use @/ | ||
| + | # Example: " | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: HostAliases=" | ||
| + | HostAliases=„localhost 127.0.0.1 REGEX[nausch\.org$] REGEX[www\.nausch\.org$]“ | ||
| + | |||
| + | |||
| + | # If you want to have hosts reported by name instead of ip address, AWStats | ||
| + | # need to make reverse DNS lookups (if not already done in your log file). | ||
| + | # With DNSLookup to 0, all hosts will be reported by their IP addresses and | ||
| + | # not by the full hostname of visitors (except if names are already available | ||
| + | # in log file). | ||
| + | # If you want/need to set DNSLookup to 1, don't forget that this will reduce | ||
| + | # dramatically AWStats update process speed. Do not use on large web sites. | ||
| + | # Note: Reverse DNS lookup is done on IPv4 only (Enable ipv6 plugin for IPv6). | ||
| + | # Note: Result of DNS Lookup can be used to build the Country report. However | ||
| + | # it is highly recommanded to enable the plugin ' | ||
| + | # have an accurate Country report with no need of DNS Lookup. | ||
| + | # Possible values: | ||
| + | # 0 - No DNS Lookup | ||
| + | # 1 - DNS Lookup is fully enabled | ||
| + | # 2 - DNS Lookup is made only from static DNS cache file (if it exists) | ||
| + | # Default: 2 | ||
| + | # | ||
| + | DNSLookup=2 | ||
| + | |||
| + | |||
| + | # When AWStats updates its statistics, it stores results of its analysis in | ||
| + | # files (AWStats database). All those files are written in the directory | ||
| + | # defined by the " | ||
| + | # you want AWStats to save its database and working files into. | ||
| + | # Warning: If you want to be able to use the " | ||
| + | # feature (see later), you need " | ||
| + | # directory (and " | ||
| + | # Example: "/ | ||
| + | # Example: " | ||
| + | # Example: " | ||
| + | # Default: " | ||
| + | # | ||
| + | DirData="/ | ||
| + | |||
| + | |||
| + | # Relative or absolute web URL of your awstats cgi-bin directory. | ||
| + | # This parameter is used only when AWStats is run from command line | ||
| + | # with -output option (to generate links in HTML reported page). | ||
| + | # Example: "/ | ||
| + | # Default: "/ | ||
| + | # | ||
| + | DirCgi="/ | ||
| + | |||
| + | |||
| + | # Relative or absolute web URL of your awstats icon directory. | ||
| + | # If you build static reports ("... -output > outputpath/ | ||
| + | # path of icon directory relative to the output directory ' | ||
| + | # Example: "/ | ||
| + | # Example: " | ||
| + | # Default: "/ | ||
| + | # | ||
| + | DirIcons="/ | ||
| + | |||
| + | |||
| + | # When this parameter is set to 1, AWStats adds a button on report page to | ||
| + | # allow to " | ||
| + | # made from a browser, AWStats is run as a CGI by the web server user defined | ||
| + | # in your web server (user " | ||
| + | # IIS), so the " | ||
| + | # awstatsMMYYYY[.xxx].txt must be writable by this user. Change permissions if | ||
| + | # necessary to " | ||
| + | # Warning: Update process can be long so you might experience "time out" | ||
| + | # browser errors if you don't launch AWStats frequently enough. | ||
| + | # When set to 0, update is only made when AWStats is run from the command | ||
| + | # line interface (or a task scheduler). | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 0 | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: AllowToUpdateStatsFromBrowser=0 | ||
| + | AllowToUpdateStatsFromBrowser=1 | ||
| + | |||
| + | |||
| + | # AWStats saves and sorts its database on a month basis (except if using | ||
| + | # databasebreak option from command line). | ||
| + | # However, if you choose the -month=all from command line or | ||
| + | # value ' | ||
| + | # needs to reload all data for full year (each month), and sort them, | ||
| + | # requiring a large amount of time, memory and CPU. This might be a problem | ||
| + | # for web hosting providers that offer AWStats for large sites, on shared | ||
| + | # servers, to non CPU cautious customers. | ||
| + | # For this reason, the 'full year' is only enabled on Command Line by default. | ||
| + | # You can change this by setting this parameter to 0, 1, 2 or 3. | ||
| + | # Possible values: | ||
| + | # 0 - Never allowed | ||
| + | # 1 - Allowed on CLI only, -Year- value in combo is not visible | ||
| + | # 2 - Allowed on CLI only, -Year- value in combo is visible but not allowed | ||
| + | # 3 - Possible on CLI and CGI | ||
| + | # Default: 2 | ||
| + | # | ||
| + | AllowFullYearView=2 | ||
| + | |||
| + | |||
| + | |||
| + | # | ||
| + | # OPTIONAL SETUP SECTION (Not required but increase AWStats features) | ||
| + | # | ||
| + | |||
| + | # When the update process runs, AWStats can set a lock file in TEMP or TMP | ||
| + | # directory. This lock is to avoid to have 2 update processes running at the | ||
| + | # same time to prevent unknown conflicts problems and avoid DoS attacks when | ||
| + | # AllowToUpdateStatsFromBrowser is set to 1. | ||
| + | # Because, when you use lock file, you can experience sometimes problems in | ||
| + | # lock file not correctly removed (killed process for example requires that | ||
| + | # you remove the file manualy), this option is not enabled by default (Do | ||
| + | # not enable this option with no console server access). | ||
| + | # Change : Effective immediatly | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 0 | ||
| + | # | ||
| + | EnableLockForUpdate=1 | ||
| + | |||
| + | |||
| + | # AWStats can do reverse DNS lookups through a static DNS cache file that was | ||
| + | # previously created manually. If no path is given in static DNS cache file | ||
| + | # name, AWStats will search DirData directory. This file is never changed. | ||
| + | # This option is not used if DNSLookup=0. | ||
| + | # Note: DNS cache file format is ' | ||
| + | # or just ' | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: "/ | ||
| + | # Default: " | ||
| + | # | ||
| + | DNSStaticCacheFile=" | ||
| + | |||
| + | |||
| + | # AWStats can do reverse DNS lookups through a DNS cache file that was created | ||
| + | # by a previous run of AWStats. This file is erased and recreated after each | ||
| + | # statistics update process. You don't need to create and/or edit it. | ||
| + | # AWStats will read and save this file in DirData directory. | ||
| + | # This option is used only if DNSLookup=1. | ||
| + | # Note: If a DNSStaticCacheFile is available, AWStats will check for DNS | ||
| + | # lookup in DNSLastUpdateCacheFile after checking into DNSStaticCacheFile. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: "/ | ||
| + | # Default: " | ||
| + | # | ||
| + | DNSLastUpdateCacheFile=" | ||
| + | |||
| + | |||
| + | # You can specify specific IP addresses that should NOT be looked up in DNS. | ||
| + | # This option is used only if DNSLookup=1. | ||
| + | # Note: Use space between each value. | ||
| + | # Note: You can use regular expression values writing value with REGEX[value]. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: " | ||
| + | # Default: "" | ||
| + | # | ||
| + | SkipDNSLookupFor="" | ||
| + | |||
| + | |||
| + | # The following two parameters allow you to protect a config file from being | ||
| + | # read by AWStats when called from a browser if web user has not been | ||
| + | # authenticated. Your AWStats program must be in a web protected " | ||
| + | # Apache, you can use .htaccess files to do so. With other web servers, see | ||
| + | # your server setup manual). | ||
| + | # Change : Effective immediatly | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 0 | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: AllowAccessFromWebToAuthenticatedUsersOnly=0 | ||
| + | # | ||
| + | AllowAccessFromWebToAuthenticatedUsersOnly=0 | ||
| + | |||
| + | |||
| + | # This parameter gives the list of all authorized authenticated users to view | ||
| + | # statistics for this domain/ | ||
| + | # AllowAccessFromWebToAuthenticatedUsersOnly is set to 1. | ||
| + | # Change : Effective immediatly | ||
| + | # Example: "user1 user2" | ||
| + | # Example: " | ||
| + | # Default: "" | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: AllowAccessFromWebToFollowingAuthenticatedUsers="" | ||
| + | # AllowAccessFromWebToFollowingAuthenticatedUsers=" | ||
| + | AllowAccessFromWebToFollowingAuthenticatedUsers="" | ||
| + | |||
| + | |||
| + | # When this parameter is defined to something, the IP address of the user that | ||
| + | # reads its statistics from a browser (when AWStats is used as a CGI) is | ||
| + | # checked and must match one of the IP address values or ranges. | ||
| + | # Change : Effective immediatly | ||
| + | # Example: " | ||
| + | # Default: "" | ||
| + | # | ||
| + | AllowAccessFromWebToFollowingIPAddresses="" | ||
| + | |||
| + | |||
| + | # If the " | ||
| + | # error. However, you can ask AWStats to create it. | ||
| + | # This option can be used by some Web Hosting Providers that has defined a | ||
| + | # dynamic value for DirData (for example DirData="/ | ||
| + | # don't want to have to create a new directory each time they add a new user. | ||
| + | # Change : Effective immediatly | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 0 | ||
| + | # | ||
| + | CreateDirDataIfNotExists=0 | ||
| + | |||
| + | |||
| + | # You can choose in which format the Awstats history database is saved. | ||
| + | # Note: Using " | ||
| + | # larger than using " | ||
| + | # Change : Database format is switched after next update | ||
| + | # Possible values: text or xml | ||
| + | # Default: text | ||
| + | # | ||
| + | BuildHistoryFormat=text | ||
| + | |||
| + | |||
| + | # If you prefer having the report output pages be built as XML compliant pages | ||
| + | # instead of simple HTML pages, you can set this to ' | ||
| + | # properly with old browsers). | ||
| + | # Change : Effective immediatly | ||
| + | # Possible values: html or xhtml | ||
| + | # Default: html | ||
| + | # | ||
| + | BuildReportFormat=html | ||
| + | |||
| + | |||
| + | # AWStats databases can be updated from command line of from a browser (when | ||
| + | # used as a cgi program). So AWStats database files need write permission | ||
| + | # for both command line user and default web server user (nobody for Unix, | ||
| + | # IUSR_xxx for IIS/ | ||
| + | # To avoid permission problems between update process (run by an admin user) | ||
| + | # and CGI process (ran by a low level user), AWStats can save its database | ||
| + | # files with read and write permissions for everyone. | ||
| + | # By default, AWStats keeps default user permissions on updated files. If you | ||
| + | # set AllowToUpdateStatsFromBrowser to 1, you can change this parameter to 1. | ||
| + | # Change : Effective for new updates only | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 0 | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: SaveDatabaseFilesWithPermissionsForEveryone=0 | ||
| + | SaveDatabaseFilesWithPermissionsForEveryone=1 | ||
| + | |||
| + | |||
| + | # AWStats can purge log file, after analyzing it. Note that AWStats is able | ||
| + | # to detect new lines in a log file, to process only them, so you can launch | ||
| + | # AWStats as often as you want, even with this parameter to 0. | ||
| + | # With 0, no purge is made, so you must use a scheduled task or a web server | ||
| + | # that make this purge frequently. | ||
| + | # With 1, the purge of the log file is made each time AWStats update is run. | ||
| + | # This parameter doesn' | ||
| + | # file to be purged). | ||
| + | # Change : Effective for new updates only | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 0 | ||
| + | # | ||
| + | PurgeLogFile=0 | ||
| + | |||
| + | |||
| + | # When PurgeLogFile is setup to 1, AWStats will clean your log file after | ||
| + | # processing it. You can however keep an archive file of all processed log | ||
| + | # records by setting this parameter (For example if you want to use another | ||
| + | # log analyzer). The archived log file is saved in " | ||
| + | # awstats_archive.configname[.suffix].log | ||
| + | # This parameter is not used if PurgeLogFile=0 | ||
| + | # Change : Effective for new updates only | ||
| + | # Possible values: 0, 1, or tags (See LogFile parameter) for suffix | ||
| + | # Example: 1 | ||
| + | # Example: %YYYY%MM%DD | ||
| + | # Default: 0 | ||
| + | # | ||
| + | ArchiveLogRecords=0 | ||
| + | |||
| + | |||
| + | # Each time you run the update process, AWStats overwrites the ' | ||
| + | # for the month (awstatsMMYYYY[.*].txt) with the updated one. | ||
| + | # When write errors occurs (IO, disk full,...), this historic file can be | ||
| + | # corrupted and must be deleted. Because this file contains information of all | ||
| + | # past processed log files, you will loose old stats if removed. So you can | ||
| + | # ask AWStats to save last non corrupted file in a .bak file. This file is | ||
| + | # stored in " | ||
| + | # Change : Effective for new updates only | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 0 | ||
| + | # | ||
| + | KeepBackupOfHistoricFiles=1 | ||
| + | |||
| + | |||
| + | # Default index page name for your web server. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: " | ||
| + | # Default: " | ||
| + | # | ||
| + | DefaultFile=" | ||
| + | |||
| + | |||
| + | # Do not include access from clients that match following criteria. | ||
| + | # If your log file contains IP addresses in host field, you must enter here | ||
| + | # matching IP addresses criteria. | ||
| + | # If DNS lookup is already done in your log file, you must enter here hostname | ||
| + | # criteria, else enter ip address criteria. | ||
| + | # The opposite parameter of " | ||
| + | # Note: Use space between each value. This parameter is not case sensitive. | ||
| + | # Note: You can use regular expression values writing value with REGEX[value]. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: " | ||
| + | # Example: " | ||
| + | # Default: "" | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: SkipHosts=" | ||
| + | SkipHosts="" | ||
| + | |||
| + | # Do not include access from clients with a user agent that match following | ||
| + | # criteria. If you want to exclude a robot, you should update the robots.pm | ||
| + | # file instead of this parameter. | ||
| + | # The opposite parameter of " | ||
| + | # Note: Use space between each value. This parameter is not case sensitive. | ||
| + | # Note: You can use regular expression values writing value with REGEX[value]. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: " | ||
| + | # Default: "" | ||
| + | # | ||
| + | SkipUserAgents="" | ||
| + | |||
| + | |||
| + | # Use SkipFiles to ignore access to URLs that match one of following entries. | ||
| + | # You can enter a list of not important URLs (like framed menus, hidden pages, | ||
| + | # etc...) to exclude them from statistics. You must enter here exact relative | ||
| + | # URL as found in log file, or a matching REGEX value. Check apply on URL with | ||
| + | # all its query paramaters. | ||
| + | # For example, to ignore / | ||
| + | # pages in a particular directory, add " | ||
| + | # The opposite parameter of " | ||
| + | # Note: Use space between each value. This parameter is or not case sensitive | ||
| + | # depending on URLNotCaseSensitive parameter. | ||
| + | # Note: You can use regular expression values writing value with REGEX[value]. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: "/ | ||
| + | # Default: "" | ||
| + | # | ||
| + | SkipFiles="" | ||
| + | |||
| + | |||
| + | # Use SkipReferrersBlackList if you want to exclude records coming from a SPAM | ||
| + | # referrer. Parameter must receive a local file name containing rules applied | ||
| + | # on referrer field. If parameter is empty, no filter is applied. | ||
| + | # An example of such a file is available in lib/ | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: "/ | ||
| + | # Default: "" | ||
| + | # | ||
| + | # WARNING!! Using this feature make AWStats running very slower (5 times slower | ||
| + | # with black list file provided with AWStats ! | ||
| + | # | ||
| + | SkipReferrersBlackList="" | ||
| + | |||
| + | |||
| + | # Include in stats, only accesses from hosts that match one of following | ||
| + | # entries. For example, if you want AWStats to filter access to keep only | ||
| + | # stats for visits from particular hosts, you can add those host names in | ||
| + | # this parameter. | ||
| + | # If DNS lookup is already done in your log file, you must enter here hostname | ||
| + | # criteria, else enter ip address criteria. | ||
| + | # The opposite parameter of " | ||
| + | # Note: Use space between each value. This parameter is not case sensitive. | ||
| + | # Note: You can use regular expression values writing value with REGEX[value]. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: " | ||
| + | # Default: "" | ||
| + | # | ||
| + | OnlyHosts="" | ||
| + | |||
| + | |||
| + | # Include in stats, only accesses from user agent that match one of following | ||
| + | # entries. For example, if you want AWStats to filter access to keep only | ||
| + | # stats for visits from particular browsers, you can add their user agents | ||
| + | # string in this parameter. | ||
| + | # The opposite parameter of " | ||
| + | # Note: Use space between each value. This parameter is not case sensitive. | ||
| + | # Note: You can use regular expression values writing value with REGEX[value]. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: " | ||
| + | # Default: "" | ||
| + | # | ||
| + | OnlyUserAgents="" | ||
| + | |||
| + | |||
| + | # Include in stats, only accesses from authenticated users that match one of | ||
| + | # following entries. For example, if you want AWStats to filter access to keep | ||
| + | # only stats for authenticated users, you can add those users names in | ||
| + | # this parameter. Useful for statistics for per user ftp logs. | ||
| + | # Note: Use space between each value. This parameter is not case sensitive. | ||
| + | # Note: You can use regular expression values writing value with REGEX[value]. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: "john bob REGEX[^testusers]" | ||
| + | # Default: "" | ||
| + | # | ||
| + | OnlyUsers="" | ||
| + | |||
| + | |||
| + | # Include in stats, only accesses to URLs that match one of following entries. | ||
| + | # For example, if you want AWStats to filter access to keep only stats that | ||
| + | # match a particular string, like a particular directory, you can add this | ||
| + | # directory name in this parameter. | ||
| + | # The opposite parameter of " | ||
| + | # Note: Use space between each value. This parameter is or not case sensitive | ||
| + | # depending on URLNotCaseSensitive parameter. | ||
| + | # Note: You can use regular expression values writing value with REGEX[value]. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: " | ||
| + | # Default: "" | ||
| + | # | ||
| + | OnlyFiles="" | ||
| + | |||
| + | |||
| + | # Add here a list of kind of url (file extension) that must be counted as | ||
| + | # "Hit only" and not as a " | ||
| + | # image extensions as they are hit downloaded that must be counted but they | ||
| + | # are not viewed pages. URLs with such extensions are not included in the TOP | ||
| + | # Pages/URL report. | ||
| + | # Note: If you want to exclude particular URLs from stats (No Pages and no | ||
| + | # Hits reported), you must use SkipFiles parameter. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: "css js class gif jpg jpeg png bmp ico rss xml swf zip arj rar gz z bz2 wav mp3 wma mpg avi" | ||
| + | # Example: "" | ||
| + | # Default: "css js class gif jpg jpeg png bmp ico rss xml swf" | ||
| + | # | ||
| + | NotPageList=" | ||
| + | |||
| + | |||
| + | # By default, AWStats considers that records found in web log file are | ||
| + | # successful hits if HTTP code returned by server is a valid HTTP code (200 | ||
| + | # and 304). Any other code are reported in HTTP status chart. | ||
| + | # Note that HTTP ' | ||
| + | # default in this list as they are not pages seen by a visitor but are | ||
| + | # protocol exchange codes to tell the browser to ask another page. Because | ||
| + | # this other page will be counted and seen with a 200 or 304 code, if you | ||
| + | # add such codes, you will have 2 pages viewed reported for only one in facts. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: "200 304 302 305" | ||
| + | # Default: "200 304" | ||
| + | # | ||
| + | ValidHTTPCodes=" | ||
| + | |||
| + | |||
| + | # By default, AWStats considers that records found in mail log file are | ||
| + | # successful mail transfers if field that represent return code in analyzed | ||
| + | # log file match values defined by this parameter. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: "1 250 200" | ||
| + | # Default: "1 250" | ||
| + | # | ||
| + | ValidSMTPCodes=" | ||
| + | |||
| + | |||
| + | # Some web servers on some Operating systems (IIS-Windows) consider that a | ||
| + | # login with same value but different case are the same login. To tell AWStats | ||
| + | # to also consider them as one, set this parameter to 1. | ||
| + | # Change : Effective for new updates only | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 0 | ||
| + | # | ||
| + | AuthenticatedUsersNotCaseSensitive=0 | ||
| + | |||
| + | |||
| + | # Some web servers on some Operating systems (IIS-Windows) considers that two | ||
| + | # URLs with same value but different case are the same URL. To tell AWStats to | ||
| + | # also considers them as one, set this parameter to 1. | ||
| + | # Change : Effective for new updates only | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 0 | ||
| + | # | ||
| + | URLNotCaseSensitive=0 | ||
| + | |||
| + | |||
| + | # Keep or remove the anchor string you can find in some URLs. | ||
| + | # Change : Effective for new updates only | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 0 | ||
| + | # | ||
| + | URLWithAnchor=0 | ||
| + | |||
| + | |||
| + | # In URL links, "?" | ||
| + | # / | ||
| + | # However, some servers/ | ||
| + | # their URLs. You can complete this list with all such characters. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: "?;," | ||
| + | # Default: "?;" | ||
| + | # | ||
| + | URLQuerySeparators="?;" | ||
| + | |||
| + | |||
| + | # Keep or remove the query string to the URL in the statistics for individual | ||
| + | # pages. This is primarily used to differentiate between the URLs of dynamic | ||
| + | # pages. If set to 1, mypage.html? | ||
| + | # different pages. | ||
| + | # Warning, when set to 1, memory required to run AWStats is dramatically | ||
| + | # increased if you have a lot of changing URLs (for example URLs with a random | ||
| + | # id inside). Such web sites should not set this option to 1 or use seriously | ||
| + | # the next parameter URLWithQueryWithOnlyFollowingParameters (or eventually | ||
| + | # URLWithQueryWithoutFollowingParameters). | ||
| + | # Change : Effective for new updates only | ||
| + | # Possible values: | ||
| + | # 0 - URLs are cleaned from the query string (ie: "/ | ||
| + | # 1 - Full URL with query string is used (ie: "/ | ||
| + | # Default: 0 | ||
| + | # | ||
| + | URLWithQuery=0 | ||
| + | |||
| + | |||
| + | # When URLWithQuery is on, you will get the full URL with all parameters in | ||
| + | # URL reports. But among thoose parameters, sometimes you don't need a | ||
| + | # particular parameter because it does not identify the page or because it's | ||
| + | # a random ID changing for each access even if URL points to same page. In | ||
| + | # such cases, it is higly recommanded to ask AWStats to keep only parameters | ||
| + | # you need (if you know them) before counting, manipulating and storing URL. | ||
| + | # Enter here list of wanted parameters. For example, with " | ||
| + | # / | ||
| + | # will be reported as 2 hits on / | ||
| + | # This parameter is not used when URLWithQuery is 0 and can't be used with | ||
| + | # URLWithQueryWithoutFollowingParameters. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: " | ||
| + | # Default: "" | ||
| + | # | ||
| + | URLWithQueryWithOnlyFollowingParameters="" | ||
| + | |||
| + | |||
| + | # When URLWithQuery is on, you will get the full URL with all parameters in | ||
| + | # URL reports. But among thoose parameters, sometimes you don't need a | ||
| + | # particular parameter because it does not identify the page or because it's | ||
| + | # a random ID changing for each access even if URL points to same page. In | ||
| + | # such cases, it is higly recommanded to ask AWStats to remove such parameters | ||
| + | # from the URL before counting, manipulating and storing URL. Enter here list | ||
| + | # of all non wanted parameters. For example if you enter " | ||
| + | # / | ||
| + | # will be reported as 2 hits on / | ||
| + | # This parameter is not used when URLWithQuery is 0 and can't be used with | ||
| + | # URLWithQueryWithOnlyFollowingParameters. | ||
| + | # Change : Effective for new updates only | ||
| + | # Example: " | ||
| + | # Default: "" | ||
| + | # | ||
| + | URLWithQueryWithoutFollowingParameters="" | ||
| + | |||
| + | |||
| + | # Keep or remove the query string to the referrer URL in the statistics for | ||
| + | # external referrer pages. This is used to differentiate between the URLs of | ||
| + | # dynamic referrer pages. If set to 1, mypage.html? | ||
| + | # are counted as two different referrer pages. | ||
| + | # Change : Effective for new updates only | ||
| + | # Possible values: | ||
| + | # 0 - Referrer URLs are cleaned from the query string (ie: "/ | ||
| + | # 1 - Full URL with query string is used (ie: "/ | ||
| + | # Default: 0 | ||
| + | # | ||
| + | URLReferrerWithQuery=0 | ||
| + | |||
| + | |||
| + | # AWStats can detect setup problems or show you important informations to have | ||
| + | # a better use. Keep this to 1, except if AWStats says you can change it. | ||
| + | # Change : Effective immediatly | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 1 | ||
| + | # | ||
| + | WarningMessages=1 | ||
| + | |||
| + | |||
| + | # When an error occurs, AWStats outputs a message related to errors. If you | ||
| + | # want (in most cases for security reasons) to have no error messages, you | ||
| + | # can set this parameter to your personalized generic message. | ||
| + | # Change : Effective immediatly | ||
| + | # Example: "An error occurred. Contact your Administrator" | ||
| + | # Default: "" | ||
| + | # | ||
| + | ErrorMessages="" | ||
| + | |||
| + | |||
| + | # AWStat can be run with debug=x parameter to output various informations | ||
| + | # to help in debugging or solving troubles. If you want to allow this (not | ||
| + | # enabled by default for security reasons), set this parameter to 0. | ||
| + | # Change : Effective immediatly | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 0 | ||
| + | # | ||
| + | DebugMessages=0 | ||
| + | |||
| + | |||
| + | # To help you to detect if your log format is good, AWStats reports an error | ||
| + | # if all the first NbOfLinesForCorruptedLog lines have a format that does not | ||
| + | # match the LogFormat parameter. | ||
| + | # However, some worm virus attack on your web server can result in a very high | ||
| + | # number of corrupted lines in your log. So if you experience awstats stop | ||
| + | # because of bad virus records at the beginning of your log file, you can | ||
| + | # increase this parameter (very rare). | ||
| + | # Change : Effective for new updates only | ||
| + | # Default: 50 | ||
| + | # | ||
| + | NbOfLinesForCorruptedLog=50 | ||
| + | |||
| + | |||
| + | # For some particular integration needs, you may want to have CGI links to | ||
| + | # point to another script than awstats.pl. | ||
| + | # Use the name of this script in WrapperScript parameter. | ||
| + | # Change : Effective immediatly | ||
| + | # Example: " | ||
| + | # Example: " | ||
| + | # Default: "" | ||
| + | # | ||
| + | WrapperScript="" | ||
| + | |||
| + | |||
| + | # DecodeUA must be set to 1 if you use Roxen web server. This server converts | ||
| + | # all spaces in user agent field into %20. This make the AWStats robots, OS | ||
| + | # and browsers detection fail in some cases. Just change it to 1 if and only | ||
| + | # if your web server is Roxen. | ||
| + | # Change : Effective for new updates only | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 0 | ||
| + | # | ||
| + | DecodeUA=0 | ||
| + | |||
| + | |||
| + | # MiscTrackerUrl can be used to make AWStats able to detect some miscellaneous | ||
| + | # things, that can not be tracked on other way, like: | ||
| + | # - Javascript disabled | ||
| + | # - Java enabled | ||
| + | # - Screen size | ||
| + | # - Color depth | ||
| + | # - Macromedia Director plugin | ||
| + | # - Macromedia Shockwave plugin | ||
| + | # - Realplayer G2 plugin | ||
| + | # - QuickTime plugin | ||
| + | # - Mediaplayer plugin | ||
| + | # - Acrobat PDF plugin | ||
| + | # To enable all these features, you must copy the awstats_misc_tracker.js file | ||
| + | # into a /js/ directory stored in your web document root and add the following | ||
| + | # HTML code at the end of your index page (but before </ | ||
| + | # | ||
| + | # <script type=" | ||
| + | # < | ||
| + | # | ||
| + | # If code is not added in index page, all those detection capabilities will be | ||
| + | # disabled. You must also check that ShowScreenSizeStats and ShowMiscStats | ||
| + | # parameters are set to 1 to make results appear in AWStats report page. | ||
| + | # If you want to use another directory than /js/, you must also change the | ||
| + | # awstatsmisctrackerurl variable into the awstats_misc_tracker.js file. | ||
| + | # Change : Effective for new updates only. | ||
| + | # Possible value: URL of javascript tracker file added in your HTML code. | ||
| + | # Default: "/ | ||
| + | # | ||
| + | MiscTrackerUrl="/ | ||
| + | |||
| + | |||
| + | |||
| + | # | ||
| + | # OPTIONAL ACCURACY SETUP SECTION (Not required but increase AWStats features) | ||
| + | # | ||
| + | |||
| + | # The following values allow you to define accuracy of AWStats entities | ||
| + | # (robots, browsers, os, referers, file types) detection. | ||
| + | # It might be a good idea for large web sites or ISP that provides AWStats to | ||
| + | # high number of customers, to set this parameter to 1 (or 0), instead of 2. | ||
| + | # Possible values: | ||
| + | # 0 = No detection, | ||
| + | # 1 = Medium/ | ||
| + | # 2 = Full detection | ||
| + | # Change : Effective for new updates only | ||
| + | # Note : LevelForBrowsersDetection can also accept value " | ||
| + | # enable detailed detection of phone/pda browsers. | ||
| + | # Default: 2 (0 for LevelForWormsDetection) | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: LevelForBrowsersDetection=2 | ||
| + | LevelForBrowsersDetection=0 | ||
| + | # 2 reduces AWStats speed by 2% | ||
| + | # allphones reduces AWStats speed by 5% | ||
| + | # Django : 2012-07-03 | ||
| + | # default: LevelForOSDetection=2 | ||
| + | LevelForOSDetection=0 | ||
| + | # 2 reduces AWStats speed by 3% | ||
| + | # Django : 2012-07-03 | ||
| + | # default: LevelForRefererAnalyze=2 | ||
| + | LevelForRefererAnalyze=0 | ||
| + | # 2 reduces AWStats speed by 14% | ||
| + | # Django : 2012-07-03 | ||
| + | # default: LevelForRobotsDetection=2 | ||
| + | LevelForRobotsDetection=0 | ||
| + | # 2 reduces AWStats speed by 2.5% | ||
| + | # Django : 2012-07-03 | ||
| + | # default: LevelForSearchEnginesDetection=2 | ||
| + | LevelForSearchEnginesDetection=0 | ||
| + | # 2 reduces AWStats speed by 9% | ||
| + | # Django : 2012-07-03 | ||
| + | # default: LevelForKeywordsDetection=2 | ||
| + | LevelForKeywordsDetection=0 | ||
| + | # 2 reduces AWStats speed by 1% | ||
| + | # Django : 2012-07-03 | ||
| + | # default: LevelForFileTypesDetection=2 | ||
| + | LevelForFileTypesDetection=0 | ||
| + | # 2 reduces AWStats speed by 1% | ||
| + | LevelForWormsDetection=0 | ||
| + | # 2 reduces AWStats speed by 15% | ||
| + | |||
| + | |||
| + | |||
| + | # | ||
| + | # OPTIONAL APPEARANCE SETUP SECTION (Not required but increase AWStats features) | ||
| + | # | ||
| + | |||
| + | # When you use AWStats as a CGI, you can have the reports shown in HTML frames. | ||
| + | # Frames are only available for report viewed dynamically. When you build | ||
| + | # pages from command line, this option is not used and no frames are built. | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 1 | ||
| + | # | ||
| + | UseFramesWhenCGI=1 | ||
| + | |||
| + | |||
| + | # This parameter asks your browser to open detailed reports into a different | ||
| + | # window than the main page. | ||
| + | # Possible values: | ||
| + | # 0 - Open all in same browser window | ||
| + | # 1 - Open detailed reports in another window except if using frames | ||
| + | # 2 - Open always in a different window even if reports are framed | ||
| + | # Default: 1 | ||
| + | # | ||
| + | DetailedReportsOnNewWindows=1 | ||
| + | |||
| + | |||
| + | # You can add, in the HTML report page, a cache lifetime (in seconds) that | ||
| + | # will be returned to the browser in HTTP header answer by server. | ||
| + | # This parameter is not used when reports are built with -staticlinks option. | ||
| + | # Example: 3600 | ||
| + | # Default: 0 | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: Expires=3600 | ||
| + | Expires=0 | ||
| + | |||
| + | |||
| + | # To avoid too large web pages, you can ask AWStats to limit number of rows of | ||
| + | # all reported charts to this number when no other limits apply. | ||
| + | # Default: 1000 | ||
| + | # | ||
| + | MaxRowsInHTMLOutput=1000 | ||
| + | |||
| + | |||
| + | # Set your primary language (ISO-639-1 language codes). | ||
| + | # Possible values: | ||
| + | # Albanian=al, | ||
| + | # Chinese (Taiwan)=tw, | ||
| + | # Danish=dk, Dutch=nl, English=en, Estonian=et, | ||
| + | # French=fr, Galician=gl, | ||
| + | # Icelandic=is, | ||
| + | # Latvian=lv, Norwegian (Nynorsk)=nn, | ||
| + | # Portuguese=pt, | ||
| + | # Serbian=sr, Slovak=sk, Slovenian=si, | ||
| + | # Ukrainian=ua, | ||
| + | # First available language accepted by browser=auto | ||
| + | # Default: " | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: Lang=" | ||
| + | Lang=" | ||
| + | |||
| + | |||
| + | # Set the location of language files. | ||
| + | # Example: "/ | ||
| + | # Default: " | ||
| + | # | ||
| + | DirLang=" | ||
| + | |||
| + | |||
| + | # Show menu header with reports' | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 1 | ||
| + | # | ||
| + | ShowMenu=1 | ||
| + | |||
| + | |||
| + | # You choose here which reports you want to see in the main page and what you | ||
| + | # want to see in those reports. | ||
| + | # Possible values: | ||
| + | # 0 - Report is not shown at all | ||
| + | # 1 - Report is shown in main page with an entry in menu and default columns | ||
| + | # XYZ - Report shows column informations defined by code X,Y,Z... | ||
| + | # | ||
| + | # U = Unique visitors | ||
| + | # V = Visits | ||
| + | # P = Number of pages | ||
| + | # H = Number of hits (or mails) | ||
| + | # B = Bandwith (or total mail size for mail logs) | ||
| + | # L = Last access date | ||
| + | # E = Entry pages | ||
| + | # X = Exit pages | ||
| + | # C = Web compression (mod_gzip, | ||
| + | # M = Average mail size (mail logs) | ||
| + | # | ||
| + | |||
| + | # Show monthly summary | ||
| + | # Context: Web, Streaming, Mail, Ftp | ||
| + | # Default: UVPHB, Possible column codes: UVPHB | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowSummary=UVPHB | ||
| + | ShowSummary=HB | ||
| + | |||
| + | # Show monthly chart | ||
| + | # Context: Web, Streaming, Mail, Ftp | ||
| + | # Default: UVPHB, Possible column codes: UVPHB | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowMonthStats=UVPHB | ||
| + | ShowMonthStats=HB | ||
| + | |||
| + | # Show days of month chart | ||
| + | # Context: Web, Streaming, Mail, Ftp | ||
| + | # Default: VPHB, Possible column codes: VPHB | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowDaysOfMonthStats=VPHB | ||
| + | ShowDaysOfMonthStats=HB | ||
| + | |||
| + | # Show days of week chart | ||
| + | # Context: Web, Streaming, Mail, Ftp | ||
| + | # Default: PHB, Possible column codes: PHB | ||
| + | # Default: VPHB, Possible column codes: VPHB | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowDaysOfWeekStats=PHB | ||
| + | ShowDaysOfWeekStats=HB | ||
| + | |||
| + | # Show hourly chart | ||
| + | # Context: Web, Streaming, Mail, Ftp | ||
| + | # Default: PHB, Possible column codes: PHB | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowHoursStats=PHB | ||
| + | ShowHoursStats=HB | ||
| + | |||
| + | # Show domains/ | ||
| + | # Context: Web, Streaming, Mail, Ftp | ||
| + | # Default: PHB, Possible column codes: PHB | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowDomainsStats=PHB | ||
| + | ShowDomainsStats=0 | ||
| + | |||
| + | # Show hosts chart | ||
| + | # Context: Web, Streaming, Mail, Ftp | ||
| + | # Default: PHBL, Possible column codes: PHBL | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowHostsStats=PHBL | ||
| + | ShowHostsStats=HBL | ||
| + | |||
| + | # Show authenticated users chart | ||
| + | # Context: Web, Streaming, Ftp | ||
| + | # Default: 0, Possible column codes: PHBL | ||
| + | ShowAuthenticatedUsers=0 | ||
| + | |||
| + | # Show robots chart | ||
| + | # Context: Web, Streaming | ||
| + | # Default: HBL, Possible column codes: HBL | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowRobotsStats=HBL | ||
| + | ShowRobotsStats=0 | ||
| + | |||
| + | # Show worms chart | ||
| + | # Context: Web, Streaming | ||
| + | # Default: 0 (If set to other than 0, see also LevelForWormsDetection), | ||
| + | ShowWormsStats=0 | ||
| + | |||
| + | # Show email senders chart (For use when analyzing mail log files) | ||
| + | # Context: Mail | ||
| + | # Default: 0, Possible column codes: HBML | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowEMailSenders=0 | ||
| + | ShowEMailSenders=HBML | ||
| + | |||
| + | # Show email receivers chart (For use when analyzing mail log files) | ||
| + | # Context: Mail | ||
| + | # Default: 0, Possible column codes: HBML | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowEMailReceivers=0 | ||
| + | ShowEMailReceivers=HBML | ||
| + | |||
| + | # Show session chart | ||
| + | # Context: Web, Streaming, Ftp | ||
| + | # Default: 1, Possible column codes: None | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowSessionsStats=1 | ||
| + | ShowSessionsStats=0 | ||
| + | |||
| + | # Show pages-url chart. | ||
| + | # Context: Web, Streaming, Ftp | ||
| + | # Default: PBEX, Possible column codes: PBEX | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowPagesStats=PBEX | ||
| + | ShowPagesStats=0 | ||
| + | |||
| + | # Show file types chart. | ||
| + | # Context: Web, Streaming, Ftp | ||
| + | # Default: HB, Possible column codes: HBC | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowFileTypesStats=HB | ||
| + | ShowFileTypesStats=0 | ||
| + | |||
| + | # Show file size chart (Not yet available) | ||
| + | # Context: Web, Streaming, Mail, Ftp | ||
| + | # Default: 1, Possible column codes: None | ||
| + | ShowFileSizesStats=0 | ||
| + | |||
| + | # Show downloads chart. | ||
| + | # Context: Web, Streaming, Ftp | ||
| + | # Default: HB, Possible column codes: HB | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowDownloadsStats=HB | ||
| + | ShowDownloadsStats=0 | ||
| + | |||
| + | # Show operating systems chart | ||
| + | # Context: Web, Streaming, Ftp | ||
| + | # Default: 1, Possible column codes: None | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowOSStats=1 | ||
| + | ShowOSStats=0 | ||
| + | |||
| + | # Show browsers chart | ||
| + | # Context: Web, Streaming | ||
| + | # Default: 1, Possible column codes: None | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowBrowsersStats=1 | ||
| + | ShowBrowsersStats=0 | ||
| + | |||
| + | # Show screen size chart | ||
| + | # Context: Web, Streaming | ||
| + | # Default: 0 (If set to 1, see also MiscTrackerUrl), | ||
| + | ShowScreenSizeStats=0 | ||
| + | |||
| + | # Show origin chart | ||
| + | # Context: Web, Streaming | ||
| + | # Default: PH, Possible column codes: PH | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowOriginStats=PH | ||
| + | ShowOriginStats=0 | ||
| + | |||
| + | # Show keyphrases chart | ||
| + | # Context: Web, Streaming | ||
| + | # Default: 1, Possible column codes: None | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowKeyphrasesStats=1 | ||
| + | ShowKeyphrasesStats=0 | ||
| + | |||
| + | # Show keywords chart | ||
| + | # Context: Web, Streaming | ||
| + | # Default: 1, Possible column codes: None | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowKeywordsStats=1 | ||
| + | ShowKeywordsStats=0 | ||
| + | |||
| + | # Show misc chart | ||
| + | # Context: Web, Streaming | ||
| + | # Default: a (See also MiscTrackerUrl parameter), Possible column codes: anjdfrqwp | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowMiscStats=a | ||
| + | ShowMiscStats=0 | ||
| + | |||
| + | # Show http errors chart | ||
| + | # Context: Web, Streaming | ||
| + | # Default: 1, Possible column codes: None | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowHTTPErrorsStats=1 | ||
| + | ShowHTTPErrorsStats=0 | ||
| + | |||
| + | # Show smtp errors chart (For use when analyzing mail log files) | ||
| + | # Context: Mail | ||
| + | # Default: 0, Possible column codes: None | ||
| + | # Django : 2012-07-03 | ||
| + | # default: ShowSMTPErrorsStats=0 | ||
| + | ShowSMTPErrorsStats=1 | ||
| + | |||
| + | # Show the cluster report (Your LogFormat must contains the %cluster tag) | ||
| + | # Context: Web, Streaming, Ftp | ||
| + | # Default: 0, Possible column codes: PHB | ||
| + | ShowClusterStats=0 | ||
| + | |||
| + | |||
| + | # Some graphical reports are followed by the data array of values. | ||
| + | # If you don't want this array (to reduce the report size for example), you | ||
| + | # can set thoose options to 0. | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 1 | ||
| + | # | ||
| + | # Data array values for the ShowMonthStats report | ||
| + | AddDataArrayMonthStats=1 | ||
| + | # Data array values for the ShowDaysOfMonthStats report | ||
| + | AddDataArrayShowDaysOfMonthStats=1 | ||
| + | # Data array values for the ShowDaysOfWeekStats report | ||
| + | AddDataArrayShowDaysOfWeekStats=1 | ||
| + | # Data array values for the ShowHoursStats report | ||
| + | AddDataArrayShowHoursStats=1 | ||
| + | |||
| + | |||
| + | # In the Origin chart, you have stats on where your hits came from. You can | ||
| + | # include hits on pages that come from pages of same sites in this chart. | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 0 | ||
| + | # | ||
| + | IncludeInternalLinksInOriginSection=0 | ||
| + | |||
| + | |||
| + | # The following parameters can be used to choose the maximum number of lines | ||
| + | # shown for the particular following reports. | ||
| + | # | ||
| + | # Stats by countries/ | ||
| + | MaxNbOfDomain = 10 | ||
| + | MinHitDomain | ||
| + | # Stats by hosts | ||
| + | MaxNbOfHostsShown = 10 | ||
| + | MinHitHost | ||
| + | # Stats by authenticated users | ||
| + | MaxNbOfLoginShown = 10 | ||
| + | MinHitLogin | ||
| + | # Stats by robots | ||
| + | MaxNbOfRobotShown = 10 | ||
| + | MinHitRobot | ||
| + | # Stats for Downloads | ||
| + | MaxNbOfDownloadsShown = 10 | ||
| + | MinHitDownloads = 1 | ||
| + | # Stats by pages | ||
| + | MaxNbOfPageShown = 10 | ||
| + | MinHitFile | ||
| + | # Stats by OS | ||
| + | MaxNbOfOsShown = 10 | ||
| + | MinHitOs | ||
| + | # Stats by browsers | ||
| + | MaxNbOfBrowsersShown = 10 | ||
| + | MinHitBrowser = 1 | ||
| + | # Stats by screen size | ||
| + | MaxNbOfScreenSizesShown = 5 | ||
| + | MinHitScreenSize = 1 | ||
| + | # Stats by window size (following 2 parameters are not yet used) | ||
| + | MaxNbOfWindowSizesShown = 5 | ||
| + | MinHitWindowSize = 1 | ||
| + | # Stats by referers | ||
| + | MaxNbOfRefererShown = 10 | ||
| + | MinHitRefer | ||
| + | # Stats for keyphrases | ||
| + | MaxNbOfKeyphrasesShown = 10 | ||
| + | MinHitKeyphrase = 1 | ||
| + | # Stats for keywords | ||
| + | MaxNbOfKeywordsShown = 10 | ||
| + | MinHitKeyword = 1 | ||
| + | # Stats for sender or receiver emails | ||
| + | MaxNbOfEMailsShown = 20 | ||
| + | MinHitEMail | ||
| + | |||
| + | |||
| + | # Choose if you want the week report to start on sunday or monday | ||
| + | # Possible values: | ||
| + | # 0 - Week starts on sunday | ||
| + | # 1 - Week starts on monday | ||
| + | # Default: 1 | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: FirstDayOfWeek=0 | ||
| + | FirstDayOfWeek=1 | ||
| + | |||
| + | |||
| + | # List of visible flags that link to other language translations. | ||
| + | # See Lang parameter for list of allowed flag/ | ||
| + | # If you don't want any flag link, set ShowFlagLinks to "" | ||
| + | # This parameter is used only if ShowMenu parameter is set to 1. | ||
| + | # Possible values: "" | ||
| + | # Example: "en es fr nl de" | ||
| + | # Default: "" | ||
| + | # | ||
| + | ShowFlagLinks="" | ||
| + | |||
| + | |||
| + | # Each URL, shown in stats report views, are links you can click. | ||
| + | # Possible values: 0 or 1 | ||
| + | # Default: 1 | ||
| + | # | ||
| + | ShowLinksOnUrl=1 | ||
| + | |||
| + | |||
| + | # When AWStats builds HTML links in its report pages, it starts those links | ||
| + | # with " | ||
| + | # here the root of all your HTTPS links. If all your site is a SSL web site, | ||
| + | # just enter "/" | ||
| + | # This parameter is not used if ShowLinksOnUrl is 0. | ||
| + | # Example: "/ | ||
| + | # Example: "/" | ||
| + | # Default: "" | ||
| + | # | ||
| + | UseHTTPSLinkForUrl="" | ||
| + | |||
| + | |||
| + | # Maximum length of URL part shown on stats page (number of characters). | ||
| + | # This affects only URL visible text, links still work. | ||
| + | # Default: 64 | ||
| + | # | ||
| + | MaxLengthOfShownURL=64 | ||
| + | |||
| + | |||
| + | # You can enter HTML code that will be added at the top of AWStats reports. | ||
| + | # Default: "" | ||
| + | # | ||
| + | HTMLHeadSection="" | ||
| + | |||
| + | |||
| + | # You can enter HTML code that will be added at the end of AWStats reports. | ||
| + | # Great to add advert ban. | ||
| + | # Default: "" | ||
| + | # | ||
| + | HTMLEndSection="" | ||
| + | |||
| + | |||
| + | # By default AWStats page contains meta tag robots=noindex, | ||
| + | # If you want to have your statistics to be indexed, set this option to 1. | ||
| + | # Default: 0 | ||
| + | # | ||
| + | MetaRobot=0 | ||
| + | |||
| + | |||
| + | # You can set Logo and LogoLink to use your own logo. | ||
| + | # Logo must be the name of image file (must be in $DirIcons/ | ||
| + | # LogoLink is the expected URL when clicking on Logo. | ||
| + | # Default: " | ||
| + | # | ||
| + | Logo=" | ||
| + | LogoLink=" | ||
| + | |||
| + | |||
| + | # Value of maximum bar width/ | ||
| + | # Default: 260/90 | ||
| + | # | ||
| + | BarWidth | ||
| + | BarHeight | ||
| + | |||
| + | |||
| + | # You can ask AWStats to use a particular CSS (Cascading Style Sheet) to | ||
| + | # change its look. To create a style sheet, you can use samples provided with | ||
| + | # AWStats in wwwroot/css directory. | ||
| + | # Example: "/ | ||
| + | # Example: "/ | ||
| + | # Default: "" | ||
| + | # | ||
| + | StyleSheet="" | ||
| + | |||
| + | |||
| + | # Those color parameters can be used (if StyleSheet parameter is not used) | ||
| + | # to change AWStats look. | ||
| + | # Example: color_name=" | ||
| + | # | ||
| + | color_Background=" | ||
| + | color_TableBGTitle=" | ||
| + | color_TableTitle=" | ||
| + | color_TableBG=" | ||
| + | color_TableRowTitle=" | ||
| + | color_TableBGRowTitle=" | ||
| + | color_TableBorder=" | ||
| + | color_text=" | ||
| + | color_textpercent=" | ||
| + | color_titletext=" | ||
| + | color_weekend=" | ||
| + | color_link=" | ||
| + | color_hover=" | ||
| + | color_u=" | ||
| + | color_v=" | ||
| + | color_p=" | ||
| + | color_h=" | ||
| + | color_k=" | ||
| + | color_s=" | ||
| + | color_e=" | ||
| + | color_x=" | ||
| + | |||
| + | |||
| + | |||
| + | # | ||
| + | # PLUGINS | ||
| + | # | ||
| + | |||
| + | # Add here all plugin files you want to load. | ||
| + | # Plugin files must be .pm files stored in ' | ||
| + | # Uncomment LoadPlugin lines to enable a plugin after checking that perl | ||
| + | # modules required by the plugin are installed. | ||
| + | |||
| + | # PLUGIN: Tooltips | ||
| + | # REQUIRED MODULES: None | ||
| + | # PARAMETERS: None | ||
| + | # DESCRIPTION: | ||
| + | # NOTE: This will increased HTML report pages size, thus server load and bandwidth. | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: # | ||
| + | LoadPlugin=" | ||
| + | |||
| + | # PLUGIN: DecodeUTFKeys | ||
| + | # REQUIRED MODULES: Encode and URI::Escape | ||
| + | # PARAMETERS: None | ||
| + | # DESCRIPTION: | ||
| + | # keywords/ | ||
| + | # referer search engine. | ||
| + | # | ||
| + | # | ||
| + | |||
| + | |||
| + | # PLUGIN: IPv6 | ||
| + | # PARAMETERS: None | ||
| + | # REQUIRED MODULES: Net::IP and Net::DNS | ||
| + | # DESCRIPTION: | ||
| + | # lookup on IPv6 addresses. | ||
| + | # | ||
| + | # | ||
| + | |||
| + | # PLUGIN: HashFiles | ||
| + | # REQUIRED MODULES: Storable | ||
| + | # PARAMETERS: None | ||
| + | # DESCRIPTION: | ||
| + | # This increases DNS cache files loading speed, above all for very large web sites. | ||
| + | # | ||
| + | # | ||
| + | |||
| + | |||
| + | # PLUGIN: UserInfo | ||
| + | # REQUIRED MODULES: None | ||
| + | # PARAMETERS: None | ||
| + | # DESCRIPTION: | ||
| + | # authenticated user reports for each login value. | ||
| + | # A text file called userinfo.myconfig.txt, | ||
| + | # second is text to show, separated by a tab char) must be created in DirData | ||
| + | # directory. | ||
| + | # | ||
| + | # | ||
| + | |||
| + | # PLUGIN: HostInfo | ||
| + | # REQUIRED MODULES: Net::XWhois | ||
| + | # PARAMETERS: None | ||
| + | # DESCRIPTION: | ||
| + | # info on host (like whois records). | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: # | ||
| + | LoadPlugin=" | ||
| + | |||
| + | # PLUGIN: ClusterInfo | ||
| + | # REQUIRED MODULES: None | ||
| + | # PARAMETERS: None | ||
| + | # DESCRIPTION: | ||
| + | # number. A text file called clusterinfo.myconfig.txt, | ||
| + | # cluster number, second is text to show) separated by a tab char. must be | ||
| + | # created into DirData directory. | ||
| + | # Note this plugin is useless if ShowClusterStats is set to 0 or if you don't | ||
| + | # use a personalized log format that contains %cluster tag. | ||
| + | # | ||
| + | # | ||
| + | |||
| + | # PLUGIN: UrlAliases | ||
| + | # REQUIRED MODULES: None | ||
| + | # PARAMETERS: None | ||
| + | # DESCRIPTION: | ||
| + | # A text file called urlalias.myconfig.txt, | ||
| + | # second is text to show, separated by a tab char) must be created into | ||
| + | # DirData directory. | ||
| + | # | ||
| + | # | ||
| + | |||
| + | # PLUGIN: TimeHiRes | ||
| + | # REQUIRED MODULES: Time::HiRes (if Perl < 5.8) | ||
| + | # PARAMETERS: None | ||
| + | # DESCRIPTION: | ||
| + | # | ||
| + | # | ||
| + | |||
| + | # PLUGIN: TimeZone | ||
| + | # REQUIRED MODULES: Time::Local | ||
| + | # PARAMETERS: [timezone offset] | ||
| + | # DESCRIPTION: | ||
| + | # This plugin reduces AWStats speed of 10% !!!!!!! | ||
| + | # LoadPlugin=" | ||
| + | # LoadPlugin=" | ||
| + | # LoadPlugin=" | ||
| + | # | ||
| + | # | ||
| + | |||
| + | # PLUGIN: Rawlog | ||
| + | # REQUIRED MODULES: None | ||
| + | # PARAMETERS: None | ||
| + | # DESCRIPTION: | ||
| + | # content of current log files. A filter is also available. | ||
| + | # | ||
| + | # | ||
| + | |||
| + | # PLUGIN: GraphApplet | ||
| + | # REQUIRED MODULES: None | ||
| + | # PARAMETERS: [CSS classes to override] | ||
| + | # DESCRIPTION: | ||
| + | # | ||
| + | # | ||
| + | |||
| + | # PLUGIN: GraphGoogleChartAPI | ||
| + | # REQUIRED MODULES: None | ||
| + | # PARAMETERS: None | ||
| + | # DESCRIPTION: | ||
| + | # in HTML reports. If country data is available and more than one country has hits, | ||
| + | # a map will be generated using Google Visualizations. | ||
| + | # Note: The machine where reports are displayed must have Internet access for the | ||
| + | # charts to be generated. The only data sent to Google includes the statistic numbers, | ||
| + | # legend names and country names. | ||
| + | # Warning: This plugin is not compatible with option BuildReportFormat=xhtml. | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: # | ||
| + | LoadPlugin=" | ||
| + | |||
| + | # PLUGIN: GeoIPfree | ||
| + | # REQUIRED MODULES: Geo::IPfree version 0.2+ (from Graciliano M.P.) | ||
| + | # PARAMETERS: None | ||
| + | # DESCRIPTION: | ||
| + | # This plugin is useless for intranet only log files. | ||
| + | # Note: You must choose between using this plugin (need Perl Geo::IPfree | ||
| + | # module, database is free but not up to date) or the GeoIP plugin (need | ||
| + | # Perl Geo::IP module from Maxmind, database is also free and up to date). | ||
| + | # Note: Activestate provide a corrupted version of Geo::IPfree 0.2 Perl | ||
| + | # module, so install it from elsewhere (from www.cpan.org for example). | ||
| + | # This plugin reduces AWStats speed by up to 10% ! | ||
| + | # | ||
| + | # | ||
| + | |||
| + | # MAXMIND GEO IP MODULES: Please see documentation for notes on all Maxmind modules | ||
| + | |||
| + | # PLUGIN: GeoIP | ||
| + | # REQUIRED MODULES: Geo::IP or Geo:: | ||
| + | # PARAMETERS: [GEOIP_STANDARD | GEOIP_MEMORY_CACHE] [/ | ||
| + | # DESCRIPTION: | ||
| + | # table with country name | ||
| + | # Replace spaces in the path of geoip data file with string " | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: # | ||
| + | LoadPlugin=" | ||
| + | |||
| + | # PLUGIN: GeoIP_City_Maxmind | ||
| + | # REQUIRED MODULES: Geo::IP or Geo:: | ||
| + | # PARAMETERS: [GEOIP_STANDARD | GEOIP_MEMORY_CACHE] [/ | ||
| + | # DESCRIPTION: | ||
| + | # and hits by city including regions. | ||
| + | # Replace spaces in the path of geoip data file with string " | ||
| + | # | ||
| + | # Django : 2012-07-03 | ||
| + | # default: # | ||
| + | LoadPlugin=" | ||
| + | |||
| + | # PLUGIN: GeoIP_ASN_Maxmind | ||
| + | # REQUIRED MODULES: Geo::IP or Geo:: | ||
| + | # PARAMETERS: [GEOIP_STANDARD | GEOIP_MEMORY_CACHE] [/ | ||
| + | # DESCRIPTION: | ||
| + | # This plugin can display some ISP information if included in the database. You can also provide | ||
| + | # a link that will be used to lookup additional registration data. Put the link at the end of | ||
| + | # the parameter string and the report page will include the link with the full AS number at the end. | ||
| + | # Replace spaces in the path of geoip data file with string " | ||
| + | # | ||
| + | # | ||
| + | |||
| + | # PLUGIN: GeoIP_Region_Maxmind | ||
| + | # REQUIRED MODULES: Geo::IP or Geo:: | ||
| + | # PARAMETERS: [GEOIP_STANDARD | GEOIP_MEMORY_CACHE] [/ | ||
| + | # DESCRIPTION: | ||
| + | # Canada can be detected. | ||
| + | # Replace spaces in the path of geoip data file with string " | ||
| + | # | ||
| + | # | ||
| + | |||
| + | # PLUGIN: GeoIP_ISP_Maxmind | ||
| + | # REQUIRED MODULES: Geo::IP or Geo:: | ||
| + | # PARAMETERS: [GEOIP_STANDARD | GEOIP_MEMORY_CACHE] [/ | ||
| + | # DESCRIPTION: | ||
| + | # Replace spaces in the path of geoip data file with string " | ||
| + | # | ||
| + | # | ||
| + | |||
| + | # PLUGIN: GeoIP_Org_Maxmind | ||
| + | # REQUIRED MODULES: Geo::IP or Geo:: | ||
| + | # PARAMETERS: [GEOIP_STANDARD | GEOIP_MEMORY_CACHE] [/ | ||
| + | # DESCRIPTION: | ||
| + | # Replace spaces in the path of geoip data file with string " | ||
| + | # | ||
| + | # | ||
| + | |||
| + | |||
| + | # | ||
| + | # EXTRA SECTIONS | ||
| + | # | ||
| + | |||
| + | # You can define your own charts, you choose here what are rows and columns | ||
| + | # keys. This feature is particularly useful for marketing purpose, tracking | ||
| + | # products orders for example. | ||
| + | # For this, edit all parameters of Extra section. Each set of parameter is a | ||
| + | # different chart. For several charts, duplicate section changing the number. | ||
| + | # Note: Each Extra section reduces AWStats speed by 8%. | ||
| + | # | ||
| + | # WARNING: A wrong setup of Extra section might result in too large arrays | ||
| + | # that will consume all your memory, making AWStats unusable after several | ||
| + | # updates, so be sure to setup it correctly. | ||
| + | # In most cases, you don't need this feature. | ||
| + | # | ||
| + | # ExtraSectionNameX is title of your personalized chart. | ||
| + | # ExtraSectionCodeFilterX is list of codes the record code field must match. | ||
| + | # Put an empty string for no test on code. | ||
| + | # ExtraSectionConditionX are conditions you can use to count or not the hit, | ||
| + | # Use one of the field condition | ||
| + | # | ||
| + | # and a regex to match, after a coma. Use " | ||
| + | # ExtraSectionFirstColumnTitleX is the first column title of the chart. | ||
| + | # ExtraSectionFirstColumnValuesX is a string to tell AWStats which field to | ||
| + | # | ||
| + | # | ||
| + | # and how to extract the value (using regex syntax). Each different value | ||
| + | # found will appear in first column of report on a different row. Be sure | ||
| + | # that list of different possible values will not grow indefinitely. | ||
| + | # ExtraSectionFirstColumnFormatX is the string used to write value. | ||
| + | # ExtraSectionStatTypesX are things you want to count. You can use standard | ||
| + | # code letters (P for pages,H for hits,B for bandwidth,L for last access). | ||
| + | # ExtraSectionAddAverageRowX add a row at bottom of chart with average values. | ||
| + | # ExtraSectionAddSumRowX add a row at bottom of chart with sum values. | ||
| + | # MaxNbOfExtraX is maximum number of rows shown in chart. | ||
| + | # MinHitExtraX is minimum number of hits required to be shown in chart. | ||
| + | # | ||
| + | |||
| + | # Example to report the 20 products the most ordered by " | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | |||
| + | |||
| + | # There is also a global parameter ExtraTrackedRowsLimit that limits the | ||
| + | # number of possible rows an ExtraSection can report. This parameter is | ||
| + | # here to protect too much memory use when you make a bad setup in your | ||
| + | # ExtraSection. It applies to all ExtraSection independently meaning that | ||
| + | # none ExtraSection can report more rows than value defined by ExtraTrackedRowsLimit. | ||
| + | # If you know an ExtraSection will report more rows than its value, you should | ||
| + | # increase this parameter or AWStats will stop with an error. | ||
| + | # Example: 2000 | ||
| + | # Default: 500 | ||
| + | # | ||
| + | ExtraTrackedRowsLimit=500 | ||
| + | |||
| + | |||
| + | # | ||
| + | # INCLUDES | ||
| + | # | ||
| + | |||
| + | # You can include other config files using the directive with the name of the | ||
| + | # config file. | ||
| + | # This is particularly useful for users who have a lot of virtual servers, so | ||
| + | # a lot of config files and want to maintain common values in only one file. | ||
| + | # Note that when a variable is defined both in a config file and in an | ||
| + | # included file, AWStats will use the last value read for parameters that | ||
| + | # contains one value and AWStats will concat all values from both files for | ||
| + | # parameters that are lists of values. | ||
| + | # | ||
| + | |||
| + | #Include "" | ||
| + | |||
| + | </ | ||
| + | |||
| + | Zusammengefasst sieht dann unsere Konfigurationdatei entsprechend wie folgt aus: | ||
| + | # egrep -v ' | ||
| + | |||
| + | <code bash> | ||
| + | LogFile=" | ||
| + | LogType=M | ||
| + | LogFormat=" | ||
| + | LogSeparator=" | ||
| + | SiteDomain=" | ||
| + | HostAliases=„localhost 127.0.0.1 REGEX[nausch\.org$] REGEX[www\.nausch\.org$]“ | ||
| + | DNSLookup=2 | ||
| + | DirData="/ | ||
| + | DirCgi="/ | ||
| + | DirIcons="/ | ||
| + | AllowToUpdateStatsFromBrowser=1 | ||
| + | AllowFullYearView=2 | ||
| + | EnableLockForUpdate=1 | ||
| + | DNSStaticCacheFile=" | ||
| + | DNSLastUpdateCacheFile=" | ||
| + | SkipDNSLookupFor="" | ||
| + | AllowAccessFromWebToAuthenticatedUsersOnly=0 | ||
| + | AllowAccessFromWebToFollowingAuthenticatedUsers="" | ||
| + | AllowAccessFromWebToFollowingIPAddresses="" | ||
| + | CreateDirDataIfNotExists=0 | ||
| + | BuildHistoryFormat=text | ||
| + | BuildReportFormat=html | ||
| + | SaveDatabaseFilesWithPermissionsForEveryone=1 | ||
| + | PurgeLogFile=0 | ||
| + | ArchiveLogRecords=0 | ||
| + | KeepBackupOfHistoricFiles=1 | ||
| + | DefaultFile=" | ||
| + | SkipHosts="" | ||
| + | SkipUserAgents="" | ||
| + | SkipFiles="" | ||
| + | SkipReferrersBlackList="" | ||
| + | OnlyHosts="" | ||
| + | OnlyUserAgents="" | ||
| + | OnlyUsers="" | ||
| + | OnlyFiles="" | ||
| + | NotPageList=" | ||
| + | ValidHTTPCodes=" | ||
| + | ValidSMTPCodes=" | ||
| + | AuthenticatedUsersNotCaseSensitive=0 | ||
| + | URLNotCaseSensitive=0 | ||
| + | URLWithAnchor=0 | ||
| + | URLQuerySeparators="?;" | ||
| + | URLWithQuery=0 | ||
| + | URLWithQueryWithOnlyFollowingParameters="" | ||
| + | URLWithQueryWithoutFollowingParameters="" | ||
| + | URLReferrerWithQuery=0 | ||
| + | WarningMessages=1 | ||
| + | ErrorMessages="" | ||
| + | DebugMessages=0 | ||
| + | NbOfLinesForCorruptedLog=50 | ||
| + | WrapperScript="" | ||
| + | DecodeUA=0 | ||
| + | MiscTrackerUrl="/ | ||
| + | LevelForBrowsersDetection=0 | ||
| + | # 2 reduces AWStats speed by 2% | ||
| + | # allphones reduces AWStats speed by 5% | ||
| + | LevelForOSDetection=0 | ||
| + | # 2 reduces AWStats speed by 3% | ||
| + | LevelForRefererAnalyze=0 | ||
| + | # 2 reduces AWStats speed by 14% | ||
| + | LevelForRobotsDetection=0 | ||
| + | # 2 reduces AWStats speed by 2.5% | ||
| + | LevelForSearchEnginesDetection=0 | ||
| + | # 2 reduces AWStats speed by 9% | ||
| + | LevelForKeywordsDetection=0 | ||
| + | # 2 reduces AWStats speed by 1% | ||
| + | LevelForFileTypesDetection=0 | ||
| + | # 2 reduces AWStats speed by 1% | ||
| + | LevelForWormsDetection=0 | ||
| + | # 2 reduces AWStats speed by 15% | ||
| + | UseFramesWhenCGI=1 | ||
| + | DetailedReportsOnNewWindows=1 | ||
| + | Expires=0 | ||
| + | MaxRowsInHTMLOutput=1000 | ||
| + | Lang=" | ||
| + | DirLang=" | ||
| + | ShowMenu=1 | ||
| + | ShowSummary=HB | ||
| + | ShowMonthStats=HB | ||
| + | ShowDaysOfMonthStats=HB | ||
| + | ShowDaysOfWeekStats=HB | ||
| + | ShowHoursStats=HB | ||
| + | ShowDomainsStats=0 | ||
| + | ShowHostsStats=HBL | ||
| + | ShowAuthenticatedUsers=0 | ||
| + | ShowRobotsStats=0 | ||
| + | ShowWormsStats=0 | ||
| + | ShowEMailSenders=HBML | ||
| + | ShowEMailReceivers=HBML | ||
| + | ShowSessionsStats=0 | ||
| + | ShowPagesStats=0 | ||
| + | ShowFileTypesStats=0 | ||
| + | ShowFileSizesStats=0 | ||
| + | ShowDownloadsStats=0 | ||
| + | ShowOSStats=0 | ||
| + | ShowBrowsersStats=0 | ||
| + | ShowScreenSizeStats=0 | ||
| + | ShowOriginStats=0 | ||
| + | ShowKeyphrasesStats=0 | ||
| + | ShowKeywordsStats=0 | ||
| + | ShowMiscStats=0 | ||
| + | ShowHTTPErrorsStats=0 | ||
| + | ShowSMTPErrorsStats=1 | ||
| + | ShowClusterStats=0 | ||
| + | AddDataArrayMonthStats=1 | ||
| + | AddDataArrayShowDaysOfMonthStats=1 | ||
| + | AddDataArrayShowDaysOfWeekStats=1 | ||
| + | AddDataArrayShowHoursStats=1 | ||
| + | IncludeInternalLinksInOriginSection=0 | ||
| + | MaxNbOfDomain = 10 | ||
| + | MinHitDomain | ||
| + | MaxNbOfHostsShown = 10 | ||
| + | MinHitHost | ||
| + | MaxNbOfLoginShown = 10 | ||
| + | MinHitLogin | ||
| + | MaxNbOfRobotShown = 10 | ||
| + | MinHitRobot | ||
| + | MaxNbOfDownloadsShown = 10 | ||
| + | MinHitDownloads = 1 | ||
| + | MaxNbOfPageShown = 10 | ||
| + | MinHitFile | ||
| + | MaxNbOfOsShown = 10 | ||
| + | MinHitOs | ||
| + | MaxNbOfBrowsersShown = 10 | ||
| + | MinHitBrowser = 1 | ||
| + | MaxNbOfScreenSizesShown = 5 | ||
| + | MinHitScreenSize = 1 | ||
| + | MaxNbOfWindowSizesShown = 5 | ||
| + | MinHitWindowSize = 1 | ||
| + | MaxNbOfRefererShown = 10 | ||
| + | MinHitRefer | ||
| + | MaxNbOfKeyphrasesShown = 10 | ||
| + | MinHitKeyphrase = 1 | ||
| + | MaxNbOfKeywordsShown = 10 | ||
| + | MinHitKeyword = 1 | ||
| + | MaxNbOfEMailsShown = 20 | ||
| + | MinHitEMail | ||
| + | FirstDayOfWeek=1 | ||
| + | ShowFlagLinks="" | ||
| + | ShowLinksOnUrl=1 | ||
| + | UseHTTPSLinkForUrl="" | ||
| + | MaxLengthOfShownURL=64 | ||
| + | HTMLHeadSection="" | ||
| + | HTMLEndSection="" | ||
| + | MetaRobot=0 | ||
| + | Logo=" | ||
| + | LogoLink=" | ||
| + | BarWidth | ||
| + | BarHeight | ||
| + | StyleSheet="" | ||
| + | color_Background=" | ||
| + | color_TableBGTitle=" | ||
| + | color_TableTitle=" | ||
| + | color_TableBG=" | ||
| + | color_TableRowTitle=" | ||
| + | color_TableBGRowTitle=" | ||
| + | color_TableBorder=" | ||
| + | color_text=" | ||
| + | color_textpercent=" | ||
| + | color_titletext=" | ||
| + | color_weekend=" | ||
| + | color_link=" | ||
| + | color_hover=" | ||
| + | color_u=" | ||
| + | color_v=" | ||
| + | color_p=" | ||
| + | color_h=" | ||
| + | color_k=" | ||
| + | color_s=" | ||
| + | color_e=" | ||
| + | color_x=" | ||
| + | LoadPlugin=" | ||
| + | LoadPlugin=" | ||
| + | LoadPlugin=" | ||
| + | LoadPlugin=" | ||
| + | LoadPlugin=" | ||
| + | ExtraTrackedRowsLimit=500 | ||
| + | </ | ||
| + | |||
| + | Nach erfolgreicher Konfiguration steht dem ersten Aufruf nichts mehr im Wege. Der Aufruf erfolgt über folgende URL: | ||
| + | $ firefox http:// | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | |||
| + | ====== Links ====== | ||
| + | * **[[centos: | ||
| + | * **[[wiki: | ||
| + | * **[[http:// | ||
| + | |||