Following is a PHP script I wrote to find a PC location in a farm of CISCO switches based on its MAC address, the script connects to a central switch, trys to find where the PC is connected "on which port", if it does not find it, then the script connects to the next switch based on CDP protocol. NOTE: Some regular expressions may be not accurate in all circumstances, take it as is at your risk, or feel free to change it.
<?php
function login($telnet,$username,$password) {
$response = readBuffer($telnet);
if($username != null)
fputs($telnet,"{$username}\r\n");
fputs($telnet,"{$password}\r\n");
$response .= readBuffer($telnet);
// if the switch in user mode
// then go to exec mode
if(preg_match("/[a-z0-9_\(\)\-]+>$/i",$response) ) {
$response .= sendCommand($telnet,"en");
$response .= sendCommand($telnet,$password);
}
preg_match("/[a-z0-9_\(\)\-]+[#>]$/i",$response,$out);
return str_replace("#","",$out[0]); // return hostname
}
function sendCommand($telnet,$c) {
fputs($telnet,"{$c}\r\n");
return readBuffer($telnet);
}
function readBuffer($telnet) {
$str = "";
while(true) {
$result = fgets($telnet,2);
if(ord($result) != 8) //backspace
$str .= $result;
if( substr($str,-8) == "--More--" ) {
$str =
preg_replace("/[\-]{2}More[\-]{2}/i","",
$str);
fputs($telnet," ");
}
if( ( $result == "#" ||
$result == ">" ||
$result == ":" ||
) &&
( preg_match("/[a-z0-9_\(\)\-]+[#>]$/i",$str)
preg_match("/Password:\s$/i",$str)
)
)
break;
}
return $str;
}
// the following function are executed through
// regular expression to replace short interface
// names with full names
// you can add other short names here
function fullname($shortname) {
switch($shortname) {
case "fa":
return "FastEthernet";
case "gi":
return "GigabitEthernet";
}
return $shortname;
}
function findMAC($switch,$mac) {
$telnet = fsockopen($switch,"23",$errno,$errstr,60*30);
$hostname = login($telnet,null,"PASSWORD");
// execute show mac-address-table on the switch
$result =
sendCommand($telnet,
"sh mac-address-table | include ".$mac);
// get the interface where the PC
// connects to (it may be the next switch
// based on cdp output below)
preg_match("/\s([A-Z]+([0-9]+\/)+[0-9]+)\s/i",$result,$out);
$interface = $out[1];
// if the interface is in short name format
// convert it to full name
$interface =
preg_replace("/^([a-z]{2})([0-9])/ie",
"fullname(strtolower('\\1')).'\2'",
$interface);
// execute show cdp neighbors detail on the switch
$result = sendCommand($telnet,"sh cdp ne de");
// get all neighbors
$deviceid = "\sDevice\sID:\s+?([a-z0-9_\(\)\-]+)";
$ipaddress =
"IP\saddress:\s+?([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)";
$port = "Interface:\s+?([A-Z]+([0-9]+\/)+[0-9]+)";
$neighbors_count =
preg_match_all("/{$deviceid}(.\s)*?"
.
"{$ipaddress}(.\s)*?"
.
"{$port}/i",
$result,
$out);
// if the interface in the cdp neighbors output
// then the PC is not connected to this switch
// repeat the process on the neighbor switch
for($i=0;$i<$neighbors_count;$i++) {
if(strcasecmp ($out[5][$i],$interface) == 0) {
echo "Device ID: ".$hostname."<br />";
echo "IP Address: ".$switch."<br />";
echo "Interface: ".$interface."<br />";
echo "Next Device: ".$out[1][$i]."<hr />";
findMAC($out[3][$i],$mac);
return;
}
}
// if we reach here then we find the interface
// print it out
echo "Device ID: ".$hostname."<br />";
echo "IP Address: ".$switch."<br />";
echo "Interface: ".$interface."<hr />";
}
// how to use
$mainswitch = "192.168.1.1";
$macaddress = "xxxx.xxxx.xxxx";
findMAC($mainswitch,$macaddress);
?>