Home | History | Annotate | Line # | Download | only in tools
      1 #! /usr/pkg/bin/perl
      2 # -*- mode: perl; perl-indent-level: 8 -*-
      3 # 
      4 # Copyright (c) 2003 Kungliga Tekniska Hgskolan
      5 # (Royal Institute of Technology, Stockholm, Sweden). 
      6 # All rights reserved. 
      7 # 
      8 # Redistribution and use in source and binary forms, with or without 
      9 # modification, are permitted provided that the following conditions 
     10 # are met: 
     11 # 
     12 # 1. Redistributions of source code must retain the above copyright 
     13 #    notice, this list of conditions and the following disclaimer. 
     14 # 
     15 # 2. Redistributions in binary form must reproduce the above copyright 
     16 #    notice, this list of conditions and the following disclaimer in the 
     17 #    documentation and/or other materials provided with the distribution. 
     18 # 
     19 # 3. Neither the name of the Institute nor the names of its contributors 
     20 #    may be used to endorse or promote products derived from this software 
     21 #    without specific prior written permission. 
     22 # 
     23 # THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
     24 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
     25 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
     26 # ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
     27 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
     28 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
     29 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
     30 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
     31 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
     32 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
     33 # SUCH DAMAGE. 
     34 #
     35 # Id
     36 #
     37 # kdc-log-analyze - Analyze a KDC log file and give a report on the contents
     38 #
     39 # Note: The parts you want likely want to customize are the variable $notlocal,
     40 # the array @local_network_re and the array @local_realms.
     41 #
     42 # Idea and implemetion for MIT Kerberos was done first by 
     43 # Ken Hornstein <kenh (at] cmf.nrl.navy.mil>, this program wouldn't exists
     44 # without his help.
     45 #
     46 
     47 use strict;
     48 use Sys::Hostname;
     49 
     50 my $notlocal = 'not SU';
     51 my @local_realms = ( "SU.SE" );
     52 my @local_networks_re = 
     53     ( 
     54       "130\.237",
     55       "193\.11\.3[0-9]\.",
     56       "130.242.128",
     57       "2001:6b0:5:"
     58       );
     59 
     60 my $as_req = 0;
     61 my %as_req_addr;
     62 my %as_req_addr_nonlocal;
     63 my %as_req_client;
     64 my %as_req_server;
     65 my %addr_uses_des;
     66 my %princ_uses_des;
     67 my $five24_req = 0;
     68 my %five24_req_addr;
     69 my %five24_req_addr_nonlocal;
     70 my %five24_req_server;
     71 my %five24_req_client;
     72 my $as_req_successful = 0;
     73 my $as_req_error = 0;
     74 my $no_such_princ = 0;
     75 my %no_such_princ_princ;
     76 my %no_such_princ_addr;
     77 my %no_such_princ_addr_nonlocal;
     78 my $as_req_etype_odd = 0;
     79 my %bw_addr;
     80 my $pa_alt_princ_request = 0;
     81 my $pa_alt_princ_verify = 0;
     82 my $tgs_req = 0;
     83 my %tgs_req_addr;
     84 my %tgs_req_addr_nonlocal;
     85 my %tgs_req_client;
     86 my %tgs_req_server;
     87 my $tgs_xrealm_out = 0;
     88 my %tgs_xrealm_out_realm;
     89 my %tgs_xrealm_out_princ;
     90 my $tgs_xrealm_in = 0;
     91 my %tgs_xrealm_in_realm;
     92 my %tgs_xrealm_in_princ;
     93 my %enctype_session;
     94 my %enctype_ticket;
     95 my $restarts = 0;
     96 my $forward_non_forward = 0;
     97 my $v4_req = 0;
     98 my %v4_req_addr;
     99 my %v4_req_addr_nonlocal;
    100 my $v4_cross = 0;
    101 my %v4_cross_realm;
    102 my $v5_cross = 0;
    103 my %v5_cross_realm;
    104 my $referrals = 0;
    105 my %referral_princ;
    106 my %referral_realm;
    107 my %strange_tcp_data;
    108 my $http_malformed = 0;
    109 my %http_malformed_addr;
    110 my $http_non_kdc = 0;
    111 my %http_non_kdc_addr;
    112 my $tcp_conn_timeout = 0;
    113 my %tcp_conn_timeout_addr;
    114 my $failed_processing = 0;
    115 my %failed_processing_addr;
    116 my $connection_closed = 0;
    117 my %connection_closed_addr;
    118 my $pa_failed = 0;
    119 my %pa_failed_princ;
    120 my %pa_failed_addr;
    121 my %ip;
    122 
    123 $ip{'4'} = $ip{'6'} = 0;
    124 
    125 while (<>) {
    126 	process_line($_);
    127 }
    128 
    129 print "Kerberos KDC Log Report for ", 
    130     hostname, " on ", scalar localtime, "\n\n";
    131 
    132 print "General Statistics\n\n";
    133 
    134 print "\tNumber of IPv4 requests: $ip{'4'}\n";
    135 print "\tNumber of IPv6 requests: $ip{'6'}\n\n";
    136 
    137 print "\tNumber of restarts: $restarts\n";
    138 print "\tNumber of V4 requests: $v4_req\n";
    139 if ($v4_req > 0) {
    140 	print "\tTop ten IP addresses performing V4 requests:\n";
    141 	topten(\%v4_req_addr);
    142 }
    143 if (int(keys %v4_req_addr_nonlocal) > 0) {
    144 	print "\tTop ten $notlocal IP addresses performing V4 requests:\n";
    145 	topten(\%v4_req_addr_nonlocal);
    146 
    147 }
    148 print "\n";
    149 
    150 print "\tNumber of V4 cross realms (krb4 and 524) requests: $v4_cross\n";
    151 if ($v4_cross > 0) {
    152 	print "\tTop ten realms performing V4 cross requests:\n";
    153 	topten(\%v4_cross_realm);
    154 }
    155 print "\n";
    156 
    157 print "\tNumber of V45 cross realms requests: $v5_cross\n";
    158 if ($v5_cross > 0) {
    159 	print "\tTop ten realms performing V4 cross requests:\n";
    160 	topten(\%v5_cross_realm);
    161 }
    162 print "\n";
    163 
    164 print "\tNumber of failed lookups: $no_such_princ\n";
    165 if ($no_such_princ > 0) {
    166 	print "\tTop ten IP addresses failing to find principal:\n";
    167 	topten(\%no_such_princ_addr);
    168 	print "\tTop ten $notlocal IP addresses failing find principal:\n";
    169 	topten(\%no_such_princ_addr_nonlocal);
    170 	print "\tTop ten failed to find principals\n";
    171 	topten(\%no_such_princ_princ);
    172 }
    173 print "\n";
    174 
    175 print "\tBandwidth pigs:\n";
    176 topten(\%bw_addr);
    177 print "\n";
    178 
    179 print "\tStrange TCP data clients: ", int(keys %strange_tcp_data),"\n";
    180 topten(\%strange_tcp_data);
    181 print "\n";
    182 
    183 print "\tTimeout waiting on TCP requests: ", $tcp_conn_timeout,"\n";
    184 if ($tcp_conn_timeout > 0) {
    185 	print "\tTop ten TCP timeout request clients\n";
    186 	topten(\%tcp_conn_timeout_addr);
    187 }
    188 print "\n";
    189 
    190 print "\tFailed processing requests: ", $failed_processing,"\n";
    191 if ($failed_processing > 0) {
    192 	print "\tTop ten failed processing request clients\n";
    193 	topten(\%failed_processing_addr);
    194 }
    195 print "\n";
    196 
    197 print "\tConnection closed requests: ", $connection_closed,"\n";
    198 if ($connection_closed > 0) {
    199 	print "\tTop ten connection closed request clients\n";
    200 	topten(\%connection_closed_addr);
    201 }
    202 print "\n";
    203 
    204 print "\tMalformed HTTP requests: ", $http_malformed,"\n";
    205 if ($http_malformed > 0) {
    206 	print "\tTop ten malformed HTTP request clients\n";
    207 	topten(\%http_malformed_addr);
    208 }
    209 print "\n";
    210 
    211 print "\tHTTP non kdc requests: ", $http_non_kdc,"\n";
    212 if ($http_non_kdc > 0) {
    213 	print "\tTop ten HTTP non KDC request clients\n";
    214 	topten(\%http_non_kdc_addr);
    215 }
    216 print "\n";
    217 
    218 print "Report on AS_REQ requests\n\n";
    219 print "Overall AS_REQ statistics\n\n";
    220 
    221 print "\tTotal number: $as_req\n";
    222 
    223 print "\nAS_REQ client/server statistics\n\n";
    224 
    225 print "\tDistinct IP Addresses performing requests: ", 
    226     int(keys %as_req_addr),"\n";
    227 print "\tOverall top ten IP addresses\n";
    228 topten(\%as_req_addr);
    229 
    230 print "\tDistinct non-local ($notlocal) IP Addresses performing requests: ",
    231 					int(keys %as_req_addr_nonlocal), "\n";
    232 print "\tTop ten non-local ($notlocal) IP address:\n";
    233 topten(\%as_req_addr_nonlocal);
    234 
    235 print "\n\tPreauth failed for for: ", $pa_failed, " requests\n";
    236 if ($pa_failed) {
    237 	print "\tPreauth failed top ten IP addresses:\n";
    238 	topten(\%pa_failed_addr);
    239 	print "\tPreauth failed top ten principals:\n";
    240 	topten(\%pa_failed_princ);
    241 }
    242 
    243 print "\n\tDistinct clients performing requests: ", 
    244     int(keys %as_req_client), "\n";
    245 print "\tTop ten clients:\n";
    246 topten(\%as_req_client);
    247 
    248 print "\tDistinct services requested: ", int(keys %as_req_server), "\n";
    249 print "\tTop ten requested services:\n";
    250 topten(\%as_req_server);
    251 
    252 print "\n\n\nReport on TGS_REQ requests:\n\n";
    253 print "Overall TGS_REQ statistics\n\n";
    254 print "\tTotal number: $tgs_req\n";
    255 
    256 print "\nTGS_REQ client/server statistics\n\n";
    257 print "\tDistinct IP addresses performing requests: ",
    258 				int(keys %tgs_req_addr), "\n";
    259 print "\tOverall top ten IP addresses\n";
    260 topten(\%tgs_req_addr);
    261 
    262 print "\tDistinct non-local ($notlocal) IP Addresses performing requests: ",
    263 				int(keys %tgs_req_addr_nonlocal), "\n";
    264 print "\tTop ten non-local ($notlocal) IP address:\n";
    265 topten(\%tgs_req_addr_nonlocal);
    266 
    267 print "\tDistinct clients performing requests: ",
    268 				int(keys %tgs_req_client), "\n";
    269 print "\tTop ten clients:\n";
    270 topten(\%tgs_req_client);
    271 
    272 print "\tDistinct services requested: ", int(keys %tgs_req_server), "\n";
    273 print "\tTop ten requested services:\n";
    274 topten(\%tgs_req_server);
    275 
    276 print "\n\n\nReport on 524_REQ requests:\n\n";
    277 
    278 print "\t524_REQ client/server statistics\n\n";
    279 
    280 print "\tDistinct IP Addresses performing requests: ", 
    281     int(keys %five24_req_addr),"\n";
    282 print "\tOverall top ten IP addresses\n";
    283 topten(\%five24_req_addr);
    284 
    285 print "\tDistinct non-local ($notlocal) IP Addresses performing requests: ",
    286 					int(keys %five24_req_addr_nonlocal), "\n";
    287 print "\tTop ten non-local ($notlocal) IP address:\n";
    288 topten(\%five24_req_addr_nonlocal);
    289 
    290 print "\tDistinct clients performing requests: ", int(keys %five24_req_client), "\n";
    291 print "\tTop ten clients:\n";
    292 topten(\%five24_req_client);
    293 
    294 print "\tDistinct services requested: ", int(keys %five24_req_server), "\n";
    295 print "\tTop ten requested services:\n";
    296 topten(\%five24_req_server);
    297 print "\n";
    298 
    299 print "Cross realm statistics\n\n";
    300 
    301 print "\tNumber of cross-realm tgs out: $tgs_xrealm_out\n";
    302 if ($tgs_xrealm_out > 0) {
    303 	print "\tTop ten realms used for out cross-realm:\n";
    304 	topten(\%tgs_xrealm_out_realm);
    305 	print "\tTop ten principals use out cross-realm:\n";
    306 	topten(\%tgs_xrealm_out_princ);
    307 }
    308 print "\tNumber of cross-realm tgs in: $tgs_xrealm_in\n";
    309 if ($tgs_xrealm_in > 0) {
    310 	print "\tTop ten realms used for in cross-realm:\n";
    311 	topten(\%tgs_xrealm_in_realm);
    312 	print "\tTop ten principals use in cross-realm:\n";
    313 	topten(\%tgs_xrealm_in_princ);
    314 }
    315 
    316 print "\n\nReport on referral:\n\n";
    317 
    318 print "\tNumber of referrals: $referrals\n";
    319 if ($referrals > 0) {
    320 	print "\tTop ten referral-ed principals:\n";
    321 	topten(\%referral_princ);
    322 	print "\tTop ten to realm referrals:\n";
    323 	topten(\%referral_realm);
    324 }
    325 
    326 print "\n\nEnctype Statistics:\n\n";
    327 print "\tTop ten session enctypes:\n";
    328 topten(\%enctype_session);
    329 print "\tTop ten ticket enctypes:\n";
    330 topten(\%enctype_ticket);
    331 
    332 print "\tDistinct IP addresses using DES: ", int(keys %addr_uses_des), "\n";
    333 print "\tTop IP addresses using DES:\n";
    334 topten(\%addr_uses_des);
    335 print "\tDistinct principals using DES: ", int(keys %princ_uses_des), "\n";
    336 print "\tTop ten principals using DES:\n";
    337 topten(\%princ_uses_des);
    338 
    339 print "\n";
    340 
    341 printf("Requests to forward non-forwardable ticket: $forward_non_forward\n");
    342 
    343 
    344 exit 0;
    345 
    346 my $last_addr = "";
    347 my $last_principal = "";
    348 
    349 sub process_line {
    350 	local($_) = @_;
    351 	#
    352 	# Eat these lines that are output as a result of startup (but
    353 	# log the number of restarts)
    354 	#
    355 	if (/AS-REQ \(krb4\) (.*) from IPv([46]):([0-9\.:a-fA-F]+) for krbtgt.*$/){
    356 		$v4_req++;
    357 		$v4_req_addr{$3}++;
    358 		$v4_req_addr_nonlocal{$3}++ if (!islocaladdr($3));
    359 		$last_addr = $3;
    360 		$last_principal = $1;
    361 		$ip{$2}++;
    362 	} elsif (/AS-REQ (.*) from IPv([46]):([0-9\.:a-fA-F]+) for (.*)$/) {
    363 		$as_req++;
    364 		$as_req_client{$1}++;
    365 		$as_req_server{$4}++;
    366 		$as_req_addr{$3}++;
    367 		$as_req_addr_nonlocal{$3}++ if (!islocaladdr($3));
    368 		$last_addr = $3;
    369 		$last_principal = $1;
    370 		$ip{$2}++;
    371 	} elsif (/TGS-REQ \(krb4\)/) {
    372 		#Nothing
    373 	} elsif (/TGS-REQ (.+) from IPv([46]):([0-9\.:a-fA-F]+) for (.*?)( \[.*\]){0,1}$/) {
    374 		$tgs_req++;
    375 		$tgs_req_client{$1}++;
    376 		$tgs_req_server{$4}++;
    377 		$tgs_req_addr{$3}++;
    378 		$tgs_req_addr_nonlocal{$3}++ if (!islocaladdr($3));
    379 		$last_addr = $3;
    380 		$last_principal = $1;
    381 		$ip{$2}++;
    382 
    383 		my $source = $1;
    384 		my $dest = $4;
    385 		
    386 		if (!islocalrealm($source)) {
    387 			$tgs_xrealm_in++;
    388 			$tgs_xrealm_in_princ{$source}++;
    389 			if ($source =~ /[^@]+@([^@]+)/ ) {
    390 				$tgs_xrealm_in_realm{$1}++;
    391 			}
    392 		}
    393 		if ($dest =~ /krbtgt\/([^@]+)@[^@]+/) {
    394 			if (!islocalrealm($1)) {
    395 				$tgs_xrealm_out++;
    396 				$tgs_xrealm_out_realm{$1}++;
    397 				$tgs_xrealm_out_princ{$source}++;
    398 			}
    399 		}
    400 	} elsif (/524-REQ (.*) from IPv([46]):([0-9\.:a-fA-F]+) for (.*)$/) {
    401 		$five24_req++;
    402 		$five24_req_client{$1}++;
    403 		$five24_req_server{$4}++;
    404 		$five24_req_addr{$3}++;
    405 		$five24_req_addr_nonlocal{$3}++ if (!islocaladdr($3));
    406 		$last_addr = $3;
    407 		$last_principal = $1;
    408 		$ip{$2}++;
    409 	} elsif (/TCP data of strange type from IPv[46]:([0-9\.:a-fA-F]+)/) {
    410 		$strange_tcp_data{$1}++;
    411 	} elsif (/Lookup (.*) failed: No such entry in the database/) {
    412 		$no_such_princ++;
    413 		$no_such_princ_addr{$last_addr}++;
    414 		$no_such_princ_addr_nonlocal{$last_addr}++ if (!islocaladdr($last_addr));
    415 		$no_such_princ_princ{$1}++;
    416 	} elsif (/Lookup .* succeeded$/) {
    417 		# Nothing
    418 	} elsif (/Malformed HTTP request from IPv[46]:([0-9\.:a-fA-F]+)$/) {
    419 		$http_malformed++;
    420 		$http_malformed_addr{$1}++;
    421 	} elsif (/TCP-connection from IPv[46]:([0-9\.:a-fA-F]+) expired after [0-9]+ bytes/) {
    422 		$tcp_conn_timeout++;
    423 		$tcp_conn_timeout_addr{$1}++;
    424 	} elsif (/Failed processing [0-9]+ byte request from IPv[46]:([0-9\.:a-fA-F]+)/) {
    425 		$failed_processing++;
    426 		$failed_processing_addr{$1}++;
    427 	} elsif (/connection closed before end of data after [0-9]+ bytes from IPv[46]:([0-9\.:a-fA-F]+)/) {
    428 		$connection_closed++;
    429 		$connection_closed_addr{$1}++;
    430 	} elsif (/HTTP request from IPv[46]:([0-9\.:a-fA-F]+) is non KDC request/) {
    431 		$http_non_kdc++;
    432 		$http_non_kdc_addr{$1}++;
    433 	} elsif (/returning a referral to realm (.*) for server (.*) that was not found/) {
    434 		$referrals++;
    435 		$referral_princ{$2}++;
    436 		$referral_realm{$1}++;
    437 	} elsif (/krb4 Cross-realm (.*) -> (.*) disabled/) {
    438 		$v4_cross++;
    439 		$v4_cross_realm{$1."->".$2}++;
    440 	} elsif (/524 cross-realm (.*) -> (.*) disabled/) {
    441 		$v4_cross++;
    442 		$v4_cross_realm{$1."->".$2}++;
    443 	} elsif (/cross-realm (.*) -> (.*): no transit through realm (.*)/) {
    444 	} elsif (/cross-realm (.*) -> (.*) via \[([^\]]+)\]/) {
    445 		$v5_cross++;
    446 		$v5_cross_realm{$1."->".$2}++;
    447 	} elsif (/cross-realm (.*) -> (.*)/) {
    448 		$v5_cross++;
    449 		$v5_cross_realm{$1."->".$2}++;
    450 	} elsif (/sending ([0-9]+) bytes to IPv[46]:([0-9\.:a-fA-F]+)/) {
    451 		$bw_addr{$2} += $1;
    452 	} elsif (/Using ([-a-z0-9]+)\/([-a-z0-9]+)/) {
    453 		$enctype_ticket{$1}++;
    454 		$enctype_session{$2}++;
    455 
    456 		my $ticket = $1;
    457 		my $session = $2;
    458 
    459 		if ($ticket =~ /des-cbc-(crc|md4|md5)/) {
    460 			$addr_uses_des{$last_addr}++;
    461 			$princ_uses_des{$last_principal}++;
    462 		}
    463 
    464 	} elsif (/Failed to decrypt PA-DATA -- (.+)$/) {
    465 		$pa_failed++;
    466 		$pa_failed_princ{$last_principal}++;
    467 		$pa_failed_addr{$last_addr}++;
    468 
    469 	} elsif (/Request to forward non-forwardable ticket/) {
    470 		$forward_non_forward++;
    471 	} elsif (/HTTP request:/) {
    472 	} elsif (/krb_rd_req: Incorrect network address/) {
    473 	} elsif (/krb_rd_req: Ticket expired \(krb_rd_req\)/) {
    474 	} elsif (/Ticket expired \(.*\)/) {
    475 	} elsif (/krb_rd_req: Can't decode authenticator \(krb_rd_req\)/) {
    476 	} elsif (/Request from wrong address/) {
    477 		# XXX
    478 	} elsif (/UNKNOWN --/) {
    479 		# XXX
    480 	} elsif (/Too large time skew -- (.*)$/) {
    481 		# XXX
    482 	} elsif (/No PA-ENC-TIMESTAMP --/) {
    483 		# XXX
    484 	} elsif (/Looking for pa-data --/) {
    485 		# XXX
    486 	} elsif (/Pre-authentication succeded -- (.+)$/) {
    487 		# XXX
    488 	} elsif (/Bad request for ([,a-zA-Z0-9]+) ticket/) {
    489 		# XXX
    490 	} elsif (/Failed to verify AP-REQ: Ticket expired/) {
    491 		# XXX 
    492 	} elsif (/Client not found in database:/) {
    493 		# XXX
    494 	} elsif (/Server not found in database \(krb4\)/) {
    495 	} elsif (/Server not found in database:/) {
    496 		# XXX
    497 	} elsif (/newsyslog.*logfile turned over/) {
    498 		# Nothing
    499 	} elsif (/Requested flags:/) {
    500 		# Nothing
    501 	} elsif (/shutting down/) {
    502 		# Nothing
    503 	} elsif (/listening on IP/) {
    504 		# Nothing
    505 	} elsif (/commencing operation/) {
    506 		$restarts++;
    507 	}
    508 	#
    509 	# Log it if we didn't parse the line
    510 	#
    511 	else {
    512 		print "Unknown log file line: $_";
    513 	}
    514 }
    515 
    516 sub topten {
    517 	my ($list) = @_;
    518 	my @keys;
    519 
    520 	my $key;
    521 
    522 	@keys = (sort {$$list{$b} <=> $$list{$a}} (keys %{$list}));
    523 	splice @keys, 10;
    524 
    525 	foreach $key (@keys) {
    526 		print "\t\t$key - $$list{$key}\n";
    527 	}
    528 }
    529 
    530 sub islocaladdr (\$) {
    531 	my ($addr) = @_;
    532 	my $net;
    533 
    534 	foreach $net (@local_networks_re) {
    535 		return 1 if ($addr =~ /$net/);
    536 	}
    537 	return 0;
    538 }
    539 
    540 sub islocalrealm (\$) {
    541 	my ($princ) = @_;
    542 	my $realm;
    543 
    544 	foreach $realm (@local_realms) {
    545 		return 1 if ($princ eq $realm);
    546 		return 1 if ($princ =~ /[^@]+\@${realm}/);
    547 	}
    548 	return 0;
    549 }
    550