Basic set-up of a 3com 4500 managed network switch

I’m a PHP developer by trade with a strong Linux background. One thing that has been lacking from my skill set is how networking really works.

In an effort to rectify this, I bought myself a 2nd hand managed network switch from ebay. A 26 port (24 x 10/100mb + 2 x 1gb) “3com SuperStack 3 Switch 4500″.

Flashing lights and noisy fans, I feel like I’m headed in the right direction.

First things first – can I plug it into my router (with DHCP), have it get an IP address and log into the web interface?

No :(

Using nmap to sweep the subnet, that the router manages, returned no results for the known MAC address of the switch.

Even checking the router for connected devices didn’t list the known MAC address of the switch.

If I wasn’t getting into the system via the network, I would have to use the console port instead.

As I didn’t have a null modem cable to hand, and I don’t have an active machine with a d9 serial port, I grabbed something from Amazon: http://www.amazon.co.uk/gp/product/B00HUZ6OMQ (NB: does not work with this switch, keep reading)

As I’m a Linux user, I would be playing with /dev/ttyUSB0. And to use that, my user has to be in the dialout group:

sudo usermod -a -G dialout iain

Connecting to the serial console should be easy with:

byobu-screen /dev/ttyUSB0 19200

Hooked up the cable, ran the command to bring up the serial interface and switched on the switch.

This, annoyingly vertical, video shows that something happens (watch the green block skit around in the black window) but no text appears: https://www.youtube.com/watch?v=sXVYtClNDYU

Every different program I tried (screen, minicom, putty) to connect to the device all resulted in the same output.

Thanks to fellow 3com switch owner Intrbiz, I have been able to borrow a known working cable.

Hooked up between the PC and switch, ran the byobu-screen command and turned on the switch – It lives!

Now that I have a way of talking to the switch, I can configure it in a way so that I don’t need the console cable (as much).

 

Factory reset (this requires the console cable):

We need to factory reset for the following reasons:

  • remove any unknown users
  • restore the admin password to the factory default
  • remove any network configuration set-up by the previous owners
  • set-up our own network configuration

Start a console session and power on or reboot the switch.

  • Hit ctrl+b when prompted. Be quick, you don’t get long.
  • Now in the boot menu, tell the switch to ignore the saved configuration for the next reboot (option 7).
  • Reboot the switch (option 0).

Let it boot normally and wait until something like this appears:

User interface aux0 is available.
Please press ENTER.
  • Hitting enter will log you in as the admin user.
<4500>
%Jun 6 13:41:38:126 2015 4500 SHELL/5/LOGIN:- 1 - Console(aux0) in unit1 login
  • Hit enter again to put your cursor on a new line, not at the end of the debug output line. Enter “save” to save the default configuration over the configuration that was written by the previous owner.
<4500>save
The configuration will be written to the device.
Are you sure?[Y/N]y
Please input the file name(*.cfg)(To leave the existing filename 
 unchanged press the enter key):
Now saving current configuration to the device.
Saving configuration. Please wait...
......
 Unit1 save configuration flash:/ccc.cfg successfully
<4500>
%Jun 6 13:43:04:746 2015 4500 CFM/3/CFM_LOG:- 1 -Unit1 saved configuration successfully.
<4500>

It’s now safe to reboot or power cycle the switch as much as you like and it’ll have the factory default settings.

 

Assign a static IP address to the network switch (this requires the console cable):

  • Ensure that the switch has booted and then connect to the console
byobu-screen /dev/ttyUSB0 19200
[- press enter if the screen is just blank -]
<4500>
  • Enter the system view
<4500>system-view
System View: return to User View with Ctrl+Z.
[4500]
  • Switch to vlan 1
[4500]interface vlan 1
[4500-Vlan-interface1]
  • Set an IP address followed by netmask
[4500-Vlan-interface1]ip address 192.168.1.13 255.255.255.0
[4500-Vlan-interface1]
  • Set the default route for the switch
[4500-Vlan-interface1]ip route-static 0.0.0.0 0.0.0.0 192.168.1.1
[4500]
  • Return to the user view
[4500]quit
<4500>
  • Save the configuration
<4500>save
The configuration will be written to the device.
Are you sure?[Y/N]y
Please input the file name(*.cfg)(To leave the existing filename 
 unchanged press the enter key):
Now saving current configuration to the device.
Saving configuration. Please wait...
......
 Unit1 save configuration flash:/ccc.cfg successfully
<4500>

 

Enable SSH login (this requires the console cable):

  • Ensure that the switch has booted and then connect to the console
byobu-screen /dev/ttyUSB0 19200
[- press enter if the screen is just blank -]
<4500>
  • Enter the system view
<4500>system-view
System View: return to User View with Ctrl+Z.
[4500]
  • Create the public SSH key
[4500]public-key local create rsa
The range of public key size is (512 ~ 2048). 
NOTES: If the key modulus is greater than 512, 
 It will take a few minutes.
Input the bits in the modulus[default = 1024]:
Generating keys...
...............................................................................++++++
.....................................................++++++
......
[4500]
  • Configure the authentication mode
[4500]user-interface vty 0 4
[4500-ui-vty0-4]authentication-mode scheme
[4500-ui-vty0-4]
  • Enable the SSH protocol for inbound connections
[4500-ui-vty0-4]protocol inbound ssh
[4500-ui-vty0-4]
  • Exit the interface configuration and return to the system-view
[4500-ui-vty0-4]quit
[4500]
  • Create a new user for our SSH connections
[4500]local-user client001
New local user added.
[4500-luser-client001]
  • Set the user’s password
[4500-luser-client001]password simple abc4567890
Updating user password, please wait..........
[4500-luser-client001]
  • Give the user SSH access
[4500-luser-client001]service-type ssh level 3
[4500-luser-client001]
  • Exit back to the system view
[4500-luser-client001]quit
[4500]
  • Allow the user to login via SSH using their password
[4500]ssh user client001 authentication-type password
[4500]
  • Exit back to the user view
[4500]quit
<4500>
  • Save the configuration
<4500>save
The configuration will be written to the device.
Are you sure?[Y/N]y
Please input the file name(*.cfg)(To leave the existing filename 
 unchanged press the enter key):
Now saving current configuration to the device.
Saving configuration. Please wait...
......
 Unit1 save configuration flash:/ccc.cfg successfully
<4500>
  • Check that the SSH login works
snafu2 ~ $ ssh client0011@192.168.1.13
The authenticity of host '192.168.1.13 (192.168.1.13)' can't be established.
RSA key fingerprint is 6c:46:57:da:74:f3:9d:e0:80:4e:46:c1:a8:9a:d3:83.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.13' (RSA) to the list of known hosts.
client001@192.168.1.13's password:
********************************************************************************
* Copyright(c) 2004-2012 3Com Corp. and its licensors. All rights reserved. *
* Without the owner's prior written consent, *
* no decompiling or reverse-engineering shall be allowed. *
********************************************************************************
<4500>
%Apr 1 23:58:56:199 2000 4500 SHELL/5/LOGIN:- 1 - client001(192.168.1.4) in unit1 login
<4500>

 

Enable Web login (this can be done with the console cable or an SSH session to the switch):

  • Connect to the switch via the console
  • Change to the system view
<4500>system-view
System View: return to User View with Ctrl+Z.
[4500]
  • Switch to the admin user
[4500]local-user admin
[4500-luser-admin]
  • Configuration stuff
[4500-luser-admin]attribute access-limit 1
[4500-luser-admin]level 3
[4500-luser-admin]service-type telnet level 3
[4500-luser-admin]service-type lan-access
[4500-luser-admin]
  • Return to the user view
[4500-luser-admin]quit
[4500]quit
<4500>
  • Save the config changes
<4500>save
The configuration will be written to the device. 
Are you sure?[Y/N]y
Please input the file name(*.cfg)(To leave the existing filename 
 unchanged press the enter key):
Now saving current configuration to the device. 
Saving configuration. Please wait...
......
 Unit1 save configuration flash:/ccc.cfg successfully
<4500>

 

Reference

Firmware: https://h10145.www1.hp.com/downloads/SoftwareReleases.aspx?ProductNumber=JE045A

Enabling SSH logins: http://h30499.www3.hp.com/t5/Comware-Wireless-Unified-Series/How-To-Enable-SSH-In-3com-4500-Switch/td-p/2318357#.VXLVtd9jPRY

Fixing the web login: http://brittadams.com/blog/2014/08/25/unable-to-log-into-web-interface-3com-4500-switch/

Vagrant hostsupdater plugin without having to enter your sudo password

Vagrant – Great

Hosts Updater plugin – very handy

Having to enter your sudo password when the plugin edits your hosts file – really annoying.

I finally got around to addressing this on my dev system. Looking at the plugin source there are two sudo commands that we need to cater for. One to add hosts and one to remove.

Adding the following to my sudoers file worked a treat:

Cmnd_Alias VAGRANT_HOSTS_ADD = /bin/sh -c echo "*" >> /etc/hosts
Cmnd_Alias VAGRANT_HOSTS_REMOVE = /bin/sed -i -e /*/ d /etc/hosts
iain ALL=(root) NOPASSWD: VAGRANT_HOSTS_ADD, VAGRANT_HOSTS_REMOVE

There are a couple of things to address when you add this to your own sudoers file:
1. Change ‘iain’ to your own user name
2. ‘sed’ might be running from a different path. You can find out by running: which sed

Multi-screen with Ubuntu Unity

This tweet has to have been the most popular thing I have ever said. At time of posting it has gained 80 retweets, 25 favourites and many replies/questions.

Work recently bought me a new workstation, so the 1st thing I always do is to dual boot with Ubuntu.

Some might consider me an edge case user. Though as a developer, I like a rather particular set-up. That is, 3 wide screen monitors with the central one rotated 90 degrees for my IDE.

This is something that Windows gets right without having to dig about installing things. While Linux distros have always struggled (in my experience).

Because my tweet gained quite a few questions, I thought it best to reply to them here for everybody to see.

@ankitvad asks what specs. I use for Ubuntu.
Titanium Rimless Glasses from Spex4Less.com
Couldn’t resist, sorry :)

Dell Alienware X51
CPU: i7
Memory: 8GB
Graphics card: nVidia GeForce GTX 660
Storage: 1TB HDD (Windows) 120GB SSD (Linux)
Mouse: Logictech M570 trackball
OSs: Window 7 SP1, Ubuntu 12.10 64bit
Monitors: 2 x 22″ Dell, 1 x 22″ LG

All 3 monitors are connected to the one graphics card. Two by DVI and one by HDMI.

As I said, this is a working system from a fresh install without updates being applied or any 3rd party packages installed. So the default graphics driver is doing quite well these days :)

The only downside to this is that the default graphics driver is dog slow and won’t let me play games on Steam 😉 The next step will be to get the nVidia binary driver working.

Symfony2 pagination

Using Symfony2, DQL and knplabs/knp-paginator-bundle – how to get around “Cannot count query which selects two FROM components, cannot make distinction”

Chroot SFTP home dir

Example user ‘iain’

sudo mkdir -p /chroot/iain/home/iain
sudo useradd -M -d /home/iain iain
sudo passwd iain
sudo chwon iain: /chroot/iain/home/iain

sudo nano -w /etc/ssh/sshd_config
# At the end of the file, add:

Match User paypoint
    ChrootDirectory /chroot/iain
    AllowTCPForwarding no
    X11Forwarding no
    ForceCommand internal-sftp

sudo /etc/init.d/ssh restart

Making an entity repository container aware in Symfony2.1

I had a need to add ACL rules to entities at the repository level.

My biggest struggle was getting dependancy injection working.

This is what I finally came up with after a fresh mind and an instant coffee:

Adding extra fields to FOSUserBundle / SonataUserBundle

Sadly, this isn’t really documented (at time of writing).

Adding new protected variables to your User.php entity will not actually create database entries when you try to do a doctrine:schema:update.

While one still needs to have the protected variables in this entity class, along with getters and setters, the actual creation work is within UserBundle/Resources/config/doctrine/User.orm.xml

Here is an example for adding a foreign key:

<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
        http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

    <entity name="Application\Sonata\UserBundle\Entity\User" table="fos_user_user">

        <id name="id" column="id" type="integer">
            <generator strategy="AUTO" />
        </id>

        <many-to-one field="client" target-entity="Myvendor\MyBundle\Entity\Client" orphan-removal="">
            <join-columns>
                <join-column name="client_id" referenced-column-name="id" nullable="1"/>
            </join-columns>
        </many-to-one>

    </entity>

</doctrine-mapping>

Ubuntu 12.04 LTS on Bytemark VM

If, like me, you can’t wait for Ubuntu 12.04.1 to be released, you can force an upgrade of your favourite OS OS.

sudo apt-get update;
sudo do-release-upgrade -d

If you are going from the previous LTS 10.04, then the -d is important. Otherwise there would be no upgrade to offer.

The upgrade process should go smoothly enough. Except for when it comes to the kernel.

Bytemark VM’s make use of kernels that sit outside of the VM itself.

I didn’t realise this until I tried to fix syslog doing this:

Jun 26 10:30:01 banana kernel: Cannot read proc file system: 1 - Operation not permitted.
Jun 26 10:31:02 banana kernel: last message repeated 1745888 times
Jun 26 10:32:03 banana kernel: last message repeated 1722636 times
Jun 26 10:33:04 banana kernel: last message repeated 1621724 times
Jun 26 10:34:05 banana kernel: last message repeated 1761707 times

Even if you update grub, it’ll be ignored. Instead, follow the instructions here: http://www.bytemark.co.uk/support/technical_documents/kernelchange?tags=VirtualMachine

At the time of writing, I chose 3.2.0-kvm-i386-20110111 as it’s fairly close to the kernel being used by other Ubuntu 12.04 machines I have.

Your mileage may vary, but I hope this helps somebody else with the same trouble.

Updating a WordPress database with new domain details

Further to my original quick db update queries, I found the need for a more in-depth approach.

A WordPress site my father works on has weekly backups, but he wanted to see that they actually worked.
To do so, I set up a subdomain vhost on my bytemark server and set about getting the back to work with it.

One of the most annoying/lazy/strange things about WordPress is that it uses serialised arrays within database fields. This makes a simple search and replace fail if you need to do anything more than update the two fields here.

This script works for the database set-up for my father. It may require further tweaks if additional plugins store absolute paths or URLs.

It also could do with a heavy dose of refactoring, but it works for my needs at this point in time :)

<?php
$argv = (isset($argv)) ? $argv : array(1 => 'wp3/wp-config.php');
if (!isset($argv[1]))
{
	die("Please tell me where wp-config.php is\n");
}

$oldURL = 'http://oldDomainName.com';
$newURL = 'http://backup.of.my.wordpress.site.com';

$oldPath = '/home/chem9598/public_html/';
$newPath = '/var/www/backup_wordpres_site/codebase/htdocs/';

$configFile = $argv[1];
include_once($configFile);

$db = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD);

/*
* 1.1) wp_options - simple options
*/
echo "<br />1.1) wp_options - simple options: ";
$updateOptionsSql = "UPDATE wp_options SET option_value = REPLACE(option_value, '" . $oldURL . "', '" . $newURL . "') WHERE option_name IN ('siteurl', 'home');";
$updateOptionsRes = mysql_query($updateOptionsSql, $db);
if (!$updateOptionsRes)
	echo mysql_error($db) . "<br />";
else
	echo mysql_affected_rows ($db) . " rows affected<br />";


/*
* 1.2) wp_options - serialised array options
*/
echo "<br />1.2) wp_options - serialised array options: ";
$selectOptionsSql = 'SELECT * FROM wp_options WHERE option_value LIKE "%' . $oldURL . '%"';
$selectOptionsRes = mysql_query($selectOptionsSql, $db);
if (!$selectOptionsRes)
	echo mysql_error($db) . "<br />";

$options = array();
while($selectOptionsRes && $row = mysql_fetch_assoc($selectOptionsRes))
{
	$options[] = $row;
}

foreach ($options as $option)
{
	if (substr($option['option_value'], 0, 2) == 'a:')
	{
		$optionValue = unserialize($option['option_value']);

		updateArray($optionValue, $oldURL, $newURL);

		$option['option_value'] = serialize($optionValue);
		$updateOptionsSql = "UPDATE wp_options SET option_value = '" . mysql_escape_string($option['option_value']) . "' WHERE option_id = " . $option['option_id'];
		$updateOptionsRes = mysql_query($updateOptionsSql, $db);
		if (!$updateOptionsRes)
			echo mysql_error($db) . "<br />";
		else
			echo ".";
	}
}
echo "<br />";


/*
* 1.3) wp_options - file path
*/
echo "<br />1.3) wp_options - file path: ";
$selectOptionsSql = 'SELECT * FROM wp_options WHERE option_value LIKE "%' . $oldPath . '%"';
$selectOptionsRes = mysql_query($selectOptionsSql, $db);
if (!$selectOptionsRes)
	echo mysql_error($db) . "<br />";

$options = array();
while($selectOptionsRes && $row = mysql_fetch_assoc($selectOptionsRes))
{
	$options[] = $row;
}

foreach ($options as $option)
{
	if (substr($option['option_value'], 0, 2) == 'a:')
	{
		$optionValue = unserialize($option['option_value']);

		updateArray($optionValue, $oldPath, $newPath);

		$option['option_value'] = serialize($optionValue);
		$updateOptionsSql = "UPDATE wp_options SET option_value = '" . mysql_escape_string($option['option_value']) . "' WHERE option_id = " . $option['option_id'];
		$updateOptionsRes = mysql_query($updateOptionsSql, $db);
		if (!$updateOptionsRes)
			echo mysql_error($db) . "<br />";
		else
			echo ".";
	}
}
echo "<br />";


/*
* 2.1) wp_posts - guid
*/
echo "<br />2.1) wp_posts - guid: ";
$updatePostsSql = "UPDATE wp_posts SET guid = REPLACE(guid, '" . $oldURL . "', '" . $newURL . "');";
$updatePostsRes = mysql_query($updatePostsSql, $db);
if (!$updatePostsRes)
	echo mysql_error($db) . "<br />";
else
	echo mysql_affected_rows ($db) . " rows affected<br />";


/*
* 2.2) wp_posts - post_content
*/
echo "<br />2.2) wp_posts - post_content: ";
$updatePostsSql = "UPDATE wp_posts SET post_content = REPLACE(post_content, '" . $oldURL . "', '" . $newURL . "');";
$updatePostsRes = mysql_query($updatePostsSql, $db);
if (!$updatePostsRes)
	echo mysql_error($db) . "<br />";
else
	echo mysql_affected_rows ($db) . " rows affected<br />";


function debug($var)
{
	echo "<pre>";
	print_r($var);
	echo "</pre>";
}

function updateArray(&$array, $find, $replace)
{
	foreach ($array as $key => &$value)
	{
		if (is_array($value))
		{
			updateArray($value, $find, $replace);
		}
		else
		{
			$array[$key] = str_replace($find, $replace, $value);
		}
	}
}

PPTP tunnels and if-up.d

Current project requires a couple of VPN tunnels to be set up. An IPsec and a PPTP.
The IPsec will wait for another day, the PPTP is set up and ready to go.
One thing that wasn’t quite right with the tunnel though, is the static route created by PPTP missed out a large chunk of the server’s network.

Starting the tunnel sets up the routing rule of 192.168.100.111 to be sent to the tunnel.

This meant that if I wanted to get to 100.10, it wasn’t being sent.

The way around this was to add a new route: route add -host 192.168.100.10 dev ppp0

Works great from the CLI, nothing happens when added to /etc/network/interfaces or /etc/network/if-up.d/foobar.

Found out (trial and error) that it was trying to add the route as soon as the tunnel was created. This doesn’t work as the tunnel takes a few seconds to wake up.

Work around was to add a ‘sleep 5′ to /etc/network/if-up.d/foobar before the route command line.

Creating race conditions isn’t nice, but it works :(