Configuring a Cisco SRW2008P switch without using Windows

I assume this page might apply to all Cisco Small Business Managed Switches (Linksys Business Series) but since I've only experience with one particual model - the SRW2008P - I'm limiting the scope to that model and the exact firmware revision:

  Model Name   	        SRW2008P
  Hardware Version   	00.03.00
  Boot Version   	1.0.1
  Firmware Version   	1.0.4 

Please let me know if the hints on this page has been successfully used with any other model.

The problem

I recently bought a Cisco SRW2008P as it seemed perfect for my home usage. I needed managed gigabit switch, and Power over Ethernet has been on my wishlist for some time. The ability to install wireless access points and PD switches like the SLM2008 with a minimum of cables and power bricks is IMHO even more important for home usage than for business.

On the marketing papers the SRW2008P has

So I hooked up the console and powered it on, only to be surprised by the rather short menu presented there. The first task would be to replace the default "admin" user, but where were my RADIUS settings? Strange. Even stranger: Where the heck were the VLAN configuration menu?

OK, time for reading the documentation. Let's see. "Advanced Configuration" sounds good. This chapter describes the features included in the Web-based Utility.

Come again? Right. So it doesn't really have console, ssh, telnet and SNMP management after all? OK, I've been screwed. No problem. I'm a bit pissed, but I can live with having to use a browser. I enter http://192.168.1.254/ in Opera and get a mostly blank webpage. OK, so it doesn't work with Opera. No big deal. I enter http://192.168.1.254/ in Firefox and I get the same mostly blank page. Starting to worry. Trying iceape and konqueror doesn't help anything.

Time for Google. "SRW2008P firefox" brought me to http://forums.linksysbycisco.com/linksys/board/message?board.id=Switches&message.id=628 which only confirmed my experience.

The SRW2008P just doesn't work. It does not support any standard management interface at all, neither console, ssh, telnet nor http. It requires a dedicated management application sold by Microsoft only as part of their line of operating systems. If you don't have a management station with such an operating system already, you're up for a cost far exceeding the price of the switch itself. Nice.

I later found that Cisco confirms this. It's in fact in the release notes and their Q&A:

Do note that the mentioned "Firefox IE Tab add-on" is a Windows only add-on allowing you to run Internet Explorer embedded in a Firefox tab. It does not change anything, and most important: It is not a solution unless you are using Windows.

The simplest solution (new)

After writing this page, I did a bit more Googling and finally found this procedure:

Voila! You've now got a IOS-like CLI:

srw2008a# sh ver
SW version    1.0.4 ( date  06-Sep-2007 time  09:11:40 )
Boot version    1.0.1 ( date  06-Jun-2006 time  17:23:21 )
HW version    00.03.00

It's not IOS, but sufficiently lookalike that anyone familiar with IOS should be able to use it. Some notable differences:

This might work with ssh too, but I haven't tested it as I can't find any way to generate host keys of sufficient length for my ssh-client

Note that although I had configured radius+local authentication prior to testing this, the second login only accepted local accounts. This could be fixed after logging into the CLI shell with

aaa authentication login default radius local 

I've not found any way of doing that in the Web GUI.

This might just be me, but I do find the CLI version of the VLAN configuration much more intuitive than the web GUI:

vlan database
vlan 7
exit
interface range ethernet g(2-4,6-8)
switchport access vlan 7
exit
interface range ethernet g(1,5)
switchport trunk allowed vlan add 7
exit
interface vlan 7
name Wireless
exit

Nice and clean. Note the usage of port ranges. This is in fact much nicer than (switch) IOS. It looks more like Foundry's IOS CLI clone, IMHO.

Using RANCID for backups

The existence of a real CLI opens a whole new world. Personally I like keeping simple config backups using RANCID. So I wrote (well, copied mostly) two small scripts to be able to use it against these switches as well. I guess the srwlogin might be useful to do automated logins for other purposes as well:

To use these from RANCID,

The simple solution

I am lucky enough to be using Linux on PC hardware, so I do have the ability to run Windows applications under WINE. I got a tip that installing older Internet Explorer versions is really easier under WINE than under real Windows. There are even automated solutions: IEs4Linux - Internet Explorer 6, 5.5, 5 on Linux

This is sufficient to configure the switch and may be the best solution if you can run WINE. That is if you run Linux, BSD, Solaris or Mac OS X on "PC like" hardware.

The brute force solution

But what if you can't or won't run WINE? There is a rather unpleasant license problem with the solution above - as menitoned before: Microsoft will only sell you an Internet Explorer license as part an operating system. So for those of us who try our best to respect licensing, Internet Explorer is really not an option.

Unfortunately, the other option seems to be violating Cisco's firmware license. Personally I feel fine about that. I live in a country where I'm explicitly allowed to do that if it's necessary to make a device/software I've bought work. And it certainly is in this case. But YMMV and I guess there are strange places around the world where you actually risk being sued by Cisco for tampering with their code. Consider yourself warned.

Looking at the code

WARNING: Looking at the CSS, HTML and JavaScript code embedded on these devices may cause sickness.

The device uses cookie authentication, but fortunately

This means that you can authenticate using any browser, look at the source with "View Source", and start downloading the referenced scripts using wget, lynx or whatever.

I started out by looking a the Error Console in Firefox. Boy were there many errors! No way I'm going to be able to fix all those. If you want an example of Cisco's firmware quality assurance, download http://192.168.1.254/css/newlink.css from the device and look at it. You don't have to be a CSS guru to notice that this doesn't look good. You'll find spelling errors like

TEXT-ALIGN: ceneter;
Value errors like
FONT-STYLE: bold;
(bold is not a style, it's a weight) Typos like
align=center
etc. There are so many of these that I gave up fixing them all. In fact, Internet Explorer will also fail on most of these and we can therefore conclude that they don't matter. It's ugly as hell, but let's look for the real problem.

Looking at the JavaScript

Looking at the source of /home.htm:

<script src="js/common_data.js"></script>
<script src="js/initFunctions.js"></script>
<script src="js/common_functions.js"></script>
<script src="js/tabs.js"></script>
<script src="js/tab_items_208_no_poe.js"></script>

<script src="js/tab_items_srs.js"></script>
<script src="js/tab_items_cheetah.js"></script>
<script src="js/tab_items_soho.js"></script>
<script src="js/tab_items_salsa.js"></script>
<script src="js/tab_items_cheetah_cut.js"></script>
<script src="js/tab_items_106.js"></script>
<script src="js/String.js"></script>
Ugh, lots of code to fix. I downloaded all of these from the switch, using wget, and started grepping for the problems reported by the Firefox Error Console. Note that Firefox will display the source for you if you select an error in the Error Console. But I wanted a local copy I could modify, so therefore the wget download.

After several hours of fixing bugs all over the place to try to pinpoint the exact bugs preventing Firefox from displaying the Web GUI properly, I ended up with only a handful of small changes to two of the script files:

This was all that was actually needed to make it (mostly) work. Most of the bugs are still left, in particular all CSS bugs, and will show up as somewhat funny tables and such. I have chosen to ignore those for now, as I don't have enough time to fix all of it properly and I wanted a minimalistic solution to demonstrate how easily Cisco could have fixed these devices if they wanted to.

In addition to the list above, I could not resist making two optional changes to initFunctions.js since I already was modifying it:

Note that the last change will make an alert box pop up in case of errors.

Making the browsers use the fixed code

There are several possible approaches. The best would of course be to upload a fixed firmware to the device. I have not, and I will not, modify the firmware myself. I fear I'll break it, and I don't want to risk that. So I've used a http proxy configured to replace the files in question with local copies. Another solution would be to create a dedicated frontend doing the same http proxy job.

Note that as we only fiddle with static JavaScript files, which are executed locally by the browser anyway, the changes should be totally transparent to the device itself. Given that we don't change the exposed API of course...

HOWTO for the impatient

You'll of course need to replace 192.168.1.254 with whatever address your device has if it's different.

1. Download the to JavaScript files needing modification

Norwegian law do allow me to create fixed versions of these files for may own usage, but not to distribute the fixed versions. You'll therefore have to repair the files yourself. I do not provide them. For simplicity I've chosen to describe the necessary changes as a patch. This ensures that the version you are changing is compatible with the version I've changed.
wget http://192.168.1.254/js/initFunctions.js
wget http://192.168.1.254/js/tabs.js
Note: Some of the other files contain code used for other models. You may have to modify some of these if your device isn't a SRW2008x

2. Patch the JavaScript files

NEW: Note that this patch just comments out part of the code that failed. Dave Hall has analysed that particular bug and suggested a fix. I''ve not implemented this.

Patch the files using this patch:

patch -p1 < srw2008-js.diff
The patch is included below for easy viewing and reference. You can cut it from this page, save it to a file and patch, but be careful as it is likely that either your browser or my web conversion will corrupt it...
Index: js/initFunctions.js
===================================================================
RCS file: /usr/local/cvsroot/scripts/privat/diverse/srw2008/js/initFunctions.js,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -u -r1.1 -r1.2
--- js/initFunctions.js	3 Jun 2009 17:06:31 -0000	1.1
+++ js/initFunctions.js	3 Jun 2009 17:07:04 -0000	1.2
@@ -29,12 +29,12 @@
 if (funcOnLoad=='getGeneralDB'){xmlToLoad='../device/generalDB.xml?Filter:(rlHostParamName="l2_num_of_out_of_band_ports")||(rlHostParamName="l2_first_out_of_band_ifIndex")||(rlHostParamName="l2_num_of_trunks")||(rlHostParamName="l2_first_trunk_ifIndex")||(rlHostParamName="l2_max_num_ports_in_trunk")||(rlHostParamName="cosParams_ingressRateLimitSupported")||(rlHostParamName="poe_supported")||(rlHostParamName="unit_max_number_of_units") || (rlHostParamName="vlanDefaultVID")||(rlHostParamName="l2_num_of_vlans")'; nextFunct='getPortDB'; nextURL='../device/portDB.xml?Filter:(ifOperStatus!=6)';}
 else if (funcOnLoad=='getPortDB'){nextFunct='getModuleDB'; nextURL='../device/moduleDB.xml';}
 else if (funcOnLoad=='getModuleDB'){nextFunct='getLAGDB'; nextURL='../device/lagDB.xml?[portsToLAGsDataTable]Filter:(ifOperStatus!=6)[LAGsDataTable]Filter:(ifOperStatus!=6)';}
-else if (funcOnLoad=='getLAGDB'){nextFunct='endOfFunc';nextURL=''};
+else if (funcOnLoad=='getLAGDB'){nextFunct='endOfFunc';nextURL=''}
 else if (funcOnLoad=='getExtraPortsDB'){nextFunct='endOfFunc';nextURL=''}
 else if (funcOnLoad=='endOfFunc')
 {
-set_ref_state('sub_tab_','hand');
-set_ref_state('tab_','hand');
+set_ref_state('sub_tab_','pointer');
+set_ref_state('tab_','pointer');
 setTimeout("importXML('getPortDB','../device/portDB.xml?Filter:(ifOperStatus!=6)')",pollingInterval);
 if(isFirstLoad==true)
 writeModel(document.getElementById("t1"));
@@ -47,7 +47,7 @@
 {
 if (window.XMLHttpRequest && window.navigator.userAgent.indexOf("MSIE")==-1)
 { xmlDoc = new XMLHttpRequest();
-addEventReadyState(xmlDoc);
+//addEventReadyState(xmlDoc);
 xmlDoc.onreadystatechange = function() { if (nextURL!=null && xmlDoc.readyState == 4) {eval( funcOnLoad+'(xmlDoc.responseXML)');importXML(nextFunct,nextURL); }};
 xmlDoc.open("GET", xmlToLoad, true);
 xmlDoc.send(null);
@@ -66,7 +66,7 @@
 }
 else{alert('Your browser can\'t handle this script');}
 }
-catch(e) { if(funcOnLoad=='getGeneralDB'){setTimeout("importXML('"+funcOnLoad+"','"+xmlToLoad+"')",20000);}
+catch(e) { alert(e.message); if(funcOnLoad=='getGeneralDB'){setTimeout("importXML('"+funcOnLoad+"','"+xmlToLoad+"')",20000);}
 else {setTimeout("importXML('getPortDB','../device/portDB.xml?Filter:(ifOperStatus!=6)')",top.pollingInterval);}
 }
 }
Index: js/tabs.js
===================================================================
RCS file: /usr/local/cvsroot/scripts/privat/diverse/srw2008/js/tabs.js,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -u -r1.1 -r1.2
--- js/tabs.js	3 Jun 2009 17:06:31 -0000	1.1
+++ js/tabs.js	3 Jun 2009 17:07:04 -0000	1.2
@@ -17,26 +17,31 @@
 if( !confirm(msg) )
 return;
 }
+/* FIXME:  Why doesn't this work, and what's the purpose?
 curTd=tbl.firstChild.firstChild.childNodes[parseInt(ths.id.substr(4))].style;
 curTd.backgroundColor="";
 if(tbl.lastChild.firstChild.childNodes[tab])tbl.lastChild.firstChild.childNodes[tab].style.backgroundColor="#000000";
+*/
 tab=i+1;
+/*
 curTd= tbl.firstChild.firstChild.childNodes[parseInt(ths.id.substr(4))].style
 curTd.backgroundColor="#6666cc";
 curTd.backgroundImage="url('')"
 tbl.lastChild.firstChild.childNodes[parseInt(ths.id.substr(4))].style.backgroundColor="#6666cc";
+*/
 idx=i;
-}
+/*}
 else
 {
 curTd=tbl.firstChild.firstChild.childNodes[i].style;
 curTd.backgroundColor="";
 curTd.backgroundImage="url('../images/img22_1.jpg')"
 tbl.lastChild.firstChild.childNodes[i].style.backgroundColor="#000000";
+*/
 }
 }
-var txt=ths.innerHTML
-document.getElementById('caption').innerHTML=txt
+var txt=ths.innerHTML;
+document.getElementById('caption').innerHTML=txt;
 removeTabs();
 Loading(idx);
 subTab=0;
@@ -272,12 +277,12 @@
 {
 for(var i=0;i<tabs.length;i++)
 {
-var tdObjHead = createElement("<TD align='center'>")
+var tdObjHead = createElement("TD")
 oHeadTr.appendChild(tdObjHead);
 }
 for(var i=0;i<tabs.length;i++)
 {
-var tdObj = createElement("<TD align='center'>")
+var tdObj = createElement("TD")
 tdObj.innerHTML ="<A name='lnk' id='tab_"+i+"' onclick=setTabset(this);>" + tabs[i].title + "</A>"
 oTabTr.appendChild(tdObj);
 }

3 a) Either: Use the patched version, using Squid

Place the fixed versions on some web server and use a redirector script to point squid there. E.g. something like

#!/usr/bin/perl
# squid redirector plugin - save as e.g. /usr/local/sbin/fix_srw2008p.pl
my %srw2008p = (
    '/js/initFunctions.js' => 'http://www.example.com/srw2008p/js/initFunctions.js',
    '/js/tabs.js'          => 'http://www.example.com/srw2008p/js/tabs.js',
    );
$|=1; # autoflush required
while (<>) {
    if (m!^http://192.168.1.254/([^? ]*)! && (my $r = $srw2008p{"/$1"})) {
	s!^http://192.168.1.254/([^? ]*)!$r!;
	print;
    } else {
	print "\n";
    }
}
Include this in squid.conf:
redirect_program /usr/local/sbin/fix_srw2008p.pl
refer to the squid manual for details.

3 b) Or: Use the patched version, using Apache

Add a new virtual server forwarding anything but requests for the modified files to the switch using mod_proxy. You'll probably want to change this definition to suit your needs wrt locations, server name etc:


<VirtualHost 127.0.0.1:80>
ServerName srw2008a.viaproxy.example.com
DocumentRoot /var/www/srw2008

<IfModule mod_proxy.c>
ProxyRequests Off
ProxyPass /js/initFunctions.js !
ProxyPass /js/tabs.js !
ProxyPass / http://192.168.1.254/
ProxyPassReverse / http://192.168.1.254/

<Proxy *>
Order deny,allow
Allow from 127.0.0.1
</Proxy>

</IfModule>

</VirtualHost>

This config assumes that

You need to enable the virtual server and ensure that mod_proxy is loaded. Refer to the apache manual for further details.

The hostname can be added to /etc/hosts if it's only going to be used by the local host (like the config example suggests):

127.0.0.1       srw2008a.viaproxy.example.com

FAQ

Why does this page look so ugly?

Because it's all about content. The main advantage is that there are no CSS related bugs. If only Cisco could do the same...

Can I email you?

Yes, please do! I'd love to know if this is useful to anyone. My address is bjorn@mork.no

Please feel free to ask any questions too. The above was written primarily as a summary to myself, and I do realise that it does presume a bit of additional knowledge. Either pre-aquired or Googled. But then again: It's only applicable to those not using Windows, so I consider it safe :-)

Can I copy and change your work

Yes, please do! In particular, if Cisco is interested in integrating the patch above, hire a web developer for a week fixing all the remaining bugs, and releasing a fixed firmware, then Go Ahead! I'll applaud and include a nice link to the fixed firmware download here instead of this page.

References

Some of this information was taken from other pages. Thanks!

http://davehall.com.au/blog/dave/2007/12/04/linksys-srw224g4-webgui-broken

explains the

     curTd = tbl.firstChild.firstChild.childNodes[tab].style;
bug and shows how it can be fixed

http://forums.linksys.com/linksys/board/message?board.id=Switches&thread.id=1473

shows how to access the cli:

     Ctrl+Z
     lcli

authenticate using *local* user/password!


Copyright 2009 Bjørn Mork