4. Scripts

4.1. Intro

When I have to do things twice, I get bored. When I have to do it three times, I create a script to automate it.

My switch still uses telnet (yes I know) and I used expect to interface with my switch.

The following template will be used.
#!/usr/bin/expect
set timeout 60
set ip 192.168.10.1
set user cisco
set password secret
spawn telnet $ip
expect "ername:" 
send "$user\r"
expect "assword: "
send "$password\r"
expect "DEMO" 
send "enable\r"
expect "assword: "
send "$password\r"
expect "DEMO"
send -- "exit\r"

Because I have a test of short duration and becaise I am on a stand-alone network without connection to the rest of the world, I can put the password in my script. In a real life situation that would be unthinkable.

the DEMO is a part of the prompt for the switch. If you are very precise, you could put in the exact prompt that will be presented ( DEMO> or DEMO# in enable mode, and so on for the different config modes. That will make the scripts better, but this will do for our test.

4.2. Resetting scripts with expect

If a port needs to be reset, you can log in to the switch, do enable and conf t and type all the IOS commands by hand. Or you could use an expect script.
#!/usr/bin/expect
set port [lindex $argv 0]
set mac [lindex $argv 1]
set timeout 60
set ip 192.168.10.1
set user cisco
set password secret
spawn telnet $ip
expect "ername:" 
send "$user\r"
expect "assword: "
send "$password\r"
expect "DEMO>" 
send "enable\r"
expect "assword: "
send "$password\r"
expect "DEMO"
send "conf t\r"
expect "DEMO"
send "int fa0/$port\r"
expect "DEMO"
send "shut\r"
expect "DEMO"
send "end\r"
expect "DEMO"
send "conf t\r"
expect "DEMO"
send "int fa0/$port\r"
expect "DEMO"
send "no shut\r"
expect "DEMO"
send "end\r"
expect "DEMO"
send -- "exit\r"

It should not be dificult to create scripts for the main transactions. I created expect scripts for the following.
script
purpose
commands
down_port.xpct
make a port admin down
conf t
int fa0/port
shut
end
remove mac on port sticky.exp
remove a sticky mac from a port
conf t
int fa0/port
shut
no switchport port-security mac-address sticky mac
no shut
reset_port.xpct
reset a port
conf t
int fa0/port
shut
no shut
end
show_port.xpct
show settings
sh run interface fa0/port
sh port-security interface fa0/port

4.3. A demo menu

This test was part of a demonstration of how port security works. I used the following script to hide the nitty gritty details from the audience.
#!/bin/bash
TMP=/tmp/rgh.$$
sudo tail -f /var/log/messages | grep PSECURE_VIOLATION &
tokill=$!

The syslog messages about port security violations are written over the menu. This shows that we actually see an alert when something is happening.
disp(){
	printf "%4.4s  %16.16s  %16.16s  %12.12s\n" port allowed last_seen status
	for port in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
		expect show_port.xpct $port | sed 's/\r//' > $TMP
		mac=`awk '/switchport port-security mac-address.*[0-9a-f]+\.[0-9a-f]/{print $NF}' $TMP`
		lastseen=`sed -n 's/Last Source Address:Vlan *: *//p' $TMP | sed 's/:1*0//'`
		status=`sed -n 's/Port Status *: *//p' $TMP`
		nstat='unknown'
		case a$status in
		(aSecure-up)	nstat='UP' ;;
		(aSecure-down)	nstat='No device' ;;
		(aSecure-shutdown)
				if [ "$mac" = "" ] ; then
					nstat='No device'
				else
					nstat="Violation"
				fi
				;;
		esac
		if grep '^ *shutdown' $TMP > /dev/null ; then 
			nstat='adm down'
		fi
		printf "%4.4s  %16.16s  %16.16s  %12.12s\n" "$port" "$mac" "$lastseen" "$nstat"
	done
	rm -f $TMP
}

The goal of this function is to provide a display of what is actually happening. It shows a table that is easier to interpret than the standard IOS output.
rmmac(){
	port=$1
	expect show_port.xpct $port | sed 's/\r//' > $TMP
	mac=`awk '/switchport port-security mac-address.*[0-9a-f]+\.[0-9a-f]/{print $NF}' $TMP`
	if [ "$mac" != "" ] ; then
		expect remove_mac_on_port_sticky.exp $port $mac
	fi
}

This function removes a MAC ID from a port. The function first looks which MAC ID is available on the port.
reset(){
	port=$1
	expect reset_port.xpct $port
}
down(){
	port=$1
	expect down_port.xpct $port
}

These functions reset a port (shut, no shut) or just shut the port.
quit=no
while [ $quit = no ] ; do
	clear
	disp
	echo "d for shut down a port"
	echo "n for new MAC id"
	echo "r for reset port"
	echo "q for quit"
	echo "enter for refresh"
	read line
	case a$line in
	(ar)	echo -n "Port nummer : "
		read line
		reset $line
		;;
	(ad)	echo -n "Port nummer : "
		read line
		down $line
		;;
	(an)	echo -n "Port nummer : "
		read line
		rmmac $line
		;;
	(aq)	quit=yes
		;;
	esac
done
sudo pkill tail
exit

The main loop presents a simple menu.