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