######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # freeradius logwatch filter # written by Jonas Marczona 28.12.2011 # ## 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; if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside freeradius Filter \n\n"; $DebugCounter = 1; } my %OtherList = (); my %loginsOk = (); my %certificateExpired = (); my %wrongPassword = (); my %wrongUser = (); my %wrong_client = (); my %invalidUser = (); my %discards = (); my %warnings = (); my %givingUps = (); my $crlExpired = 0; my $killedChilds = 0; my $reloaded = 0; my $requests = 0; my $requests_duration = 0; my $started = 0; my $stopped = 0; my $ThisLine; while (defined($ThisLine = )) { if ( $Debug >= 5 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } chomp($ThisLine); # Strip leading session id my ($SessionID) = ($ThisLine =~ s/^\((\d+)\) *//); if ( ( $ThisLine =~ /^(?:Info: )?F-TICKS/ ) || ( $ThisLine =~ /^(?:Info: )?Access-Request from/ ) || ( $ThisLine =~ /^(?:Info: )? \.\.\. (?:closing|adding new) socket/ ) || ( $ThisLine =~ /^(?:Info: )?(?:SSL|TLS|rlm_(?:unix|eap|sql|radutmp)| TLS_accept| \[ldap\])/ ) || ( $ThisLine =~ /^(?:Info: )?Ready to process requests/ ) || ( $ThisLine =~ /^(?:Info: )?Debugger not attached/ ) || ( $ThisLine =~ /^(?:Info: )?Exiting normally/ ) || ( $ThisLine =~ /^(?:Info: )?Loaded virtual server/ ) || ( $ThisLine =~ /^(?:Info: )?HUP - / ) || ( $ThisLine =~ /^(?:Info: )?Ignoring / ) || ( $ThisLine =~ /^(?:Info: )?Received HUP signal/ ) || ( $ThisLine =~ /^(?:Info: )? ?Module: Reloaded module/ ) || ( $ThisLine =~ /^(?:Info: )?Signalled to terminate/ ) || # TD: # Skipping contents of 'if' as it is always 'false' -- /etc/raddb/sites-enabled/inner-tunnel # This is a standard config item ( $ThisLine =~ /^(?:Info: )? *# Skipping contents of 'if' as it is always 'false' -- .*inner-tunnel/ ) || # TD: [/etc/raddb/mods-config/attr_filter/access_reject]:11 Check item "FreeRADIUS-Response-Delay-USec" found in filter list for realm "DEFAULT". # This is triggered by a standard config item and is harmless ( $ThisLine =~ /access_reject\]:\d+ Check item "FreeRADIUS-Response-Delay(?:-USec)?"\s*found in filter list for realm/ ) || # These should precede Login incoreect messages ( $ThisLine =~ /^eap_tls: *ERROR: \(TLS\) .*(?:certificate.*expired|Error in error)/ ) || # We count completed events below ( $ThisLine =~ /^(?:Info: )?(?:Start|Stopp|Reload)ing FreeRADIUS/ ) ) { # ignore } # TD: Login OK: [user@example.com] (from client radius port 0) # TD: Login OK: [user@example.com] (from client radius port 9 cli 00-11-22-33-44-AA;eduroam via TLS tunnel) elsif ( my ($user) = ($ThisLine =~ m/^(?:Auth: )?Login OK: \[(.+)\] \(from client [^ ]* port \d{1,10}(?: cli [-0-9a-fA-F.:]+)?(?:;\w+)?(?: via TLS tunnel)?\)/) ) { $loginsOk{$user}++; } # TD: Login incorrect ( [ldap] User not found): [user@example.com] (from client radius port 13 cli 38-16-dd-aa-bb-cc via TLS tunnel) # TD: Login incorrect (mschap: External script says Logon failure (0xc000006d)): [user@example.com] (from client radius port 13 cli aa-bb-cc-11-22-33 via TLS tunnel) # TD: Login incorrect (TLS Alert write:fatal:handshake failure): [user@example.com] (from client radius port 13 cli aa-bb-cc-11-22-33) # TD: Login incorrect (No Auth-Type found: rejecting the user via Post-Auth-Type = Reject): [04d9f5bc5541] (from client nwra port 50104 cli 04-D9-F5-BC-55-41) elsif ( my ($user, $client) = ( $ThisLine =~ m/^(?:Auth: )?Login incorrect(?: \([^)]+\))?: \[(.*)\] \(from client [^ ]* port \d{1,10}(?: cli ([-0-9a-fA-F.:]+)(?:;\w+)?)?(?: via TLS tunnel)?\)/) ) { if (! $client) { $client = "*not named*"; } $wrongUser{$client}{$user}++; $wrong_client{$client}++; } # TD: Login incorrect: [user@example.com] (from client radius port 175143 cli cc08.e051.a240) # TD: Login incorrect: [user@example.com] (from client radius1 port 0) elsif ( my ($user, $client) = ($ThisLine =~ m/^(?:Auth: )?Login incorrect: \[(.+)\] \(from client [^ ]* port \d{1,10}(?: cli ([-0-9a-fA-F.:]+))?(?: via TLS tunnel)?\)/) ) { if (! $client) { $client = "*not named*"; } $wrongPassword{$client}{$user}++; $wrong_client{$client}++; } # TD: Login incorrect (eap_tls: (TLS) OpenSSL says error 10 : certificate has expired): [USERNAME] (from client CLIENTNAME port 50427 cli F8-E4-3B-F1-80-90) elsif ( my ($user, $client) = ( $ThisLine =~ m/^(?:Auth: )?Login incorrect \(.*certificate has expired\): \[(.*)\] \(from client [^ ]* port \d{1,10}(?: cli ([-0-9a-fA-F.:]+)(?:;\w+)?)?(?: via TLS tunnel)?\)/) ) { if (! $client) { $client = "*not named*"; } $certificateExpired{$client}{$user}++; $wrong_client{$client}++; } # TD: Invalid user ( [ldap] Access Attribute denies access): [user@example.com] (from client radius port 13 cli aa-bb-cc-dd-ee-11 via TLS tunnel) # TD: Invalid user: [user@example.com] (from client port 13 cli aa-bb-cc-dd-ee-11) elsif ( my ($reason, $user, $client) = ($ThisLine =~ m/^(?:Auth: )?Invalid user(?: \(\s*(.+)\))?: \[(.+)\] \(from client [^ ]* port \d{1,10}(?: cli ([-0-9a-fA-F.:]+))?(?: via TLS tunnel)?\)/) ) { if (! $client) { $client = "*not named*"; } if (! $reason) { $reason = "*no reason*"; } $invalidUser{$reason}{$user}++; } # TD: Discarding duplicate request from client port 47609 - ID: 182 due to unfinished request 12713766 # TD: Discarding conflicting packet from client port 42221 - ID: 85 due to recent request 9008535. elsif ( my ($reason, $client) = ($ThisLine =~ /Discarding (duplicate request|conflicting packet) from client (\S+) port \d+ - ID: \d+ due to (unfinished|recent) request/) ) { $discards{$reason}{$client}++; } # TD: Received conflicting packet from client radius2 port 60612 - ID: 30 due to unfinished request 1136681. Giving up on old request. elsif ( my ($client) = ($ThisLine =~ /Received conflicting packet from client ([^ ]+) port \d{1,10} - ID: \d+ due to unfinished request \d+/) ) { $givingUps{$client}++; } # TD: eap_tls: ERROR: SSL says error 12 : CRL has expired elsif ( $ThisLine =~ m/CRL has expired/ ) { $crlExpired++; } # TD: Child PID 57436 is taking too much time: forcing failure and killing child. elsif ( $ThisLine =~ m/Child PID \d+ is taking too much time: forcing failure and killing child/ ) { $killedChilds++; } # TD: Started FreeRADIUS high performance RADIUS server.. elsif ( $ThisLine =~ /^Started FreeRADIUS/ ) { $started++; } # TD: Stopping FreeRADIUS high performance RADIUS server.. elsif ( $ThisLine =~ /^Stopped FreeRADIUS/ ) { $stopped++; } # TD: Reloading FreeRADIUS high performance RADIUS server elsif ( $ThisLine =~ /^Reloaded FreeRADIUS/ ) { $reloaded++; } # TD: Request 67678577 has been waiting in the processing queue for 378 seconds. Check that all databases are running properly! elsif ($ThisLine =~ m/^Request \d+ has been waiting in the processing queue for (\d+) seconds/) { $requests++; $requests_duration += $1; } # TD: WARNING: Unresponsive child for request 4737598, in component accounting module unix # TD: WARNING: Child is hung for request 4737598 in component accounting module unix. elsif ( $ThisLine =~ m/^WARNING: (Unresponsive child|Child is hung) for request \d+,? in component ([<>\w]+) module ?([<>\w]*)/ ) { $warnings{"$1 in component:"}{"$2 [module: $3]"}++; } # TD: WARNING: Allowing fast client radius2 port 60612 - ID: 102 for recent request 9035637. elsif ( $ThisLine =~ m/^WARNING: (Allowing fast client) ([^ ]+) port \d{1,10} - ID: \d+/ ) { $warnings{"${1}s:"}{$2}++; } else { # Report any unmatched entries... $OtherList{$ThisLine}++; } } ################################# # Output section ################################ if ($requests > 0) { printf "Long running requests: Check that all databases are running properly!\n"; printf " %-40s : %5d\n", 'Long running requests', $requests; printf " %-40s : %5d s\n", 'avg queue time per long running request', $requests_duration / $requests; print "\n"; } sub compPerMacAddr { return $wrong_client{$b} <=> $wrong_client{$a}; } if ($Detail >= 8) { if (keys %wrong_client) { print "\nSum of failed logins per client (wrong password or user)\n"; foreach my $client (sort compPerMacAddr keys %wrong_client) { printf " %-40s : %5d time(s)\n", $client, $wrong_client{$client}; } } } if (keys %certificateExpired) { if ($Detail >= 3) { print "\nFailed logins - certificate expired:\n"; foreach my $client (sort compPerMacAddr keys %certificateExpired) { my $users = $certificateExpired{$client}; printf " %-40s\n", $client ; foreach my $user (sort {$users->{$b} <=> $users->{$a}} keys %$users) { #print " $user ", $users->{$user}, " time(s)\n"; printf " %-38s : %5d time(s)\n", $user, $users->{$user}; } } } else { my $certificateExpiredSum = 0; foreach my $client (%certificateExpired) { my $users = $certificateExpired{$client}; foreach my $user (keys %$users) { $certificateExpiredSum += $users->{$user}; } } printf "\n%-42s : %5d time(s)\n", "Failed logins - certificate expired", $certificateExpiredSum; } } if (keys %wrongUser) { if ($Detail >= 3) { print "\nFailed logins - wrong user name:\n"; foreach my $client (sort compPerMacAddr keys %wrongUser) { printf " %-40s\n", $client; my $users = $wrongUser{$client}; foreach my $user (sort {$users->{$b} <=> $users->{$a}} keys %$users) { printf " %-38s : %5d time(s)\n", $user, $users->{$user}; } } } else { my $userSum = 0; foreach my $client (keys %wrongUser) { my $users = $wrongUser{$client}; foreach my $user (keys %$users) { $userSum += $users->{$user}; } } printf "\n%-42s : %5d time(s)\n", "Failed logins - wrong user name", $userSum; } } if (keys %wrongPassword) { if ($Detail >= 6) { print "\nFailed logins - wrong password:\n"; foreach my $client (sort compPerMacAddr keys %wrongPassword) { my $users = $wrongPassword{$client}; printf " %-40s\n", $client ; foreach my $user (sort {$users->{$b} <=> $users->{$a}} keys %$users) { #print " $user ", $users->{$user}, " time(s)\n"; printf " %-38s : %5d time(s)\n", $user, $users->{$user}; } } } else { my $wrongPasswordSum = 0; foreach my $client (%wrongPassword) { my $users = $wrongPassword{$client}; foreach my $user (keys %$users) { $wrongPasswordSum += $users->{$user}; } } printf "\n%-42s : %5d time(s)\n", "Failed logins - wrong password", $wrongPasswordSum; } } if (keys %invalidUser) { if ($Detail >= 6) { print "\nInvalid User:\n"; foreach my $reason (keys %invalidUser) { my $users = $invalidUser{$reason}; printf " %-40s\n", $reason; foreach my $user (sort {$users->{$b} <=> $users->{$a}} keys %$users) { printf " %-38s : %5d time(s)\n", $user, $users->{$user}; } } } else { my $invalidUserSum = 0; foreach my $reason (keys %invalidUser) { my $users = $invalidUser{$reason}; foreach my $user (keys %$users) { $invalidUserSum += $users->{$user}; } } printf "\n%-42s : %5d time(s)\n", "Invalid Users", $invalidUserSum; } } if (keys %discards) { print "\nDiscards:\n"; foreach my $reason (keys %discards) { my $clients = $discards{$reason}; printf " %-40s\n", $reason; foreach my $client (keys %$clients) { printf " %-38s : %5d time(s)\n", $client, $clients->{$client}; } } } if (keys %givingUps) { print "\nGiving up on old requests:\n"; foreach my $client (keys %givingUps) { printf " %-40s : %5d time(s)\n", $client, $givingUps{$client}; } } if ($crlExpired) { printf "\nCRL Expired: %5d time(s)\n", $crlExpired; } if ($killedChilds) { printf "\n%-42s : %5d time(s)\n", "Killed Childs (taking too much time)", $killedChilds; } if (%warnings) { print "\nWarnings:\n"; foreach my $warning (keys %warnings) { my $components = $warnings{$warning}; printf " %-40s\n", $warning; foreach my $component (keys %$components) { printf " %-38s : %5d time(s)\n", $component, $components->{$component}; } } } if (keys %loginsOk) { if ($Detail >= 10) { print "\nSuccessful logins:\n"; foreach my $user (sort {$loginsOk{$b} <=> $loginsOk{$a}} keys %loginsOk) { printf " %-40s : %5d time(s)\n", $user, $loginsOk{$user}; } } elsif ($Detail >= 6) { my $loginsOkSum = 0; foreach my $user (keys %loginsOk) { $loginsOkSum += $loginsOk{$user}; } printf "\n%-42s : %5d time(s)\n", "Successful logins", $loginsOkSum; } } if ($Detail >= 5 && $started) { printf "\nServer started: %5d time(s)\n", $started; } if ($Detail >= 5 && $stopped) { printf "\nServer stopped: %5d time(s)\n", $stopped; } if ($Detail >= 5 && $reloaded) { printf "\nServer reloaded: %5d time(s)\n", $reloaded; } if (keys %OtherList) { print "\n**** Unmatched entries ****\n"; foreach (keys %OtherList) { print " $_ : $OtherList{$_} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et