#!/usr/local/bin/perl -w # ########################################################################### # pmstat.pl # Version 1.3.3 # # Chris Adams # http://ro.com/~cadams/files/ # ########################################################################### # This program may be distributed under the terms of either the GNU # General Public License or the Artistic License, as specified in the # Perl README file. # ########################################################################### # # READ ALL OF THIS TO MAKE THIS PROGRAM WORK!! # -------------------------------------------- # # Requires the Perl SNMP module version 1.7 or higher (see # http://www.perl.com/CPAN/modules/by-module/SNMP/ or the home site at # ftp://ftp.wellfleet.com/netman/snmp/perl5/) and UCD SNMP # (ftp://ftp.ece.ucdavis.edu:/pub/snmp/). I reccomend using UCD SNMP 3.5.3 # and SNMP 1.8. # # Queries one (or more) PortMasters via SNMP to get connection information. # Usage: # pmstat.pl [-f] [-u ] [ ...] # -f run a little faster (no header or hostname lookups) # -u only show info for logins of this username # # You can specify as many PortMaster hostnames as you want. # # Configuration: # -------------- # Change $MAXNAMELEN to the longest username you will be showing. # Longer usernames take away from hostname display. # # Change $MYDOMAIN below if you don't want to see your own domain name # in hostname lookups. # ########################################################################### # VERSION HISTORY - you don't have to read this # # Version 1.0 - 12 Dec 1997 # - initial version # # Version 1.1 - 27 Jan 1998 # - modified to use SNMP 1.7 and did some general cleanup # # Version 1.1.1 - 30 Jan 1998 # - some more cleanup # # Version 1.2 - 13 Feb 1998 # - rearranged and reorganized the main loop to speed things up a bit # # Version 1.2.1 - 23 Feb 1998 # - put more better documentation in # # Version 1.2.2 - 9 Apr 1998 # - fixed error checking a bit # # Version 1.3 - 17 Jul 1998 # - changed to not require the Livingston MIB be installed, updated docs # # Version 1.3.1 - 7 Sep 1998 # - changed some formatting # # Version 1.3.2 - 14 Sep 1998 # - fixed a few spacing problems, added "strict" checking during testing # # Version 1.3.3 - 16 Sep 1998 # - if there is no username, use the router/port name (for non-auth # connections) # - better spacing for speed on non-modem connections # use integer; use SNMP; use Socket; use Getopt::Std; #use strict; #use diagnostics; ########################################################################### # User settable variables # my $MAXNAMELEN = 15; #my $MYDOMAIN = "ro.com"; my $MYDOMAIN = ""; ########################################################################### # Parse the options # $Getopt::Std::opt_u = ""; $Getopt::Std::opt_f = 0; getopts ('fu:'); my $user = $Getopt::Std::opt_u; $main::fastrun = $Getopt::Std::opt_f; ########################################################################### # Figure the column sizes # my $hostlen = 29 - $MAXNAMELEN; $MAXNAMELEN *= -1; $hostlen *= -1; ########################################################################### # Print the header and quote the metacharacters in the domain name # if (! $main::fastrun) { printf "%${MAXNAMELEN}s %${hostlen}s %11s %5s %-11s %-10s %-5s\n", "", "", "Connect ", "Idle", " Speed", "Protocol/", " Reneg/"; printf "%${MAXNAMELEN}s %${hostlen}s %11s %5s %-11s %-10s %-5s\n", "Username", "Hostname", "Time/Date ", "Time", " In/Out ", "Compress", " Retrn"; print "---------------------------------------------------------------", "----------------"; print "\n"; # Escape domain name $MYDOMAIN =~ s/^([^\.])/.$1/; $MYDOMAIN = quotemeta ($MYDOMAIN); } ########################################################################### # A few defines and the SNMP initialization # @main::comps = ("-", "None", "v42bis", "MNP5", "STAC"); @main::protos = ("-", "None", "LAPM", "MNP"); $SNMP::use_long_names = 0; $SNMP::auto_init_mib = 0; ########################################################################### # For each host on the command line, get the stats. # while ($ARGV[0]) { pmstat ($ARGV[0], $user, $MYDOMAIN, $MAXNAMELEN, $hostlen); shift @ARGV; } ########################################################################### # The main function # sub pmstat { my ($pm, $muser, $mydomain, $namelen, $hostlen) = @_; ################################################################### # Open a session and initialize the variable list # my $sess = new SNMP::Session (DestHost => $pm, Community => 'public') or die "can't open SNMP session: $!"; my $sess_err = \$sess->{ErrorStr}; my $lemib = ".1.3.6.1.4.1.307"; my $vars = new SNMP::VarList ( [$lemib . '.3.2.1.1.1.4',1], # livingstonSerialUser [$lemib . '.3.2.1.1.1.14',1], # livingstonSerialIpAddress [$lemib . '.3.2.1.1.1.8',1], # livingstonSerialPortStatus [$lemib . '.3.2.1.1.1.9',1], # livingstonSerialStarted [$lemib . '.3.2.1.1.1.10',1], # livingstonSerialIdle [$lemib . '.3.2.1.1.1.11',1], # livingstonSerialInSpeed [$lemib . '.3.2.1.1.1.12',1], # livingstonSerialOutSpeed [$lemib . '.3.2.1.1.1.20',1], # livingstonSerialModemCompression [$lemib . '.3.2.1.1.1.21',1], # livingstonSerialModemProtocol [$lemib . '.3.2.1.1.1.23',1], # livingstonSerialModemRenegotiates [$lemib . '.3.2.1.1.1.22',1], # livingstonSerialModemRetrains [$lemib . '.3.2.1.1.1.3',1], # livingstonSerialPhysType [$lemib . '.3.2.1.1.1.2',1] # livingstonSerialPortName ); ################################################################### # Get the first set of vars # my ($user, $ip, $stat, $started, $idletime, $in, $out, $compress, $protocol, $reneg, $retr, $type, $pname); my $getvars = sub { ($user, $ip, $stat, $started, $idletime, $in, $out, $compress, $protocol, $reneg, $retr, $type, $pname) = $sess->getnext ($vars); }; &{$getvars}; ################################################################### # As long as there is not an error, process the vars and get more # while (($$sess_err eq "") && ($vars->[0]->[0] =~ /.1.3.6.1.4.1.307.3.2.1.1.1.4\.\d+$/)) { ########################################################### # If there is no username, take the router/port name # if (defined ($user) && ($user eq "")) { $user = $pm; $user =~ s/$MYDOMAIN$//; $user .= "/" . $pname; } ########################################################### # Skip this entry if there is not a user logged in or if we # are looking for a particular user and this is not the # right one # next if ($stat != 3); next if (($muser ne "") && ($user ne $muser)); ########################################################### # Convert the info for printing # my $hostname = host_lookup ($ip, $hostlen, $mydomain); my $start = convert_date ($started); my $idle = convert_time ($idletime); my $comp = $main::comps[$compress]; my $proto = $main::protos[$protocol]; ########################################################### # Print everything out # my $con_info; if ($type != 5) { my $space = 11 - length ("$out"); my $left = int ($space / 2); my $right = $space - $left; $con_info = sprintf "%s%s%s %6s", " " x $left, $out, " " x $right, $comp; } else { $con_info = sprintf "%5s/%-5s %4s/%-6s %2s/%-2s", $in, $out, $proto, $comp, $reneg, $retr; } printf "%${MAXNAMELEN}s %${hostlen}s %11s %5s %s\n", $user, $hostname, $start, $idle, $con_info; } ################################################################### # Continue block - get the next set of variables continue { &{$getvars}; } } ########################################################################### # convert_time - Take the number of seconds and make it into a short # readable field # sub convert_time { my ($time) = @_; my $seconds = $time / 100; my $minutes = $seconds / 60; my $hours = $minutes / 60; my $days = $hours / 24; $seconds %= 60; $minutes %=60; $hours %=24; if ($minutes == 0) { return ($seconds); } elsif ($hours == 0) { return (sprintf "%d:%02d", $minutes, $seconds); } elsif ($hours < 10) { return (sprintf "%dh:%02d", $hours, $minutes); } elsif ($days == 0) { return (sprintf "%dh", $hours); } elsif ($days < 10) { return (sprintf "%dd:%02d", $days, $hours); } else { return (sprintf "%dd", $days); } } ########################################################################### # convert_date - Print the time in a nice format # sub convert_date { my ($time) = @_; my $start = time () - $time / 100; my ($sec, $min, $hour, $mday, $mon) = localtime ($start); return (sprintf "%2d/%-2d %2d:%02d", $mon + 1, $mday, $hour, $min); } ########################################################################### # host_lookup - Lookup a hostname, either in the builtin cache or from # DNS (and then cache it) # sub host_lookup { my ($addr, $hostlen, $mydomain) = @_; ################################################################### # Initialize the cache to empty except for a telnet login # my %host_hash; BEGIN { %host_hash = (); $host_hash{0} = "(telnet)"; } my $ret; if (defined ($host_hash{$addr})) { $ret = $host_hash{$addr}; } else { my $name = gethostbyaddr (inet_aton ($addr), AF_INET) if (! $main::fastrun); if ($name) { $ret = $name; } else { $ret = $addr; } $host_hash{$addr} = $ret; } $ret =~ s/$mydomain$//i; $ret = substr ($ret, 0, (-1 * $hostlen)); return ($ret); }