Firewalls guard the perimeter — but most real attacks start from a wall socket in the lobby. Port security, DHCP snooping, dynamic ARP inspection, and BPDU guard turn dumb access ports into a defended edge. This is the layer-2 hardening most networks skip.
Layer 2 is trusting by design. A switch learns MAC addresses from whoever sends them, hands DHCP to whoever asks, and believes any ARP reply it hears. Every one of those courtesies is an attack: MAC flooding to overflow the CAM table and force the switch to broadcast private traffic, a rogue DHCP server to become everyone's default gateway, ARP spoofing to man-in-the-middle a subnet, and a rogue switch to hijack the spanning-tree topology. None of these need credentials — just an ethernet socket.
The defence is a set of four features that ship on every Catalyst and are off by default: port security, DHCP snooping, dynamic ARP inspection, and BPDU guard. Each takes minutes to configure. Together they mean a hostile device plugged into your lobby gets a dead port instead of your accounting VLAN. This is where our pentest findings and our network engineering meet — these four are the fixes we end up recommending most.
01
Limit each access port to a known number of MAC addresses — usually one or two — and decide what happens when an extra one shows up. This kills MAC flooding and casual device swapping in one stroke.
SW1(config)# interface range GigabitEthernet0/2 - 24 SW1(config-if-range)# switchport mode access # required — not on trunks/dynamic SW1(config-if-range)# switchport port-security SW1(config-if-range)# switchport port-security maximum 2 # PC + IP phone SW1(config-if-range)# switchport port-security mac-address sticky SW1(config-if-range)# switchport port-security violation restrict SW1(config-if-range)# end # "sticky" learns the first MACs seen and writes them into running-config — # save with "wr" and they persist. No typing MAC addresses by hand. SW1# show port-security interface gi0/2 Port Security : Enabled Violation Mode : Restrict Maximum MAC Addresses : 2 Sticky MAC Addresses : 1 Security Violation Count : 0
| Mode | On violation |
|---|---|
| protect | Silently drops frames from unknown MACs. No log, no counter — you'll never know it happened. Avoid. |
| restrict | Drops, increments the violation counter, sends a syslog/SNMP trap. Visibility without an outage. |
| shutdown (default) | Puts the whole port in err-disabled — hard down until recovered. Maximum security, maximum help-desk calls. |
With the default shutdown mode, one violation kills the port until someone runs shutdown / no shutdown on it. A cleaner pattern for real offices: use restrict on user ports, or enable automatic recovery so a violation costs minutes instead of a site visit: errdisable recovery cause psecure-violation and errdisable recovery interval 300. Check what's dead and why with show interfaces status err-disabled.
02
A laptop running a DHCP server — malicious or just a helpful home router someone plugged in — can hand out itself as everyone's gateway. DHCP snooping declares which ports may answer DHCP: the uplink. Everything else may only ask.
# 1. Turn snooping on globally AND per VLAN SW1(config)# ip dhcp snooping SW1(config)# ip dhcp snooping vlan 10,20 # 2. Mark the uplink (toward the real DHCP server) as trusted SW1(config)# interface GigabitEthernet0/1 SW1(config-if)# ip dhcp snooping trust SW1(config-if)# exit # 3. Rate-limit DHCP requests on user ports (DoS protection) SW1(config)# interface range GigabitEthernet0/2 - 24 SW1(config-if-range)# ip dhcp snooping limit rate 10 SW1(config-if-range)# end # Server OFFERs arriving on untrusted ports are now dropped cold. # Bonus: the switch builds a binding table — who has which IP on which port: SW1# show ip dhcp snooping binding MacAddress IpAddress Lease(sec) Type VLAN Interface 00:1A:2B:3C:4D:5E 192.168.10.21 43021 dhcp-snooping 10 Gi0/4
Enable snooping and forget ip dhcp snooping trust on the uplink, and the switch drops the legitimate server's OFFERs too — the whole VLAN stops getting addresses and it looks like a DHCP outage. Order of operations matters: trust the uplink first, then enable snooping on the VLANs. Also: if your DHCP relay sits beyond another switch, every inter-switch link on the path to the server needs to be trusted.
03
ARP spoofing — answering "who has the gateway IP?" with your own MAC — is still the easiest LAN man-in-the-middle. DAI checks every ARP packet on untrusted ports against the DHCP snooping binding table and drops the lies.
# Requires DHCP snooping (section 02) — DAI validates against its bindings SW1(config)# ip arp inspection vlan 10,20 # Trust the same inter-switch/uplink ports as snooping SW1(config)# interface GigabitEthernet0/1 SW1(config-if)# ip arp inspection trust SW1(config-if)# end # Watch it work: spoofed ARP on an untrusted port is dropped and logged SW1# show ip arp inspection statistics vlan 10 Vlan Forwarded Dropped DHCP Drops ACL Drops ---- --------- ------- ---------- --------- 10 1420 12 12 0
DAI trusts the DHCP snooping table — so a host with a static IP has no binding entry, and every ARP it sends looks like a spoof and is dropped. It falls off the network the moment DAI goes live. For printers, servers, and cameras with static addresses, either add static bindings (ip source binding <mac> vlan <id> <ip> interface <port>) or move them to DHCP reservations — reservations are cleaner and self-documenting.
04
Access ports talk to hosts, and hosts don't speak spanning tree. If a BPDU arrives on an access port, someone plugged in a switch — accidental loop or deliberate topology hijack. BPDU guard kills the port instantly.
# Per interface: SW1(config)# interface range GigabitEthernet0/2 - 24 SW1(config-if-range)# spanning-tree portfast # skip listening/learning for hosts SW1(config-if-range)# spanning-tree bpduguard enable SW1(config-if-range)# exit # Or the global shortcut — every PortFast port gets BPDU guard automatically: SW1(config)# spanning-tree portfast bpduguard default SW1(config)# end # A BPDU arriving on Gi0/7 now err-disables it on the spot: %SPANTREE-2-BLOCK_BPDUGUARD: Received BPDU on port Gi0/7 with BPDU Guard enabled. Disabling port.
PortFast and BPDU guard are a natural pair: PortFast makes host ports come up instantly (no 30-second spanning-tree wait for DHCP-hungry PCs), and BPDU guard is the insurance that nobody abuses a PortFast port to inject topology changes. Spanning tree itself — root bridges, and why a port might be blocking — is the next post in this series.
05
The cheapest hardening there is: a port nobody uses should be shut down and parked in a dead VLAN. An attacker can't negotiate with an interface that's administratively down.
# A VLAN that routes nowhere and is allowed on no trunk SW1(config)# vlan 999 SW1(config-vlan)# name PARKING SW1(config-vlan)# exit # Find what's unused (notconnect), then park it SW1# show interfaces status | include notconnect SW1(config)# interface range GigabitEthernet0/13 - 24 SW1(config-if-range)# switchport mode access SW1(config-if-range)# switchport access vlan 999 SW1(config-if-range)# shutdown SW1(config-if-range)# end # Bringing a port into service later is deliberate: assign the right VLAN, # no shutdown, document it. Exactly how it should be.
On internal engagements, the first thing tested at the wall socket is, in order: do we get a DHCP lease (no snooping?), can we ARP-spoof the gateway (no DAI?), does the port take a second MAC (no port security?), and does it accept our BPDUs (no BPDU guard?). The four features in this post close exactly that checklist, and the parking VLAN removes the "found a live socket in an empty office" freebie. This is the least glamorous security work there is, and some of the most effective.
06
Six read-only commands audit the whole posture. Run them on any switch you inherit — the blanks tell you what's missing.
| Command | Shows |
|---|---|
| show port-security | Per-port security state, MAC counts, violation counters. |
| show port-security address | The learned/sticky MAC table. |
| show ip dhcp snooping | Snooping state per VLAN, trusted ports, rate limits. |
| show ip dhcp snooping binding | The IP↔MAC↔port truth table — also great for tracking devices. |
| show ip arp inspection | DAI state and drop statistics per VLAN. |
| show interfaces status err-disabled | Ports killed by a guard, and which feature killed them. |
| show spanning-tree summary | Confirms PortFast/BPDU-guard defaults are actually on. |
07
RouterOS bridges grew the same protections; the names are just less standardized. If you run mixed access layers, this is the translation.
| MikroTik / RouterOS | Cisco IOS |
|---|---|
| bridge port learn=no + static hosts | Port security with static/sticky MACs |
| /interface bridge settings dhcp-snooping | ip dhcp snooping (+ trusted=yes ↔ trust) |
| bridge port trusted=yes | ip dhcp snooping trust |
| ARP mode reply-only + DHCP add-arp | Dynamic ARP inspection (validated against leases) |
| bridge port bpdu-guard=yes | spanning-tree bpduguard enable |
| Disabled port + isolated VLAN | shutdown + parking VLAN 999 |
Takeaways
spanning-tree portfast bpduguard default covers future ports too.shutdown, done. Re-enabling becomes a deliberate, documented act.show interfaces status err-disabled tells you which one; configure errdisable recovery where a 5-minute self-heal beats a truck roll.NOCTIS audits and hardens switch infrastructures for offices, hotels, and SMBs in Crete — the same L2 checks we run as attackers on pentests, applied as defences on your gear, Cisco or MikroTik. You get the findings and the fixes.
Book a Discovery Call →