#!/usr/bin/perl -w
###
# Project: pflogstats
# Module: pflogstats-statistics-accpopimap.pm
# Type: statistics
# Description: Statistics module for accounting
# Copyright: Dr. Peter Bieringer <pbieringer at aerasec dot de>
# AERAsec GmbH <http://www.aerasec.de/>
# License: GNU GPL v2
# CVS: $Id: pflogstats-statistics-accpopimap.pm,v 1.16 2005/05/02 12:09:34 peter Exp $
###
## ChangeLog
# 0.01
# - initial split-off
# 0.02
# - support new format code style
# 0.03
# - adjust loglineparser arguments, fix some not well transferred code
# 0.04
# - tag some match patterns with "o"
# 0.05
# - adjustments for external network check module
# 0.06
# - account TCP overhead also
# 0.07
# - convert IPv4 compatible IPv6 addresses into IPv4 ones
# 0.08
# - replace all hash references with proper code
# 0.09
# - make Perl 5.0 compatible
# 0.10
# - add support of option print-max-width
# 0.11
# - reorganize hook names
# 0.12
# - fix check for exisiting data
##
use strict;
## Local constants
my $module_type = "statistics";
my $module_name = $module_type . "-accpopimap";
my $module_version = "0.12";
package pflogstats::statistics::accpopimap;
## Export module info
$main::moduleinfo{$module_name}->{'version'} = $module_version;
$main::moduleinfo{$module_name}->{'type'} = $module_type;
$main::moduleinfo{$module_name}->{'name'} = $module_name;
# Global prototyping
## Local prototyping
## Register options
$main::options{'acc_notcpoverhead'} = \$main::opts{'acc_notcpoverhead'};
## Register calling hooks
$main::hooks{'loglineparser'}->{$module_name} = \&loglineparser;
$main::hooks{'print_result'}->{$module_name} = \&print_result;
$main::hooks{'checkoptions'}->{$module_name} = \&checkoptions;
$main::hooks{'help'}->{$module_name} = \&help;
# Define type
$main::types{'accpopimap'} = 0;
## Global variables
## Local variables
my %accounting_pop_imap;
my ($user, $ip, $rcvd, $sent);
my $tcpoverhead;
## Global callable functions
# Help
sub help() {
my $helpstring = "
Type: accpopimap
[--acc_notcpoverhead] Don't account estimated TCP overhead
[--debug <debug>] Debug value
| 0x0001 : display imap/pop lines
| 0x0002 : display imap/pop accounting data lines
| 0x0010 : display accounting information
";
return $helpstring;
};
# Check options
sub checkoptions() {
};
# Parse logline
sub loglineparser(\$\$) {
return if ( $main::types{'accpopimap'} == 0);
if (! defined $_[0]) { die "Missing time pointer (arg1)"; };
if (! defined $_[1]) { die "Missing logline pointer (arg2)"; };
# Looking for pop3/imapd lines, nothing else
return unless (${$_[1]} =~ /^.*\s+(pop3d|pop3d-ssl|imapd|imapd-ssl):\s+.*$/o);
# Looking for accounting lines only
printf STDERR "DEBUG: ACC_POP_IMAP: %s\n", ${$_[1]} if ($main::opts{'debug'} & 0x0001 ) ;
return unless (/^.*\s+(rcvd|sent)=\d+.*$/o) ;
printf STDERR "DEBUG: ACC_POP_IMAP: %s\n", ${$_[1]} if ($main::opts{'debug'} & 0x0002 ) ;
undef $user; undef $ip; undef $rcvd; undef $sent;
# Get user
if (${$_[1]} =~ /\s+user=([^\s,]+).*/o ) {
$user = lc($1);
};
if (${$_[1]} =~ /\s+ip=\[([^\s,]+)\].*$/o ) {
$ip = lc($1);
# Convert IPv4 compatible IPv6 addresses into IPv4 ones
$ip =~ s/^::ffff:([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})$/$1/o;
};
if (${$_[1]} =~ /\s+rcvd=([^\s,]+).*$/o ) {
$rcvd = $1;
};
if (${$_[1]} =~ /\s+sent=([^\s,]+).*$/o ) {
$sent = $1;
};
if ( ! (defined $user && defined $ip && defined $rcvd && defined $sent ) ) {
# not a proper accounting line
return;
};
# Append domain to user
if (! ( $user =~ /@/o ) ) {
$user .= "@" . $main::opts{'mydomainname'};
};
printf STDERR "DEBUG: ACC_POP_IMAP: user=%s ip=[%s] rcvd=%s sent=%s\n", $user, $ip, $rcvd, $sent if ($main::opts{'debug'} & 0x0010 ) ;
# Hook "testipaddress"
for my $p_hook (keys %{$main::hooks{'testipaddress'}}) {
if ( &{$main::hooks{'testipaddress'}->{$p_hook}} ($ip) != 0 ) {
# excluded
printf STDERR "DEBUG: ACC_POP_IMAP: excluded from accounting\n" if ($main::opts{'debug'} & 0x0010 ) ;
return;
};
};
if ( ! defined $main::opts{'acc_notcpoverhead'} ) {
# 3x40 SYN, 4x40 FIN = 7x40 = 280
# Assume MTU 1500 and 10% ACKs by receiver, uncalculable: TCP options
$tcpoverhead = 280 + ( int(($sent + 1459) / 1460) + int(($rcvd + 1459) / 1460) ) * 44;
} else {
$tcpoverhead = 0;
};
$accounting_pop_imap{'user'}->{$user} += $rcvd + $sent + $tcpoverhead;
$accounting_pop_imap{'domain'}->{::extract_domain($user)} += $rcvd + $sent + $tcpoverhead;
return;
};
# print result
sub print_result() {
return if ( $main::types{'accpopimap'} == 0);
my $sum;
my %accounting;
my $p_hash;
my $format;
print "\n# Accounting data also contains following overheads:\n";
print "# + TCP overhead (partially estimated)\n" if (! defined $main::opts{'acc_notcpoverhead'});
# Format: treeview
if (defined $main::format{"treeview"}) {
$format = "treeview";
print "\n\nWARNING(accpopimap): Format '" . $format . "' is currently not supported!\n\n";
};
# Format: computer
if (defined $main::format{"computer"}) {
$format = "computer";
print "\n\nWARNING(accpopimap): Format '" . $format . "' is currently not supported!\n\n";
};
# Format: indented
if (defined $main::format{"indented"}) {
$format = "indented";
print "\n\nWARNING(accpopimap): Format '" . $format . "' is currently not supported!\n\n";
};
# Format: txttable
if (defined $main::format{"txttable"}) {
$format = "txttable";
::print_headline("Accounting statistics for POP & IMAP", $format);
::print_timerange($format);
if (defined $main::opts{'show_users'}) {
$p_hash = $accounting_pop_imap{'user'};
%accounting = %$p_hash;
if (%accounting) {
$sum = 0;
print '=' x $main::opts{'print-max-width'} . "\n";
printf "%-*s: %6s\n", $main::opts{'print-max-width'} - 25, "User", "BytesTraffic";
print '-' x $main::opts{'print-max-width'} . "\n";
for my $user (sort keys %accounting) {
if ( ! defined $accounting{$user} ) { $accounting{$user} = 0; };
$sum += $accounting{$user};
printf "%-*s: %9d %9s\n",
$main::opts{'print-max-width'} - 25,
substr ($user, 0, $main::opts{'print-max-width'} - 25),
$accounting{$user},
$main::numberformat{$main::opts{'numberformat'}}->format_bytes($accounting{$user});
};
print '-' x $main::opts{'print-max-width'} . "\n";
printf "%-*s: %9d %9s\n", $main::opts{'print-max-width'} - 25, "Total",
$sum,
$main::numberformat{$main::opts{'numberformat'}}->format_bytes($sum);
print '=' x $main::opts{'print-max-width'} . "\n";
} else {
print "!! NO DATA !!\n";
};
print "\n";
};
$p_hash = $accounting_pop_imap{'domain'};
if (defined $p_hash) {
%accounting = %$p_hash;
$sum = 0;
print '=' x $main::opts{'print-max-width'} . "\n";
printf "%-*s: %6s\n", $main::opts{'print-max-width'} - 25, "Domain", "BytesTraffic";
print '-' x $main::opts{'print-max-width'} . "\n";
for my $domain (sort keys %accounting) {
if ( ! defined $accounting{$domain} ) { $accounting{$domain} = 0; };
$sum += $accounting{$domain};
printf "%-*s: %9d %9s\n",
$main::opts{'print-max-width'} - 25,
substr ($domain, 0, $main::opts{'print-max-width'} - 25),
$accounting{$domain},
$main::numberformat{$main::opts{'numberformat'}}->format_bytes($accounting{$domain});
};
print '-' x $main::opts{'print-max-width'} . "\n";
printf "%-*s: %9d %9s\n", $main::opts{'print-max-width'} - 25, "Total",
$sum,
$main::numberformat{$main::opts{'numberformat'}}->format_bytes($sum);
print '=' x $main::opts{'print-max-width'} . "\n";
} else {
print "!! NO DATA !!\n";
};
print "\n";
};
};
## Local functions
## End of module
return 1;
syntax highlighted by Code2HTML, v. 0.9.1