The Moose and Squirrel Files

December 23, 2010

Quick and dirty UDP servers with wireshark

Filed under: Network, Wireshark — Tags: , , — networknerd @ 3:16 pm

I’m not suggesting wireshark is the right choice for production but if you need a udp server for a quick debugging session then this trick might just be worth tucking away for later.

If you need to perform a short data collection from  applications like syslog  or netflow that just pump out  udp packets then wireshark/tshark can work for you in a pinch.

Here’s the recipe for syslog.

tshark -i 2 -f "port 514" -T fields -e syslog

Using the -T fields switch allows us to specify which data to output with one or more  -e switches.  Since we have specified a protocol (syslog),  tshark prints multiple fields, in this case its the facility(LOCAL7),severity(NOTICE), and the remainder of the output below is the actual message.

Syslog message: LOCAL7.NOTICE: 27403: Dec 23 14:44:29: %SYS-5-CONFIG_I: Configured from console by root on vty0 (10.0.2.19)

The people that wrote the dissectors in wireshark have done all the hard work of interpreting the binary fields for us.  It’s worth noting that there is no documentation (that I am aware of)  for the field names. I usually just capture a couple of packets and export them in PDML format.  You can then open that file in any text editor and determine the field names from the XML.

June 11, 2010

Cisco IPSEC MTU Bug

Filed under: Network — Tags: , , , — networknerd @ 9:52 am

Cisco made the process of site to site ipsec encrypted communications fairly easy with the introduction of virtual tunnel interfaces (VTI) in IOS version 12.2(13)T.  The problems caused by the overhead of ipsec/ESP encapsulation of a payload are fairly well documented in their knowledge base document “Resolve IP Fragmentation, MTU, MSS, and PMTUD Issues with GRE and IPSEC”. The “Readers Digest” version of the above article is that you need to reduce the IP mtu of the tunnel interface to a size that allows for the additional overhead of ipsec and/or GRE encapsulation.

Now as luck would have it I stumbled across a bug with tunnel interfaces miscalculating the IP mtu after the router is rebooted.   For  readers who just want the short story, the workaround is to always specify tunnel source by interface name, not ip address. Cisco TAC report that the bug exists across a large number of IOS versions and platforms. A bug ID has been requested from Cisco so that we can follow it. I’ll post it here once they allocate it.  The bug ID is CSCth31172. For those that would like proof of the bug read on.

To test this I configured two 2811 routers in the lab.  The configs can be viewed here for R1 and R2.  The relevant interface configurations for each are below.
R1 config

interface Tunnel2
  ip address 10.0.0.1 255.255.255.252
  ip mtu 1400  ip tcp adjust-mss 1360
  tunnel source Serial0/0/0.100 
  tunnel destination 192.168.0.2
  tunnel mode ipsec ipv4
  tunnel path-mtu-discovery
  tunnel protection ipsec profile MY_VTI
!
interface Serial0/0/0
  no ip address
  encapsulation frame-relay IETF
  clock rate 2000000
!
interface Serial0/0/0.100 point-to-point
  ip address 192.168.0.1 255.255.255.252
  frame-relay interface-dlci 100

R2 Config

interface Tunnel1
  ip address 10.0.0.2 255.255.255.252
  ip mtu 1400
  ip tcp adjust-mss 1360
  tunnel source 192.168.0.2
  tunnel destination 192.168.0.1
  tunnel mode ipsec ipv4
  tunnel protection ipsec profile MY_VTI
!
interface Serial0/0/0
  no ip address
  encapsulation frame-relay IETF
  frame-relay intf-type dce
!
interface Serial0/0/0.100 point-to-point
  ip address 192.168.0.2 255.255.255.252
  frame-relay interface-dlci 100

The serial interface on router R1 that carries the tunnel traffic should have an mtu of 1500 bytes. We verify this by doing a ping with the df bit set.

R1#ping 192.168.0.2 df size 1500
Type escape sequence to abort.
Sending 5, 1500-byte ICMP Echos to 192.168.0.2, timeout is 2 seconds:
Packet sent with the DF bit set
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 12/12/16 ms

The IP  mtu of the tunnel2 interface is configured to 1400 bytes, an allowance of 100 bytes for ESP header/trailer and GRE headers.  That’s plenty, and we should be able to send 1400 bytes through with the DF bit set.

R1#ping 10.0.0.2 df size 1400

Type escape sequence to abort.
Sending 5, 1400-byte ICMP Echos to 10.0.0.2, timeout is 2 seconds:
Packet sent with the DF bit set
.....
Success rate is 0 percent (0/5)

Something is not quite right. We can check the IP mtu of the crypto SA by issuing the command.

R1#show crypto ipsec sa | include mtu|interface
 interface: Tunnel2
      path mtu 1500, ip mtu 1500, ip mtu idb Serial0/0/0.100
 interface: Tunnel21
      path mtu 1500, ip mtu 1500, ip mtu idb FastEthernet0/0

Nothing obvious there, time to move on to router R2 and repeat the tests.  First confirm the mtu of the underlying interface.

R2#ping 192.168.0.1 df size 1500
 Type escape sequence to abort.
 Sending 5, 1500-byte ICMP Echos to 192.168.0.1, timeout is 2 seconds: Packet sent with the DF bit set
 !!!!!
 Success rate is 100 percent (5/5), round-trip min/avg/max = 12/12/16 ms

All good, now we can test the tunnel to R1 with 1400 byte packets.

R2#ping 10.0.0.1 df size 1400
 Type escape sequence to abort. Sending 5, 1400-byte ICMP Echos to 10.0.0.1, timeout is 2 seconds: Packet sent with the DF bit set
 M.M.M
*Jun  7 01:08:10.855: CRYPTO_ENGINE: locally-sourced pkt w/DF bit set is too big,ip->tl=1400, mtu=1343
*Jun  7 01:08:10.855: CRYPTO_ENGINE: locally-sourced pkt w/DF bit set is too big,ip->tl=1400, mtu=1343
*Jun  7 01:08:12.855: CRYPTO_ENGINE: locally-sourced pkt w/DF bit set is too big,ip->tl=1400, mtu=1343
*Jun  7 01:08:12.855: CRYPTO_ENGINE: locally-sourced pkt w/DF bit set is too big,ip->tl=1400, mtu=1343
*Jun  7 01:08:14.855: CRYPTO_ENGINE: locally-sourced pkt w/DF bit set is too big,ip->tl=1400, mtu=1343

Okay, so now we’re on to something.  The crypto engine tells us the mtu is 1343 or 57 bytes short of our expectation. Coincidentally that is suspiciously close to the 52 bytes overhead for ESP that Cisco has documented in “QoS DESIGN FOR IPsec VPNs“.

R2#show crypto ipsec sa | include interface|mtu
interface: Tunnel1
      path mtu 1400, ip mtu 1400, ip mtu idb Tunnel1
interface: Tunnel12
      path mtu 1500, ip mtu 1500, ip mtu idb FastEthernet0/0

Notice the differences between tunnel 2 on R1 and Tunnel 1 on R2.  The IP mtu is 1400 bytes and the idb (I have no idea what idb means Interface Descriptor Block, thanks for the correction Ivan) is the actual tunnel interface and not the transit interface of the tunnel. We can reset the tunnel interfaces and the crypto SA’s by briefly shutting the interface.

R2#conf t
 Enter configuration commands, one per line.  End with CNTL/Z.
R2(config)#int tu1
R2(config-if)#shut
R2(config-if)#no shut
*Jun  7 01:10:48.571: %LINK-5-CHANGED: Interface Tunnel1, changed state to administratively down
*Jun  7 01:10:49.571: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel1, changed state to down
*Jun  7 01:11:07.555: %LINK-3-UPDOWN: Interface Tunnel1, changed state to up
*Jun  7 01:11:08.555: %LINEPROTO-5-UPDOWN: Line protocol on Interface Tunnel1, changed state to up
R2(config-if)#end
*Jun  7 01:11:18.515: %SYS-5-CONFIG_I: Configured from console by console
R2#show crypto ipsec sa | include interface|mtu
interface: Tunnel1
      path mtu 1500, ip mtu 1500, ip mtu idb Serial0/0/0.100
interface: Tunnel12
      path mtu 1500, ip mtu 1500, ip mtu idb FastEthernet0/0

The difference to tunnel1 after shutting down the interface is readily apparent. The IP mtu is now 1500 bytes and the idb is now the serial subinterface.  A 1400 byte ping should now be possible.

R2#ping 10.0.0.1 df size 1400
Type escape sequence to abort.
Sending 5, 1400-byte ICMP Echos to 10.0.0.1, timeout is 2 seconds:
Packet sent with the DF bit set
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 12/14/16 ms
R2#

It’s not really viable resetting  tunnel  interfaces after every reboot, but our testing has found that Cisco’s workaround of specifying tunnel source by interface name rather than IP address has been 100% effective so far.

March 19, 2010

Using VRF’s to Simulate Physical Routers

Filed under: Network — Tags: , — networknerd @ 3:36 pm

I recently had the need to test a frame-relay configuration that was soon to be commissioned, but didn’t have a spare pair of routers to connect  to. VRF to the rescue.  VRF’s are a technology that allow multiple instances of the routing table to exist within one physical device. NB: This is not a new concept (see here), just a record of my work. The only real limitation when you do this on a production router is that you need one  interface per VRF interconnection. 

I had an unused two port E1 card in a Cisco 3845 router, making the testing easy.  One VRF for each E1 interface,  an E1 crossover cable and I was good to go.  Once the E1 controller channel group is configured a new serial port is created. This was the final config I used, and fortunately the frame relay pvc’s came up straight away. Mission accomplished. 

An important point to remember with VRF’s is that many of the usual commands have VRF specific variations. To do a ping test with this configuration you need to use the ping VRF command as shown below, or else you’ll just be using what’s in the global routing table.
router#ping vrf E1-0/0/0
Protocol [ip]:
Target IP address: 192.168.1.2
Repeat count [5]:
Datagram size [100]:
Timeout in seconds [2]:
Extended commands [n]: y
Source address or interface: Serial0/0/0:0.37
Type of service [0]:
Set DF bit in IP header? [no]:
Validate reply data? [no]:
Data pattern [0xABCD]:
Loose, Strict, Record, Timestamp, Verbose[none]:
Sweep range of sizes [n]:
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 192.168.1.2, timeout is 2 seconds:
Packet sent with a source address of 192.168.1.1
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/2/4 ms
router#sh ip route vrf E1-0/0/0

Routing Table: E1-0/0/0
Codes: C - connected, S - static, R - RIP, M - mobile, B - BGP
D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area
N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
E1 - OSPF external type 1, E2 - OSPF external type 2
i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
ia - IS-IS inter area, * - candidate default, U - per-user static route
o - ODR, P - periodic downloaded static route

Gateway of last resort is not set

192.168.1.0/30 is subnetted, 1 subnets
C 192.168.1.0 is directly connected, Serial0/0/0:0.37

! Create the two VRF's and assign route distinguishers
ip vrf E1-0/0/0
rd 100:0
!
ip vrf E1-0/0/1
rd 200:1
! Configure the E1 controllers. They need to be joined with an E1 crossover cable
controller E1 0/0/0
  channel-group 0 timeslots 1-31 speed 64
!
controller E1 0/0/1
  channel-group 0 timeslots 1-31 speed 64

! Configure the serial controller on E1 0/0/0 with frame-relay encapsulation
! Note that one of the two serial interfaces has to be Frame-relay DCE when using a crossover.
interface Serial0/0/0:0
  no ip address
  encapsulation frame-relay IETF
  frame-relay lmi-type q933a
  frame-relay intf-type dce
!
interface Serial0/0/0:0.37 point-to-point
  no ip address
  ip vrf forwarding E1-0/0/0
  ip address 192.168.1.1 255.255.255.252
  frame-relay interface-dlci 37
!
interface Serial0/0/1:0
  no ip address
  encapsulation frame-relay IETF
  frame-relay lmi-type q933a
!
interface Serial0/0/1:0.37 point-to-point
  ip vrf forwarding E1-0/0/1
  ip address 192.168.1.2 255.255.255.252
  frame-relay interface-dlci 37

September 11, 2009

Cisco Embedded Event Manager Applets

Filed under: Code, Network — Tags: , , , — networknerd @ 4:11 pm

Embedded event manager is a feature incorporated into most new cisco equipment. You can find more information on the Cisco site and some excellent examples at the IOSHINTS blog.

This applet is used to add/delete static arp entries on 6509 core switches in a HSRP pairing, since you can’t have a static arp configured more than once on the HSRP cluster.  The mac address is a multicast mac address of a windows network load balanced server.

Listing 1

event manager applet deletearpvlan234
event syslog occurs 1 pattern "%HSRP-5-STATECHANGE: Vlan234 Grp 1 state Speak -> Standby"
action 0.0 cli command "enable"
action 1.0 cli command "configure terminal"
action 2.0 cli command "no arp vrf SERVERS 192.168.1.100 0100.5e7f.00ac ARPA"
action 4.0 syslog msg "EEM deleted arp entry for 192.168.1.100"

event manager applet addarpvlan234
event syslog occurs 1 pattern "%HSRP-5-STATECHANGE: Vlan234 Grp 1 state Standby -> Active"
action 0.0 cli command "enable"
action 1.0 cli command "configure terminal"
action 2.0 cli command "arp vrf SERVERS 192.168.1.100 0100.5e7f.00ac ARPA"
action 4.0 syslog msg "EEM added arp entry for 192.168.1.100"

August 5, 2009

SwitchPort Visualisations

Filed under: audit, Code, Network, visualisation — Tags: , , — networknerd @ 2:58 pm

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

  1. 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.
  2. 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

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 &gt;= 100) and (@Vlan &lt;= 199)and ((@Vlan mod 4) = 0)">
        <xsl:value-of select="$color_wireless"/>
      </xsl:when>
      <xsl:when test="(@Vlan &gt;= 200) and (@Vlan &lt;= 387) and ((@Vlan mod 20) = 0)">
        <xsl:value-of select="$color_dot1xauth"/>
      </xsl:when>
      <xsl:when test="(@Vlan &gt;= 200) and (@Vlan &lt;= 387) and ((@Vlan mod 20) = 5)">
        <xsl:value-of select="$color_dot1xguest"/>
      </xsl:when>
      <xsl:when test="(@Vlan &gt;= 200) and (@Vlan &lt;= 387) and ((@Vlan mod 20) = 4)">
        <xsl:value-of select="$color_printer"/>
      </xsl:when>
      <xsl:when test="(@Vlan &gt;= 200) and (@Vlan &lt;= 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>&lt;BR/&gt;</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>&lt;BR/&gt;</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>&lt;BR/&gt;</xsl:text>
    <xsl:value-of select="concat('Vlan: ',@Vlan)"/>
    <xsl:text>&lt;BR/&gt;</xsl:text>
    <xsl:value-of select="concat('Desc: ',@Description)"/>
    <xsl:text>&lt;BR/&gt;</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>

February 28, 2009

Combine Wireshark Summary and Detail Information with XML Joins

Filed under: Code, Network — Tags: , , , , — networknerd @ 8:45 am

Wireshark users may occasionally find themselves wishing for the ability the add some packet detail to the summary information. In the previous post I was looking at DSCP  and TOS information and wanted to add that to the summary rather than drilling down into every packet.  The first solution is to use Tshark and a lua script as I did in the previous post.  The second solution is to export the capture file in both PSML and PDML format packet detail and render them in a web browser.

PSML and PDML are both XML files, so they can be rendered using an XML stylesheet and displayed in a web browser. Sensibly parsing the output of two different XML files can be a bit tricky. Fortunately there is a common field in each file, the packet number, which can be used to perform the equivalent of an SQL join on the two files.

First I captured the request and response of two single pings, one with and one without the ToS byte set.  Then I exported the files in PDML and PSML formats as shown below.  Note the reference in line 2 of packetsumm2.xml to the stylesheet table7.xsl.  When using a browser to transform the xml we have to modify it manually to include the reference rather than pass it as a command line parameter like we would with saxon or xalan.

The important parts of the stylesheet are highlighted in red.  The first of the highlighted lines creates a reference to the document element of the packet details file. The template below does all the hard work of performing the join.

<xsl:template match="/psml/packet">
      <tr>
  <xsl:variable name="packetnum" select="section[1]"/>
  <xsl:for-each select="section">
    <xsl:if test="position()=last()">
        <td><xsl:value-of select= "$packetdetail/pdml/packet/proto[@name = 'geninfo']/field[@name = 'num' and @show = $packetnum]/../../proto[@name = 'ip']/field[@name='ip.dsfield']/@showname"/></td>
    </xsl:if>
    <td><xsl:value-of select="."/></td>
  </xsl:for-each>
      </tr>
</xsl:template>

The packet number is in the first element and is saved in the variable packetnum.  A for-each  loop is created to output all the section elements of the packet summary.  In this case they are “No.”,  “Time”,  ” Source”,  ” Destination”,  ” Protocol” and  “Info”. As the loop progresses we test to see if we are at the last “section” element, and if we are it inserts the DS field information from the packet detail file. Now this is where the going gets heavy. We insert the DS field information using a <xsl:value-of> tag,  which contains a select attribute with an xpath expression to that information.

There are two main parts to this xpath expression

  1. $packetdetail/pdml/packet/proto[@name = 'geninfo']/field[@name = 'num' and @show = $packetnum]/
  2. ../../proto[@name = 'ip']/field[@name='ip.dsfield']/@showname

Part 1 drills down to the proto element of the packet that has  a field element with a name attribute equal to num and a show attribute equal to the packetnum variable.  This is the common part where we perform the join on the two files.

Part 2 solves the problem of accessing the DS field information.  This is a problem because our xpath expression has already taken us down one proto element and we need to be in another proto element at the same level. To get there we need to go back to the common ancestor of the two proto elements, using the ../.. expression and then match the proto element with a name attribute of ip and field element with a name attribute of ip.dsfield and finally selecting the showname attribute.

Conclusion

I admit the example using wireshark is a little contrived.  However, the ability to join xml files on a common field is a powerful technique worth keeping in the toolkit.  Who knows somebody may actually wish to display packet capture information in a web browser.

Table7.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:variable name="packetdetail" select="document('packets2.xml')"/>

<xsl:template match="/psml">
  <html>
  <body>
    <table border="2" bgcolor="lightgrey">
      <xsl:apply-templates/>
    </table>
  </body>
  </html>
</xsl:template>

<xsl:template match="/psml/structure">
      <tr>
  <xsl:for-each select="section">
  <xsl:if test="position() = last()">
        <th>DS Field</th>
  </xsl:if>
        <th><xsl:value-of select="."/></th>
  </xsl:for-each>
      </tr>
</xsl:template>
<xsl:template match="/psml/packet">
      <tr>
  <xsl:variable name="packetnum" select="section[1]"/>
  <xsl:for-each select="section">
    <xsl:if test="position()=last()">
        <td><xsl:value-of select= "$packetdetail/pdml/packet/proto[@name = 'geninfo']/field[@name = 'num' and @show = $packetnum]/../../proto[@name = 'ip']/field[@name='ip.dsfield']/@showname"/></td>
    </xsl:if>
    <td><xsl:value-of select="."/></td>
  </xsl:for-each>
      </tr>
</xsl:template>
</xsl:stylesheet>

Packetsumm2.xml

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="table7.xsl"?>
<psml version="0" creator="wireshark/1.0.2">
<structure>
<section>No.</section>
<section>Time</section>
<section>Source</section>
<section>Destination</section>
<section>Protocol</section>
<section>Info</section>
</structure>

<packet>
<section>1</section>
<section>0.000000</section>
<section>192.168.0.7</section>
<section>74.125.19.147</section>
<section>ICMP</section>
<section>Echo (ping) request</section>
</packet>

<packet>
<section>2</section>
<section>0.181465</section>
<section>74.125.19.147</section>
<section>192.168.0.7</section>
<section>ICMP</section>
<section>Echo (ping) reply</section>
</packet>

<packet>
<section>3</section>
<section>9.897599</section>
<section>192.168.0.7</section>
<section>74.125.19.147</section>
<section>ICMP</section>
<section>Echo (ping) request</section>
</packet>

<packet>
<section>4</section>
<section>10.079768</section>
<section>74.125.19.147</section>
<section>192.168.0.7</section>
<section>ICMP</section>
<section>Echo (ping) reply</section>
</packet>

</psml>

Packets2.xml

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="packets.xsl"?>
<pdml version="0" creator="wireshark/1.0.2">
<packet>
  <proto name="geninfo" pos="0" showname="General information" size="74">
    <field name="num" pos="0" show="1" showname="Number" value="1" size="74"/>
    <field name="len" pos="0" show="74" showname="Packet Length" value="4a" size="74"/>
    <field name="caplen" pos="0" show="74" showname="Captured Length" value="4a" size="74"/>
    <field name="timestamp" pos="0" show="Jan  8, 2009 10:14:57.971166000" showname="Captured Time" value="1231373697.971166000" size="74"/>
  </proto>
  <proto name="frame" showname="Frame 1 (74 bytes on wire, 74 bytes captured)" size="74" pos="0">
    <field name="frame.time" showname="Arrival Time: Jan  8, 2009 10:14:57.971166000" size="0" pos="0" show="Jan  8, 2009 10:14:57.971166000"/>
    <field name="frame.time_delta" showname="Time delta from previous captured frame: 0.000000000 seconds" size="0" pos="0" show="0.000000000"/>
    <field name="frame.time_delta_displayed" showname="Time delta from previous displayed frame: 0.000000000 seconds" size="0" pos="0" show="0.000000000"/>
    <field name="frame.time_relative" showname="Time since reference or first frame: 0.000000000 seconds" size="0" pos="0" show="0.000000000"/>
    <field name="frame.number" showname="Frame Number: 1" size="0" pos="0" show="1"/>
    <field name="frame.pkt_len" showname="Packet Length: 74 bytes" hide="yes" size="0" pos="0" show="74"/>
    <field name="frame.len" showname="Frame Length: 74 bytes" size="0" pos="0" show="74"/>
    <field name="frame.cap_len" showname="Capture Length: 74 bytes" size="0" pos="0" show="74"/>
    <field name="frame.marked" showname="Frame is marked: False" size="0" pos="0" show="0"/>
    <field name="frame.protocols" showname="Protocols in frame: eth:ip:icmp:data" size="0" pos="0" show="eth:ip:icmp:data"/>
  </proto>
  <proto name="eth" showname="Ethernet II, Src: Intel_28:c7:f7 (00:18:de:28:c7:f7), Dst: Netgear_ea:06:78 (00:09:5b:ea:06:78)" size="14" pos="0">
    <field name="eth.dst" showname="Destination: Netgear_ea:06:78 (00:09:5b:ea:06:78)" size="6" pos="0" show="00:09:5b:ea:06:78" value="00095bea0678">
      <field name="eth.addr" showname="Address: Netgear_ea:06:78 (00:09:5b:ea:06:78)" size="6" pos="0" show="00:09:5b:ea:06:78" value="00095bea0678"/>
      <field name="eth.ig" showname=".... ...0 .... .... .... .... = IG bit: Individual address (unicast)" size="3" pos="0" show="0" value="0" unmaskedvalue="00095b"/>
      <field name="eth.lg" showname=".... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)" size="3" pos="0" show="0" value="0" unmaskedvalue="00095b"/>
    </field>
    <field name="eth.src" showname="Source: Intel_28:c7:f7 (00:18:de:28:c7:f7)" size="6" pos="6" show="00:18:de:28:c7:f7" value="0018de28c7f7">
      <field name="eth.addr" showname="Address: Intel_28:c7:f7 (00:18:de:28:c7:f7)" size="6" pos="6" show="00:18:de:28:c7:f7" value="0018de28c7f7"/>
      <field name="eth.ig" showname=".... ...0 .... .... .... .... = IG bit: Individual address (unicast)" size="3" pos="6" show="0" value="0" unmaskedvalue="0018de"/>
      <field name="eth.lg" showname=".... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)" size="3" pos="6" show="0" value="0" unmaskedvalue="0018de"/>
    </field>
    <field name="eth.type" showname="Type: IP (0x0800)" size="2" pos="12" show="0x0800" value="0800"/>
  </proto>
  <proto name="ip" showname="Internet Protocol, Src: 192.168.0.7 (192.168.0.7), Dst: 74.125.19.147 (74.125.19.147)" size="20" pos="14">
    <field name="ip.version" showname="Version: 4" size="1" pos="14" show="4" value="45"/>
    <field name="ip.hdr_len" showname="Header length: 20 bytes" size="1" pos="14" show="20" value="45"/>
    <field name="ip.dsfield" showname="Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00)" size="1" pos="15" show="0" value="00">
      <field name="ip.dsfield.dscp" showname="0000 00.. = Differentiated Services Codepoint: Default (0x00)" size="1" pos="15" show="0x00" value="0" unmaskedvalue="00"/>
      <field name="ip.dsfield.ect" showname=".... ..0. = ECN-Capable Transport (ECT): 0" size="1" pos="15" show="0" value="0" unmaskedvalue="00"/>
      <field name="ip.dsfield.ce" showname=".... ...0 = ECN-CE: 0" size="1" pos="15" show="0" value="0" unmaskedvalue="00"/>
    </field>
    <field name="ip.len" showname="Total Length: 60" size="2" pos="16" show="60" value="003c"/>
    <field name="ip.id" showname="Identification: 0x84c6 (33990)" size="2" pos="18" show="0x84c6" value="84c6"/>
    <field name="ip.flags" showname="Flags: 0x00" size="1" pos="20" show="0x00" value="00">
      <field name="ip.flags.rb" showname="0... = Reserved bit: Not set" size="1" pos="20" show="0" value="0" unmaskedvalue="00"/>
      <field name="ip.flags.df" showname=".0.. = Don't fragment: Not set" size="1" pos="20" show="0" value="0" unmaskedvalue="00"/>
      <field name="ip.flags.mf" showname="..0. = More fragments: Not set" size="1" pos="20" show="0" value="0" unmaskedvalue="00"/>
    </field>
    <field name="ip.frag_offset" showname="Fragment offset: 0" size="2" pos="20" show="0" value="0000"/>
    <field name="ip.ttl" showname="Time to live: 128" size="1" pos="22" show="128" value="80"/>
    <field name="ip.proto" showname="Protocol: ICMP (0x01)" size="1" pos="23" show="0x01" value="01"/>
    <field name="ip.checksum" showname="Header checksum: 0x973b [correct]" size="2" pos="24" show="0x973b" value="973b">
      <field name="ip.checksum_good" showname="Good: True" size="2" pos="24" show="1" value="973b"/>
      <field name="ip.checksum_bad" showname="Bad : False" size="2" pos="24" show="0" value="973b"/>
    </field>
    <field name="ip.src" showname="Source: 192.168.0.7 (192.168.0.7)" size="4" pos="26" show="192.168.0.7" value="c0a80007"/>
    <field name="ip.addr" showname="Source or Destination Address: 192.168.0.7 (192.168.0.7)" hide="yes" size="4" pos="26" show="192.168.0.7" value="c0a80007"/>
    <field name="ip.src_host" showname="Source Host: 192.168.0.7" hide="yes" size="4" pos="26" show="192.168.0.7" value="c0a80007"/>
    <field name="ip.host" showname="Source or Destination Host: 192.168.0.7" hide="yes" size="4" pos="26" show="192.168.0.7" value="c0a80007"/>
    <field name="ip.dst" showname="Destination: 74.125.19.147 (74.125.19.147)" size="4" pos="30" show="74.125.19.147" value="4a7d1393"/>
    <field name="ip.addr" showname="Source or Destination Address: 74.125.19.147 (74.125.19.147)" hide="yes" size="4" pos="30" show="74.125.19.147" value="4a7d1393"/>
    <field name="ip.dst_host" showname="Destination Host: 74.125.19.147" hide="yes" size="4" pos="30" show="74.125.19.147" value="4a7d1393"/>
    <field name="ip.host" showname="Source or Destination Host: 74.125.19.147" hide="yes" size="4" pos="30" show="74.125.19.147" value="4a7d1393"/>
  </proto>
  <proto name="icmp" showname="Internet Control Message Protocol" size="40" pos="34">
    <field name="icmp.type" showname="Type: 8 (Echo (ping) request)" size="1" pos="34" show="8" value="08"/>
    <field name="icmp.code" showname="Code: 0 ()" size="1" pos="35" show="0x00" value="00"/>
    <field name="icmp.checksum" showname="Checksum: 0x415c [correct]" size="2" pos="36" show="0x415c" value="415c"/>
    <field name="icmp.ident" showname="Identifier: 0x0200" size="2" pos="38" show="0x0200" value="0200"/>
    <field name="icmp.seq" showname="Sequence number: 2560 (0x0a00)" size="2" pos="40" show="2560" value="0a00"/>
    <field name="data" value="6162636465666768696a6b6c6d6e6f7071727374757677616263646566676869"/>
      <field name="data.data" showname="Data: 6162636465666768696A6B6C6D6E6F707172737475767761..." size="32" pos="42" show="61:62:63:64:65:66:67:68:69:6a:6b:6c:6d:6e:6f:70:71:72:73:74:75:76:77:61:62:63:64:65:66:67:68:69" value="6162636465666768696a6b6c6d6e6f7071727374757677616263646566676869"/>
      </proto>
</packet>

<packet>
  <proto name="geninfo" pos="0" showname="General information" size="74">
    <field name="num" pos="0" show="2" showname="Number" value="2" size="74"/>
    <field name="len" pos="0" show="74" showname="Packet Length" value="4a" size="74"/>
    <field name="caplen" pos="0" show="74" showname="Captured Length" value="4a" size="74"/>
    <field name="timestamp" pos="0" show="Jan  8, 2009 10:14:58.152631000" showname="Captured Time" value="1231373698.152631000" size="74"/>
  </proto>
  <proto name="frame" showname="Frame 2 (74 bytes on wire, 74 bytes captured)" size="74" pos="0">
    <field name="frame.time" showname="Arrival Time: Jan  8, 2009 10:14:58.152631000" size="0" pos="0" show="Jan  8, 2009 10:14:58.152631000"/>
    <field name="frame.time_delta" showname="Time delta from previous captured frame: 0.181465000 seconds" size="0" pos="0" show="0.181465000"/>
    <field name="frame.time_delta_displayed" showname="Time delta from previous displayed frame: 0.181465000 seconds" size="0" pos="0" show="0.181465000"/>
    <field name="frame.time_relative" showname="Time since reference or first frame: 0.181465000 seconds" size="0" pos="0" show="0.181465000"/>
    <field name="frame.number" showname="Frame Number: 2" size="0" pos="0" show="2"/>
    <field name="frame.pkt_len" showname="Packet Length: 74 bytes" hide="yes" size="0" pos="0" show="74"/>
    <field name="frame.len" showname="Frame Length: 74 bytes" size="0" pos="0" show="74"/>
    <field name="frame.cap_len" showname="Capture Length: 74 bytes" size="0" pos="0" show="74"/>
    <field name="frame.marked" showname="Frame is marked: False" size="0" pos="0" show="0"/>
    <field name="frame.protocols" showname="Protocols in frame: eth:ip:icmp:data" size="0" pos="0" show="eth:ip:icmp:data"/>
  </proto>
  <proto name="eth" showname="Ethernet II, Src: Netgear_ea:06:78 (00:09:5b:ea:06:78), Dst: Intel_28:c7:f7 (00:18:de:28:c7:f7)" size="14" pos="0">
    <field name="eth.dst" showname="Destination: Intel_28:c7:f7 (00:18:de:28:c7:f7)" size="6" pos="0" show="00:18:de:28:c7:f7" value="0018de28c7f7">
      <field name="eth.addr" showname="Address: Intel_28:c7:f7 (00:18:de:28:c7:f7)" size="6" pos="0" show="00:18:de:28:c7:f7" value="0018de28c7f7"/>
      <field name="eth.ig" showname=".... ...0 .... .... .... .... = IG bit: Individual address (unicast)" size="3" pos="0" show="0" value="0" unmaskedvalue="0018de"/>
      <field name="eth.lg" showname=".... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)" size="3" pos="0" show="0" value="0" unmaskedvalue="0018de"/>
    </field>
    <field name="eth.src" showname="Source: Netgear_ea:06:78 (00:09:5b:ea:06:78)" size="6" pos="6" show="00:09:5b:ea:06:78" value="00095bea0678">
      <field name="eth.addr" showname="Address: Netgear_ea:06:78 (00:09:5b:ea:06:78)" size="6" pos="6" show="00:09:5b:ea:06:78" value="00095bea0678"/>
      <field name="eth.ig" showname=".... ...0 .... .... .... .... = IG bit: Individual address (unicast)" size="3" pos="6" show="0" value="0" unmaskedvalue="00095b"/>
      <field name="eth.lg" showname=".... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)" size="3" pos="6" show="0" value="0" unmaskedvalue="00095b"/>
    </field>
    <field name="eth.type" showname="Type: IP (0x0800)" size="2" pos="12" show="0x0800" value="0800"/>
  </proto>
  <proto name="ip" showname="Internet Protocol, Src: 74.125.19.147 (74.125.19.147), Dst: 192.168.0.7 (192.168.0.7)" size="20" pos="14">
    <field name="ip.version" showname="Version: 4" size="1" pos="14" show="4" value="45"/>
    <field name="ip.hdr_len" showname="Header length: 20 bytes" size="1" pos="14" show="20" value="45"/>
    <field name="ip.dsfield" showname="Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00)" size="1" pos="15" show="0" value="00">
      <field name="ip.dsfield.dscp" showname="0000 00.. = Differentiated Services Codepoint: Default (0x00)" size="1" pos="15" show="0x00" value="0" unmaskedvalue="00"/>
      <field name="ip.dsfield.ect" showname=".... ..0. = ECN-Capable Transport (ECT): 0" size="1" pos="15" show="0" value="0" unmaskedvalue="00"/>
      <field name="ip.dsfield.ce" showname=".... ...0 = ECN-CE: 0" size="1" pos="15" show="0" value="0" unmaskedvalue="00"/>
    </field>
    <field name="ip.len" showname="Total Length: 60" size="2" pos="16" show="60" value="003c"/>
    <field name="ip.id" showname="Identification: 0x57d9 (22489)" size="2" pos="18" show="0x57d9" value="57d9"/>
    <field name="ip.flags" showname="Flags: 0x00" size="1" pos="20" show="0x00" value="00">
      <field name="ip.flags.rb" showname="0... = Reserved bit: Not set" size="1" pos="20" show="0" value="0" unmaskedvalue="00"/>
      <field name="ip.flags.df" showname=".0.. = Don't fragment: Not set" size="1" pos="20" show="0" value="0" unmaskedvalue="00"/>
      <field name="ip.flags.mf" showname="..0. = More fragments: Not set" size="1" pos="20" show="0" value="0" unmaskedvalue="00"/>
    </field>
    <field name="ip.frag_offset" showname="Fragment offset: 0" size="2" pos="20" show="0" value="0000"/>
    <field name="ip.ttl" showname="Time to live: 239" size="1" pos="22" show="239" value="ef"/>
    <field name="ip.proto" showname="Protocol: ICMP (0x01)" size="1" pos="23" show="0x01" value="01"/>
    <field name="ip.checksum" showname="Header checksum: 0x5528 [correct]" size="2" pos="24" show="0x5528" value="5528">
      <field name="ip.checksum_good" showname="Good: True" size="2" pos="24" show="1" value="5528"/>
      <field name="ip.checksum_bad" showname="Bad : False" size="2" pos="24" show="0" value="5528"/>
    </field>
    <field name="ip.src" showname="Source: 74.125.19.147 (74.125.19.147)" size="4" pos="26" show="74.125.19.147" value="4a7d1393"/>
    <field name="ip.addr" showname="Source or Destination Address: 74.125.19.147 (74.125.19.147)" hide="yes" size="4" pos="26" show="74.125.19.147" value="4a7d1393"/>
    <field name="ip.src_host" showname="Source Host: 74.125.19.147" hide="yes" size="4" pos="26" show="74.125.19.147" value="4a7d1393"/>
    <field name="ip.host" showname="Source or Destination Host: 74.125.19.147" hide="yes" size="4" pos="26" show="74.125.19.147" value="4a7d1393"/>
    <field name="ip.dst" showname="Destination: 192.168.0.7 (192.168.0.7)" size="4" pos="30" show="192.168.0.7" value="c0a80007"/>
    <field name="ip.addr" showname="Source or Destination Address: 192.168.0.7 (192.168.0.7)" hide="yes" size="4" pos="30" show="192.168.0.7" value="c0a80007"/>
    <field name="ip.dst_host" showname="Destination Host: 192.168.0.7" hide="yes" size="4" pos="30" show="192.168.0.7" value="c0a80007"/>
    <field name="ip.host" showname="Source or Destination Host: 192.168.0.7" hide="yes" size="4" pos="30" show="192.168.0.7" value="c0a80007"/>
  </proto>
  <proto name="icmp" showname="Internet Control Message Protocol" size="40" pos="34">
    <field name="icmp.type" showname="Type: 0 (Echo (ping) reply)" size="1" pos="34" show="0" value="00"/>
    <field name="icmp.code" showname="Code: 0 ()" size="1" pos="35" show="0x00" value="00"/>
    <field name="icmp.checksum" showname="Checksum: 0x495c [correct]" size="2" pos="36" show="0x495c" value="495c"/>
    <field name="icmp.ident" showname="Identifier: 0x0200" size="2" pos="38" show="0x0200" value="0200"/>
    <field name="icmp.seq" showname="Sequence number: 2560 (0x0a00)" size="2" pos="40" show="2560" value="0a00"/>
    <field name="data" value="6162636465666768696a6b6c6d6e6f7071727374757677616263646566676869"/>
      <field name="data.data" showname="Data: 6162636465666768696A6B6C6D6E6F707172737475767761..." size="32" pos="42" show="61:62:63:64:65:66:67:68:69:6a:6b:6c:6d:6e:6f:70:71:72:73:74:75:76:77:61:62:63:64:65:66:67:68:69" value="6162636465666768696a6b6c6d6e6f7071727374757677616263646566676869"/>
      </proto>
</packet>

<packet>
  <proto name="geninfo" pos="0" showname="General information" size="74">
    <field name="num" pos="0" show="3" showname="Number" value="3" size="74"/>
    <field name="len" pos="0" show="74" showname="Packet Length" value="4a" size="74"/>
    <field name="caplen" pos="0" show="74" showname="Captured Length" value="4a" size="74"/>
    <field name="timestamp" pos="0" show="Jan  8, 2009 10:15:07.868765000" showname="Captured Time" value="1231373707.868765000" size="74"/>
  </proto>
  <proto name="frame" showname="Frame 3 (74 bytes on wire, 74 bytes captured)" size="74" pos="0">
    <field name="frame.time" showname="Arrival Time: Jan  8, 2009 10:15:07.868765000" size="0" pos="0" show="Jan  8, 2009 10:15:07.868765000"/>
    <field name="frame.time_delta" showname="Time delta from previous captured frame: 9.716134000 seconds" size="0" pos="0" show="9.716134000"/>
    <field name="frame.time_delta_displayed" showname="Time delta from previous displayed frame: 9.716134000 seconds" size="0" pos="0" show="9.716134000"/>
    <field name="frame.time_relative" showname="Time since reference or first frame: 9.897599000 seconds" size="0" pos="0" show="9.897599000"/>
    <field name="frame.number" showname="Frame Number: 3" size="0" pos="0" show="3"/>
    <field name="frame.pkt_len" showname="Packet Length: 74 bytes" hide="yes" size="0" pos="0" show="74"/>
    <field name="frame.len" showname="Frame Length: 74 bytes" size="0" pos="0" show="74"/>
    <field name="frame.cap_len" showname="Capture Length: 74 bytes" size="0" pos="0" show="74"/>
    <field name="frame.marked" showname="Frame is marked: False" size="0" pos="0" show="0"/>
    <field name="frame.protocols" showname="Protocols in frame: eth:ip:icmp:data" size="0" pos="0" show="eth:ip:icmp:data"/>
  </proto>
  <proto name="eth" showname="Ethernet II, Src: Intel_28:c7:f7 (00:18:de:28:c7:f7), Dst: Netgear_ea:06:78 (00:09:5b:ea:06:78)" size="14" pos="0">
    <field name="eth.dst" showname="Destination: Netgear_ea:06:78 (00:09:5b:ea:06:78)" size="6" pos="0" show="00:09:5b:ea:06:78" value="00095bea0678">
      <field name="eth.addr" showname="Address: Netgear_ea:06:78 (00:09:5b:ea:06:78)" size="6" pos="0" show="00:09:5b:ea:06:78" value="00095bea0678"/>
      <field name="eth.ig" showname=".... ...0 .... .... .... .... = IG bit: Individual address (unicast)" size="3" pos="0" show="0" value="0" unmaskedvalue="00095b"/>
      <field name="eth.lg" showname=".... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)" size="3" pos="0" show="0" value="0" unmaskedvalue="00095b"/>
    </field>
    <field name="eth.src" showname="Source: Intel_28:c7:f7 (00:18:de:28:c7:f7)" size="6" pos="6" show="00:18:de:28:c7:f7" value="0018de28c7f7">
      <field name="eth.addr" showname="Address: Intel_28:c7:f7 (00:18:de:28:c7:f7)" size="6" pos="6" show="00:18:de:28:c7:f7" value="0018de28c7f7"/>
      <field name="eth.ig" showname=".... ...0 .... .... .... .... = IG bit: Individual address (unicast)" size="3" pos="6" show="0" value="0" unmaskedvalue="0018de"/>
      <field name="eth.lg" showname=".... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)" size="3" pos="6" show="0" value="0" unmaskedvalue="0018de"/>
    </field>
    <field name="eth.type" showname="Type: IP (0x0800)" size="2" pos="12" show="0x0800" value="0800"/>
  </proto>
  <proto name="ip" showname="Internet Protocol, Src: 192.168.0.7 (192.168.0.7), Dst: 74.125.19.147 (74.125.19.147)" size="20" pos="14">
    <field name="ip.version" showname="Version: 4" size="1" pos="14" show="4" value="45"/>
    <field name="ip.hdr_len" showname="Header length: 20 bytes" size="1" pos="14" show="20" value="45"/>
    <field name="ip.dsfield" showname="Differentiated Services Field: 0x88 (DSCP 0x22: Assured Forwarding 41; ECN: 0x00)" size="1" pos="15" show="136" value="88">
      <field name="ip.dsfield.dscp" showname="1000 10.. = Differentiated Services Codepoint: Assured Forwarding 41 (0x22)" size="1" pos="15" show="0x22" value="22" unmaskedvalue="88"/>
      <field name="ip.dsfield.ect" showname=".... ..0. = ECN-Capable Transport (ECT): 0" size="1" pos="15" show="0" value="0" unmaskedvalue="88"/>
      <field name="ip.dsfield.ce" showname=".... ...0 = ECN-CE: 0" size="1" pos="15" show="0" value="0" unmaskedvalue="88"/>
    </field>
    <field name="ip.len" showname="Total Length: 60" size="2" pos="16" show="60" value="003c"/>
    <field name="ip.id" showname="Identification: 0x8519 (34073)" size="2" pos="18" show="0x8519" value="8519"/>
    <field name="ip.flags" showname="Flags: 0x00" size="1" pos="20" show="0x00" value="00">
      <field name="ip.flags.rb" showname="0... = Reserved bit: Not set" size="1" pos="20" show="0" value="0" unmaskedvalue="00"/>
      <field name="ip.flags.df" showname=".0.. = Don't fragment: Not set" size="1" pos="20" show="0" value="0" unmaskedvalue="00"/>
      <field name="ip.flags.mf" showname="..0. = More fragments: Not set" size="1" pos="20" show="0" value="0" unmaskedvalue="00"/>
    </field>
    <field name="ip.frag_offset" showname="Fragment offset: 0" size="2" pos="20" show="0" value="0000"/>
    <field name="ip.ttl" showname="Time to live: 128" size="1" pos="22" show="128" value="80"/>
    <field name="ip.proto" showname="Protocol: ICMP (0x01)" size="1" pos="23" show="0x01" value="01"/>
    <field name="ip.checksum" showname="Header checksum: 0x9660 [correct]" size="2" pos="24" show="0x9660" value="9660">
      <field name="ip.checksum_good" showname="Good: True" size="2" pos="24" show="1" value="9660"/>
      <field name="ip.checksum_bad" showname="Bad : False" size="2" pos="24" show="0" value="9660"/>
    </field>
    <field name="ip.src" showname="Source: 192.168.0.7 (192.168.0.7)" size="4" pos="26" show="192.168.0.7" value="c0a80007"/>
    <field name="ip.addr" showname="Source or Destination Address: 192.168.0.7 (192.168.0.7)" hide="yes" size="4" pos="26" show="192.168.0.7" value="c0a80007"/>
    <field name="ip.src_host" showname="Source Host: 192.168.0.7" hide="yes" size="4" pos="26" show="192.168.0.7" value="c0a80007"/>
    <field name="ip.host" showname="Source or Destination Host: 192.168.0.7" hide="yes" size="4" pos="26" show="192.168.0.7" value="c0a80007"/>
    <field name="ip.dst" showname="Destination: 74.125.19.147 (74.125.19.147)" size="4" pos="30" show="74.125.19.147" value="4a7d1393"/>
    <field name="ip.addr" showname="Source or Destination Address: 74.125.19.147 (74.125.19.147)" hide="yes" size="4" pos="30" show="74.125.19.147" value="4a7d1393"/>
    <field name="ip.dst_host" showname="Destination Host: 74.125.19.147" hide="yes" size="4" pos="30" show="74.125.19.147" value="4a7d1393"/>
    <field name="ip.host" showname="Source or Destination Host: 74.125.19.147" hide="yes" size="4" pos="30" show="74.125.19.147" value="4a7d1393"/>
  </proto>
  <proto name="icmp" showname="Internet Control Message Protocol" size="40" pos="34">
    <field name="icmp.type" showname="Type: 8 (Echo (ping) request)" size="1" pos="34" show="8" value="08"/>
    <field name="icmp.code" showname="Code: 0 ()" size="1" pos="35" show="0x00" value="00"/>
    <field name="icmp.checksum" showname="Checksum: 0x405c [correct]" size="2" pos="36" show="0x405c" value="405c"/>
    <field name="icmp.ident" showname="Identifier: 0x0200" size="2" pos="38" show="0x0200" value="0200"/>
    <field name="icmp.seq" showname="Sequence number: 2816 (0x0b00)" size="2" pos="40" show="2816" value="0b00"/>
    <field name="data" value="6162636465666768696a6b6c6d6e6f7071727374757677616263646566676869"/>
      <field name="data.data" showname="Data: 6162636465666768696A6B6C6D6E6F707172737475767761..." size="32" pos="42" show="61:62:63:64:65:66:67:68:69:6a:6b:6c:6d:6e:6f:70:71:72:73:74:75:76:77:61:62:63:64:65:66:67:68:69" value="6162636465666768696a6b6c6d6e6f7071727374757677616263646566676869"/>
      </proto>
</packet>

<packet>
  <proto name="geninfo" pos="0" showname="General information" size="74">
    <field name="num" pos="0" show="4" showname="Number" value="4" size="74"/>
    <field name="len" pos="0" show="74" showname="Packet Length" value="4a" size="74"/>
    <field name="caplen" pos="0" show="74" showname="Captured Length" value="4a" size="74"/>
    <field name="timestamp" pos="0" show="Jan  8, 2009 10:15:08.050934000" showname="Captured Time" value="1231373708.050934000" size="74"/>
  </proto>
  <proto name="frame" showname="Frame 4 (74 bytes on wire, 74 bytes captured)" size="74" pos="0">
    <field name="frame.time" showname="Arrival Time: Jan  8, 2009 10:15:08.050934000" size="0" pos="0" show="Jan  8, 2009 10:15:08.050934000"/>
    <field name="frame.time_delta" showname="Time delta from previous captured frame: 0.182169000 seconds" size="0" pos="0" show="0.182169000"/>
    <field name="frame.time_delta_displayed" showname="Time delta from previous displayed frame: 0.182169000 seconds" size="0" pos="0" show="0.182169000"/>
    <field name="frame.time_relative" showname="Time since reference or first frame: 10.079768000 seconds" size="0" pos="0" show="10.079768000"/>
    <field name="frame.number" showname="Frame Number: 4" size="0" pos="0" show="4"/>
    <field name="frame.pkt_len" showname="Packet Length: 74 bytes" hide="yes" size="0" pos="0" show="74"/>
    <field name="frame.len" showname="Frame Length: 74 bytes" size="0" pos="0" show="74"/>
    <field name="frame.cap_len" showname="Capture Length: 74 bytes" size="0" pos="0" show="74"/>
    <field name="frame.marked" showname="Frame is marked: False" size="0" pos="0" show="0"/>
    <field name="frame.protocols" showname="Protocols in frame: eth:ip:icmp:data" size="0" pos="0" show="eth:ip:icmp:data"/>
  </proto>
  <proto name="eth" showname="Ethernet II, Src: Netgear_ea:06:78 (00:09:5b:ea:06:78), Dst: Intel_28:c7:f7 (00:18:de:28:c7:f7)" size="14" pos="0">
    <field name="eth.dst" showname="Destination: Intel_28:c7:f7 (00:18:de:28:c7:f7)" size="6" pos="0" show="00:18:de:28:c7:f7" value="0018de28c7f7">
      <field name="eth.addr" showname="Address: Intel_28:c7:f7 (00:18:de:28:c7:f7)" size="6" pos="0" show="00:18:de:28:c7:f7" value="0018de28c7f7"/>
      <field name="eth.ig" showname=".... ...0 .... .... .... .... = IG bit: Individual address (unicast)" size="3" pos="0" show="0" value="0" unmaskedvalue="0018de"/>
      <field name="eth.lg" showname=".... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)" size="3" pos="0" show="0" value="0" unmaskedvalue="0018de"/>
    </field>
    <field name="eth.src" showname="Source: Netgear_ea:06:78 (00:09:5b:ea:06:78)" size="6" pos="6" show="00:09:5b:ea:06:78" value="00095bea0678">
      <field name="eth.addr" showname="Address: Netgear_ea:06:78 (00:09:5b:ea:06:78)" size="6" pos="6" show="00:09:5b:ea:06:78" value="00095bea0678"/>
      <field name="eth.ig" showname=".... ...0 .... .... .... .... = IG bit: Individual address (unicast)" size="3" pos="6" show="0" value="0" unmaskedvalue="00095b"/>
      <field name="eth.lg" showname=".... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)" size="3" pos="6" show="0" value="0" unmaskedvalue="00095b"/>
    </field>
    <field name="eth.type" showname="Type: IP (0x0800)" size="2" pos="12" show="0x0800" value="0800"/>
  </proto>
  <proto name="ip" showname="Internet Protocol, Src: 74.125.19.147 (74.125.19.147), Dst: 192.168.0.7 (192.168.0.7)" size="20" pos="14">
    <field name="ip.version" showname="Version: 4" size="1" pos="14" show="4" value="45"/>
    <field name="ip.hdr_len" showname="Header length: 20 bytes" size="1" pos="14" show="20" value="45"/>
    <field name="ip.dsfield" showname="Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00)" size="1" pos="15" show="0" value="00">
      <field name="ip.dsfield.dscp" showname="0000 00.. = Differentiated Services Codepoint: Default (0x00)" size="1" pos="15" show="0x00" value="0" unmaskedvalue="00"/>
      <field name="ip.dsfield.ect" showname=".... ..0. = ECN-Capable Transport (ECT): 0" size="1" pos="15" show="0" value="0" unmaskedvalue="00"/>
      <field name="ip.dsfield.ce" showname=".... ...0 = ECN-CE: 0" size="1" pos="15" show="0" value="0" unmaskedvalue="00"/>
    </field>
    <field name="ip.len" showname="Total Length: 60" size="2" pos="16" show="60" value="003c"/>
    <field name="ip.id" showname="Identification: 0x57db (22491)" size="2" pos="18" show="0x57db" value="57db"/>
    <field name="ip.flags" showname="Flags: 0x00" size="1" pos="20" show="0x00" value="00">
      <field name="ip.flags.rb" showname="0... = Reserved bit: Not set" size="1" pos="20" show="0" value="0" unmaskedvalue="00"/>
      <field name="ip.flags.df" showname=".0.. = Don't fragment: Not set" size="1" pos="20" show="0" value="0" unmaskedvalue="00"/>
      <field name="ip.flags.mf" showname="..0. = More fragments: Not set" size="1" pos="20" show="0" value="0" unmaskedvalue="00"/>
    </field>
    <field name="ip.frag_offset" showname="Fragment offset: 0" size="2" pos="20" show="0" value="0000"/>
    <field name="ip.ttl" showname="Time to live: 239" size="1" pos="22" show="239" value="ef"/>
    <field name="ip.proto" showname="Protocol: ICMP (0x01)" size="1" pos="23" show="0x01" value="01"/>
    <field name="ip.checksum" showname="Header checksum: 0x5526 [correct]" size="2" pos="24" show="0x5526" value="5526">
      <field name="ip.checksum_good" showname="Good: True" size="2" pos="24" show="1" value="5526"/>
      <field name="ip.checksum_bad" showname="Bad : False" size="2" pos="24" show="0" value="5526"/>
    </field>
    <field name="ip.src" showname="Source: 74.125.19.147 (74.125.19.147)" size="4" pos="26" show="74.125.19.147" value="4a7d1393"/>
    <field name="ip.addr" showname="Source or Destination Address: 74.125.19.147 (74.125.19.147)" hide="yes" size="4" pos="26" show="74.125.19.147" value="4a7d1393"/>
    <field name="ip.src_host" showname="Source Host: 74.125.19.147" hide="yes" size="4" pos="26" show="74.125.19.147" value="4a7d1393"/>
    <field name="ip.host" showname="Source or Destination Host: 74.125.19.147" hide="yes" size="4" pos="26" show="74.125.19.147" value="4a7d1393"/>
    <field name="ip.dst" showname="Destination: 192.168.0.7 (192.168.0.7)" size="4" pos="30" show="192.168.0.7" value="c0a80007"/>
    <field name="ip.addr" showname="Source or Destination Address: 192.168.0.7 (192.168.0.7)" hide="yes" size="4" pos="30" show="192.168.0.7" value="c0a80007"/>
    <field name="ip.dst_host" showname="Destination Host: 192.168.0.7" hide="yes" size="4" pos="30" show="192.168.0.7" value="c0a80007"/>
    <field name="ip.host" showname="Source or Destination Host: 192.168.0.7" hide="yes" size="4" pos="30" show="192.168.0.7" value="c0a80007"/>
  </proto>
  <proto name="icmp" showname="Internet Control Message Protocol" size="40" pos="34">
    <field name="icmp.type" showname="Type: 0 (Echo (ping) reply)" size="1" pos="34" show="0" value="00"/>
    <field name="icmp.code" showname="Code: 0 ()" size="1" pos="35" show="0x00" value="00"/>
    <field name="icmp.checksum" showname="Checksum: 0x485c [correct]" size="2" pos="36" show="0x485c" value="485c"/>
    <field name="icmp.ident" showname="Identifier: 0x0200" size="2" pos="38" show="0x0200" value="0200"/>
    <field name="icmp.seq" showname="Sequence number: 2816 (0x0b00)" size="2" pos="40" show="2816" value="0b00"/>
    <field name="data" value="6162636465666768696a6b6c6d6e6f7071727374757677616263646566676869"/>
      <field name="data.data" showname="Data: 6162636465666768696A6B6C6D6E6F707172737475767761..." size="32" pos="42" show="61:62:63:64:65:66:67:68:69:6a:6b:6c:6d:6e:6f:70:71:72:73:74:75:76:77:61:62:63:64:65:66:67:68:69" value="6162636465666768696a6b6c6d6e6f7071727374757677616263646566676869"/>
      </proto>
</packet>
</pdml>

January 20, 2009

DSCP to Type of Service Mappings

Filed under: Code, Network — Tags: , , , — networknerd @ 11:45 am

When working with quality of service configurations you’ll inevitably come across the need to perform packet markings with DSCP.  With routers this is generally fairly simple.  Performing the same function on a host is not always that simple.  All the socket API’s were designed around type of service (ToS),as defined in RFC791, rather than DSCP as defined in RFC2474.

If you’re in a hurry, the conversion is simply ToS = DSCP * 4. If you have the time the rfc’s are full of interesting information. The DSCP field with the DS field contains six bits allowing for 64 possible codepoint values. RFC2474 defines 3 pools of DSCP values, one for standardised use and the other two for local/experimental use. The standardised pool has the least significant bit set to 0, which means only the even numbers from 0 to 62 are used. A cheat sheet with the standardised DSCP values and equivalent IP precedence and ToS values can be found here.

We can test the ToS/DSCP mapping using the ping program and specifying a ToS byte value. Using the windows ping program we specify the ToS byte as a numeric argument to the -v command line switch. In this example we specify the the ToS byte as 136 which corresponds to a DSCP value of 34  or AF41.

ping -n 1 -v 136 http://www.google.com

Performing a similar test for tcp connection requires a little bit of coding effort. Listing 1 shows some c# code to do a simple get request to http://www.google.com.au,  using the SetSocketOption function to set the ToS byte to 136.  The wireshark output for both tests is shown below.  The  lua script shown in listing 2 was used to extract the diffserv field and dscp values while running the capture with Tshark. It is worth noting that even though the socketoption is set prior to the connection, no dscp values are set on the two packets from the client during the TCP three way handshake (frame 5 and 7 below).

tshark  -X lua_script:getdscp.lua -i 2 host http://www.google.com.au
Frame #1    Diffserv Field: 136    DSCP: 34
192.168.0.7 -> 74.125.19.103 ICMP Echo (ping) request

Frame #2    Diffserv Field: 0    DSCP: 0
74.125.19.103 -> 192.168.0.7  ICMP Echo (ping) reply

Frame #3    Diffserv Field: 136    DSCP: 34
192.168.0.7 -> 74.125.19.103 ICMP Echo (ping) request

Frame #4    Diffserv Field: 0    DSCP: 0
74.125.19.103 -> 192.168.0.7  ICMP Echo (ping) reply

Frame #5    Diffserv Field: 0    DSCP: 0
192.168.0.7 -> 74.125.19.103 TCP linx > http [SYN] Seq=0 Win=16384 Len=0 MSS=1260

Frame #6    Diffserv Field: 0    DSCP: 0
74.125.19.103 -> 192.168.0.7  TCP http > linx [SYN, ACK] Seq=0 Ack=1 Win=5720 Len=0 MSS=1430

Frame #7    Diffserv Field: 0    DSCP: 0
192.168.0.7 -> 74.125.19.103 TCP linx > http [ACK] Seq=1 Ack=1 Win=17640 Len=0

Frame #8    Diffserv Field: 136    DSCP: 34
192.168.0.7 -> 74.125.19.103 HTTP GET / HTTP/1.0

Frame #9    Diffserv Field: 0    DSCP: 0
74.125.19.103 -> 192.168.0.7  TCP http > linx [ACK] Seq=1 Ack=41 Win=5720 Len=0

Frame #10    Diffserv Field: 0    DSCP: 0
74.125.19.103 -> 192.168.0.7  TCP [TCP segment of a reassembled PDU]

Frame #11    Diffserv Field: 0    DSCP: 0
74.125.19.103 -> 192.168.0.7  TCP [TCP segment of a reassembled PDU]

Frame #12    Diffserv Field: 136    DSCP: 34
192.168.0.7 -> 74.125.19.103 TCP linx > http [ACK] Seq=41 Ack=2521 Win=17640 Len=0

Frame #13    Diffserv Field: 0    DSCP: 0
74.125.19.103 -> 192.168.0.7  TCP [TCP segment of a reassembled PDU]

Frame #14    Diffserv Field: 0    DSCP: 0
74.125.19.103 -> 192.168.0.7  TCP [TCP segment of a reassembled PDU]

Frame #15    Diffserv Field: 136    DSCP: 34
192.168.0.7 -> 74.125.19.103 TCP linx > http [ACK] Seq=41 Ack=5041 Win=17640 Len=0

Frame #16    Diffserv Field: 0    DSCP: 0
74.125.19.103 -> 192.168.0.7  TCP [TCP segment of a reassembled PDU]

Frame #17    Diffserv Field: 0    DSCP: 0
74.125.19.103 -> 192.168.0.7  HTTP HTTP/1.0 200 OK  (text/html)

Frame #18    Diffserv Field: 136    DSCP: 34
192.168.0.7 -> 74.125.19.103 TCP linx > http [ACK] Seq=41 Ack=6611 Win=17640 Len=0

Frame #19    Diffserv Field: 136    DSCP: 34
192.168.0.7 -> 74.125.19.103 TCP linx > http [FIN, ACK] Seq=41 Ack=6611 Win=17640 Len=0

Frame #20    Diffserv Field: 0    DSCP: 0
74.125.19.103 -> 192.168.0.7  TCP http > linx [ACK] Seq=6611 Ack=42 Win=5720 Len=0
Listing  1

using System;
using System.Text;
using System.Net.Sockets;

namespace tcptos
{
	class Program
	{
		public static void Main(string[] args)
		{
			Console.WriteLine("Testing DSCP packet marking.Wireshark should already be running!\n");

			TcpClient cli = new TcpClient();
			cli.Client.SetSocketOption(SocketOptionLevel.IP,
			                           SocketOptionName.TypeOfService, 136);
			cli.Connect("www.google.com.au",80);
			byte[] buf = Encoding.ASCII.GetBytes("GET / HTTP/1.0\nHost: www.google.com.au\n\n");
			byte[] readbuf = new byte[4096];
			int bytesRead;
			StringBuilder response = new StringBuilder();
			NetworkStream mystream = cli.GetStream();
			mystream.Write(buf,0,buf.Length);
			do{
				bytesRead = mystream.Read(readbuf, 0, readbuf.Length);
				response.AppendFormat("{0}", Encoding.ASCII.GetString(readbuf, 0, bytesRead));
			}
			while(bytesRead > 0);
			Console.Write(response.ToString());
			Console.Write("\nPress any key to continue . . . ");
			Console.ReadKey(true);
			cli.Close();
		}
	}
}

Listing 2

local dsfield = Field.new("ip.dsfield")
local dscp = Field.new("ip.dsfield.dscp")
local fnum = Field.new("frame.number")
do
    packets = 0;
    local function init_listener()
        local tap = Listener.new("frame","ip.version == 4")

        function tap.reset()
        end
        function tap.packet(pinfo,tvb,ip)
            local fnumber = tostring(fnum())
            local diffserv = tostring(dsfield())
            local codepoint = tostring(dscp())
            local stroutput = "\nFrame #" .. fnumber .. "\tDiffserv Field: " ..
				diffserv .. "\tDSCP: " ..codepoint
            print(stroutput)
        end
        function tap.draw()

        end
    end
    init_listener()
end

October 29, 2008

IOS Upgrade – %SYS-3-IMAGE_TOO_BIG

Filed under: Cisco, Network — networknerd @ 8:49 pm

I attempted an IOS upgrade on a 3845 router on the weekend and, upon reboot received this error on the console:

%SYS-3-IMAGE_TOO_BIG: ‘flash:c3845-advipservicesk9-mz.124-22.T.bin’ is too large for available memory (50954264 bytes).boot of “c3845-advipservicesk9-mz.124-22.T.bin” using boot helper “flash:c3845-advipservicesk9-mz.123-11.T5.bin” failed

The message seems self explanatory.  The image is too big for memory.  However I did do my homework and the router had the minimum 512 mb memory and 128 mb flash.  The interesting thing here is the second sentence. I had left the original image in the flash (since there was plenty of room) and used a boot system command to ensure that the new IOS was loaded. The old image was being loaded, at least partially, as a boot helper.

I thought that the boot helper came from the ROM but this indicates a second stage boot process using the first image found in flash, not the image specified in the config.  Possibilities here are that the second stage boot loader from the 12.3 image took up too much memory. Alternatively it may be possible that the boot loader has a hardcoded limit for allocating a buffer to read the image into.  I didn’t have any extra memory to test that theory.

Since the second stage boot loader was being loaded from the first available image, and we know the image is selected in dir (alphabetical) order it was a simple matter to rename the old image from c3845-advipservicesk9-mz.123-11.T5.bin to c3845-advipservicesk9-mz.128-11.T5.bin. After rebooting the image loaded perfectly.

So the moral of the story is if the image should fit in memory and you have old images in flash, you should either delete them or rename them so that they appear after the desired boot image when you execute the show flash command.

Leave a comment if you’ve struck this problem before or you know more about the boot process.

October 1, 2008

Wireshark Scripting – Extracting HTTP Host Headers

Filed under: Network — Tags: , , — networknerd @ 11:00 pm

Anyone who’s looked at packets knows about Wireshark. There seems to be considerably less known about Wireshark’s scripting interface though.

While reviewing a very old packet capture I noticed that the host names as resolved by wireshark weren’t consistent with what I knew of the data. Well what can you do? DNS names and IP addresses are in a constant state of flux. It hit me then that the packet capture itself had all the data I needed to create a hosts file for wireshark. It was just a matter of extracting the data from the http requests or the DNS requests/responses into hosts file format and putting a hosts file in the Wireshark directory.

Every http request contains a host header.  The purpose of the header is to allow web servers with a single IP address to host websites for more than one domain.  The webserver uses the host header to multiplex multiple virtual directories/websites onto a single IP address.

Host Header in an HTTP request

Host Header in an HTTP request

To run the script make sure that you edit the init.lua file in the wireshark directory and comment out the line beginning with disable_lua. The usage is shown below in the script and because we are using tshark we can just redirect the output directly to a hosts file.

Listing 1 – gethttphosts.lua

-- Lua script to extract http host headers to create a hosts
-- file for wireshark name resolution.
-- command line:
--	Tshark –r websurf.pcap –q –X lua_script:gethttphosts.lua

Do
-- Create the field extractors
hostname = Field.new("http.host")
ip_dst = Field.new("ip.dst")

	local function init_listener()
-- Create a listener that filters for http requests
	  local tap = Listener.new("frame", "tcp && http.request")
	  function tap.reset()
	  end

	  function tap.packet(pinfo,tvb,ip)
-- Format the data and output it
		local strTemp = tostring(ip_dst()) .. " " ..
                                  tostring(hostname()) .. "\n";
		io.write(strTemp);
	  end
	  function tap.draw()
	  end
	end
	init_listener()
end

September 24, 2008

Re-Imaging Computers in 802.1x Networks – Part 5

Filed under: Code, Network — Tags: , , , , — networknerd @ 8:24 pm

This is the final post in this series on re-imaging in 802.1x networks. It ties all the other posts together and contains the complete altiris re-imaging script in one listing.  Although I haven’t covered it here, a post-image script is also required to set the switch port back to using dot1x after the image is dropped from the computer and joined to the domain to get it’s authentication credentials.

Altiris scripting
The observant reader would have noticed that additional information is required before we can perform the previous five steps in a script. The mac address of the computer, the re-imaging vlan and the management IP address of the switch are also required. Variables are provided by altiris which help obtain the additional information. The mac address is provided straight up as %NIC1MACADDR%. The management IP address of the switch and re-imaging vlan aren’t directly available. Altiris has no knowledge of these items. However networks built to a standard allow calculation of the remaining two parameters. The computers ip address provided in the %NIC1IPADDR% variable is used for this calculation. The example network was built to the design standard below.

  • Floor vlans will be allocated in the range 100 – 299 with 10 vlans being reserved per floor.
  • Floor ip addresses will be allocated in the range 192.168.32.0 – 192.168.191.255 with 8 class C networks reserved per floor.
  • The first three networks and vlans per floor will be allocated to authenticated computers, guest/auth-fail computers and re-imaging vlan respectively.
  • The fourth network and vlan will be reserved for future IP telephony projects.
  • The fifth network will be allocated to switch management IP addresses with all others reserved for future use.
  • Switch management vlans will be allocated in the range 300 – 350.
  • Edge switch management address will start at 192.168.x.11

The ip address of the first network on a floor is calculated by masking the last three bits in the third octet of the computers ip address (%NIC1IPADDR%). The fifth network on each floor is reserved for switch management. Adding 4 to the third octet gives the switch management network. Assuming the last octet of the switch management IP addresses are also kept consistent, the address can be completed by simply changing the fourth octet to the standard value. Refer to the getSwitchMgmtAddr() function in listing 1.

The vlan of the first network on a floor is calculated using a similar technique. The vlan in which the computers mac address was found is divided, using integer division, by the number of vlans per floor. The result is then multiplied by the number of vlans per floor. The third network and vlan are reserved for re-imaging. Adding 2 to the first vlan on the floor will give the re-imaging vlan.

As an example, assume that the computer to be re-imaged has an ip address of 192.168.42.157 and its mac address was found in vlan 112 (probably due to a failed re-image job). Masking the last three bits of the third octet gives the first network on the floor.
00101010 (42)
AND 11111000 (248)
= 00101000 (40)
The management network is found by adding 4 to the third octet and gives 192.168.44.0/24, and the switch management ip address will be 192.168.44.11. The first vlan on a floor is calculated as (112\10) * 10 = 110. The re-imaging vlan is found by adding 2 to give 112. Note that the use of integer division- denoted by \ rather than / – means that remainders are ignored.

Not every network is the way we would design it with hindsight. Networks often grow in odd ways. You may have inherited a flat network that won’t lend itself to this kind of calculation. In this case you can simply build an array of switch management ip addresses and loop through steps one and two for each switch until the bridgeport on which the mac address appears is found on a non-trunking port. Then continue with steps three to five.

The script in listing 1 should be easy to customise for your environment. Pay particular attention to the constants defined at the beginning, the regular expression patterns used to match the output from the snmp commands, and the snmp commands. If you aren’t familiar with regular expressions take a look at “Mastering Regular expressions” by Jeffrey Friedl.

With snmp and a modicum of scripting know-how you can now have dot1x security without fearing an uprising of angry helpdesk staff.

References

How To Add, Modify, and Remove VLANs on a Catalyst Using SNMP. (October 26, 2005).
     Retrieved 11 November, 2006, from
     http://www.cisco.com/en/US/tech/tk648/tk362/technologies_tech_note09186a00801c6035.shtml

Using SNMP to Find a Port Number from a MAC Address on a Catalyst Switch. (October 26, 2005).
     Retrieved 11 November, 2006, from
     http://www.cisco.com/en/US/tech/tk648/tk362/technologies_tech_note09186a00801c9199.shtml

How To Get Dynamic CAM Entries (CAM Table) for Catalyst Switches Using SNMP. (October 26, 2005).
     Retrieved 11 November, 2006, from
     http://www.cisco.com/en/US/tech/tk648/tk362/technologies_tech_note09186a0080094a9b.shtml

How to Get VLAN Information From a Catalyst Using SNMP. (October 26, 2005).
     Retrieved 11 November, 2006, from
     http://www.cisco.com/en/US/tech/tk648/tk362/technologies_configuration_example09186a008015773e.shtml

SNMP Community String Indexing. (October 26, 2005).
     Retrieved 11 November, 2006, from
     http://www.cisco.com/en/US/tech/tk648/tk362/technologies_tech_note09186a00801576ff.shtml

IEEE Standard for Local and metropolitan area networks—Port-Based Network Access Control. (2004).
     Retrieved 11 November, 2006, from
     http://standards.ieee.org/getieee802/download/802.1X-2004.pdf

Friedl, J. (2002). Mastering Regular Expressions (Second ed.): O'Reilly Media Inc.
 (more...)
Older Posts »

Blog at WordPress.com.