(PM) SNMP port monitoring script

Stefan Hudson (hudson@mbay.net)
Sun, 8 Feb 1998 17:58:05 -0800

As promised, this is the script that I use for kicking users offline. I don't
use the radius timers, so this handles my session and idle timers, in addition
to kicking users off for multiple connections. This version will not kick off
users with an MP connection (all ports have the same address). It uses the
SNMP Perl module; I can't remember where I got it, but I think it's included
in the default perl5 distrib these days. If you have trouble finding it, let
me know and I'll find a URL for it.

I've been running it once per minute lately, and it seems to be working fine;
no problems with system or network load.

See http://prime-mover.cc.waikato.ac.nz/Bastard.html if you don't get name.

#!/usr/local/bin/perl5
#
# bofh.pl - version 1.0 Copyright 1998 Stefan Hudson <hudson@mbay.net>
# Distribution permitted in unmodified form only.
#
# Run from a crontab with somethine like this:
# 0,5,10,15,20,25,30,35,40,45,50,55 * * * * (/usr/local/sbin/bofh.pl)>/dev/null 2>/dev/null
#
# Bugs/missing features:
# - No facility for excepting special users (staff or full time accounts)
# - In rare cases, MP users will get kicked if the second channel is just coming
# up and still has a 0.0.0.0 IP address.

$PMCOM='/usr/local/sbin/pmcom'; # Location of the "pmcom" command.
$BUSY = 360; # Number of ports that must be used before we start kicking people off
$IDLE = 570; # Idle timer in seconds (9.5 minutes) (when we are over $BUSY)
$LIMIT = 28800; # Session timer in seconds (8 hours) (all the time)

# Specify terminal servers to monitor here.
@SERVERS=("pm1.foo.net", "pm2.foo.net", "pm3.foo.net");

$COMMUNITY="public"; # SNMP read community for portmasters
$LOGSERV = 'local5|info'; # syslog service for logging. I use the same one the PMs use.

# You shouldn't need to modify anything below here...

use SNMP 1.6;
use Sys::Syslog;
$Sys::Syslog::host = "localhost";

foreach $pm (@SERVERS) {
$session = new SNMP::Session ( DestHost => $pm, Community => $COMMUNITY );
next if(!$session);
$pm = $session->{DestAddr}; # make sure host is dotted decimal ip addr

$pinfo = new SNMP::VarList (
['livingstonSerialUser', 1], # 0
['livingstonSerialPortName', 1], # 1
['livingstonSerialStarted', 1], # 2
['livingstonSerialIdle', 1], # 3
['livingstonSerialIpAddress', 1], # 4
);

@ret = $session->get($pinfo);

while(@ret) {
# print join(" ", @ret), "\n";
@ret = $session->getnext($pinfo);
next if(!$ret[0]);
last if($pinfo->[0][$SNMP::Varbind::tag_f] ne 'livingstonSerialUser');
next if ($ret[0] eq 'PPP');

$ret[0]=~ s/(.ppp|.slip|.cslip)//;
$port[0] = $pm;
$port[1] = $ret[1]; # port name
$port[2] = $ret[0]; # username
$port[3] = join('.', unpack("C4", $ret[4])); # address
$port[4] = int($ret[2]/100); # uptime
$port[5] = int($ret[3]/100); # busy

# print("$port[3]\n");
push(@ports, [@port]);
push(@{$users{$port[2]}}, [@port]);
}
}

foreach(@ports) { # Check idle/session timeouts
if(($#ports > $BUSY && ($_->[5] > $IDLE)) || $ports{$_}[4] > $LIMIT) {
# print("$_->[1] $_->[2] $_->[3] $_->[4] $_->[5]\n");
&killport(@$_);
}
}

foreach $user (sort(keys(%users))) { # Check for multiple connections
if($#{@users{$user}}) { # More than one port in use
# print("$user $users{$user}[0]->[3] $port->[3]\n");
foreach $port (@{$users{$user}}) { # Check each port user is on
if($port->[3] ne $users{$user}[0]->[3]) {
printf("%s duplicate $user ($users{$user}[0]->[3] $port->[3])\n", scalar(localtime()));
syslog($LOGSERV, "portcheck: duplicate $user ($users{$user}[0]->[3] $port->[3])\n");
foreach $port (@{$users{$user}}) {&killport(@{$port})};
last;
}
}
}
}

#print("$_ $#{@users{$_}} $users{$_}[0]->[3] $users{$_}[1]->[3]\n");

sub killport {
local(@port)=@_;
printf("%s terminating %s %s (up %s idle %s)\n", scalar(localtime()), $port[2], $port[3], timestr($port[4]), timestr($port[5]));
syslog($LOGSERV, "portcheck: terminating %s %s (up %s idle %s)\n", $port[2], $port[3], timestr($port[4]), timestr($port[5]));
system($PMCOM, $port[0], "reset $port[1]");
}

sub timestr {
local($ttime) = @_;
$str=sprintf("%02d:%02d:%02d", int(($ttime%86400)/3600), int(($ttime%3600)/60), $ttime%60);
$str=sprintf("%d $str", int($ttime/86400)) if($ttime>86400);
return($str);
}

-- 
     /// Stefan Hudson <hudson@mbay.net>  
__  /// Senior Network Administrator - Monterey Bay Internet
\\\/// http://www.mbay.net/  -  Email: info@mbay.net
 \XX/ Voice: 408-642-6100  Fax: 408-642-6101  Modem: 408-642-6102
-
To unsubscribe, email 'majordomo@livingston.com' with
'unsubscribe portmaster-users' in the body of the message.