1. Portsecurity
Portsecurity is a feature that can limit the MAC adresses that are allowed on a physical port. A violation of the port security occurs if
-
the number if MAC adresses on a port is reached an the MAC id is different from the allowed list
-
an allowed MAC id is connected to a differnt port in the same VLAN
Port security is seen as a deterrent for people that want to connect rogue devices to your network.
You can allow a single MAC to connect, or allow multiple MAC IDs. The maximum number of MAC IDs depends on the switch model and IOS version.
There are 3 modes for determining the allowed MAC IDs:
-
Dynamic: The switch automatically learns the MAC addresses of devices that connect to the port. The switch automatically learns the MAC addresses of devices that connect to the port. When the switch restarts or the port goes down, these dynamically learned addresses are lost.
-
Static or fixed: You manually configure the allowed MAC addresses on the switchport using commands. These statically configured addresses are stored in the switch's configuration file. They remain even after a switch restart.
-
The switch dynamically learns MAC addresses, like in the dynamic method. Then, it "sticks" those learned addresses, adding them to the running configuration. If you save the running configuration to the startup configuration, these sticky addresses will persist across switch restarts.
Port security depends on MAC-IDs. It is therefore vulnerable for MAC ID spoofing, where you copy the MAC ID from an allowed device to your own adapter. On Linux, this is trivial to do.
GNS3, which I use for most simulations, does not provide a switch that supports portsecurity. Therefore, this is not a simulated lab, but a real switch was used.
2. The network
2.1. The switch
Because GNS3 does not support port security, the test needs to be done with physical hardware.

The switch is a Cisco Catalyst 3560 with IOS 12.2, because that is what I got. most cisco switches will support port security, so it doesn't really matter. The switch has a DHCP server and all ports are assigned to VLAN 10. Syslog is redirected to the management server
The most relevant parts of the general config are:
ip dhcp excluded-address 192.168.10.1 192.168.10.10 ip dhcp excluded-address 192.168.10.51 192.168.10.255 ! ip dhcp pool CLIENT network 192.168.10.0 255.255.255.0 ! spanning-tree mode pvst spanning-tree portfast default spanning-tree extend system-id vlan 10 ! interface Vlan10 ip address 192.168.10.1 255.255.255.0 ! logging 192.168.10.2
2.2. The management server
The management server is a raspberry pi. Besides the reception of syslog, it is used to launch scripts that automate the tedious cisco command line use.
The pi uses rsyslogd. Standard, it does not receive syslog from other servers. In /etc/rsyslog.conf you need to add:
$ModLoad imudp $UDPServerRun 514 # provides TCP syslog reception $ModLoad imtcp $InputTCPServerRun 514
In the catch-all section, I added local7 to /var/log/messages because cisco logs on local7:
*.=info;*.=notice;*.=warn;\ auth,authpriv.none;\ cron,daemon.none;\ local7.*;\ mail,news.none -/var/log/messages
2.3. The rest
For computer1 and computer2, you can use anything that has an ethernet NIC. The admin workstation needs to be able to ssh into the pi.
3. Port security
3.1. Enabling portsecurity
In our switch, we set all ports on VLAN 10. For most interfaces, we set:
interface FastEthernet0/1 switchport access vlan 10 switchport mode access switchport port-security switchport port-security mac-address sticky
For most interfaces; not for all:
-
I noticed some strange behaviour when the Raspberry Pi boots. It triggers a port security violation, but only sometimes.
-
I do not have a console cable, so I left port 23 and port 24 without port security to prevent locking myself out.
Let's examine the configuration.
switchport access vlan 10
Port security in this older versions can onl be applied on access ports.
switchport port-security switchport port-security mac-address sticky
This defines the port security. Here, we have chosen to use sticky. You have the folowing options:
type
|
command
|
explanation
|
fixed
|
switchport port-security mac-address xxxx.yyyy.zzzz
|
Puts a fixed MAC ID on the port
|
sticky
|
switchport port-security mac-address sticky
|
Allows MAC ID to be dynamically learned and stores the MAC ID in the config
|
dynamic
|
(no additional command)
|
Allows MAC ID to be dynamically learned but does not store the MAC ID in the config
|
In general, sticky will be the preferred option. If you have a very good administration of devices, MAC IDs and cabling, fixed could be an option. Dyanamic is the default.
There are some additional options, for which I have chosen the default.
switchport port-security maximum 1
Defines the maximum number of MAC IDs allowed on the port. The default is 1.
switchport port-security violation {protect | restrict | shutdown}
Default is shutdown; this means that if a port has a vioaltion, it will be closed. Options are:
protect
|
Drops packets with unknown source addresses until you remove a sufficient number of secure MAC addresses to drop below the maximum value.
|
restrict
|
Drops packets with unknown source addresses until you remove a sufficient number of secure MAC addresses to drop below the maximum value and causes the SecurityViolation counter to increment.
|
shutdown
|
Puts the interface into the error-disabled state immediately and sends an SNMP trap notification.
|
You can also put some aging parameters on the port security. When the aging type is configured with the absolute keyword, all the dynamically learned secure addresses age out when the aging time expires. When the aging type is configured with the inactivity keyword, the aging time defines the period of inactivity after which all the dynamically learned secure addresses age out. I have not tried this.
3.2. And testing it...
I have tested two scenario's with mac address sticky.
3.2.1. Abusing the port and restoring the original situation
In this scenario, we removed one of the fixed computers and attached the rogue laptop. If the laptop is blocked, we put back the original computer. This is our original situation (an extract from sh run for the two interfaces):
interface FastEthernet0/1 switchport access vlan 10 switchport mode access switchport port-security switchport port-security mac-address sticky 0080.6494.adba interface FastEthernet0/2 switchport access vlan 10 switchport mode access switchport port-security switchport port-security mac-address sticky 0080.6494.b208
The two MAC adresses are dynamically learned.
So now we put our rogue laptop on the switch. The port will be blocked and in our syslog we see:
Oct 3 16:10:09 192.168.10.1 311: 08:51:11: %PM-4-ERR_DISABLE: psecure-violation error detected on Fa0/1, putting Fa0/1 in err-disable state Oct 3 16:10:10 192.168.10.1 312: 08:51:11: %PORT_SECURITY-2-PSECURE_VIOLATION: Security violation occurred, caused by MAC address 847b.eb43.c06d on port FastEthernet0/1.
Puting back the cable in the original computer will still block any trafic; the port is still shut. To get things working again, we have to issue:
config t int fa0/1 shut no shut end
Which will result in the following syslog:
Oct 3 13:11:41 192.168.10.1 182: 05:52:42: %SYS-5-CONFIG_I: Configured from console by cisco on vty0 (192.168.10.13) Oct 3 13:12:31 192.168.10.1 183: 05:53:31: %LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet0/1, changed state to down Oct 3 13:12:32 192.168.10.1 184: 05:53:32: %LINK-3-UPDOWN: Interface FastEthernet0/1, changed state to down Oct 3 13:12:36 192.168.10.1 185: 05:53:37: %LINK-3-UPDOWN: Interface FastEthernet0/1, changed state to up Oct 3 13:12:36 192.168.10.1 186: 05:53:38: %LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet0/1, changed state to up
Now the port is back up after some manual intervention.
3.2.2. Put a new device in
This time, we do not put in a rogue laptop, but a replacement device. Attaching the device will ofcourse lead to a port security violation:
Oct 3 23:49:53 192.168.10.1 678: 3d01h: %PM-4-ERR_DISABLE: psecure-violation error detected on Fa0/2, putting Fa0/2 in err-disable state Oct 3 23:49:54 192.168.10.1 679: 3d01h: %PORT_SECURITY-2-PSECURE_VIOLATION: Security violation occurred, caused by MAC address 847b.eb43.c06d on port FastEthernet0/2.
This time, we not only need to reset the port, but will also need to remove the sticky MAC ID to allow a new one to be learned:
config t int fa0/2 shut no switchport port-security mac-address sticky 0080.6494.b208 no shut end
And, as expected, the new MAC ID is learned and the port comes back up.
3.3. Some problems I encountered
If the MAC ID of computer_1 is allowed on Fa0/1, connecting that computer to a new port (for example Fa0/5) will cause a port security violation. In other words: if your computer connects to a specific port, you cannot just connect it to another port. This means that you need to keep an administration of which port has which MAC ID.
For some inexplicable reason, the portsecurity sticky did not learn the MAC ID correctly. A reload of the switch did nothing to improve the situation. I had to remove all cables, remove all MAC IDs and disable/re-enable port security to get everything working again.
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<br>int fa0/port<br>shut<br>end
|
remove_mac_on_port_sticky.exp
|
remove a sticky mac from a port
|
conf t<br> int fa0/port<br> shut<br> no switchport port-security mac-address sticky mac<br> no shut
|
reset_port.xpct
|
reset a port
|
conf t<br>int fa0/port<br>shut<br>no shut<br>end
|
show_port.xpct
|
show settings
|
sh run interface fa0/port<br>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.