| [1145] | 1 | #!/usr/bin/env perl
 | 
|---|
 | 2 | #
 | 
|---|
 | 3 | # Program: Generate LDAP Statistics Reports <ldap-stats.pl>
 | 
|---|
 | 4 | #
 | 
|---|
 | 5 | # Source code home: http://prefetch.net/code/ldap-stats.pl
 | 
|---|
 | 6 | #
 | 
|---|
 | 7 | # Author: Matty < matty91 @ gmail dot com >
 | 
|---|
 | 8 | #
 | 
|---|
 | 9 | # Current Version: 5.2
 | 
|---|
 | 10 | #
 | 
|---|
 | 11 | # Revision History:
 | 
|---|
 | 12 | #
 | 
|---|
 | 13 | #  - add support for rsyslog log format -- Joerg Steffens, dass II GmbH
 | 
|---|
 | 14 | #
 | 
|---|
 | 15 | #  Version 5.2
 | 
|---|
 | 16 | #  Perl::Tidy and Perl::Critic -- Gavin Henry, Suretec Systems Ltd.
 | 
|---|
 | 17 | #
 | 
|---|
 | 18 | #  Version 5.1
 | 
|---|
 | 19 | #  - Changed the location of the uc() statement -- Quanah Gibson-Mount
 | 
|---|
 | 20 | #
 | 
|---|
 | 21 | #  Version 5.0
 | 
|---|
 | 22 | #  - Changed reporting structure to be dynamic -- Quanah Gibson-Mount
 | 
|---|
 | 23 | #  - Fixed a bug with name resolution -- Quanah Gibson-Mount
 | 
|---|
 | 24 | #  - Added the URL to the script -- Quanah Gibson-Mount
 | 
|---|
 | 25 | #
 | 
|---|
 | 26 | #  Version 4.2
 | 
|---|
 | 27 | #  - Utilize strict mode --  Peter Schober
 | 
|---|
 | 28 | #
 | 
|---|
 | 29 | #  Version 4.1
 | 
|---|
 | 30 | #  - Fixed a typo in the length() function -- Peter Schober
 | 
|---|
 | 31 | #
 | 
|---|
 | 32 | #  Version 4.0
 | 
|---|
 | 33 | #  - Added "-d" option to print all days
 | 
|---|
 | 34 | #  - Fixed day sort order
 | 
|---|
 | 35 | #  - Added "-m" option to print all months
 | 
|---|
 | 36 | #  - Fixed month sort order
 | 
|---|
 | 37 | #  - Correct spelling. -- Dave Horsfall
 | 
|---|
 | 38 | #  - Align headings. -- Dave Horsfall
 | 
|---|
 | 39 | #  - Support ldapi:// connections ("LOCAL-SOCKET"). -- Dave Horsfall
 | 
|---|
 | 40 | #  - Only do lookup if numeric IP. -- Dave Horsfall
 | 
|---|
 | 41 | #
 | 
|---|
 | 42 | #  Version 3.0 - 3.4
 | 
|---|
 | 43 | #  - Added ability to resolve IP addresses to hostnames with "-n" option
 | 
|---|
 | 44 | #  - Adjusted print() routines to limit lines to 80-characters -- Dave Horsfall
 | 
|---|
 | 45 | #  - Clean up unnecessary (..) in regexes -- Peter Marschall
 | 
|---|
 | 46 | #  - Split attributes found in searches (controlled by new option -s) -- Peter Marschall
 | 
|---|
 | 47 | #  - Added report to print which filters are used
 | 
|---|
 | 48 | #  - Added report to print explicit attributes requested -- Francis Swasey
 | 
|---|
 | 49 | #  - Fix usage: correct line break, all lines < 80 chars -- Peter Marschall
 | 
|---|
 | 50 | #  - Replace unnecessary printf() by print -- Peter Marschall
 | 
|---|
 | 51 | #  - Concatenate arguments into one call to print instead of multiple calls -- Peter Marschall
 | 
|---|
 | 52 | #  - Adapt underlining of some headers to length of logfile / date -- Peter Marschall
 | 
|---|
 | 53 | #  - Added additional checks to address missing entries during logfile rotation
 | 
|---|
 | 54 | #  - Fixed "uninitialized value in hash element" -- Todd Lyons
 | 
|---|
 | 55 | #  - Added additional comments to code
 | 
|---|
 | 56 | #  - Added report for operations by time of day
 | 
|---|
 | 57 | #  - Added report for operations per day
 | 
|---|
 | 58 | #  - Added report for operations per month
 | 
|---|
 | 59 | #  - Removed debug statements to speedup logfile processing
 | 
|---|
 | 60 | #  - Changed printf() format specifiers to match column definitions
 | 
|---|
 | 61 | #
 | 
|---|
 | 62 | #  Version 2.0 - 2.2
 | 
|---|
 | 63 | #  - Adjusted the Search base comparison to catch ""
 | 
|---|
 | 64 | #  - Translate "" to RootDSE in the search base results
 | 
|---|
 | 65 | #  - Only print "Unindexed attribute" if unindexed attributes exist
 | 
|---|
 | 66 | #  - Normalize the bind DN and search base to avoid duplicates
 | 
|---|
 | 67 | #  - Fix typo with binddn array
 | 
|---|
 | 68 | #  - Improved filter for anonymous and authenticated binds -- Peter Marschall
 | 
|---|
 | 69 | #  - Logfiles are now passed as arguments to ldap-stats.pl
 | 
|---|
 | 70 | #    (e.g, ldap-stats.pl openldap1 openldap2 openldap3 old* ) -- Peter Marschall
 | 
|---|
 | 71 | #  - Cleaned up and combined filters for ADDs, MODs, DELs -- Peter Marschall
 | 
|---|
 | 72 | #  - Added support for CMPs & MODRDNs -- Peter Marschall
 | 
|---|
 | 73 | #  - Reduced number of regular expressions to one per filter -- Peter Marschall
 | 
|---|
 | 74 | #  - Removed head and tail program requirements, as dates are read on the fly from the
 | 
|---|
 | 75 | #    decoded logfile -- Peter Marschall
 | 
|---|
 | 76 | #  - Support for gzip and bzip2 compressed files  -- Peter Marschall
 | 
|---|
 | 77 | #  - Optimized some expressions -- Peter Marschall
 | 
|---|
 | 78 | #  - Removed several Perl warnings, and added "-w" to default runtime options -- Peter Marschall
 | 
|---|
 | 79 | #  - Support for regular expressions in logfile names (e.g., ldap-stats.pl /var/log/openldap* ) -- Peter Marschall
 | 
|---|
 | 80 | #  - Changed default Perl interpreter to /usr/bin/perl
 | 
|---|
 | 81 | #  - Changed to OpenLDAP license
 | 
|---|
 | 82 | #
 | 
|---|
 | 83 | #  Version 1.1 - 1.9
 | 
|---|
 | 84 | #  - Updated the bind, binddn, search, search base, and unindexed search regexs to
 | 
|---|
 | 85 | #    match a wider array of characters -- added by Peter Marschall
 | 
|---|
 | 86 | #  - Shortened several regular expressions by replacing "[0-9]" with "\d" -- added by Peter Marschall
 | 
|---|
 | 87 | #  - Fixed a divide by zero bug when logfiles contain 0 connections  -- added by  Dave Horsfall
 | 
|---|
 | 88 | #  - Removed unnecessary file open(s)
 | 
|---|
 | 89 | #  - Removed end of line ($) character from anonymous BIND regular expressions
 | 
|---|
 | 90 | #  - Added "-l" option to print lines as they are processed from a logfile
 | 
|---|
 | 91 | #  - Updated documentation
 | 
|---|
 | 92 | #  - Updated formatting of search dn report
 | 
|---|
 | 93 | #  - Updated formatting of search base report
 | 
|---|
 | 94 | #  - Added an additional report with the number of binds per DN
 | 
|---|
 | 95 | #  - Updated examples
 | 
|---|
 | 96 | #  - Added additional debug messages to connection setup
 | 
|---|
 | 97 | #  - Fixed documentation issues
 | 
|---|
 | 98 | #  - Added debugging flag (-d) to give detailed information on logfile processing
 | 
|---|
 | 99 | #  - Added "usage" subroutine to ease option maintenance
 | 
|---|
 | 100 | #  - Fixed a bug in the BIND calculations -- found and fixed by Quanah Gibson-Mount
 | 
|---|
 | 101 | #  - Fixed a bug in the MOD calculations -- found and fixed by Quanah Gibson-Mount
 | 
|---|
 | 102 | #  - Fixed a bug in the SRCH calculations -- found and fixed by Quanah Gibson-Mount
 | 
|---|
 | 103 | #  - Added a connection associative array to coorelate conn identifiers w/hosts -- Quanah Gibson-Mount
 | 
|---|
 | 104 | #  - Updated the usage message with information on "-c" option
 | 
|---|
 | 105 | #  - The "-f" option now accepts multiple logfiles
 | 
|---|
 | 106 | #  - Changed the headers to include information on all logfiles processed
 | 
|---|
 | 107 | #  - Added the day the report was run to the report headers
 | 
|---|
 | 108 | #
 | 
|---|
 | 109 | #  Version 1.0
 | 
|---|
 | 110 | #   Original release
 | 
|---|
 | 111 | #
 | 
|---|
 | 112 | # Last Updated: 13-11-2006
 | 
|---|
 | 113 | #
 | 
|---|
 | 114 | # Purpose:
 | 
|---|
 | 115 | #   Produces numerous reports from OpenLDAP 2.1, 2.2 and 2.3 logfiles.
 | 
|---|
 | 116 | #
 | 
|---|
 | 117 | # License:
 | 
|---|
 | 118 | #
 | 
|---|
 | 119 | #  Redistribution and use in source and binary forms, with or without
 | 
|---|
 | 120 | #  modification, are permitted only as authorized by the OpenLDAP
 | 
|---|
 | 121 | #  Public License.
 | 
|---|
 | 122 | #
 | 
|---|
 | 123 | #  A copy of this license is available in the file LICENSE in the
 | 
|---|
 | 124 | #  top-level directory of the distribution or, alternatively, at
 | 
|---|
 | 125 | #  <http://www.OpenLDAP.org/license.html>.
 | 
|---|
 | 126 | #
 | 
|---|
 | 127 | # Installation:
 | 
|---|
 | 128 | #   1. Enable a minimum of 'loglevel 256' in the slapd.conf configuration file.
 | 
|---|
 | 129 | #   2. Copy the shell script to a suitable location.
 | 
|---|
 | 130 | #   3. Refer to the usage section for options and examples.
 | 
|---|
 | 131 | #
 | 
|---|
 | 132 | # Usage:
 | 
|---|
 | 133 | #   Refer to the usage subroutine,
 | 
|---|
 | 134 | #
 | 
|---|
 | 135 | # Example:
 | 
|---|
 | 136 | #   Refer to http://prefetch.net/code/ldap-stats.pl.txt to see sample output
 | 
|---|
 | 137 | 
 | 
|---|
 | 138 | use strict;
 | 
|---|
 | 139 | use warnings;
 | 
|---|
 | 140 | use Getopt::Long;
 | 
|---|
 | 141 | use Socket;
 | 
|---|
 | 142 | use Carp;
 | 
|---|
 | 143 | use 5.006;    # As returned by Perl::MinimumVersion
 | 
|---|
 | 144 | 
 | 
|---|
 | 145 | #######################
 | 
|---|
 | 146 | ### usage subroutine
 | 
|---|
 | 147 | ### Parameters: None
 | 
|---|
 | 148 | #######################
 | 
|---|
 | 149 | sub usage {
 | 
|---|
 | 150 |     print
 | 
|---|
 | 151 | "Usage: ldap-stats.pl [ -s ] [ -c <count> ] [ -l <count> ] [ -h ] <logfile> ...\n"
 | 
|---|
 | 152 |       . "   -c <count>             Number of lines to display for each report [25]\n"
 | 
|---|
 | 153 |       . "   -d                     Display all available days in the day of month report\n"
 | 
|---|
 | 154 |       . "   -h                     Display a usage help screen\n"
 | 
|---|
 | 155 |       . "   -l <count>             Print status message after processing <count> lines [0]\n"
 | 
|---|
 | 156 |       . "   -m                     Display all available months in the month of year report\n"
 | 
|---|
 | 157 |       . "   -n                     Resolve IP addresses to hostnames\n"
 | 
|---|
 | 158 |       . "   -o <ops> -o <ops> ...  Operations to print in the reports [ALL]\n"
 | 
|---|
 | 159 |       . "                          Valid operations are: CONNECT, FAILURES, BIND, UNBIND,\n"
 | 
|---|
 | 160 |       . "                          SRCH, CMP, ADD, MOD, MODRDN, DEL\n"
 | 
|---|
 | 161 |       . "                          Predefined reports are: ALL, READ, WRITE\n"
 | 
|---|
 | 162 |       . "   -s                     Split attributes found used in searches\n";
 | 
|---|
 | 163 |     return;
 | 
|---|
 | 164 | }
 | 
|---|
 | 165 | 
 | 
|---|
 | 166 | ### Declare lexical variables
 | 
|---|
 | 167 | my ( $logfile, $i, $counter, $help );
 | 
|---|
 | 168 | my ( %unindexed, %search, @operations );
 | 
|---|
 | 169 | 
 | 
|---|
 | 170 | ### Allow the number of entries displayed to be variable
 | 
|---|
 | 171 | my $count = 25;
 | 
|---|
 | 172 | 
 | 
|---|
 | 173 | ### Figure out if we need to print "Processing X lines"
 | 
|---|
 | 174 | my $increment = 0;
 | 
|---|
 | 175 | 
 | 
|---|
 | 176 | ## tell whether to split attributes in searches
 | 
|---|
 | 177 | my $splitattrs = 0;
 | 
|---|
 | 178 | 
 | 
|---|
 | 179 | # Tell whether to lookup names
 | 
|---|
 | 180 | my $resolvename = 0;
 | 
|---|
 | 181 | 
 | 
|---|
 | 182 | # Print all months
 | 
|---|
 | 183 | my $printmonths = 0;
 | 
|---|
 | 184 | 
 | 
|---|
 | 185 | # Print all days
 | 
|---|
 | 186 | my $printdays = 0;
 | 
|---|
 | 187 | 
 | 
|---|
 | 188 | ###################################
 | 
|---|
 | 189 | #### Get some options from the user
 | 
|---|
 | 190 | ###################################
 | 
|---|
 | 191 | #getopts("o:l:c:nhsmd", \%options);
 | 
|---|
 | 192 | 
 | 
|---|
 | 193 | GetOptions(
 | 
|---|
 | 194 |     'count|c=i'      => \$count,
 | 
|---|
 | 195 |     'days|d'         => \$printdays,
 | 
|---|
 | 196 |     'help|h'         => \$help,
 | 
|---|
 | 197 |     'length|l=i'     => \$increment,
 | 
|---|
 | 198 |     'months|m'       => \$printmonths,
 | 
|---|
 | 199 |     'network|n'      => \$resolvename,
 | 
|---|
 | 200 |     'operations|o=s' => \@operations,
 | 
|---|
 | 201 |     'split|s'        => \$splitattrs
 | 
|---|
 | 202 | );
 | 
|---|
 | 203 | 
 | 
|---|
 | 204 | ### print a nice usage message
 | 
|---|
 | 205 | if ($help) {
 | 
|---|
 | 206 |     usage;
 | 
|---|
 | 207 |     exit 1;
 | 
|---|
 | 208 | }
 | 
|---|
 | 209 | 
 | 
|---|
 | 210 | ### Make sure there is at least one logfile
 | 
|---|
 | 211 | if ( !@ARGV ) {
 | 
|---|
 | 212 |     usage;
 | 
|---|
 | 213 |     exit 1;
 | 
|---|
 | 214 | }
 | 
|---|
 | 215 | 
 | 
|---|
 | 216 | ############################
 | 
|---|
 | 217 | ### Define various variables
 | 
|---|
 | 218 | ############################
 | 
|---|
 | 219 | my $date = localtime time;
 | 
|---|
 | 220 | 
 | 
|---|
 | 221 | if ( !@operations ) {
 | 
|---|
 | 222 |     @operations = ('ALL');
 | 
|---|
 | 223 | }
 | 
|---|
 | 224 | 
 | 
|---|
 | 225 | my %stats = (
 | 
|---|
 | 226 |     TOTAL_CONNECT      => 0,
 | 
|---|
 | 227 |     TOTAL_BIND         => 0,
 | 
|---|
 | 228 |     TOTAL_UNBIND       => 0,
 | 
|---|
 | 229 |     TOTAL_SRCH         => 0,
 | 
|---|
 | 230 |     TOTAL_DEL          => 0,
 | 
|---|
 | 231 |     TOTAL_ADD          => 0,
 | 
|---|
 | 232 |     TOTAL_CMP          => 0,
 | 
|---|
 | 233 |     TOTAL_MOD          => 0,
 | 
|---|
 | 234 |     TOTAL_MODRDN       => 0,
 | 
|---|
 | 235 |     TOTAL_UNINDEXED    => 0,
 | 
|---|
 | 236 |     TOTAL_AUTHFAILURES => 0,
 | 
|---|
 | 237 | );
 | 
|---|
 | 238 | 
 | 
|---|
 | 239 | my %hours;               # Hash to store the time of day (e.g., 21st of August)
 | 
|---|
 | 240 | my %days;                # Hash to store the days of each month (e.g., 21st)
 | 
|---|
 | 241 | my %months;              # Hash to store the day of the month (e.g., Dec)
 | 
|---|
 | 242 | my %hosts;               # Hash to store client IP addresses
 | 
|---|
 | 243 | my %conns;               # Hash to store connection identifiers
 | 
|---|
 | 244 | my %binddns;             # Hash to store bind DNs
 | 
|---|
 | 245 | my %logarray;            # Hash to store logfiles
 | 
|---|
 | 246 | my %filters;             # Hash to store search filters
 | 
|---|
 | 247 | my %searchattributes;    # Hash to store specific attributes that are requested
 | 
|---|
 | 248 | my %operations;          # Hash to store operations information
 | 
|---|
 | 249 | 
 | 
|---|
 | 250 | $operations{CONNECT} = {
 | 
|---|
 | 251 |     DATA    => 0,
 | 
|---|
 | 252 |     STRING  => '  Connect',
 | 
|---|
 | 253 |     SPACING => ' --------',
 | 
|---|
 | 254 |     FIELD   => '%8s',
 | 
|---|
 | 255 | };
 | 
|---|
 | 256 | 
 | 
|---|
 | 257 | $operations{FAILURES} = {
 | 
|---|
 | 258 |     DATA    => 0,
 | 
|---|
 | 259 |     STRING  => ' Failed',
 | 
|---|
 | 260 |     SPACING => ' ------',
 | 
|---|
 | 261 |     FIELD   => '%6s',
 | 
|---|
 | 262 | };
 | 
|---|
 | 263 | 
 | 
|---|
 | 264 | $operations{BIND} = {
 | 
|---|
 | 265 |     DATA    => 0,
 | 
|---|
 | 266 |     STRING  => '    Bind',
 | 
|---|
 | 267 |     SPACING => ' -------',
 | 
|---|
 | 268 |     FIELD   => '%7s',
 | 
|---|
 | 269 | };
 | 
|---|
 | 270 | 
 | 
|---|
 | 271 | $operations{UNBIND} = {
 | 
|---|
 | 272 |     DATA    => 0,
 | 
|---|
 | 273 |     STRING  => '  Unbind',
 | 
|---|
 | 274 |     SPACING => ' -------',
 | 
|---|
 | 275 |     FIELD   => '%7s',
 | 
|---|
 | 276 | };
 | 
|---|
 | 277 | 
 | 
|---|
 | 278 | $operations{SRCH} = {
 | 
|---|
 | 279 |     DATA    => 0,
 | 
|---|
 | 280 |     STRING  => '   Search',
 | 
|---|
 | 281 |     SPACING => ' --------',
 | 
|---|
 | 282 |     FIELD   => '%8s',
 | 
|---|
 | 283 | };
 | 
|---|
 | 284 | 
 | 
|---|
 | 285 | $operations{ADD} = {
 | 
|---|
 | 286 |     DATA    => 0,
 | 
|---|
 | 287 |     STRING  => '   Add',
 | 
|---|
 | 288 |     SPACING => ' -----',
 | 
|---|
 | 289 |     FIELD   => '%5s',
 | 
|---|
 | 290 | };
 | 
|---|
 | 291 | 
 | 
|---|
 | 292 | $operations{CMP} = {
 | 
|---|
 | 293 |     DATA    => 0,
 | 
|---|
 | 294 |     STRING  => '   Cmp',
 | 
|---|
 | 295 |     SPACING => ' -----',
 | 
|---|
 | 296 |     FIELD   => '%5s',
 | 
|---|
 | 297 | };
 | 
|---|
 | 298 | 
 | 
|---|
 | 299 | $operations{MOD} = {
 | 
|---|
 | 300 |     DATA    => 0,
 | 
|---|
 | 301 |     STRING  => '   Mod',
 | 
|---|
 | 302 |     SPACING => ' -----',
 | 
|---|
 | 303 |     FIELD   => '%5s',
 | 
|---|
 | 304 | };
 | 
|---|
 | 305 | 
 | 
|---|
 | 306 | $operations{MODRDN} = {
 | 
|---|
 | 307 |     DATA    => 0,
 | 
|---|
 | 308 |     STRING  => ' ModRDN',
 | 
|---|
 | 309 |     SPACING => ' ------',
 | 
|---|
 | 310 |     FIELD   => '%6s',
 | 
|---|
 | 311 | };
 | 
|---|
 | 312 | 
 | 
|---|
 | 313 | $operations{DEL} = {
 | 
|---|
 | 314 |     DATA    => 0,
 | 
|---|
 | 315 |     STRING  => '  Del',
 | 
|---|
 | 316 |     SPACING => ' ----',
 | 
|---|
 | 317 |     FIELD   => '%4s',
 | 
|---|
 | 318 | };
 | 
|---|
 | 319 | 
 | 
|---|
 | 320 | # slapd log file can use different date formats:
 | 
|---|
 | 321 | #   rsyslog: 2013-04-17T10:45:15.576386+02:00
 | 
|---|
 | 322 | #   syslog:  Mar 23 09:54:34
 | 
|---|
 | 323 | # We check the first lone of the log file 
 | 
|---|
 | 324 | # and use the first date regex that matches.
 | 
|---|
 | 325 | my @date_formats=('\d\d\d\d-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)\.\d\d\d\d\d\d\+\d\d:\d\d', '(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)');
 | 
|---|
 | 326 | my $regex_date;
 | 
|---|
 | 327 | 
 | 
|---|
 | 328 | ###################################################
 | 
|---|
 | 329 | ### Open the logfile and process all of the entries
 | 
|---|
 | 330 | ###################################################
 | 
|---|
 | 331 | FILE: for my $file (@ARGV) {
 | 
|---|
 | 332 |     $logfile = $file;
 | 
|---|
 | 333 |     my $lines = 0;
 | 
|---|
 | 334 | 
 | 
|---|
 | 335 |     ### find open filter to use
 | 
|---|
 | 336 |     my $openfilter = '<' . $logfile . q{};
 | 
|---|
 | 337 | 
 | 
|---|
 | 338 |     ### decode gzipped / bzip2-compressed files
 | 
|---|
 | 339 |     if ( $logfile =~ /\.bz2$/mx ) {
 | 
|---|
 | 340 |         $openfilter = q{bzip2 -dc "} . $logfile . q{"|}
 | 
|---|
 | 341 |           or carp "Problem decompressing!: $!\n";
 | 
|---|
 | 342 |     }
 | 
|---|
 | 343 | 
 | 
|---|
 | 344 |     if ( $logfile =~ /\.(gz|Z)$/mx ) {
 | 
|---|
 | 345 |         $openfilter = q{gzip -dc "} . $logfile . q{"|}
 | 
|---|
 | 346 |           or carp "Problem decompressing!: $!\n";
 | 
|---|
 | 347 |     }
 | 
|---|
 | 348 | 
 | 
|---|
 | 349 |     ### If the logfile isn't valid, move on to the next one
 | 
|---|
 | 350 |     if ( !open LOGFILE, $openfilter ) {
 | 
|---|
 | 351 |         print "ERROR: unable to open '$logfile': $!\n";
 | 
|---|
 | 352 |         next;
 | 
|---|
 | 353 |     }
 | 
|---|
 | 354 | 
 | 
|---|
 | 355 |     ### setup the arrray to hold the start/stop times
 | 
|---|
 | 356 |     $logarray{$logfile} = {
 | 
|---|
 | 357 |         SDATE => q{},
 | 
|---|
 | 358 |         EDATE => q{},
 | 
|---|
 | 359 |     };
 | 
|---|
 | 360 | 
 | 
|---|
 | 361 |     ### Only print banner if requested
 | 
|---|
 | 362 |     if ( $increment > 0 ) {
 | 
|---|
 | 363 |         ### Print a banner and initialize the $counter variable
 | 
|---|
 | 364 |         print "\nProcessing file \"$logfile\"\n"
 | 
|---|
 | 365 |           . q{-} x ( 18 + length ${$logfile} ) . "\n";
 | 
|---|
 | 366 |         $counter = 0;
 | 
|---|
 | 367 |         $lines   = $increment;
 | 
|---|
 | 368 |     }
 | 
|---|
 | 369 | 
 | 
|---|
 | 370 |     while ( my $line = <LOGFILE> ) {
 | 
|---|
 | 371 | 
 | 
|---|
 | 372 |         # first line
 | 
|---|
 | 373 |         if ( !$logarray{$logfile}{SDATE} ) {
 | 
|---|
 | 374 |             # check date format in logfile
 | 
|---|
 | 375 |             for my $regex (@date_formats) {
 | 
|---|
 | 376 |                 if ( $line =~ /^($regex)/mx ) {
 | 
|---|
 | 377 |                     $logarray{$logfile}{SDATE} = $1;
 | 
|---|
 | 378 |                     $regex_date = $regex;
 | 
|---|
 | 379 |                     last;
 | 
|---|
 | 380 |                 }
 | 
|---|
 | 381 |             }
 | 
|---|
 | 382 |             if( ! $regex_date ) {
 | 
|---|
 | 383 |                 print "ERROR: unable to determine date format in '$logfile'\n";
 | 
|---|
 | 384 |                 next FILE;
 | 
|---|
 | 385 |             }
 | 
|---|
 | 386 |         }
 | 
|---|
 | 387 | 
 | 
|---|
 | 388 |         ### check start and end dates
 | 
|---|
 | 389 |         if ( $line =~ /^($regex_date)/mx ) {
 | 
|---|
 | 390 |             $logarray{$logfile}{EDATE} = $1;
 | 
|---|
 | 391 |         }
 | 
|---|
 | 392 | 
 | 
|---|
 | 393 |         ### Check to see if we have processed $lines lines
 | 
|---|
 | 394 |         if ( ( $lines > 0 ) && ( $counter == $lines ) ) {
 | 
|---|
 | 395 |             print "  Processed $lines lines in \"$logfile\"\n";
 | 
|---|
 | 396 |             $lines += $increment;
 | 
|---|
 | 397 |         }
 | 
|---|
 | 398 | 
 | 
|---|
 | 399 |         ### Check for a new connection
 | 
|---|
 | 400 |         if ( $line =~
 | 
|---|
 | 401 | /^$regex_date .*conn=(\d+) [ ] fd=\d+ [ ] (?:ACCEPT|connection) [ ] from/mx
 | 
|---|
 | 402 |           )
 | 
|---|
 | 403 |         {
 | 
|---|
 | 404 |             my $month = $1;
 | 
|---|
 | 405 |             my $day   = $2;
 | 
|---|
 | 406 |             my $hour  = $3;
 | 
|---|
 | 407 |             my $conn  = $6;
 | 
|---|
 | 408 |             my $host;
 | 
|---|
 | 409 | 
 | 
|---|
 | 410 |             if ( $line =~ /IP=(\d+\.\d+\.\d+\.\d+):/mx ) {
 | 
|---|
 | 411 |                 $host = $1;
 | 
|---|
 | 412 |             }
 | 
|---|
 | 413 |             elsif ( $line =~ /PATH=(\S+)/mx ) {
 | 
|---|
 | 414 |                 $host = 'LOCAL-SOCKET';
 | 
|---|
 | 415 |             }
 | 
|---|
 | 416 |             else {
 | 
|---|
 | 417 |                 $host = 'UNKNOWN';
 | 
|---|
 | 418 |             }
 | 
|---|
 | 419 | 
 | 
|---|
 | 420 |             ### Create an array to store the list of hosts
 | 
|---|
 | 421 |             if ( !( defined $hosts{$host} ) ) {
 | 
|---|
 | 422 |                 $hosts{$host} = {
 | 
|---|
 | 423 |                     CONNECT      => 1,
 | 
|---|
 | 424 |                     AUTHFAILURES => 0,
 | 
|---|
 | 425 |                     BIND         => 0,
 | 
|---|
 | 426 |                     UNBIND       => 0,
 | 
|---|
 | 427 |                     SRCH         => 0,
 | 
|---|
 | 428 |                     ADD          => 0,
 | 
|---|
 | 429 |                     CMP          => 0,
 | 
|---|
 | 430 |                     MOD          => 0,
 | 
|---|
 | 431 |                     MODRDN       => 0,
 | 
|---|
 | 432 |                     DEL          => 0,
 | 
|---|
 | 433 |                 };
 | 
|---|
 | 434 |             }
 | 
|---|
 | 435 |             else {
 | 
|---|
 | 436 |                 ### Entry exists, increment the CONNECT value
 | 
|---|
 | 437 |                 $hosts{$host}{CONNECT}++;
 | 
|---|
 | 438 |             }
 | 
|---|
 | 439 | 
 | 
|---|
 | 440 |             ### Create an array to store the hours
 | 
|---|
 | 441 |             if ( !( defined $hours{$hour} ) ) {
 | 
|---|
 | 442 |                 $hours{$hour} = {
 | 
|---|
 | 443 |                     CONNECT      => 1,
 | 
|---|
 | 444 |                     AUTHFAILURES => 0,
 | 
|---|
 | 445 |                     BIND         => 0,
 | 
|---|
 | 446 |                     UNBIND       => 0,
 | 
|---|
 | 447 |                     SRCH         => 0,
 | 
|---|
 | 448 |                     ADD          => 0,
 | 
|---|
 | 449 |                     CMP          => 0,
 | 
|---|
 | 450 |                     MOD          => 0,
 | 
|---|
 | 451 |                     MODRDN       => 0,
 | 
|---|
 | 452 |                     DEL          => 0,
 | 
|---|
 | 453 |                 };
 | 
|---|
 | 454 |             }
 | 
|---|
 | 455 |             else {
 | 
|---|
 | 456 |                 ### Entry exists, increment the CONNECT value
 | 
|---|
 | 457 |                 $hours{$hour}{CONNECT}++;
 | 
|---|
 | 458 |             }
 | 
|---|
 | 459 | 
 | 
|---|
 | 460 |             ### Create an array to store the months
 | 
|---|
 | 461 |             if ( !( defined $months{$month} ) ) {
 | 
|---|
 | 462 |                 $months{$month} = {
 | 
|---|
 | 463 |                     CONNECT      => 1,
 | 
|---|
 | 464 |                     AUTHFAILURES => 0,
 | 
|---|
 | 465 |                     BIND         => 0,
 | 
|---|
 | 466 |                     UNBIND       => 0,
 | 
|---|
 | 467 |                     SRCH         => 0,
 | 
|---|
 | 468 |                     ADD          => 0,
 | 
|---|
 | 469 |                     CMP          => 0,
 | 
|---|
 | 470 |                     MOD          => 0,
 | 
|---|
 | 471 |                     MODRDN       => 0,
 | 
|---|
 | 472 |                     DEL          => 0,
 | 
|---|
 | 473 |                 };
 | 
|---|
 | 474 |             }
 | 
|---|
 | 475 |             else {
 | 
|---|
 | 476 |                 ### Entry exists, increment the CONNECT value
 | 
|---|
 | 477 |                 $months{$month}{CONNECT}++;
 | 
|---|
 | 478 |             }
 | 
|---|
 | 479 | 
 | 
|---|
 | 480 |             ### Create an array to store the days
 | 
|---|
 | 481 |             if ( !( defined $days{$day} ) ) {
 | 
|---|
 | 482 |                 $days{$day} = {
 | 
|---|
 | 483 |                     CONNECT      => 1,
 | 
|---|
 | 484 |                     AUTHFAILURES => 0,
 | 
|---|
 | 485 |                     BIND         => 0,
 | 
|---|
 | 486 |                     UNBIND       => 0,
 | 
|---|
 | 487 |                     SRCH         => 0,
 | 
|---|
 | 488 |                     ADD          => 0,
 | 
|---|
 | 489 |                     CMP          => 0,
 | 
|---|
 | 490 |                     MOD          => 0,
 | 
|---|
 | 491 |                     MODRDN       => 0,
 | 
|---|
 | 492 |                     DEL          => 0,
 | 
|---|
 | 493 |                 };
 | 
|---|
 | 494 |             }
 | 
|---|
 | 495 |             else {
 | 
|---|
 | 496 |                 ### Entry exists, increment the CONNECT value
 | 
|---|
 | 497 |                 $days{$day}{CONNECT}++;
 | 
|---|
 | 498 |             }
 | 
|---|
 | 499 | 
 | 
|---|
 | 500 |             ### Add the host to the connection table
 | 
|---|
 | 501 |             $conns{$conn} = $host;
 | 
|---|
 | 502 | 
 | 
|---|
 | 503 |             ### Increment the total number of connections
 | 
|---|
 | 504 |             $stats{TOTAL_CONNECT}++;
 | 
|---|
 | 505 | 
 | 
|---|
 | 506 |             ### Check for anonymous binds
 | 
|---|
 | 507 |         }
 | 
|---|
 | 508 |         elsif ( $line =~
 | 
|---|
 | 509 | /^$regex_date .*conn=(\d+)  [ ] op=\d+ [ ] BIND [ ] dn="" [ ] method=128/mx
 | 
|---|
 | 510 |           )
 | 
|---|
 | 511 |         {
 | 
|---|
 | 512 |             my $month = $1;
 | 
|---|
 | 513 |             my $day   = $2;
 | 
|---|
 | 514 |             my $hour  = $3;
 | 
|---|
 | 515 |             my $conn  = $6;
 | 
|---|
 | 516 | 
 | 
|---|
 | 517 |             ### Increment the counters
 | 
|---|
 | 518 |             if (   defined $conns{$conn}
 | 
|---|
 | 519 |                 && defined $hosts{ $conns{$conn} } )
 | 
|---|
 | 520 |             {
 | 
|---|
 | 521 |                 $hosts{ $conns{$conn} }{BIND}++;
 | 
|---|
 | 522 |                 $hours{$hour}{BIND}++;
 | 
|---|
 | 523 |                 $days{$day}{BIND}++;
 | 
|---|
 | 524 |                 $months{$month}{BIND}++;
 | 
|---|
 | 525 |                 $stats{TOTAL_BIND}++;
 | 
|---|
 | 526 |             }
 | 
|---|
 | 527 | 
 | 
|---|
 | 528 |             ### Add the binddn to the binddns array
 | 
|---|
 | 529 |             $binddns{anonymous}++;
 | 
|---|
 | 530 | 
 | 
|---|
 | 531 |             ### Check for non-anonymous binds
 | 
|---|
 | 532 |         }
 | 
|---|
 | 533 |         elsif ( $line =~
 | 
|---|
 | 534 | /^$regex_date .*conn=(\d+) [ ] op=\d+ [ ] BIND [ ] dn="([^"]+)" [ ] mech=/mx
 | 
|---|
 | 535 |           )
 | 
|---|
 | 536 |         {
 | 
|---|
 | 537 |             my $month  = $1;
 | 
|---|
 | 538 |             my $day    = $2;
 | 
|---|
 | 539 |             my $hour   = $3;
 | 
|---|
 | 540 |             my $conn   = $6;
 | 
|---|
 | 541 |             my $binddn = lc $7;
 | 
|---|
 | 542 | 
 | 
|---|
 | 543 |             ### Increment the counters
 | 
|---|
 | 544 |             if (   defined $conns{$conn}
 | 
|---|
 | 545 |                 && defined $hosts{ $conns{$conn} } )
 | 
|---|
 | 546 |             {
 | 
|---|
 | 547 |                 $hosts{ $conns{$conn} }{BIND}++;
 | 
|---|
 | 548 |                 $hours{$hour}{BIND}++;
 | 
|---|
 | 549 |                 $days{$day}{BIND}++;
 | 
|---|
 | 550 |                 $months{$month}{BIND}++;
 | 
|---|
 | 551 |                 $stats{TOTAL_BIND}++;
 | 
|---|
 | 552 |             }
 | 
|---|
 | 553 | 
 | 
|---|
 | 554 |             ### Add the binddn to the binddns array
 | 
|---|
 | 555 |             $binddns{$binddn}++;
 | 
|---|
 | 556 | 
 | 
|---|
 | 557 |             ### Check the search base
 | 
|---|
 | 558 |         }
 | 
|---|
 | 559 |         elsif ( $line =~
 | 
|---|
 | 560 | /\bconn=\d+ [ ] op=\d+ [ ] SRCH [ ] base="([^"]*?)" [ ] .*filter="([^"]*?)"/mx
 | 
|---|
 | 561 |           )
 | 
|---|
 | 562 |         {
 | 
|---|
 | 563 |             my $base   = lc $1;
 | 
|---|
 | 564 |             my $filter = $2;
 | 
|---|
 | 565 | 
 | 
|---|
 | 566 |             ### Stuff the search base into an array
 | 
|---|
 | 567 |             if ( defined $base ) {
 | 
|---|
 | 568 |                 $search{$base}++;
 | 
|---|
 | 569 |             }
 | 
|---|
 | 570 | 
 | 
|---|
 | 571 |             if ( defined $filter ) {
 | 
|---|
 | 572 |                 $filters{$filter}++;
 | 
|---|
 | 573 |             }
 | 
|---|
 | 574 | 
 | 
|---|
 | 575 |             ### Check for search attributes
 | 
|---|
 | 576 |         }
 | 
|---|
 | 577 |         elsif ( $line =~ /\bconn=\d+ [ ] op=\d+ [ ] SRCH [ ] attr=(.+)/mx ) {
 | 
|---|
 | 578 |             my $attrs = lc $1;
 | 
|---|
 | 579 | 
 | 
|---|
 | 580 |             if ($splitattrs) {
 | 
|---|
 | 581 |                 for my $attr ( split q{ }, $attrs ) {
 | 
|---|
 | 582 |                     $searchattributes{$attr}++;
 | 
|---|
 | 583 |                 }
 | 
|---|
 | 584 |             }
 | 
|---|
 | 585 |             else {
 | 
|---|
 | 586 |                 $searchattributes{$attrs}++;
 | 
|---|
 | 587 |             }
 | 
|---|
 | 588 | 
 | 
|---|
 | 589 |             ### Check for SEARCHES
 | 
|---|
 | 590 |         }
 | 
|---|
 | 591 |         elsif ( $line =~
 | 
|---|
 | 592 | /^$regex_date .*conn=(\d+) [ ] op=\d+ [ ] SEARCH [ ] RESULT/mx
 | 
|---|
 | 593 |           )
 | 
|---|
 | 594 |         {
 | 
|---|
 | 595 |             my $month = $1;
 | 
|---|
 | 596 |             my $day   = $2;
 | 
|---|
 | 597 |             my $hour  = $3;
 | 
|---|
 | 598 |             my $conn  = $6;
 | 
|---|
 | 599 | 
 | 
|---|
 | 600 |             ### Increment the counters
 | 
|---|
 | 601 |             if (   defined $conns{$conn}
 | 
|---|
 | 602 |                 && defined $hosts{ $conns{$conn} } )
 | 
|---|
 | 603 |             {
 | 
|---|
 | 604 |                 $hosts{ $conns{$conn} }{SRCH}++;
 | 
|---|
 | 605 |                 $hours{$hour}{SRCH}++;
 | 
|---|
 | 606 |                 $days{$day}{SRCH}++;
 | 
|---|
 | 607 |                 $months{$month}{SRCH}++;
 | 
|---|
 | 608 |                 $stats{TOTAL_SRCH}++;
 | 
|---|
 | 609 |             }
 | 
|---|
 | 610 | 
 | 
|---|
 | 611 |             ### Check for unbinds
 | 
|---|
 | 612 |         }
 | 
|---|
 | 613 |         elsif ( $line =~
 | 
|---|
 | 614 |             /^$regex_date .*conn=(\d+) [ ] op=\d+ [ ] UNBIND/mx
 | 
|---|
 | 615 |           )
 | 
|---|
 | 616 |         {
 | 
|---|
 | 617 |             my $month = $1;
 | 
|---|
 | 618 |             my $day   = $2;
 | 
|---|
 | 619 |             my $hour  = $3;
 | 
|---|
 | 620 |             my $conn  = $6;
 | 
|---|
 | 621 | 
 | 
|---|
 | 622 |             ### Increment the counters
 | 
|---|
 | 623 |             if (   defined $conns{$conn}
 | 
|---|
 | 624 |                 && defined $hosts{ $conns{$conn} } )
 | 
|---|
 | 625 |             {
 | 
|---|
 | 626 |                 $hosts{ $conns{$conn} }{UNBIND}++;
 | 
|---|
 | 627 |                 $hours{$hour}{UNBIND}++;
 | 
|---|
 | 628 |                 $days{$day}{UNBIND}++;
 | 
|---|
 | 629 |                 $months{$month}{UNBIND}++;
 | 
|---|
 | 630 |                 $stats{TOTAL_UNBIND}++;
 | 
|---|
 | 631 |             }
 | 
|---|
 | 632 | 
 | 
|---|
 | 633 |             ### Check the result of the last operation
 | 
|---|
 | 634 |             ### TODO: Add other err=X values from contrib/ldapc++/src/LDAPResult.h
 | 
|---|
 | 635 |         }
 | 
|---|
 | 636 |         elsif ( $line =~
 | 
|---|
 | 637 | /^$regex_date  .*conn=(\d+) [ ] op=\d+(?: SEARCH)? [ ] RESULT [ ]/mx
 | 
|---|
 | 638 |           )
 | 
|---|
 | 639 |         {
 | 
|---|
 | 640 |             my $month = $1;
 | 
|---|
 | 641 |             my $day   = $2;
 | 
|---|
 | 642 |             my $hour  = $3;
 | 
|---|
 | 643 |             my $conn  = $6;
 | 
|---|
 | 644 | 
 | 
|---|
 | 645 |             if ( $line =~ /\berr=49\b/mx ) {
 | 
|---|
 | 646 |                 ### Increment the counters
 | 
|---|
 | 647 |                 if (   defined $conns{$conn}
 | 
|---|
 | 648 |                     && defined $hosts{ $conns{$conn} } )
 | 
|---|
 | 649 |                 {
 | 
|---|
 | 650 |                     $hosts{ $conns{$conn} }{AUTHFAILURES}++;
 | 
|---|
 | 651 |                     $hours{$hour}{AUTHFAILURES}++;
 | 
|---|
 | 652 |                     $days{$day}{AUTHFAILURES}++;
 | 
|---|
 | 653 |                     $months{$month}{AUTHFAILURES}++;
 | 
|---|
 | 654 |                     $stats{TOTAL_AUTHFAILURES}++;
 | 
|---|
 | 655 |                 }
 | 
|---|
 | 656 |             }
 | 
|---|
 | 657 | 
 | 
|---|
 | 658 |             ### Check for entry changes: add, modify modrdn, delete
 | 
|---|
 | 659 |         }
 | 
|---|
 | 660 |         elsif ( $line =~
 | 
|---|
 | 661 | /^$regex_date .*conn=(\d+) [ ] op=\d+ [ ] (ADD|CMP|MOD|MODRDN|DEL) [ ] dn=/mx
 | 
|---|
 | 662 |           )
 | 
|---|
 | 663 |         {
 | 
|---|
 | 664 |             my $month = $1;
 | 
|---|
 | 665 |             my $day   = $2;
 | 
|---|
 | 666 |             my $hour  = $3;
 | 
|---|
 | 667 |             my $conn  = $6;
 | 
|---|
 | 668 |             my $type  = $7;
 | 
|---|
 | 669 | 
 | 
|---|
 | 670 |             ### Increment the counters
 | 
|---|
 | 671 |             if (   defined $conns{$conn}
 | 
|---|
 | 672 |                 && defined $hosts{ $conns{$conn} } )
 | 
|---|
 | 673 |             {
 | 
|---|
 | 674 |                 $hosts{ $conns{$conn} }{$type}++;
 | 
|---|
 | 675 |                 $hours{$hour}{$type}++;
 | 
|---|
 | 676 |                 $days{$day}{$type}++;
 | 
|---|
 | 677 |                 $months{$month}{$type}++;
 | 
|---|
 | 678 |                 $stats{ 'TOTAL_' . $type }++;
 | 
|---|
 | 679 |             }
 | 
|---|
 | 680 | 
 | 
|---|
 | 681 |             ### Check for unindexed searches
 | 
|---|
 | 682 |         }
 | 
|---|
 | 683 |         elsif ( $line =~
 | 
|---|
 | 684 |             /: [ ] \(([a-zA-Z0-9\;\-]+)\) [ ] index_param [ ] failed/mx )
 | 
|---|
 | 685 |         {
 | 
|---|
 | 686 |             my $attr = $1;
 | 
|---|
 | 687 | 
 | 
|---|
 | 688 |             $unindexed{$attr}++;
 | 
|---|
 | 689 |             $stats{TOTAL_UNINDEXED}++;
 | 
|---|
 | 690 |         }
 | 
|---|
 | 691 |         $counter++;
 | 
|---|
 | 692 |     }
 | 
|---|
 | 693 |     close LOGFILE;
 | 
|---|
 | 694 | }
 | 
|---|
 | 695 | 
 | 
|---|
 | 696 | ###################################################################
 | 
|---|
 | 697 | ### Print a nice header with the logfiles and date ranges processed
 | 
|---|
 | 698 | ###################################################################
 | 
|---|
 | 699 | ## Please see file perltidy.ERR
 | 
|---|
 | 700 | print "\n\n"
 | 
|---|
 | 701 |   . "Report Generated on $date\n"
 | 
|---|
 | 702 |   . q{-} x ( 20 + length $date ) . "\n";
 | 
|---|
 | 703 | 
 | 
|---|
 | 704 | for my $logfile ( sort keys %logarray ) {
 | 
|---|
 | 705 |     if ( !-z $logfile ) {
 | 
|---|
 | 706 |         printf "Processed \"$logfile\":  %s - %s\n", $logarray{$logfile}{SDATE},
 | 
|---|
 | 707 |           $logarray{$logfile}{EDATE};
 | 
|---|
 | 708 |     }
 | 
|---|
 | 709 |     else {
 | 
|---|
 | 710 |         printf "Processed \"$logfile\":  no data\n";
 | 
|---|
 | 711 |     }
 | 
|---|
 | 712 | }
 | 
|---|
 | 713 | 
 | 
|---|
 | 714 | #######################################
 | 
|---|
 | 715 | ### Print an overall report with totals
 | 
|---|
 | 716 | #######################################
 | 
|---|
 | 717 | 
 | 
|---|
 | 718 | my $total_operations =
 | 
|---|
 | 719 |   $stats{TOTAL_BIND} + $stats{TOTAL_UNBIND} + $stats{TOTAL_SRCH} +
 | 
|---|
 | 720 |   $stats{TOTAL_MOD} + $stats{TOTAL_ADD} + $stats{TOTAL_MODRDN} +
 | 
|---|
 | 721 |   $stats{TOTAL_DEL};
 | 
|---|
 | 722 | 
 | 
|---|
 | 723 | print "\n\n" . "Operation totals\n" . "----------------\n";
 | 
|---|
 | 724 | printf "Total operations              : %d\n", $total_operations;
 | 
|---|
 | 725 | printf "Total connections             : %d\n", $stats{TOTAL_CONNECT};
 | 
|---|
 | 726 | printf "Total authentication failures : %d\n", $stats{TOTAL_AUTHFAILURES};
 | 
|---|
 | 727 | printf "Total binds                   : %d\n", $stats{TOTAL_BIND};
 | 
|---|
 | 728 | printf "Total unbinds                 : %d\n", $stats{TOTAL_UNBIND};
 | 
|---|
 | 729 | printf "Total searches                : %d\n", $stats{TOTAL_SRCH};
 | 
|---|
 | 730 | printf "Total compares                : %d\n", $stats{TOTAL_CMP};
 | 
|---|
 | 731 | printf "Total modifications           : %d\n", $stats{TOTAL_MOD};
 | 
|---|
 | 732 | printf "Total modrdns                 : %d\n", $stats{TOTAL_MODRDN};
 | 
|---|
 | 733 | printf "Total additions               : %d\n", $stats{TOTAL_ADD};
 | 
|---|
 | 734 | printf "Total deletions               : %d\n", $stats{TOTAL_DEL};
 | 
|---|
 | 735 | printf "Unindexed attribute requests  : %d\n", $stats{TOTAL_UNINDEXED};
 | 
|---|
 | 736 | printf "Operations per connection     : %.2f\n",
 | 
|---|
 | 737 |   $stats{TOTAL_CONNECT} ? $total_operations / $stats{TOTAL_CONNECT} : 0;
 | 
|---|
 | 738 | 
 | 
|---|
 | 739 | ###################################################
 | 
|---|
 | 740 | ### Process the host information and print a report
 | 
|---|
 | 741 | ###################################################
 | 
|---|
 | 742 | for my $selected (@operations) {
 | 
|---|
 | 743 |     $selected = uc $selected;
 | 
|---|
 | 744 | 
 | 
|---|
 | 745 |     my $ops_ref = {
 | 
|---|
 | 746 |         CONNECT  => sub { $operations{CONNECT}{DATA}  = 1 },
 | 
|---|
 | 747 |         FAILURES => sub { $operations{FAILURES}{DATA} = 1 },
 | 
|---|
 | 748 |         BIND     => sub { $operations{BIND}{DATA}     = 1 },
 | 
|---|
 | 749 |         UNBIND   => sub { $operations{UNBIND}{DATA}   = 1 },
 | 
|---|
 | 750 |         SRCH     => sub { $operations{SRCH}{DATA}     = 1 },
 | 
|---|
 | 751 |         CMP      => sub { $operations{CMP}{DATA}      = 1 },
 | 
|---|
 | 752 |         ADD      => sub { $operations{ADD}{DATA}      = 1 },
 | 
|---|
 | 753 |         MOD      => sub { $operations{MOD}{DATA}      = 1 },
 | 
|---|
 | 754 |         MODRDN   => sub { $operations{MODRDN}{DATA}   = 1 },
 | 
|---|
 | 755 |         DEL      => sub { $operations{DEL}{DATA}      = 1 },
 | 
|---|
 | 756 |         ALL => sub {
 | 
|---|
 | 757 |             $operations{CONNECT}{DATA}  = 1;
 | 
|---|
 | 758 |             $operations{FAILURES}{DATA} = 1;
 | 
|---|
 | 759 |             $operations{BIND}{DATA}     = 1;
 | 
|---|
 | 760 |             $operations{UNBIND}{DATA}   = 1;
 | 
|---|
 | 761 |             $operations{SRCH}{DATA}     = 1;
 | 
|---|
 | 762 |             $operations{CMP}{DATA}      = 1;
 | 
|---|
 | 763 |             $operations{ADD}{DATA}      = 1;
 | 
|---|
 | 764 |             $operations{MOD}{DATA}      = 1;
 | 
|---|
 | 765 |             $operations{MODRDN}{DATA}   = 1;
 | 
|---|
 | 766 |             $operations{DEL}{DATA}      = 1;
 | 
|---|
 | 767 |         },
 | 
|---|
 | 768 |         READ => sub {
 | 
|---|
 | 769 |             $operations{CONNECT}{DATA} = 1;
 | 
|---|
 | 770 |             $operations{BIND}{DATA}    = 1;
 | 
|---|
 | 771 |             $operations{UNBIND}{DATA}  = 1;
 | 
|---|
 | 772 |             $operations{SRCH}{DATA}    = 1;
 | 
|---|
 | 773 |             $operations{CMP}{DATA}     = 1;
 | 
|---|
 | 774 |         },
 | 
|---|
 | 775 |         WRITE => sub {
 | 
|---|
 | 776 |             $operations{CONNECT}{DATA} = 1;
 | 
|---|
 | 777 |             $operations{BIND}{DATA}    = 1;
 | 
|---|
 | 778 |             $operations{UNBIND}{DATA}  = 1;
 | 
|---|
 | 779 |             $operations{ADD}{DATA}     = 1;
 | 
|---|
 | 780 |             $operations{MOD}{DATA}     = 1;
 | 
|---|
 | 781 |             $operations{MODRDN}{DATA}  = 1;
 | 
|---|
 | 782 |             $operations{DEL}{DATA}     = 1;
 | 
|---|
 | 783 |         },
 | 
|---|
 | 784 |     };
 | 
|---|
 | 785 |     if   ( $ops_ref->{$selected} ) { $ops_ref->{$selected}->() }
 | 
|---|
 | 786 |     else                           { croak "Unknown operation: '$selected';\n" }
 | 
|---|
 | 787 | }
 | 
|---|
 | 788 | 
 | 
|---|
 | 789 | print "\n\n";
 | 
|---|
 | 790 | my $printstr = 'Hostname       ';
 | 
|---|
 | 791 | $printstr .= $operations{CONNECT}{DATA}  ? $operations{CONNECT}{STRING}  : q{};
 | 
|---|
 | 792 | $printstr .= $operations{FAILURES}{DATA} ? $operations{FAILURES}{STRING} : q{};
 | 
|---|
 | 793 | $printstr .= $operations{BIND}{DATA}     ? $operations{BIND}{STRING}     : q{};
 | 
|---|
 | 794 | $printstr .= $operations{UNBIND}{DATA}   ? $operations{UNBIND}{STRING}   : q{};
 | 
|---|
 | 795 | $printstr .= $operations{SRCH}{DATA}     ? $operations{SRCH}{STRING}     : q{};
 | 
|---|
 | 796 | $printstr .= $operations{CMP}{DATA}      ? $operations{CMP}{STRING}      : q{};
 | 
|---|
 | 797 | $printstr .= $operations{ADD}{DATA}      ? $operations{ADD}{STRING}      : q{};
 | 
|---|
 | 798 | $printstr .= $operations{MOD}{DATA}      ? $operations{MOD}{STRING}      : q{};
 | 
|---|
 | 799 | $printstr .= $operations{MODRDN}{DATA}   ? $operations{MODRDN}{STRING}   : q{};
 | 
|---|
 | 800 | $printstr .= $operations{DEL}{DATA}      ? $operations{DEL}{STRING}      : q{};
 | 
|---|
 | 801 | $printstr .= "\n";
 | 
|---|
 | 802 | print $printstr;
 | 
|---|
 | 803 | $printstr = '---------------';
 | 
|---|
 | 804 | $printstr .= $operations{CONNECT}{DATA}  ? $operations{CONNECT}{SPACING}  : q{};
 | 
|---|
 | 805 | $printstr .= $operations{FAILURES}{DATA} ? $operations{FAILURES}{SPACING} : q{};
 | 
|---|
 | 806 | $printstr .= $operations{BIND}{DATA}     ? $operations{BIND}{SPACING}     : q{};
 | 
|---|
 | 807 | $printstr .= $operations{UNBIND}{DATA}   ? $operations{UNBIND}{SPACING}   : q{};
 | 
|---|
 | 808 | $printstr .= $operations{SRCH}{DATA}     ? $operations{SRCH}{SPACING}     : q{};
 | 
|---|
 | 809 | $printstr .= $operations{CMP}{DATA}      ? $operations{CMP}{SPACING}      : q{};
 | 
|---|
 | 810 | $printstr .= $operations{ADD}{DATA}      ? $operations{ADD}{SPACING}      : q{};
 | 
|---|
 | 811 | $printstr .= $operations{MOD}{DATA}      ? $operations{MOD}{SPACING}      : q{};
 | 
|---|
 | 812 | $printstr .= $operations{MODRDN}{DATA}   ? $operations{MODRDN}{SPACING}   : q{};
 | 
|---|
 | 813 | $printstr .= $operations{DEL}{DATA}      ? $operations{DEL}{SPACING}      : q{};
 | 
|---|
 | 814 | print "$printstr\n";
 | 
|---|
 | 815 | 
 | 
|---|
 | 816 | for my $index ( sort keys %hosts ) {
 | 
|---|
 | 817 | 
 | 
|---|
 | 818 |     ### Resolve IP addresses to names if requested
 | 
|---|
 | 819 |     my $host = $index;
 | 
|---|
 | 820 | 
 | 
|---|
 | 821 |     ### Convert the IP address to an Internet address, and resolve with gethostbyaddr()
 | 
|---|
 | 822 |     if ( $resolvename && ( $index =~ /\d+\.\d+\.\d+\.\d+/mx ) ) {
 | 
|---|
 | 823 |         my $ipaddr = inet_aton($index);
 | 
|---|
 | 824 |         $host = gethostbyaddr $ipaddr, AF_INET;
 | 
|---|
 | 825 |         if ( !defined $host ) {
 | 
|---|
 | 826 |             $host = $index;
 | 
|---|
 | 827 |         }
 | 
|---|
 | 828 |     }
 | 
|---|
 | 829 |     printf '%-15.15s', $host;
 | 
|---|
 | 830 |     if ( $operations{CONNECT}{DATA} ) {
 | 
|---|
 | 831 |         printf " $operations{CONNECT}{FIELD}",
 | 
|---|
 | 832 |           $hosts{$index}{CONNECT} ? $hosts{$index}{CONNECT} : 0;
 | 
|---|
 | 833 |     }
 | 
|---|
 | 834 |     if ( $operations{FAILURES}{DATA} ) {
 | 
|---|
 | 835 |         printf " $operations{FAILURES}{FIELD}",
 | 
|---|
 | 836 |           $hosts{$index}{AUTHFAILURES} ? $hosts{$index}{AUTHFAILURES} : 0;
 | 
|---|
 | 837 |     }
 | 
|---|
 | 838 |     if ( $operations{BIND}{DATA} ) {
 | 
|---|
 | 839 |         printf " $operations{BIND}{FIELD}",
 | 
|---|
 | 840 |           $hosts{$index}{BIND} ? $hosts{$index}{BIND} : 0;
 | 
|---|
 | 841 |     }
 | 
|---|
 | 842 |     if ( $operations{UNBIND}{DATA} ) {
 | 
|---|
 | 843 |         printf " $operations{UNBIND}{FIELD}",
 | 
|---|
 | 844 |           $hosts{$index}{UNBIND} ? $hosts{$index}{UNBIND} : 0;
 | 
|---|
 | 845 |     }
 | 
|---|
 | 846 |     if ( $operations{SRCH}{DATA} ) {
 | 
|---|
 | 847 |         printf " $operations{SRCH}{FIELD}",
 | 
|---|
 | 848 |           $hosts{$index}{SRCH} ? $hosts{$index}{SRCH} : 0;
 | 
|---|
 | 849 |     }
 | 
|---|
 | 850 |     if ( $operations{CMP}{DATA} ) {
 | 
|---|
 | 851 |         printf " $operations{CMP}{FIELD}",
 | 
|---|
 | 852 |           $hosts{$index}{CMP} ? $hosts{$index}{CMP} : 0;
 | 
|---|
 | 853 |     }
 | 
|---|
 | 854 |     if ( $operations{ADD}{DATA} ) {
 | 
|---|
 | 855 |         printf " $operations{ADD}{FIELD}",
 | 
|---|
 | 856 |           $hosts{$index}{ADD} ? $hosts{$index}{ADD} : 0;
 | 
|---|
 | 857 |     }
 | 
|---|
 | 858 |     if ( $operations{MOD}{DATA} ) {
 | 
|---|
 | 859 |         printf " $operations{MOD}{FIELD}",
 | 
|---|
 | 860 |           $hosts{$index}{MOD} ? $hosts{$index}{MOD} : 0;
 | 
|---|
 | 861 |     }
 | 
|---|
 | 862 |     if ( $operations{MODRDN}{DATA} ) {
 | 
|---|
 | 863 |         printf " $operations{MODRDN}{FIELD}",
 | 
|---|
 | 864 |           $hosts{$index}{MODRDN} ? $hosts{$index}{MODRDN} : 0;
 | 
|---|
 | 865 |     }
 | 
|---|
 | 866 |     if ( $operations{DEL}{DATA} ) {
 | 
|---|
 | 867 |         printf " $operations{DEL}{FIELD}",
 | 
|---|
 | 868 |           $hosts{$index}{DEL} ? $hosts{$index}{DEL} : 0;
 | 
|---|
 | 869 |     }
 | 
|---|
 | 870 |     print "\n";
 | 
|---|
 | 871 | }
 | 
|---|
 | 872 | 
 | 
|---|
 | 873 | #######################################################
 | 
|---|
 | 874 | ### Process the hours information and print a report
 | 
|---|
 | 875 | ########################################################
 | 
|---|
 | 876 | print "\n\n";
 | 
|---|
 | 877 | $printstr = 'Hour of Day  ';
 | 
|---|
 | 878 | $printstr .= $operations{CONNECT}{DATA}  ? $operations{CONNECT}{STRING}  : q{};
 | 
|---|
 | 879 | $printstr .= $operations{FAILURES}{DATA} ? $operations{FAILURES}{STRING} : q{};
 | 
|---|
 | 880 | $printstr .= $operations{BIND}{DATA}     ? $operations{BIND}{STRING}     : q{};
 | 
|---|
 | 881 | $printstr .= $operations{UNBIND}{DATA}   ? $operations{UNBIND}{STRING}   : q{};
 | 
|---|
 | 882 | $printstr .= $operations{SRCH}{DATA}     ? $operations{SRCH}{STRING}     : q{};
 | 
|---|
 | 883 | $printstr .= $operations{CMP}{DATA}      ? $operations{CMP}{STRING}      : q{};
 | 
|---|
 | 884 | $printstr .= $operations{ADD}{DATA}      ? $operations{ADD}{STRING}      : q{};
 | 
|---|
 | 885 | $printstr .= $operations{MOD}{DATA}      ? $operations{MOD}{STRING}      : q{};
 | 
|---|
 | 886 | $printstr .= $operations{MODRDN}{DATA}   ? $operations{MODRDN}{STRING}   : q{};
 | 
|---|
 | 887 | $printstr .= $operations{DEL}{DATA}      ? $operations{DEL}{STRING}      : q{};
 | 
|---|
 | 888 | $printstr .= "\n";
 | 
|---|
 | 889 | print $printstr;
 | 
|---|
 | 890 | $printstr = '-------------';
 | 
|---|
 | 891 | $printstr .= $operations{CONNECT}{DATA}  ? $operations{CONNECT}{SPACING}  : q{};
 | 
|---|
 | 892 | $printstr .= $operations{FAILURES}{DATA} ? $operations{FAILURES}{SPACING} : q{};
 | 
|---|
 | 893 | $printstr .= $operations{BIND}{DATA}     ? $operations{BIND}{SPACING}     : q{};
 | 
|---|
 | 894 | $printstr .= $operations{UNBIND}{DATA}   ? $operations{UNBIND}{SPACING}   : q{};
 | 
|---|
 | 895 | $printstr .= $operations{SRCH}{DATA}     ? $operations{SRCH}{SPACING}     : q{};
 | 
|---|
 | 896 | $printstr .= $operations{CMP}{DATA}      ? $operations{CMP}{SPACING}      : q{};
 | 
|---|
 | 897 | $printstr .= $operations{ADD}{DATA}      ? $operations{ADD}{SPACING}      : q{};
 | 
|---|
 | 898 | $printstr .= $operations{MOD}{DATA}      ? $operations{MOD}{SPACING}      : q{};
 | 
|---|
 | 899 | $printstr .= $operations{MODRDN}{DATA}   ? $operations{MODRDN}{SPACING}   : q{};
 | 
|---|
 | 900 | $printstr .= $operations{DEL}{DATA}      ? $operations{DEL}{SPACING}      : q{};
 | 
|---|
 | 901 | print "$printstr\n";
 | 
|---|
 | 902 | 
 | 
|---|
 | 903 | for my $index ( sort keys %hours ) {
 | 
|---|
 | 904 |     printf '%-2s:00 - %2s:59', $index, $index;
 | 
|---|
 | 905 |     if ( $operations{CONNECT}{DATA} ) {
 | 
|---|
 | 906 |         printf " $operations{CONNECT}{FIELD}",
 | 
|---|
 | 907 |           $hours{$index}{CONNECT} ? $hours{$index}{CONNECT} : 0;
 | 
|---|
 | 908 |     }
 | 
|---|
 | 909 |     if ( $operations{FAILURES}{DATA} ) {
 | 
|---|
 | 910 |         printf " $operations{FAILURES}{FIELD}",
 | 
|---|
 | 911 |           $hours{$index}{AUTHFAILURES} ? $hours{$index}{AUTHFAILURES} : 0;
 | 
|---|
 | 912 |     }
 | 
|---|
 | 913 |     if ( $operations{BIND}{DATA} ) {
 | 
|---|
 | 914 |         printf " $operations{BIND}{FIELD}",
 | 
|---|
 | 915 |           $hours{$index}{BIND} ? $hours{$index}{BIND} : 0;
 | 
|---|
 | 916 |     }
 | 
|---|
 | 917 |     if ( $operations{UNBIND}{DATA} ) {
 | 
|---|
 | 918 |         printf " $operations{UNBIND}{FIELD}",
 | 
|---|
 | 919 |           $hours{$index}{UNBIND} ? $hours{$index}{UNBIND} : 0;
 | 
|---|
 | 920 |     }
 | 
|---|
 | 921 |     if ( $operations{SRCH}{DATA} ) {
 | 
|---|
 | 922 |         printf " $operations{SRCH}{FIELD}",
 | 
|---|
 | 923 |           $hours{$index}{SRCH} ? $hours{$index}{SRCH} : 0;
 | 
|---|
 | 924 |     }
 | 
|---|
 | 925 |     if ( $operations{CMP}{DATA} ) {
 | 
|---|
 | 926 |         printf " $operations{CMP}{FIELD}",
 | 
|---|
 | 927 |           $hours{$index}{CMP} ? $hours{$index}{CMP} : 0;
 | 
|---|
 | 928 |     }
 | 
|---|
 | 929 |     if ( $operations{ADD}{DATA} ) {
 | 
|---|
 | 930 |         printf " $operations{ADD}{FIELD}",
 | 
|---|
 | 931 |           $hours{$index}{ADD} ? $hours{$index}{ADD} : 0;
 | 
|---|
 | 932 |     }
 | 
|---|
 | 933 |     if ( $operations{MOD}{DATA} ) {
 | 
|---|
 | 934 |         printf " $operations{MOD}{FIELD}",
 | 
|---|
 | 935 |           $hours{$index}{MOD} ? $hours{$index}{MOD} : 0;
 | 
|---|
 | 936 |     }
 | 
|---|
 | 937 |     if ( $operations{MODRDN}{DATA} ) {
 | 
|---|
 | 938 |         printf " $operations{MODRDN}{FIELD}",
 | 
|---|
 | 939 |           $hours{$index}{MODRDN} ? $hours{$index}{MODRDN} : 0;
 | 
|---|
 | 940 |     }
 | 
|---|
 | 941 |     if ( $operations{DEL}{DATA} ) {
 | 
|---|
 | 942 |         printf " $operations{DEL}{FIELD}",
 | 
|---|
 | 943 |           $hours{$index}{DEL} ? $hours{$index}{DEL} : 0;
 | 
|---|
 | 944 |     }
 | 
|---|
 | 945 |     print "\n";
 | 
|---|
 | 946 | }
 | 
|---|
 | 947 | 
 | 
|---|
 | 948 | #######################################################
 | 
|---|
 | 949 | ### Process the month information and print a report
 | 
|---|
 | 950 | ########################################################
 | 
|---|
 | 951 | print "\n\n";
 | 
|---|
 | 952 | $printstr = 'Day of Month ';
 | 
|---|
 | 953 | $printstr .= $operations{CONNECT}{DATA}  ? $operations{CONNECT}{STRING}  : q{};
 | 
|---|
 | 954 | $printstr .= $operations{FAILURES}{DATA} ? $operations{FAILURES}{STRING} : q{};
 | 
|---|
 | 955 | $printstr .= $operations{BIND}{DATA}     ? $operations{BIND}{STRING}     : q{};
 | 
|---|
 | 956 | $printstr .= $operations{UNBIND}{DATA}   ? $operations{UNBIND}{STRING}   : q{};
 | 
|---|
 | 957 | $printstr .= $operations{SRCH}{DATA}     ? $operations{SRCH}{STRING}     : q{};
 | 
|---|
 | 958 | $printstr .= $operations{CMP}{DATA}      ? $operations{CMP}{STRING}      : q{};
 | 
|---|
 | 959 | $printstr .= $operations{ADD}{DATA}      ? $operations{ADD}{STRING}      : q{};
 | 
|---|
 | 960 | $printstr .= $operations{MOD}{DATA}      ? $operations{MOD}{STRING}      : q{};
 | 
|---|
 | 961 | $printstr .= $operations{MODRDN}{DATA}   ? $operations{MODRDN}{STRING}   : q{};
 | 
|---|
 | 962 | $printstr .= $operations{DEL}{DATA}      ? $operations{DEL}{STRING}      : q{};
 | 
|---|
 | 963 | $printstr .= "\n";
 | 
|---|
 | 964 | print $printstr;
 | 
|---|
 | 965 | $printstr = '-------------';
 | 
|---|
 | 966 | $printstr .= $operations{CONNECT}{DATA}  ? $operations{CONNECT}{SPACING}  : q{};
 | 
|---|
 | 967 | $printstr .= $operations{FAILURES}{DATA} ? $operations{FAILURES}{SPACING} : q{};
 | 
|---|
 | 968 | $printstr .= $operations{BIND}{DATA}     ? $operations{BIND}{SPACING}     : q{};
 | 
|---|
 | 969 | $printstr .= $operations{UNBIND}{DATA}   ? $operations{UNBIND}{SPACING}   : q{};
 | 
|---|
 | 970 | $printstr .= $operations{SRCH}{DATA}     ? $operations{SRCH}{SPACING}     : q{};
 | 
|---|
 | 971 | $printstr .= $operations{CMP}{DATA}      ? $operations{CMP}{SPACING}      : q{};
 | 
|---|
 | 972 | $printstr .= $operations{ADD}{DATA}      ? $operations{ADD}{SPACING}      : q{};
 | 
|---|
 | 973 | $printstr .= $operations{MOD}{DATA}      ? $operations{MOD}{SPACING}      : q{};
 | 
|---|
 | 974 | $printstr .= $operations{MODRDN}{DATA}   ? $operations{MODRDN}{SPACING}   : q{};
 | 
|---|
 | 975 | $printstr .= $operations{DEL}{DATA}      ? $operations{DEL}{SPACING}      : q{};
 | 
|---|
 | 976 | print "$printstr\n";
 | 
|---|
 | 977 | 
 | 
|---|
 | 978 | for ( 1 .. 31 ) {
 | 
|---|
 | 979 |     if ( defined $days{$_} || $printdays ) {
 | 
|---|
 | 980 |         printf '  %-11s', $_;
 | 
|---|
 | 981 |         if ( $operations{CONNECT}{DATA} ) {
 | 
|---|
 | 982 |             printf " $operations{CONNECT}{FIELD}",
 | 
|---|
 | 983 |               $days{$_}{CONNECT} ? $days{$_}{CONNECT} : 0;
 | 
|---|
 | 984 |         }
 | 
|---|
 | 985 |         if ( $operations{FAILURES}{DATA} ) {
 | 
|---|
 | 986 |             printf " $operations{FAILURES}{FIELD}",
 | 
|---|
 | 987 |               $days{$_}{AUTHFAILURES} ? $days{$_}{AUTHFAILURES} : 0;
 | 
|---|
 | 988 |         }
 | 
|---|
 | 989 |         if ( $operations{BIND}{DATA} ) {
 | 
|---|
 | 990 |             printf " $operations{BIND}{FIELD}",
 | 
|---|
 | 991 |               $days{$_}{BIND} ? $days{$_}{BIND} : 0;
 | 
|---|
 | 992 |         }
 | 
|---|
 | 993 |         if ( $operations{UNBIND}{DATA} ) {
 | 
|---|
 | 994 |             printf " $operations{UNBIND}{FIELD}",
 | 
|---|
 | 995 |               $days{$_}{UNBIND} ? $days{$_}{UNBIND} : 0;
 | 
|---|
 | 996 |         }
 | 
|---|
 | 997 |         if ( $operations{SRCH}{DATA} ) {
 | 
|---|
 | 998 |             printf " $operations{SRCH}{FIELD}",
 | 
|---|
 | 999 |               $days{$_}{SRCH} ? $days{$_}{SRCH} : 0;
 | 
|---|
 | 1000 |         }
 | 
|---|
 | 1001 |         if ( $operations{CMP}{DATA} ) {
 | 
|---|
 | 1002 |             printf " $operations{CMP}{FIELD}",
 | 
|---|
 | 1003 |               $days{$_}{CMP} ? $days{$_}{CMP} : 0;
 | 
|---|
 | 1004 |         }
 | 
|---|
 | 1005 |         if ( $operations{ADD}{DATA} ) {
 | 
|---|
 | 1006 |             printf " $operations{ADD}{FIELD}",
 | 
|---|
 | 1007 |               $days{$_}{ADD} ? $days{$_}{ADD} : 0;
 | 
|---|
 | 1008 |         }
 | 
|---|
 | 1009 |         if ( $operations{MOD}{DATA} ) {
 | 
|---|
 | 1010 |             printf " $operations{MOD}{FIELD}",
 | 
|---|
 | 1011 |               $days{$_}{MOD} ? $days{$_}{MOD} : 0;
 | 
|---|
 | 1012 |         }
 | 
|---|
 | 1013 |         if ( $operations{MODRDN}{DATA} ) {
 | 
|---|
 | 1014 |             printf " $operations{MODRDN}{FIELD}",
 | 
|---|
 | 1015 |               $days{$_}{MODRDN} ? $days{$_}{MODRDN} : 0;
 | 
|---|
 | 1016 |         }
 | 
|---|
 | 1017 |         if ( $operations{DEL}{DATA} ) {
 | 
|---|
 | 1018 |             printf " $operations{DEL}{FIELD}",
 | 
|---|
 | 1019 |               $days{$_}{DEL} ? $days{$_}{DEL} : 0;
 | 
|---|
 | 1020 |         }
 | 
|---|
 | 1021 |         print "\n";
 | 
|---|
 | 1022 |     }
 | 
|---|
 | 1023 | }
 | 
|---|
 | 1024 | #######################################################
 | 
|---|
 | 1025 | ### Process the month information and print a report
 | 
|---|
 | 1026 | ########################################################
 | 
|---|
 | 1027 | print "\n\n";
 | 
|---|
 | 1028 | $printstr = ' Month       ';
 | 
|---|
 | 1029 | $printstr .= $operations{CONNECT}{DATA}  ? $operations{CONNECT}{STRING}  : q{};
 | 
|---|
 | 1030 | $printstr .= $operations{FAILURES}{DATA} ? $operations{FAILURES}{STRING} : q{};
 | 
|---|
 | 1031 | $printstr .= $operations{BIND}{DATA}     ? $operations{BIND}{STRING}     : q{};
 | 
|---|
 | 1032 | $printstr .= $operations{UNBIND}{DATA}   ? $operations{UNBIND}{STRING}   : q{};
 | 
|---|
 | 1033 | $printstr .= $operations{SRCH}{DATA}     ? $operations{SRCH}{STRING}     : q{};
 | 
|---|
 | 1034 | $printstr .= $operations{CMP}{DATA}      ? $operations{CMP}{STRING}      : q{};
 | 
|---|
 | 1035 | $printstr .= $operations{ADD}{DATA}      ? $operations{ADD}{STRING}      : q{};
 | 
|---|
 | 1036 | $printstr .= $operations{MOD}{DATA}      ? $operations{MOD}{STRING}      : q{};
 | 
|---|
 | 1037 | $printstr .= $operations{MODRDN}{DATA}   ? $operations{MODRDN}{STRING}   : q{};
 | 
|---|
 | 1038 | $printstr .= $operations{DEL}{DATA}      ? $operations{DEL}{STRING}      : q{};
 | 
|---|
 | 1039 | $printstr .= "\n";
 | 
|---|
 | 1040 | print $printstr;
 | 
|---|
 | 1041 | $printstr = '-------------';
 | 
|---|
 | 1042 | $printstr .= $operations{CONNECT}{DATA}  ? $operations{CONNECT}{SPACING}  : q{};
 | 
|---|
 | 1043 | $printstr .= $operations{FAILURES}{DATA} ? $operations{FAILURES}{SPACING} : q{};
 | 
|---|
 | 1044 | $printstr .= $operations{BIND}{DATA}     ? $operations{BIND}{SPACING}     : q{};
 | 
|---|
 | 1045 | $printstr .= $operations{UNBIND}{DATA}   ? $operations{UNBIND}{SPACING}   : q{};
 | 
|---|
 | 1046 | $printstr .= $operations{SRCH}{DATA}     ? $operations{SRCH}{SPACING}     : q{};
 | 
|---|
 | 1047 | $printstr .= $operations{CMP}{DATA}      ? $operations{CMP}{SPACING}      : q{};
 | 
|---|
 | 1048 | $printstr .= $operations{ADD}{DATA}      ? $operations{ADD}{SPACING}      : q{};
 | 
|---|
 | 1049 | $printstr .= $operations{MOD}{DATA}      ? $operations{MOD}{SPACING}      : q{};
 | 
|---|
 | 1050 | $printstr .= $operations{MODRDN}{DATA}   ? $operations{MODRDN}{SPACING}   : q{};
 | 
|---|
 | 1051 | $printstr .= $operations{DEL}{DATA}      ? $operations{DEL}{SPACING}      : q{};
 | 
|---|
 | 1052 | print "$printstr\n";
 | 
|---|
 | 1053 | 
 | 
|---|
 | 1054 | for my $index qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) {
 | 
|---|
 | 1055 |     if ( defined $months{$index} || $printmonths ) {
 | 
|---|
 | 1056 |         printf '  %-11s', $index;
 | 
|---|
 | 1057 |         if ( $operations{CONNECT}{DATA} ) {
 | 
|---|
 | 1058 |             printf " $operations{CONNECT}{FIELD}",
 | 
|---|
 | 1059 |               $months{$index}{CONNECT} ? $months{$index}{CONNECT} : 0;
 | 
|---|
 | 1060 |         }
 | 
|---|
 | 1061 |         if ( $operations{FAILURES}{DATA} ) {
 | 
|---|
 | 1062 |             printf " $operations{FAILURES}{FIELD}",
 | 
|---|
 | 1063 |               $months{$index}{AUTHFAILURES}
 | 
|---|
 | 1064 |               ? $months{$index}{AUTHFAILURES}
 | 
|---|
 | 1065 |               : 0;
 | 
|---|
 | 1066 |         }
 | 
|---|
 | 1067 |         if ( $operations{BIND}{DATA} ) {
 | 
|---|
 | 1068 |             printf " $operations{BIND}{FIELD}",
 | 
|---|
 | 1069 |               $months{$index}{BIND} ? $months{$index}{BIND} : 0;
 | 
|---|
 | 1070 |         }
 | 
|---|
 | 1071 |         if ( $operations{UNBIND}{DATA} ) {
 | 
|---|
 | 1072 |             printf " $operations{UNBIND}{FIELD}",
 | 
|---|
 | 1073 |               $months{$index}{UNBIND} ? $months{$index}{UNBIND} : 0;
 | 
|---|
 | 1074 |         }
 | 
|---|
 | 1075 |         if ( $operations{SRCH}{DATA} ) {
 | 
|---|
 | 1076 |             printf " $operations{SRCH}{FIELD}",
 | 
|---|
 | 1077 |               $months{$index}{SRCH} ? $months{$index}{SRCH} : 0;
 | 
|---|
 | 1078 |         }
 | 
|---|
 | 1079 |         if ( $operations{CMP}{DATA} ) {
 | 
|---|
 | 1080 |             printf " $operations{CMP}{FIELD}",
 | 
|---|
 | 1081 |               $months{$index}{CMP} ? $months{$index}{CMP} : 0;
 | 
|---|
 | 1082 |         }
 | 
|---|
 | 1083 |         if ( $operations{ADD}{DATA} ) {
 | 
|---|
 | 1084 |             printf " $operations{ADD}{FIELD}",
 | 
|---|
 | 1085 |               $months{$index}{ADD} ? $months{$index}{ADD} : 0;
 | 
|---|
 | 1086 |         }
 | 
|---|
 | 1087 |         if ( $operations{MOD}{DATA} ) {
 | 
|---|
 | 1088 |             printf " $operations{MOD}{FIELD}",
 | 
|---|
 | 1089 |               $months{$index}{MOD} ? $months{$index}{MOD} : 0;
 | 
|---|
 | 1090 |         }
 | 
|---|
 | 1091 |         if ( $operations{MODRDN}{DATA} ) {
 | 
|---|
 | 1092 |             printf " $operations{MODRDN}{FIELD}",
 | 
|---|
 | 1093 |               $months{$index}{MODRDN} ? $months{$index}{MODRDN} : 0;
 | 
|---|
 | 1094 |         }
 | 
|---|
 | 1095 |         if ( $operations{DEL}{DATA} ) {
 | 
|---|
 | 1096 |             printf " $operations{DEL}{FIELD}",
 | 
|---|
 | 1097 |               $months{$index}{DEL} ? $months{$index}{DEL} : 0;
 | 
|---|
 | 1098 |         }
 | 
|---|
 | 1099 |         print "\n";
 | 
|---|
 | 1100 |     }
 | 
|---|
 | 1101 | }
 | 
|---|
 | 1102 | 
 | 
|---|
 | 1103 | ####################################################
 | 
|---|
 | 1104 | ### Process the unindexed searches and print a report
 | 
|---|
 | 1105 | ####################################################
 | 
|---|
 | 1106 | my @sarray;    # sort array
 | 
|---|
 | 1107 | if ( $stats{TOTAL_UNINDEXED} > 0 ) {
 | 
|---|
 | 1108 | 
 | 
|---|
 | 1109 |     print "\n\n"
 | 
|---|
 | 1110 |       . "# Uses        Unindexed attribute\n"
 | 
|---|
 | 1111 |       . "----------    -----------------------------------------------------------\n";
 | 
|---|
 | 1112 | 
 | 
|---|
 | 1113 |     @sarray =
 | 
|---|
 | 1114 |       reverse sort { $unindexed{$a} <=> $unindexed{$b} } keys %unindexed;
 | 
|---|
 | 1115 |   UNINDEXED:
 | 
|---|
 | 1116 |     for my $num ( 0 .. $#sarray ) {
 | 
|---|
 | 1117 |         if ( $num > $count ) {
 | 
|---|
 | 1118 |             last UNINDEXED;
 | 
|---|
 | 1119 |         }
 | 
|---|
 | 1120 |         printf "  %-8d    %-60s\n", $unindexed{ $sarray[$num] }, $sarray[$num];
 | 
|---|
 | 1121 |     }
 | 
|---|
 | 1122 | }
 | 
|---|
 | 1123 | 
 | 
|---|
 | 1124 | ######################################################
 | 
|---|
 | 1125 | ### Process the stored search bases and print a report
 | 
|---|
 | 1126 | ######################################################
 | 
|---|
 | 1127 | print "\n\n"
 | 
|---|
 | 1128 |   . "# Searches    Search base\n"
 | 
|---|
 | 1129 |   . "----------    -----------------------------------------------------------\n";
 | 
|---|
 | 1130 | 
 | 
|---|
 | 1131 | @sarray = reverse sort { $search{$a} <=> $search{$b} } keys %search;
 | 
|---|
 | 1132 | SEARCH:
 | 
|---|
 | 1133 | for my $num ( 0 .. $#sarray ) {
 | 
|---|
 | 1134 |     if ( $num > $count ) {
 | 
|---|
 | 1135 |         last SEARCH;
 | 
|---|
 | 1136 |     }
 | 
|---|
 | 1137 |     printf "  %-8d    %-60s\n", $search{ $sarray[$num] },
 | 
|---|
 | 1138 |       $sarray[$num] || 'RootDSE';
 | 
|---|
 | 1139 | }
 | 
|---|
 | 1140 | 
 | 
|---|
 | 1141 | ######################################################
 | 
|---|
 | 1142 | ### Process the stored search filters
 | 
|---|
 | 1143 | ######################################################
 | 
|---|
 | 1144 | print "\n\n"
 | 
|---|
 | 1145 |   . "# Uses        Filter\n"
 | 
|---|
 | 1146 |   . "----------    -----------------------------------------------------------\n";
 | 
|---|
 | 1147 | 
 | 
|---|
 | 1148 | @sarray = reverse sort { $filters{$a} <=> $filters{$b} } keys %filters;
 | 
|---|
 | 1149 | FILTER:
 | 
|---|
 | 1150 | for my $num ( 0 .. $#sarray ) {
 | 
|---|
 | 1151 |     if ( $num > $count ) {
 | 
|---|
 | 1152 |         last FILTER;
 | 
|---|
 | 1153 |     }
 | 
|---|
 | 1154 |     printf "  %-8d    %-60s\n", $filters{ $sarray[$num] }, $sarray[$num];
 | 
|---|
 | 1155 | }
 | 
|---|
 | 1156 | 
 | 
|---|
 | 1157 | ######################################################
 | 
|---|
 | 1158 | ### Process the stored attribute array
 | 
|---|
 | 1159 | ######################################################
 | 
|---|
 | 1160 | print "\n\n"
 | 
|---|
 | 1161 |   . "# Uses        Attributes explicitly requested in search string\n"
 | 
|---|
 | 1162 |   . "----------    -------------------------------------------------\n";
 | 
|---|
 | 1163 | 
 | 
|---|
 | 1164 | @sarray =
 | 
|---|
 | 1165 |   reverse sort { $searchattributes{$a} <=> $searchattributes{$b} }
 | 
|---|
 | 1166 |   keys %searchattributes;
 | 
|---|
 | 1167 | SEARCHATTR:
 | 
|---|
 | 1168 | for my $num ( 0 .. $#sarray ) {
 | 
|---|
 | 1169 |     if ( $num > $count ) {
 | 
|---|
 | 1170 |         last SEARCHATTR;
 | 
|---|
 | 1171 |     }
 | 
|---|
 | 1172 |     printf "  %-8d    %-60s\n", $searchattributes{ $sarray[$num] },
 | 
|---|
 | 1173 |       $sarray[$num];
 | 
|---|
 | 1174 | }
 | 
|---|
 | 1175 | 
 | 
|---|
 | 1176 | ######################################################
 | 
|---|
 | 1177 | ### Process the stored binddns and print a report
 | 
|---|
 | 1178 | ######################################################
 | 
|---|
 | 1179 | print "\n\n"
 | 
|---|
 | 1180 |   . "# Binds       Bind DN\n"
 | 
|---|
 | 1181 |   . "----------    --------------------------------------------------------------\n";
 | 
|---|
 | 1182 | 
 | 
|---|
 | 1183 | @sarray = reverse sort { $binddns{$a} <=> $binddns{$b} } keys %binddns;
 | 
|---|
 | 1184 | BINDDN:
 | 
|---|
 | 1185 | for my $num ( 0 .. $#sarray ) {
 | 
|---|
 | 1186 |     if ( $num > $count ) {
 | 
|---|
 | 1187 |         last BINDDN;
 | 
|---|
 | 1188 |     }
 | 
|---|
 | 1189 |     printf "  %-8d    %-60s\n", $binddns{ $sarray[$num] }, $sarray[$num];
 | 
|---|
 | 1190 | }
 | 
|---|
 | 1191 | 
 | 
|---|
 | 1192 | print "\n\n";
 | 
|---|
 | 1193 | 
 | 
|---|
 | 1194 | # EOF
 | 
|---|