Eli Weinstock-Herman | Tarwn
Opportunities are Measured by What You Take Away From Them

Older Scripts

This section of the site contains some of the older scripts that were on previous versions of the sites. Further additions are by request.

Cisco - Active Port Information

Origially Published: ~2007
Several months ago I found it necessary to monitor a pair of Cisco switches had roughly 90 cables connected to them and exactly zero documentation. The goal was to keep an eye on what ports went active and what vLANs they were on in order to get an idea of what cables we needed to rerun when we renovated the cabinet and wiring.

I chose PHP for this task due to it's easy ability to handle sockets and the fact that I could run it as either a web server script (while testing) or a command-line script (while actively monitoring).

Cisco Connection Info Function


The function accepts an IP address for the switch, password, and two flags indicating whether disconnected and disabled port information should be returned as well as the default connected port information. There is one major assumption in the script on line 23 where it sends spaces in order to page through the, hopefully 8 pages or less, results of the "show interface status" command.

CiscoConnectionInfo.php
function getConnectedInfo($ipAddress,$password,$incDisconnected = false,$incDisabled = false){
 $fp = fsockopen($ipAddress, 23, $errno, $errstr, 3) or die('Connection timed out when attempting to connect to ' . $ipAddress );
 if(!$fp){
  echo "$errstr ($errno)\n";
  exit;
 }

 $buffer = '';

 fwrite($fp,$password . "\n");

 $crap = ReadTo($fp,"/Password:/");
 $prompt = trim(ReadTo($fp,'/>|:/'));
 
 if(strpos($prompt,'Password') !== false){
  return array(
   'name' => 'Unknown - Password Incorrect',
   'port' => array(),
   'vlan' => array());
 }
 fwrite($fp,"show int status\n");
 fwrite($fp," ");
 fwrite($fp," ");
 fwrite($fp," ");
 fwrite($fp," ");
 fwrite($fp," ");
 fwrite($fp," ");
 fwrite($fp," ");
 fwrite($fp," ");
 $buffer = ReadTo($fp, "/$prompt/");
 fwrite($fp,"exit\n");
 fclose($fp);

 //strip unnecessary information
 $statusMatch = '(connected';
 if($incDisconnected)
  $statusMatch .= '|notconnect';
 if($incDisabled)
  $statusMatch .= '|err-disabled';
 $statusMatch .= ')';
 preg_match_all('/\n([FG][^ ]+)[^\n]+' . $statusMatch . ' +(\d+|trunk) /',$buffer, $matches);
 
 return array(
    'name' => substr($prompt, 0, strlen($prompt)-1),
    'port' => $matches[1],
    'vlan' => $matches[3],
    'status'=> $matches[2]);
}

function ReadTo($fp, $str){
 $buf = '';

 while(!feof($fp)){
  $buf .= fread($fp,8192);

  // we've encountered the prompt. Break out of the loop
  if (preg_match($str,$buf)){
   return $buf;
  }
 }

 return $buf;
}
?>


This function is then used by both the monitoring script and the web script to connect to any number of our Cisco switches and get port information.

Monitoring Script


The monitoring script is executed every 10 minutes. It retrieves the connected port information and dumps it into a database table for easy retrieval or querying. The database table is setup like so:
Database Table: portmonitor.ports
CREATE TABLE `portmonitor`.`ports` (
`port_id` int(10) unsigned NOT NULL auto_increment,
`switch` varchar(45) NOT NULL default '',
`port_name` varchar(45) NOT NULL default '',
`vlan` varchar(45) NOT NULL default '',
`scan_time` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`port_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


And the monitoring script works like so:
portMonitor.php
include('CiscoConnectionInfo.php');

$data[] = array('myIpAddress','myPassword');
$data[] = array('myIpAddress2','myPassword');

// db connection
$dbconn = mysql_connect('MyDBServer','MyDbUser','MyDbPassword');
if($dbconn === false){
 echo "Could not connect to database. Please come back later.";
 exit;
}
mysql_select_db('portmonitor',$dbconn);

// start processing data entries
if(isset($data)){
 for($i = 0; $i < sizeof($data); $i++){
  $data[$i][2] = getConnectedInfo($data[$i][0],$data[$i][1]);
 }

 for($i = 0; $i < sizeof($data); $i++){

  // insert connected ports
  $sqlhd = 'INSERT INTO ports(switch,port_name,vlan,scan_time) VALUES(';
  for($j = 0; $j < sizeof($data[$i][2]['port']); $j++){
   if($data[$i][2]['status'][$j] != 'notconnect'){
    $sql = $sqlhd . "'" . $data[$i][2]['name'] . "','" . $data[$i][2]['port'][$j] . "','" . $data[$i][2]['vlan'][$j] . "',now())";
    mysql_query($sql, $dbconn);
    if(mysql_errno() != 0){
     echo "MySQL Error: " . mysql_error() . '
';
    }
   }
  }
 }
}

// close db connection
mysql_close($dbconn);
?>


Web Page


As I mentioned in the beginning, I originally was testing the function using a web page to query switches. I later went back and expanded the page a little to list some of our common switches, color-code the port records based on VLan, etc. I did not spend much time on this page, so don't expect it to be pretty, but it is handy.
switch.php
<?
include('CiscoConnectionInfo.php');
$includeDisconnected = false;
$includeDisabled = false;

$switches = array(
  'Common Switch #1' => array('ip' => '10.4.3.2', 'pass' => 'abcde'),
  'Common Switch #2' => array('ip' => '10.4.3.3', 'pass' => 'abcde'),
  'Common Switch #3' => array('ip' => '10.4.3.4', 'pass' => 'abcde'),
  'Common Switch #4' => array('ip' => '10.4.3.5', 'pass' => 'abcde')
 );
?>
<html>
<head>
<title>Connection Data</title>
<style>
 .data{
  float: left;
  border-collapse: collapse;
  margin-right: 10px;
 }
 .data th{
  background-color: #eeeeee;
 }
 .data th, .data td{
  padding: 3px;
  border: 1px solid #666666;
 }
 .right{
  float: right;
 }

 /* VLAN Color Coding */
 .vlan_1 td, .vlan_trunk td{ background-color: yellow; }
 .vlan_10 td{    background-color: red;  }
 .vlan_20 td{    background-color: #66CCFF; }
 .vlan_30 td{    background-color: yellow; }
 .vlan_50 td{    background-color: #FF9900; }
 .vlan_52 td{    background-color: #cccccc; }

 /* Port Status - connected, notconnect, err-disabled */
 .stat_connected td{}
 .stat_notconnect td{
  font-style: italic;
 }
 tr.stat_err-disabled td{
  color: red;
  background-color: white;
  font-weight: bold;
 }
</style>
</head>
<body>
<h1>Switch Info</h1>
<div class="top">
 <div class="right">
  <strong>Full Switch Info:</strong><ul>
   <?
   foreach(array_keys($switches) as $k){
    if(isset($_GET['sw']) && $k == $_GET['sw'])
     echo '<li><strong>' . $k . '</strong></li>';
    else
     echo '<li><a href="switch.php?sw=' . $k . '">' . $k. '</a></li>';
   }
   ?>
  </ul>
 </div>
 <div class="left">
 <form method="POST" action="">
 <table>
  <tr><th></th><th>Switch 1</th><th>Switch 2</th><th>Switch 3</th><th>Switch 4</th></tr>
  <tr>
   <th>IP Address:</th>
   <td><input type="text" name="IP_0" value="<? if(isset($_POST['IP_0'])) echo $_POST['IP_0']; ?>" tabindex="1" /></td>
   <td><input type="text" name="IP_1" value="<? if(isset($_POST['IP_1'])) echo $_POST['IP_1']; ?>" tabindex="3" /></td>
   <td><input type="text" name="IP_2" value="<? if(isset($_POST['IP_1'])) echo $_POST['IP_2']; ?>" tabindex="5" /></td>
   <td><input type="text" name="IP_3" value="<? if(isset($_POST['IP_1'])) echo $_POST['IP_3']; ?>" tabindex="7" /></td>
  </tr>
  <tr>
   <th>Password:</th>
   <td><input type="password" name="PASS_0" value="<? if(isset($_POST['PASS_0'])) echo $_POST['PASS_0']; ?>" tabindex="2" /></td>
   <td><input type="password" name="PASS_1" value="<? if(isset($_POST['PASS_1'])) echo $_POST['PASS_1']; ?>" tabindex="4" /></td>
   <td><input type="password" name="PASS_2" value="<? if(isset($_POST['PASS_2'])) echo $_POST['PASS_2']; ?>" tabindex="6" /></td>
   <td><input type="password" name="PASS_3" value="<? if(isset($_POST['PASS_3'])) echo $_POST['PASS_3']; ?>" tabindex="8" /></td>
  </tr>
 </table>
 Include Disconnected Ports? <input type="checkbox" name="incdisc" value="1" <?
  if(isset($_POST['incdisc'])){
   $includeDisconnected = true;
   echo 'checked';
  }
 ?> tabindex="9" /><br/>
 Include Disabled Ports? <input type="checkbox" name="incdisa" value="1" <?
  if(isset($_POST['incdisa'])){
   $includeDisabled = true;
   echo 'checked';
  }
 ?> tabindex="10" /><br/>
 <input type="submit" value="Request Info" onClick="this.disabled=true; this.value='Working...';" tabindex="11" />
 </form>
 </div>
</div>
<?
for($i = 0; $i < 4; $i++){
 if(isset($_POST['IP_' . $i]) && isset($_POST['PASS_' . $i]) && strlen($_POST['IP_' . $i]) > 0)
  $data[] = array($_POST['IP_' . $i], $_POST['PASS_' . $i]);
}

if(isset($data)){
 for($i = 0; $i < sizeof($data); $i++){
  $data[$i][2] = getConnectedInfo($data[$i][0],$data[$i][1],$includeDisconnected,$includeDisabled);
 }
}

if(isset($_GET['sw']) && $switches[$_GET['sw']] != null){
 if(isset($data))
  $i = sizeof($data);
 else
  $i = 0;

 $data[$i][0] = $switches[$_GET['sw']]['ip'];
 $data[$i][1] = $switches[$_GET['sw']]['pass'];
 $data[$i][2] = getConnectedInfo($data[$i][0],$data[$i][1],true,true);
 $data[$i][3] = 'pre';
}

if(isset($data)){
 echo '<hr/>';

 for($i = 0; $i < sizeof($data); $i++){
  echo '<table class="data" cellpadding="0" cellspacing="0"><tr><th colspan="3">';
  echo $data[$i][2]['name'];
  if($includeDisconnected || $includeDisabled || $data[$i][3] == 'pre')
   echo ' (' . sizeof($data[$i][2]['port']) . ' Ports)';
  else
   echo ' (' . sizeof($data[$i][2]['port']) . ' Active)';
  echo '</th></tr><tr><th>Port</th><th>VLAN</th><th>Status</th></tr>';
  for($j = 0; $j < sizeof($data[$i][2]['port']); $j++){
   echo '<tr class="vlan_' . $data[$i][2]['vlan'][$j] . ' stat_' . $data[$i][2]['status'][$j] . '"><td>' . $data[$i][2]['port'][$j] . '</td><td>' . $data[$i][2]['vlan'][$j] . '</td><td>' . $data[$i][2]['status'][$j] . '</td></tr>';
  }
  echo '</table>';
 }
}
?>
<br style="clear: both;" />
</body>
</html>

Valid XHTML Valid CSS 2.1 HCard microformat Copyright 2010 - Eli Weinstock-Herman | Tarwn Powered by PHP Delicious Integrated Built with EditPlus