#!/usr/bin/perl

##########################################################################
# $Id: stunnel 266 2014-11-12 10:29:44Z stefjakobs $
##########################################################################

#######################################################
## Copyright (c) 2008 Kirk Bauer
## Covered under the included MIT/X-Consortium License:
##    http://www.opensource.org/licenses/mit-license.php
## All modifications and contributions by other persons to
## this script are assumed to have been donated to the
## Logwatch project and thus assume the above copyright
## and licensing terms.  If you want to make contributions
## under your own copyright or a different license this
## must be explicitly stated in the contribution an the
## Logwatch project reserves the right to not accept such
## contributions.  If you have made significant
## contributions to this script and want to claim
## copyright please contact logwatch-devel@lists.sourceforge.net.
#########################################################

$^W=1;
use strict;

my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0;
my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;

my $DebugCounter = 0;
my $Top = $ENV{'stunnel_print_top'} || 20;

if ( $Debug >= 5 ) {
   print STDERR "\n\nDEBUG: Inside stunnel Filter \n\n";
   $DebugCounter = 1;
}

my @OtherList = ();
my %OtherList = ();
my %connections = ();
my %versioninfo = ();
my %errors = ();
my %notices = ();
my $sockdata = 0;
my $ssldata = 0;

sub other {
   my $msg = shift;
   unless (exists $OtherList{$msg}) {
      $OtherList{$msg} = 1;
      push(@OtherList, $msg);
   } else {
      $OtherList{$msg}++;
   }
}

my $ThisLine;
while (defined($ThisLine = <STDIN>)) {
   $ThisLine =~ s/LOG\d\[\d{1,5}:\d{15}\]: (.*)/$1/;
   if ( $Debug >= 5 ) {
      print STDERR "DEBUG($DebugCounter): $ThisLine";
      $DebugCounter++;
   }
   chomp($ThisLine);
   my $origline = $ThisLine;
   if ($ThisLine =~ m/^(.+) connected from (\d+\.\d+\.\d+\.\d+)/) {
      my $service = $1;
      my $ip = $2;
      if (! exists($connections{$service}{$ip})) {
        $connections{$service}{$ip} = 0;
      }
      ++$connections{$service}{$ip};
   } elsif ($ThisLine =~ m/^Connection (reset|closed): (\d+) bytes sent to SSL, (\d+) bytes sent to socket/) {
      $ssldata += $2;
      $sockdata += $3;
   } elsif ($ThisLine =~ m/^Connection (reset|closed)/) {
      # ignore
   } elsif ($ThisLine =~ m/^connect_blocking: connected/) {
      # ignore
   } elsif ($ThisLine =~ m/^connect_blocking: getsockopt ([0-9a-fA-F.:]+: Connection refused) \(\d+\)$/) {
      $errors{"connect_blocking: $1"}++;
   } elsif ($ThisLine =~ m/^(?:remote socket|local socket|accept): (Too many open files) \(\d+\)$/) {
      $errors{"$1: increase the maximum number of open file descriptors"}++;
   } elsif ($ThisLine =~ m/^Log file reopened$/) {
      # ignore
   } elsif ($ThisLine =~ m/^SSL socket closed on SSL_read with \d+ byte\(s\) in buffer$/) {
      # ignore
   } elsif ($ThisLine =~ m/^stunnel [\d\.]+ on [\w\-]+ [\w\+]+ with OpenSSL [\w\.]+ \d+ \w+ \d+/) {
      $versioninfo{$ThisLine} = 1;
   } elsif ($ThisLine =~ m/^Service (\S+) accepted connection from ([0-9a-fA-F.:]+):\d{1,5}/) {
      $connections{$1}{$2}++;
   } elsif ($ThisLine =~ m/^Service (\S+) connected remote server from ([0-9a-fA-F.:]+):\d{1,5}/) {
      $connections{"remote: $1"}{$2}++;
   } elsif ($ThisLine =~ m/^Error detected on (SSL|socket) \((read|write)\) file descriptor: (.*) \(\d+\)/) {
      $errors{"$1 $2 file descriptor: $3"}++;
   } elsif ($ThisLine =~ m/^(SSL_write: (?:Broken pipe|Connection reset by peer)) \(\d+\)$/) {
      $errors{"$1"}++;
   } elsif ($ThisLine =~ m/^transfer: s_poll_wait: TIMEOUTclose exceeded: closing$/) {
      $notices{"TIMEOUTclose exceeded: closing connection"}++;
   } elsif ($ThisLine =~ m/^(SSL_(?:accept|read|shutdown): .*|getpeerbyname: .*)(?: \(\d+\))?$/) {
      $notices{$1}++;
   } else {
      # Report any unmatched entries...
      other($ThisLine);
   }
}

if (keys %errors) {
   print "\nErrors:\n";
   foreach my $e (sort keys %errors) {
      printf "  %-50s  %6d time(s)\n", $e, $errors{$e};
   }
}

if (keys %notices) {
   print "\nNotices:\n";
   foreach my $n (sort keys %notices) {
      printf "  %-50s  %6d time(s)\n", $n, $notices{$n};
   }
}

if (keys %connections) {
   print "\nconnections:\n";
   foreach my $service (sort keys %connections) {
     print "  $service\n";
     my $ips = $connections{$service};
     my $i = 0;
     foreach my $ip (sort {$connections{$service}{$b} <=> $connections{$service}{$a}} keys %{$connections{$service}}) {
        if ($i >= $Top) {
           printf "    %-48s\n", "... only top $Top printed ...";
           last;
        } else {
           printf "    %-48s  %6d time(s)\n", $ip, $connections{$service}{$ip};
           $i++;
        }
     }
   }
}

if ($sockdata > 0) {
   if ($sockdata > 1024*1024) {
      printf "\n%-48s  %10.2f MB\n", "amount of socket data transferred:", $sockdata / 1024 / 1024;
   } else {
      printf "\n%-48s  %10.2f KB\n", "amount of socket data transferred:", $sockdata / 1024;
   }
}

if ($ssldata > 0) {
   if ($ssldata > 1024*1024) {
      printf "\n%-48s  %10.2f MB\n", "amount of SSL data transferred:", $ssldata / 1024 / 1024;
   } else {
      printf "\n%-48s  %10.2f KB\n", "amount of SSL data transferred:", $ssldata / 1024;
   }
}

if (keys %versioninfo) {
   print "\nversion information:\n";
   foreach my $v (sort keys %versioninfo) {
      print "  $v\n";
   }
}

if (@OtherList) {
   print "\n**Unmatched Entries**\n";
   for (@OtherList) {
     my $count = $OtherList{$_};
     print "($count) $_\n";
   }
}

exit(0);

# vi: shiftwidth=3 tabstop=3 syntax=perl et
# Local Variables:
# mode: perl
# perl-indent-level: 3
# indent-tabs-mode: nil
# End:
