Richard Bejtlich wrote late last year about an idea for security visualisations which inspired me to look for opportunities to apply visualisations in my work. Well I found that opportunity while performing an audit of switch configurations.
The objectives of the visualisation are to provide at a glance.
- whether 802.1x is enabled,
- Vlan/function by color code,
- trunking mode of the port and
- the ability to drill down for further information.
I’ve divided the solution into two parts
- A script using snmp to query the switch port configuration and save the data in xml format. This can be run as a scheduled task at suitable intervals to ensure that the information remains current. See the listing of spview.wsf below for details.
- Converting the saved xml data into a suitable visual representation. For this project an xml stylesheet is used to render the data as html in a web browser. The drill down component is provided by javascript with a “tooltip text” display when the mouse is moved onto a table cell. See the listing for spview.xsl for more details. Note that the javascript for the ” tooltip text” is courtesy of Nelson and can be found here. The only modifications I made were to the initialisation code so that I could safely move the code from the body of the html to the head section.
Cisco catalyst 3750 48 port switches were used for this project so the snmp OID’s used for checking the configuration are obviously cisco specific.
One thing that really had me stumped was how to include the javascript in the stylesheet without causing errors. I eventually worked out that wrapping everything between, but not including the <script> </script> tags in a <![CDATA[ ….]]> element did the trick.
Switchport Visualisation
spview.xsl
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:variable name="color_legacy" select="'#7bb31a'"/>
<xsl:variable name="color_vc" select="'#ff9d7f'"/>
<xsl:variable name="color_wireless" select="'Red'"/>
<xsl:variable name="color_dot1xauth" select="'#8b88ff'"/>
<xsl:variable name="color_dot1xguest" select="'#8b88ff'"/>
<xsl:variable name="color_printer" select="'lightGrey'"/>
<xsl:variable name="color_reimage" select="'#ff9c00'"/>
<xsl:variable name="color_unknown" select="'#eedb00'"/>
<xsl:variable name="color_nodot1x" select="'#cc3333'"/>
<xsl:variable name="cellheight" select="'35'"/>
<xsl:variable name="cellwidth" select="'35'"/>
<xsl:template match="/">
<html>
<head>
<title><xsl:value-of select="concat('Switch Stack View ',/stack/@hostname)"/></title>
<style type="text/css">
#dhtmltooltip{
position: absolute;
border: 1px solid red;
width: 150px;
padding: 2px;
background-color: lightyellow;
visibility: hidden;
z-index: 100;
filter: progid:DXImageTransform.Microsoft.Shadow(color=gray,direction=115);
}
</style>
<style type="text/css">
table.switch {
table-layout: fixed
}
</style>
<script type="text/javascript">
<![CDATA[
/***********************************************
* Freejavascriptkit.com
* Visit http://www.freejavascriptkit.com for more free Javascripts source code
***********************************************/
var offsetxpoint=-60 //Customize x offset of tooltip
var offsetypoint=20 //Customize y offset of tooltip
var ie=document.all
var ns6=document.getElementById && !document.all
var enabletip=false
var tipobj;
function initTipObj(){
if (ie||ns6)
tipobj=document.all? document.all["dhtmltooltip"] : document.getElementById? document.getElementById("dhtmltooltip") : ""
}
function ietruebody(){
return (document.compatMode && document.compatMode!="BackCompat")? document.documentElement : document.body
}
function ddrivetip(thetext, thecolor, thewidth){
if (ns6||ie){
if (typeof thewidth!="undefined") tipobj.style.width=thewidth+"px"
if (typeof thecolor!="undefined" && thecolor!="") tipobj.style.backgroundColor=thecolor
tipobj.innerHTML=thetext
enabletip=true
return false
}
}
function positiontip(e){
if (enabletip){
var curX=(ns6)?e.pageX : event.clientX+ietruebody().scrollLeft;
var curY=(ns6)?e.pageY : event.clientY+ietruebody().scrollTop;
//Find out how close the mouse is to the corner of the window
var rightedge=ie&&!window.opera? ietruebody().clientWidth-event.clientX-offsetxpoint : window.innerWidth-e.clientX-offsetxpoint-20
var bottomedge=ie&&!window.opera? ietruebody().clientHeight-event.clientY-offsetypoint : window.innerHeight-e.clientY-offsetypoint-20
var leftedge=(offsetxpoint<0)? offsetxpoint*(-1) : -1000
//if the horizontal distance isn't enough to accomodate the width of the context menu
if (rightedge<tipobj.offsetWidth)
//move the horizontal position of the menu to the left by it's width
tipobj.style.left=ie? ietruebody().scrollLeft+event.clientX-tipobj.offsetWidth+"px" : window.pageXOffset+e.clientX-tipobj.offsetWidth+"px"
else if (curX<leftedge)
tipobj.style.left="5px"
else
//position the horizontal position of the menu where the mouse is positioned
tipobj.style.left=curX+offsetxpoint+"px"
//same concept with the vertical position
if (bottomedge<tipobj.offsetHeight)
tipobj.style.top=ie? ietruebody().scrollTop+event.clientY-tipobj.offsetHeight-offsetypoint+"px" : window.pageYOffset+e.clientY-tipobj.offsetHeight-offsetypoint+"px"
else
tipobj.style.top=curY+offsetypoint+"px"
tipobj.style.visibility="visible"
}
}
function hideddrivetip(){
if (ns6||ie){
enabletip=false
tipobj.style.visibility="hidden"
tipobj.style.left="-1000px"
tipobj.style.backgroundColor=''
tipobj.style.width=''
}
}
document.onmousemove=positiontip
]]>
</script>
</head>
<body onload="initTipObj();">
<div id="dhtmltooltip"></div>
<xsl:apply-templates select=".//switch"/>
<table Border='1' cellspacing='2'>
<tr>
<td align='center' bgcolor='{$color_legacy}'></td>
<td><xsl:text>Legacy Vlan</xsl:text></td>
</tr>
<tr>
<td bgcolor="{$color_dot1xauth}"></td>
<td><xsl:text>Authenticated Computers Vlan</xsl:text></td>
</tr>
<tr>
<td bgcolor="{$color_dot1xguest}"></td>
<td>Guest Vlan</td>
</tr>
<tr>
<td bgcolor="{$color_vc}"></td>
<td><xsl:text>VC Equipment Vlan</xsl:text></td>
</tr>
<tr>
<td bgcolor="{$color_wireless}"></td>
<td><xsl:text>Wireless or Management Vlan</xsl:text></td>
</tr>
<tr>
<td bgcolor="{$color_printer}"></td>
<td><xsl:text>Printer Vlan</xsl:text></td>
</tr>
<tr>
<td bgcolor="{$color_reimage}"></td>
<td><xsl:text>Re-imaging Vlan</xsl:text></td>
</tr>
<tr>
<td bgcolor="{$color_unknown}"></td>
<td><xsl:text>Unknown Vlan</xsl:text></td>
</tr>
<tr>
<td style="color:{$color_nodot1x}">Text</td>
<td><xsl:text>Font color indicates access port with no dot1x</xsl:text></td>
</tr>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="switch">
<table class='switch' Border='1' width='100%' cellspacing='2'>
<tr>
<xsl:comment>Display the odd numbered ports in the top row</xsl:comment>
<xsl:apply-templates select="port[starts-with(@IfName,'Fa') and substring-after(@IfName,'0/') mod 2 = 1]"/>
</tr>
<tr>
<xsl:comment>Display the even numbered ports in the bottom row</xsl:comment>
<xsl:apply-templates select="port[starts-with(@IfName,'Fa') and substring-after(@IfName,'0/') mod 2 = 0]"/>
</tr>
</table>
<p/><p/>
</xsl:template>
<xsl:template match="port">
<xsl:variable name="tiptext">
<xsl:call-template name="tiptext"/>
</xsl:variable>
<xsl:variable name="bgcolor">
<xsl:call-template name="bgcolor"/>
</xsl:variable>
<xsl:variable name="cellstyle">
<xsl:if test="@Dot1x != 2 and @Trunking = 2">
<xsl:value-of select="concat('color:',$color_nodot1x)"/>
</xsl:if>
</xsl:variable>
<td align='center' width="{$cellheight}" height="{$cellwidth}" bgcolor="{$bgcolor}" style="{$cellstyle}"
onMouseover='ddrivetip("{$tiptext}","yellow", 180)'
onMouseout="hideddrivetip()">
<xsl:value-of select="substring-after(@IfName,'0/')"/>
<xsl:if test="@Dot1x = 2">
<xsl:text>.</xsl:text>
</xsl:if>
</td>
</xsl:template>
<xsl:template name="bgcolor">
<xsl:choose>
<xsl:when test="@Vlan = 5">
<xsl:value-of select="$color_legacy"/>
</xsl:when>
<xsl:when test="@Vlan = 910">
<xsl:value-of select="$color_vc"/>
</xsl:when>
<xsl:when test="(@Vlan >= 100) and (@Vlan <= 199)and ((@Vlan mod 4) = 0)">
<xsl:value-of select="$color_wireless"/>
</xsl:when>
<xsl:when test="(@Vlan >= 200) and (@Vlan <= 387) and ((@Vlan mod 20) = 0)">
<xsl:value-of select="$color_dot1xauth"/>
</xsl:when>
<xsl:when test="(@Vlan >= 200) and (@Vlan <= 387) and ((@Vlan mod 20) = 5)">
<xsl:value-of select="$color_dot1xguest"/>
</xsl:when>
<xsl:when test="(@Vlan >= 200) and (@Vlan <= 387) and ((@Vlan mod 20) = 4)">
<xsl:value-of select="$color_printer"/>
</xsl:when>
<xsl:when test="(@Vlan >= 200) and (@Vlan <= 387) and ((@Vlan mod 20) = 7)">
<xsl:value-of select="$color_reimage"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$color_unknown"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="tiptext">
<xsl:value-of select="concat('Port: ',@IfName)"/>
<xsl:text><BR/></xsl:text>
<xsl:choose>
<xsl:when test="@Dot1x = 1">
<xsl:value-of select="'Dot1x: Force-Unauthorised'"/>
</xsl:when>
<xsl:when test="@Dot1x = 2">
<xsl:value-of select="'Dot1x: Auto'"/>
</xsl:when>
<xsl:when test="@Dot1x = 3">
<xsl:value-of select="'Dot1x: Force-Authorised'"/>
</xsl:when>
<xsl:when test="@Dot1x = ''">
<xsl:value-of select="'Dot1x: None'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'Dot1x: Unknown'"/>
</xsl:otherwise>
</xsl:choose>
<xsl:text><BR/></xsl:text>
<xsl:choose>
<xsl:when test="@Trunking = 1">
<xsl:value-of select="'Trunking: On'"/>
</xsl:when>
<xsl:when test="@Trunking = 2">
<xsl:value-of select="'Trunking: Off'"/>
</xsl:when>
<xsl:when test="@Trunking = 3">
<xsl:value-of select="'Trunking: Desirable'"/>
</xsl:when>
<xsl:when test="@Trunking = 4">
<xsl:value-of select="'Trunking: Auto'"/>
</xsl:when>
<xsl:when test="@Trunking = 5">
<xsl:value-of select="'Trunking: OnNoNegotiate'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'Trunking: Unknown'"/>
</xsl:otherwise>
</xsl:choose>
<xsl:text><BR/></xsl:text>
<xsl:value-of select="concat('Vlan: ',@Vlan)"/>
<xsl:text><BR/></xsl:text>
<xsl:value-of select="concat('Desc: ',@Description)"/>
<xsl:text><BR/></xsl:text>
</xsl:template>
</xsl:stylesheet>
spview.wsf
<package>
<job id="spview">
<runtime>
<named
name="stylesheet"
helpstring="File path of the xml stylesheet to be referenced in the xml file."
many="false"
required="True"
type=string
/>
<named
name="agent"
helpstring="Host name or ip address of the switch to query"
many="false"
required="True"
type=string
/>
<named
name="outfile"
helpstring="Path to the file where the configuration data will be output"
many="false"
required="True"
type=string
/>
</runtime>
<script language=vbscript>
option explicit
dim counter
dim REQ_ARGNAMES
'Constants to validate our Arguments against expectations
Const REQ_ARGCOUNT=3
Const cSSARG="stylesheet"
Const cAGENT="agent"
Const cOFILE="outfile"
'*****************************************************************************
'Argument Validation Code - "Time spent on reconaissance is seldom wasted!" *
'*****************************************************************************
'Validate all our arguments before proceeding - add more validation code as required
'Initialise the array of Argument names for the named arguments
REQ_ARGNAMES=array(cSSARG,cAGENT)
'Do we have the correct number of named arguments
If wscript.Arguments.named.count < REQ_ARGCOUNT Then
wscript.echo "Incorrect number of named arguments were specified!"
wscript.Arguments.ShowUsage
wscript.sleep 1000
wscript.Quit
End If
'Was the script passed a named argument value for all arguments we expected
for counter = lbound(REQ_ARGNAMES) to ubound(REQ_ARGNAMES)
If wscript.arguments.named(REQ_ARGNAMES(counter)) = "" then
wscript.echo "Expected a named argument for " & REQ_ARGNAMES(counter)
wscript.Arguments.ShowUsage
wscript.sleep 1000
wscript.Quit
End If
next ' counter
'Validation to do list
'The existence of the stylesheet is not validated
'The ability to create the output file is not checked.
'Return codes from snmp query to switch are not checked
'*****************************************************************************
'End Argument Validation - insert more validation tests above this line. *
'*****************************************************************************
const PORTIFINDEX = " .1.3.6.1.4.1.9.5.1.4.1.1.11 "
const IFNAME = " .1.3.6.1.2.1.31.1.1.1.1 "
const VMVLAN = " .1.3.6.1.4.1.9.9.68.1.2.2.1.2. "
const IFALIAS = " .1.3.6.1.2.1.31.1.1.1.18 "
const VLANPORTVLAN = " .1.3.6.1.4.1.9.5.1.9.3.1.3 "
const VLANPORTISLADMINSTATUS = " .1.3.6.1.4.1.9.5.1.9.3.1.7 "
const SYSNAME = " .1.3.6.1.2.1.1.5.0 "
const dot1xAuthAuthControlledPortControl = " .1.0.8802.1.1.1.1.2.1.1.6 "
const SNMPWALKCMD = "f:\usr\bin\snmpwalk.exe -OnqUe -v 2c -c "
const SNMPREAD = " public "
dim strRetcode, key, value, strHostName
dim intCurrentSwitch, intSwitch
dim objIfindexName ' holds a dictionary filled by the getIfName function
dim objPIfindex ' holds a dictionary filled by the getPortIfIndex function
dim objIfindexAlias ' holds a dictionary filled by the getIfAlias function
dim objIfindexDot1x ' holds a dictionary filled by the getDot1x function
dim objPIfindexTrunk ' holds a dictionary filled by the getTrunkStatus function
dim objPIfindexVlan ' holds a dictionary filled by the getVlan function
dim intSwitchCount ' number of switches in the stack
dim strAttrIfName, strAttrDot1x, strAttrVlan
dim strAttrTrunk, strAttrDesc, strtemp
dim objDom 'As DOMDocument
dim objStackElement 'As IXMLDOMElement
dim objSwitch 'As IXMLDOMElement
dim objSwitchCount 'As IXMLDOMAttribute
dim objStackName 'As IXMLDOMAttribute
dim objSwitchNum 'As IXMLDOMAttribute
dim objText 'As IXMLDOMText
dim objPort 'As IXMLDOMElement
dim objPortAttrib 'As IXMLDOMAttribute
dim objPI 'As IXMLDOMProcessingInstruction
'****************************************************************************
'* Retrieve the switch port configuration data *
'****************************************************************************
strHostName = ""
strRetcode = getHostName(wscript.arguments.named(cAGENT),strHostName)
strRetcode = getPortIfIndex(wscript.arguments.named(cAGENT),objPIfindex)
' Get the number of switches in the stack.
intSwitchCount = 0
for each key in objPIfindex.keys
if (cint(left(key,instr(key,".")-1)) > intSwitchCount) then
intSwitchCount = cint(left(key,instr(key,".")-1))
end if
next
strRetcode = getIfName(wscript.arguments.named(cAGENT),objIfindexName)
strRetcode = getIfAlias(wscript.arguments.named(cAGENT),objIfindexAlias)
strRetcode = getDot1x(wscript.arguments.named(cAGENT),objIfindexDot1x)
strRetcode = getTrunkStatus(wscript.arguments.named(cAGENT),objPIfindexTrunk)
strRetcode = getVlan(wscript.arguments.named(cAGENT),objPIfindexVlan)
'****************************************************************************
'* Write the data to xml nodes and save to file *
'****************************************************************************
'Create the DOM document and processing instructions for version & stylesheet
Set objDom = CreateObject("Msxml2.DomDocument.4.0")
objDom.preserveWhiteSpace = 1
Set objPI = objDom.createProcessingInstruction("xml-stylesheet", "type='text/xsl' href='" & wscript.arguments.named(cSSARG) &"'")
objDom.insertBefore objPI, objDom.childNodes.Item(0)
Set objPI = objDom.createProcessingInstruction("xml", "version='1.0'")
objDom.insertBefore objPI, objDom.childNodes.Item(0)
'Creates root element, stack to represent a switch stack
Set objStackElement = objDom.createElement("stack")
objDom.appendChild objStackElement
objStackElement.Text = vbcrlf
'Creates Attribute to the stack Element = hostname of stack
Set objStackName = objDom.createAttribute("hostname")
objStackName.nodeValue = strHostName
objStackElement.setAttributeNode objStackName
'Creates Attribute to the stack Element = number of switches in stack
Set objSwitchCount = objDom.createAttribute("SwitchCount")
objSwitchCount.nodeValue = intSwitchCount
objStackElement.setAttributeNode objSwitchCount
'Loop through all the ports in the switch stack and save their config
intCurrentSwitch = 0
for each key in objPIfindex.keys()
intSwitch = cint(left(key,instr(key,".")-1))
if (intSwitch <> intCurrentSwitch) then 'next switch in the stack
intCurrentSwitch = intSwitch
' Creates Switch element as a child of stack
Set objSwitch = objDom.createElement("switch")
objStackElement.appendChild objSwitch
objSwitch.Text = vbcrlf
' Creates Attribute to the switch Element
Set objSwitchNum = objDom.createAttribute("Number")
objSwitchNum.nodeValue = intSwitch
objSwitch.setAttributeNode objSwitchNum
Set objSwitchNum = Nothing
'Make the xml prettier else it is saved on a single line
set objText = objDom.CreateTextNode(vbcrlf)
objStackElement.appendChild objText
set objText = Nothing
end if
'Create a port element and set the attributes
Set objPort = objDom.createElement("port")
objSwitch.appendChild objPort
' Creates PortIfIndex Attribute to the port Element
Set objPortAttrib = objDom.createAttribute("PortIfIndex")
objPortAttrib.nodeValue = key
objPort.setAttributeNode objPortAttrib
if objIfindexName.exists(objPIfindex.item(key)) then
strAttrIfName = objIfindexName.item(objPIfindex.item(key))
else
strAttrIfName = ""
end if
' Creates IfName Attribute to the port Element
Set objPortAttrib = objDom.createAttribute("IfName")
objPortAttrib.nodeValue = strAttrIfName
objPort.setAttributeNode objPortAttrib
if objIfindexDot1x.exists(objPIfindex.item(key)) then
strAttrDot1x = objIfindexDot1x.item(objPIfindex.item(key))
else
strAttrDot1x = ""
end if
' Creates Dot1x Attribute to the port Element
Set objPortAttrib = objDom.createAttribute("Dot1x")
objPortAttrib.nodeValue = strAttrDot1x
objPort.setAttributeNode objPortAttrib
if objPIfindexVlan.exists(key) then
strAttrVlan = objPIfindexVlan.item(key)
else
strAttrVlan = ""
end if
' Creates Vlan Attribute to the port Element
Set objPortAttrib = objDom.createAttribute("Vlan")
objPortAttrib.nodeValue = strAttrVlan
objPort.setAttributeNode objPortAttrib
if objPIfindexTrunk.exists(key) then
strAttrTrunk = objPIfindexTrunk.item(key)
else
strAttrTrunk = ""
end if
' Creates Trunking Attribute to the port Element
Set objPortAttrib = objDom.createAttribute("Trunking")
objPortAttrib.nodeValue = strAttrTrunk
objPort.setAttributeNode objPortAttrib
if objIfindexAlias.exists(objPIfindex.item(key)) then
strAttrDesc = objIfindexAlias.item(objPIfindex.item(key))
else
strAttrDesc = ""
end if
' Creates Description Attribute to the port Element
Set objPortAttrib = objDom.createAttribute("Description")
objPortAttrib.nodeValue = strAttrDesc
objPort.setAttributeNode objPortAttrib
'Make the xml prettier else it is saved on a single line
set objText = objDom.CreateTextNode(vbcrlf)
objSwitch.appendChild objText
set objText = Nothing
' Saves XML data to disk.
objDom.save (wscript.arguments.named(cOFILE))
next
wscript.quit
'************************************************************************
'FUNCTION: *
' getPortIfIndex(strAgent,objPortIfIndex) *
' *
'Purpose: *
' walk the CISCO-STACK-MIB::portIfIndex OID and populate the *
' dictionary object passed *
' *
'Inputs: *
' strAgent: management IP address of the switch *
' objPortIfIndex: dictionary to hold the port interface indices *
' *
'Returns: *
' Integer, 0 if successful or a positive value on failure. *
' *
'Calls: *
' SNMPWALKCMD - constant defining the path to an external *
' program and options used to perform an snmp set *
' *
'Comments: *
' CISCO-STACK-MIB is cisco specific. *
'************************************************************************
function getPortIfIndex(strAgent,objPortIfIndex)
dim WshShell, oExec
dim re 'as regexp
dim matches
dim match
dim tempstr, stroutput, strErr
set objPortIfIndex = CreateObject("Scripting.Dictionary")
Set WshShell = CreateObject("wscript.Shell")
Set oExec = WshShell.Exec(SNMPWALKCMD & SNMPREAD & strAgent & " " & _
PORTIFINDEX)
Do while Not oExec.StdOut.AtEndOfStream
stroutput = oExec.StdOut.readall
Loop
Do while Not oExec.StdErr.AtEndOfStream
strErr = oExec.StdErr.readall
Loop
Do While oExec.Status <> 1
wscript.Sleep 100
Loop
if (len(strErr) = 0) then
set re = new regexp
re.global = True
re.multiline = True
'Pattern to capture the last digits of the snmp output
'output lines from SNMPCMD should look like
' ".1.3.6.1.4.1.9.5.1.4.1.1.11.4.49 11545"
re.pattern = "^" & replace(trim(PORTIFINDEX),".","\.") & _
"\.(\d+\.\d+)\s+(\d+)$"
set matches = re.execute(stroutput)
for each match in matches
objPortIfIndex.add match.submatches(0), match.submatches(1)
next
end if
getPortIfIndex = len(strErr)
end function
'************************************************************************
'FUNCTION: *
' getIfName(strAgent,objIfIndexName) *
' *
'Purpose: *
' walk the IF-MIB::ifName OID and populate the dictionary object *
' passed *
' *
'Inputs: *
' strAgent: management IP address of the switch *
' objIfIndexName: dictionary to hold the port interface index to *
' name mappings *
' *
'Returns: *
' Integer, 0 if successful or a positive value on failure. *
' *
'Calls: *
' SNMPWALKCMD - constant defining the path to an external *
' program and options used to perform an snmp set *
' *
'Comments: *
' CISCO-STACK-MIB is cisco specific. *
'************************************************************************
function getIfName(strAgent,objIfIndexName)
dim WshShell, oExec
dim re 'as regexp
dim matches
dim match
dim tempstr, stroutput, strErr
set objIfIndexName = CreateObject("Scripting.Dictionary")
Set WshShell = CreateObject("wscript.Shell")
Set oExec = WshShell.Exec(SNMPWALKCMD & SNMPREAD & strAgent & " " & _
IFNAME)
Do while Not oExec.StdOut.AtEndOfStream
stroutput = oExec.StdOut.readall
Loop
Do while Not oExec.StdErr.AtEndOfStream
strErr = oExec.StdErr.readall
Loop
Do While oExec.Status <> 1
wscript.Sleep 100
Loop
if (len(strErr) = 0) then
set re = new regexp
re.global = True
re.multiline = True
'Pattern to capture the last digits of the snmp output
'output lines from SNMPCMD should look like
' ".1.3.6.1.2.1.31.1.1.1.1.10001 Fa1/0/1"
re.pattern = "^" & replace(trim(IFNAME),".","\.") & _
"\.(\d+)\s+([^\r\n]+)$"
set matches = re.execute(stroutput)
for each match in matches
objIfIndexName.add match.submatches(0), match.submatches(1)
next
end if
getIfName = len(strErr)
end function
'************************************************************************
'FUNCTION: *
' getIfAlias(strAgent,objIfIndexDesc) *
' *
'Purpose: *
' walk the IF-MIB::ifAlias OID and populate the dictionary object *
' passed *
' *
'Inputs: *
' strAgent: management IP address of the switch *
' objIfIndexDesc: dictionary to hold the port interface index to *
' description mappings *
' *
'Returns: *
' Integer, 0 if successful or a positive value on failure. *
' *
'Calls: *
' SNMPWALKCMD - constant defining the path to an external *
' program and options used to perform an snmp set *
' *
'Comments: *
' CISCO-STACK-MIB is cisco specific. *
'************************************************************************
function getIfAlias(strAgent,objIfIndexDesc)
dim WshShell, oExec
dim re 'as regexp
dim matches
dim match
dim tempstr, stroutput, strErr
set objIfIndexDesc = CreateObject("Scripting.Dictionary")
Set WshShell = CreateObject("wscript.Shell")
Set oExec = WshShell.Exec(SNMPWALKCMD & SNMPREAD & strAgent & " " & _
IFALIAS)
Do while Not oExec.StdOut.AtEndOfStream
stroutput = oExec.StdOut.readall
Loop
Do while Not oExec.StdErr.AtEndOfStream
strErr = oExec.StdErr.readall
Loop
Do While oExec.Status <> 1
wscript.Sleep 100
Loop
if (len(strErr) = 0) then
set re = new regexp
re.global = True
re.multiline = True
'Pattern to capture the snmp output
'output lines from SNMPCMD should look like
' ".1.3.6.1.2.1.31.1.1.1.18.11543 Printer port"
re.pattern = "^" & replace(trim(IFALIAS),".","\.") & _
"\.(\d+)\s{1}([^\r\n]*)$"
set matches = re.execute(stroutput)
for each match in matches
objIfIndexDesc.add match.submatches(0), match.submatches(1)
next
end if
getIfAlias = len(strErr)
end function
'************************************************************************
'FUNCTION: *
' getDot1x(strAgent,objIfIndexDot1x) *
' *
'Purpose: *
' walk the IEEE8021-PAE-MIB::dot1xAuthAuthControlledPortControl *
' OID and populate the dictionary object passed *
' *
'Inputs: *
' strAgent: management IP address of the switch *
' objIfIndexDot1x: dictionary to hold the port interface index to *
' 802.1x mappings *
' *
'Returns: *
' Integer, 0 if successful or a positive value on failure. *
' *
'Calls: *
' SNMPWALKCMD - constant defining the path to an external *
' program and options used to perform an snmp set *
' *
'Comments: *
' None. *
'************************************************************************
function getDot1x(strAgent,objIfIndexDot1x)
dim WshShell, oExec
dim re 'as regexp
dim matches
dim match
dim tempstr, stroutput, strErr
set objIfIndexDot1x = CreateObject("Scripting.Dictionary")
Set WshShell = CreateObject("wscript.Shell")
Set oExec = WshShell.Exec(SNMPWALKCMD & SNMPREAD & strAgent & " " & _
dot1xAuthAuthControlledPortControl)
Do while Not oExec.StdOut.AtEndOfStream
stroutput = oExec.StdOut.readall
Loop
Do while Not oExec.StdErr.AtEndOfStream
strErr = oExec.StdErr.readall
Loop
Do While oExec.Status <> 1
wscript.Sleep 100
Loop
if (len(strErr) = 0) then
set re = new regexp
re.global = True
re.multiline = True
'Pattern to capture the last digits of the snmp output
'output lines from SNMPCMD should look like
' ".1.0.8802.1.1.1.1.2.1.1.6.11515 2"
re.pattern = "^" & replace(trim(dot1xAuthAuthControlledPortControl),".","\.") & _
"\.(\d+)\s+(\d)$"
set matches = re.execute(stroutput)
for each match in matches
objIfIndexDot1x.add match.submatches(0), match.submatches(1)
next
end if
getDot1x = len(strErr)
end function
'************************************************************************
'FUNCTION: *
' getTrunkStatus(strAgent,objPortIfIndexTrunk) *
' *
'Purpose: *
' walk the CISCO-STACK-MIB::vlanPortIslAdminStatus OID and *
' populate the dictionary object passed *
' *
'Inputs: *
' strAgent: management IP address of the switch *
' objPortIfIndexTrunk: dictionary to hold the port interface index*
' to trunk status *
' *
'Returns: *
' Integer, 0 if successful or a positive value on failure. *
' *
'Calls: *
' SNMPWALKCMD - constant defining the path to an external *
' program and options used to perform an snmp set *
' *
'Comments: *
' CISCO-STACK-MIB is cisco specific. *
'************************************************************************
function getTrunkStatus(strAgent,objPortIfIndexTrunk)
dim WshShell, oExec
dim re 'as regexp
dim matches
dim match
dim tempstr, stroutput, strErr
set objPortIfIndexTrunk = CreateObject("Scripting.Dictionary")
Set WshShell = CreateObject("wscript.Shell")
Set oExec = WshShell.Exec(SNMPWALKCMD & SNMPREAD & strAgent & " " & _
VLANPORTISLADMINSTATUS)
Do while Not oExec.StdOut.AtEndOfStream
stroutput = oExec.StdOut.readall
Loop
Do while Not oExec.StdErr.AtEndOfStream
strErr = oExec.StdErr.readall
Loop
Do While oExec.Status <> 1
wscript.Sleep 100
Loop
if (len(strErr) = 0) then
set re = new regexp
re.global = True
re.multiline = True
'Pattern to capture the last digits of the snmp output
'output lines from SNMPCMD should look like
' ".1.3.6.1.4.1.9.5.1.9.3.1.7.4.44 2"
re.pattern = "^" & replace(trim(VLANPORTISLADMINSTATUS),".","\.") & _
"\.(\d+\.\d+)\s+(\d+)$"
set matches = re.execute(stroutput)
for each match in matches
objPortIfIndexTrunk.add match.submatches(0), match.submatches(1)
next
end if
getTrunkStatus = len(strErr)
end function
'************************************************************************
'FUNCTION: *
' getVlan(strAgent,objPortIfIndexVlan) *
' *
'Purpose: *
' walk the CISCO-STACK-MIB::vlanPortIslAdminStatus OID and *
' populate the dictionary object passed *
' *
'Inputs: *
' strAgent: management IP address of the switch *
' objPortIfIndexVlan: dictionary to hold the port interface index *
' to vlan mapping *
' *
'Returns: *
' Integer, 0 if successful or a positive value on failure. *
' *
'Calls: *
' SNMPWALKCMD - constant defining the path to an external *
' program and options used to perform an snmp set *
' *
'Comments: *
' CISCO-STACK-MIB is cisco specific. *
'************************************************************************
function getVlan(strAgent,objPortIfIndexVlan)
dim WshShell, oExec
dim re 'as regexp
dim matches
dim match
dim tempstr, stroutput, strErr
set objPortIfIndexVlan = CreateObject("Scripting.Dictionary")
Set WshShell = CreateObject("wscript.Shell")
Set oExec = WshShell.Exec(SNMPWALKCMD & SNMPREAD & strAgent & " " & _
VLANPORTVLAN)
Do while Not oExec.StdOut.AtEndOfStream
stroutput = oExec.StdOut.readall
Loop
Do while Not oExec.StdErr.AtEndOfStream
strErr = oExec.StdErr.readall
Loop
Do While oExec.Status <> 1
wscript.Sleep 100
Loop
if (len(strErr) = 0) then
set re = new regexp
re.global = True
re.multiline = True
'Pattern to capture the last digits of the snmp output
'output lines from SNMPCMD should look like
' ".1.3.6.1.4.1.9.5.1.9.3.1.3.4.46 810"
re.pattern = "^" & replace(trim(VLANPORTVLAN),".","\.") & _
"\.(\d+\.\d+)\s+(\d+)$"
set matches = re.execute(stroutput)
for each match in matches
objPortIfIndexVlan.add match.submatches(0), match.submatches(1)
next
end if
getVlan = len(strErr)
end function
'************************************************************************
'FUNCTION: *
' getHostName(strAgent,strHostName) *
' *
'Purpose: *
' walk the SNMPv2-MIB::sysName.0 OID and *
' copy the hostname into strHostName *
' *
'Inputs: *
' strAgent: management IP address of the switch *
' strHostName: string variable reference to hold the hostname *
' *
'Returns: *
' Integer, 0 if successful or a positive value on failure. *
' *
'Calls: *
' SNMPWALKCMD - constant defining the path to an external *
' program and options used to perform an snmp set *
' *
'Comments: *
' None. *
'************************************************************************
function getHostName(strAgent,strHostName)
dim WshShell, oExec
dim re 'as regexp
dim matches
dim match
dim tempstr, stroutput, strErr
Set WshShell = CreateObject("wscript.Shell")
Set oExec = WshShell.Exec(SNMPWALKCMD & SNMPREAD & strAgent & " " & _
SYSNAME)
Do while Not oExec.StdOut.AtEndOfStream
stroutput = oExec.StdOut.readall
Loop
Do while Not oExec.StdErr.AtEndOfStream
strErr = oExec.StdErr.readall
Loop
Do While oExec.Status <> 1
wscript.Sleep 100
Loop
if (len(strErr) = 0) then
set re = new regexp
re.global = True
re.multiline = True
'Pattern to capture the snmp output
'output lines from SNMPCMD should look like
' ".1.3.6.1.2.1.1.5.0 Sydney-Switch"
re.pattern = "^" & replace(trim(SYSNAME),".","\.") & _
"\s{1}([^\r\n]*)$"
set matches = re.execute(stroutput)
for each match in matches
strHostname = match.submatches(0)
next
end if
getHostName = len(strErr)
end function
</script>
</job>
</package>