The Moose and Squirrel Files

September 20, 2008

Re-Imaging Computers in 802.1x Networks – Part 2

Filed under: Code, Network — Tags: , , , , — networknerd @ 9:40 am

Obtaining a list of vlans

It’s not obvious why we’d need to obtain a list of vlans on a switch. This will become evident in the next post, but for now I will say that  Cisco uses a thing called community string indexing where a per vlan instance of an SNMP MIB is maintained on a device.  The index to the MIB is the vlan number and we’ll need to use community string indexing later on to gather more information.

There are two possible snmp object identifiers (OID’s) to query to get a list of vlans and your mileage will vary here depending on switch configuration. The vlanPortIslVlansAllowed entry from the CISCO-STACK-MIB is convenient as it returns only the vlans allowed on a specified trunk, and reduces the number of snmp operations required to find a port. The vtpVlanState entry from the CISCO-VTP-MIB returns all the vlans propagated through VTP. Vlans that are not configured on any port of the switch we are examining are included, and the number of redundant snmp operations will increase.

VlanPortIslVlansAllowed is defined as

An indication of which Virtual LANs are allowed on this Inter-Switch Link. This is an octet
string value with bits set to indicate allowed VLANs. It can be interpreted as a sum of f(x) as x
goes from 0 to 1023, where f(x) = 0 for VLAN x not allowed and f(x) = exp(2, x) for VLAN x
allowed.

For VlanPortIslVlansAllowed the return value from the query could be up to 1024 bits or 128 hexadecimal digits. The output for a switch on the example network is shown below.

G:\usr\bin>snmpget.exe -Ov -v 2c -c public 192.168.36.11 vlanPortIslVlansAllowed.1.1
Hex-STRING: 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 07 01 C0 70 00 00 00 00 00 00
00 00 00 00 00 00

Fortunately large number arithmetic is not required to reveal the allowed vlans. Each pair of
hexadecimal digits is converted to a binary string and concatenated to form the binary
representation of the number. Each bit that is set corresponds to a vlan. The string is reversed
using the strreverse() function and then searched for the character ‘1’ using the instr() function.
The index value returned from instr is the vlan number + 1. The vlan is obtained by subtracting 1
from the returned index and the search repeated until no more matches are found in the string.
More detail is available by referring to the enum_AllowedVLAN()  and supporting functions in listing 1.

Walking vtpVlanState returns output similar to that shown below. The last group of digits in the
OID is the vlan number and the number that follows is the operational state of the vlan. The vlan
number is easily extracted using a regular expression as shown in the enum_VLAN() function in
listing 2.

G:\usr\bin>snmpwalk.exe -OnqUe -v 2c -c public 192.168.36.11 vtpVlanState
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.1 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.100 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.101 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.102 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.110 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.111 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.112 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.120 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.121 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.122 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.300 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.301 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.302 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.1002 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.1003 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.1004 1
.1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.1005 1

Listing 1

const vlanPortIslVlansAllowed = " .1.3.6.1.4.1.9.5.1.9.3.1.5.1.1 "
const SNMPGETCMD2 = "f:\usr\bin\snmpget.exe -Ov -v 2c -c "
'************************************************************************
'FUNCTION:                                                              *
' enum_AllowedVLAN(strAgent)                                            *
'Purpose:                                                               *
' enumerate the vlans configured on the switch.                         *
'                                                                       *
'Inputs:                                                                *
' strAgent: management IP address of the switch                         *
'                                                                       *
'Returns:                                                               *
' Array with each element containing a vlan number                      *
'                                                                       *
'Calls:                                                                 *
' SNMPGETCMD2 - constant defining the path to an external               *
' program and options used to perform an snmp get operation.            *
' fmtBinary - function to left pad a binary number with zeros           *
' ToBinary - function to convert an integer to a binary string          *
'                                                                       *
'Comments:                                                              *
' CISCO-STACK-MIB is cisco specific.                                    *
' Reference Cisco SNMP Object Navigator viewed at                       *
' http://tools.cisco.com/Support/SNMP/do/BrowseOID.do?                  *
' objectInput=vlanPortIslVlansAllowed&translate=Translate&              *
' submitValue=SUBMIT&submitClicked=true                                 *
' on 16/11/2006                                                         *
'************************************************************************
function enum_AllowedVLAN(strAgent)
dim WshShell, oExec
dim re 'as regexp
dim matches
dim match, submatch
dim tempstr, stroutput, index, vlans
Set WshShell = CreateObject("WScript.Shell")
Set oExec = WshShell.Exec(SNMPGETCMD2 & SNMPREAD & " " & _
strAgent & " " & vlanPortIslVlansAllowed)
Do while Not oExec.StdOut.AtEndOfStream
  stroutput = oExec.StdOut.readall
Loop
Do While oExec.Status <> 1
  WScript.Sleep 100
Loop
tempstr = ""
set re = new regexp
re.global = True
re.multiline = True
'Pattern to capture the hex digits representing the allowed vlans.
re.pattern = "[0-9a-fA-F]{2}"
vlans = ""
if instr(1,stroutput, "Hex-STRING:") > 0 then
  set matches = re.execute(stroutput)
  for each match in matches
    tempstr = tempstr & fmtBinary(ToBinary(cint("&H" & match)), 8)
  next
  tempstr = strreverse(tempstr)
  index = 1
  do
    index = instr(index, tempstr, "1")
    if index <> 0 then
      vlans = vlans & " " & index - 1
      index = index + 1
    end if
  loop until index = 0
end if
enum_AllowedVLAN = split(trim(vlans))
end function
'************************************************************************
'FUNCTION:                                                              *
' fmtBinary(strNumber, intLength)                                       *
'PURPOSE:                                                               *
' function to left pad a binary number with zeros                       *
'                                                                       *
'INPUTS:                                                                *
' strNumber: binary number to left pad with zeros                       *
' intLength: The desired bit length of the binary number                *
'                                                                       *
'RETURNS:                                                               *
' string containing the binary representation of the input.             *
'                                                                       *
'CALLS:                                                                 *
' Nothing                                                               *
'                                                                       *
'COMMENTS:                                                              *
'************************************************************************
function fmtBinary(strNumber, intLength)
  fmtBinary = string(intLength - len(strNumber), "0") & strNumber
end function
'************************************************************************
'FUNCTION:                                                              *
' ToBinary(intNumber)                                                   *
'                                                                       *
'PURPOSE:                                                               *
' convert an integer number to binary.                                  *
'                                                                       *
'Inputs:                                                                *
' intNumber: Number to convert to binary                                *
'                                                                       *
'Returns:                                                               *
' string containing the binary representation of the input.             *
'                                                                       *
'Calls:                                                                 *
' Nothing                                                               *
'                                                                       *
'Comments:                                                              *
' note the use of \ (integer division operator) rather than /           *
'************************************************************************
function ToBinary(intNumber)
if intNumber > 0 then
  ToBinary = ToBinary(intNumber\2) & intNumber mod 2
end if
end function

Listing2

const SNMPWALKCMD = "f:\usr\bin\snmpwalk.exe -OnqUe -v 2c -c "
const SNMPREAD = " public "
const VTPVLANSTATE = " .1.3.6.1.4.1.9.9.46.1.3.1.1.2 "
'************************************************************************
'FUNCTION:                                                              *
' enum_VLAN(strAgent)                                                   *
'Purpose:                                                               *
' enumerate the vlans configured on the switch.                         *
'                                                                       *
'Inputs:                                                                *
' strAgent: management IP address of the switch                         *
'                                                                       *
'Returns:                                                               *
' Array with each element containing a vlan number                      *
'                                                                       *
'Calls:                                                                 *
' SNMPWALKCMD - constant defining the path to an external               *
' program used to perform an snmp walk                                  *
'                                                                       *
'Comments:                                                              *
' CISCO-VTP-MIB is cisco specific.                                      *
' Reference cisco Document ID: 41003                                    *
' "How to Get VLAN Information From a Catalyst Using SNMP" viewed       *
' at http://www.cisco.com/en/US/tech/tk648/tk362/technologies_          *
' configuration_example09186a008015773e.shtml                           *
' on 16/11/2006                                                         *
'************************************************************************
function enum_VLAN(strAgent)
dim WshShell, oExec
dim re 'as regexp
dim matches
dim match
dim tempstr, stroutput
set re = new regexp
re.global = True
re.multiline = True
'output lines from SNMPCMD should look like
' ".1.3.6.1.4.1.9.9.46.1.3.1.1.2.1.125 1"
'Pattern to capture the last digits of the snmp OID
'Include VTPVLANSTATE in the pattern to minimise regex engine backtracking
re.pattern = "^" & VTPVLANSTATE & "(?:\.\d+)+\.(\d+)\s+\d+$"
Set WshShell = CreateObject("WScript.Shell")
Set oExec = WshShell.Exec(SNMPWALKCMD & SNMPREAD & " " & strAgent & " " & VTPVLANSTATE)
Do while Not oExec.StdOut.AtEndOfStream
  stroutput = oExec.StdOut.readall
Loop
Do While oExec.Status <> 1
  WScript.Sleep 100
Loop
tempstr = ""
set matches = re.execute(stroutput)
for each match in matches
  tempstr = tempstr & match.submatches(0) & " "
next
enum_VLAN = split(trim(tempstr))
end function
Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: