Configuring IPv6 First-Hop Security (RA Guard, IPv6 Snooping)
In this lab we're going to implement IPv6 FHS with Router Advertisement Guard and IPv6 Snooping and in the following post I'll show how to configure DHCPv6 Guard. We configure IPv6 FHS on the access switch between the end hosts and the routers in the segment. In this demonstration I use the IOU L2 image on SW1, because according to my experience the IOSv_L2 image doesn't support any IPv6 FHS features, for the end hosts and routers I'm going to use the regular IOSv image. Let's configure RA Guard first with the following topology:

RA Guard
In IPv6 end hosts doesn't get their default gateway with manual configuration or with DHCP messages. Their going to use NDP and send Router Solicitation messages to the FF02::2 multicast address, and routers send Router Advertisement in response and they also send it periodically to the FF02::1 multicast address. By default nothing stops the Attacker to spoof the router and send RA messages to the hosts and accomplish a MiTM attack. If we configure RA Guard on the switch, the switch will block RA messages from the Attacker and the end hosts will never receive these RA messages. We'll need two RA Guard policies on the switch: one for the router (from which we'll accept the RA messages) and one for the end host (from which we'll drop the RA messages):
SW1(config)#ipv6 nd raguard policy HOST
SW1(config-nd-raguard)#device-role ?
host Attached device is a host (default)
monitor Attached device is a monitor/sniffer
router Attached device is a router
switch Attached device is a switch
SW1(config-nd-raguard)#device-role host
This policy will be used for the end hosts, we don't really need to configure the device role explicitly since the 'host' is the default. Now let's configure the policy for the router:
SW1(config)#ipv6 prefix-list RA_PREFIX permit 2001:db8:1234::/64
SW1(config)#ipv6 nd raguard policy ROUTER
SW1(config-nd-raguard)#device-role router
First I created a prefix-list, we can also use this for filtering if the end hosts use SLAAC: if the routers advertise other prefixes than the configured, the switch drops their RA messages.
SW1(config-nd-raguard)#?
IPv6 RA guard policy configuration mode:
default Set a command to its defaults
device-role Sets the role of the device attached to the port
exit Exit from RA guard policy configuration mode
hop-limit Enable verification of the advertised Hop count limit
managed-config-flag Enable verification of the advertised M flag
match Match a particular prefix-list or access-list
no Negate a command or set its defaults
other-config-flag Enable verification of the advertised O flag
router-preference Enable verification of the advertised Router Preference
flag
trusted-port Setup trusted port
SW1(config-nd-raguard)#match ra prefix-list RA_PREFIX
SW1(config-nd-raguard)#router-preference maximum medium
We also have many other options to match on e.g. the managed/other config flag (this determines whether we use SLAAC or DHCP for address information), or we can set a maximum preference value. I applied the prefix-list with a 'match' statement that I configured before, and I also set the max router preference value to medium, so RA messages with high precedence will be dropped. Finally let's apply the policies:
SW1(config)#vlan configuration 1
SW1(config-vlan-config)#ipv6 nd raguard attach-policy HOST
SW1(config)#int e0/0
SW1(config-if)#ipv6 nd raguard attach-policy ROUTER
I applied the 'HOST' policy for the whole VLAN 1 (every device is in VLAN 1 in this topology), and the the 'ROUTER' policy to the interface E0/0. Interface configurations are more specific, so the 'ROUTER' policy overwrites the 'HOST' policy on E0/0. That's all we need to configure on the switch. Finally for verification I turn on the following debugs on SW1:
SW1#debug ipv6 nd
SW1#debug ipv6 snooping raguard
Now let's configure the router:
ROUTER_R1(config)#ipv6 unicast-routing
ROUTER_R1(config)#int g0/0
ROUTER_R1(config-if)#ipv6 addr fe80::1 link-local
ROUTER_R1(config-if)#ipv6 addr 2001:db8:1234::1/64
ROUTER_R1(config-if)#no shut
The config of the router is very straightforward: I assigned a custom link-local address so that it'll be easier to troubleshoot the RA messages and I enabled ipv6 unicast-routing
. By doing this the router will now respond to the RS messages and advertise itself as the "default gateway" and also advertise the IPv6 prefix configured on its G0/0 interface. By default the router sends the RA messages unsolicited and periodically, we can already see that the switch forwards these messages to the end hosts:
SW1#
*Jun 25 11:06:42.364: SISF[RAG]: Et0/0 vlan 1 RA received by RA guard on Et0/0 from FE80::1
*Jun 25 11:06:42.364: SISF[RAG]: Et0/0 vlan 1 option 1 : ND_OPT_SOURCE_LINKADDR
*Jun 25 11:06:42.364: SISF[RAG]: Et0/0 vlan 1 option 3 : ND_OPT_PREFIX_INFORMATION
*Jun 25 11:06:42.364: SISF[RAG]: Et0/0 vlan 1 option 5 : ND_OPT_MTU
*Jun 25 11:06:42.364: SISF[RAG]: Et0/0 vlan 1 RA with prefix option 2001:DB8:1234:: len 64
*Jun 25 11:06:42.364: SISF[RAG]: Et0/0 vlan 1 Prefix-list RA_PREFIX permit explicitly RA prefix address 2001:DB8:1234::
Let's configure HOST 3 to obtain its IPv6 address using SLAAC:
HOST3(config)#int g0/0
HOST3(config-if)#ipv6 addr fe80::3 link-local
HOST3(config-if)#ipv6 addr autoconfig
HOST3(config-if)#no shut
By doing this HOST 3 sends RS to the FF02::2 multicast address, and the router sends a RA in response:
*Jun 25 11:08:24.997: SISF[RAG]: Et0/2 vlan 1 RS received by RA guard on Et0/2 from FE80::3
*Jun 25 11:08:24.997: SISF[RAG]: Et0/2 vlan 1 option 1 : ND_OPT_SOURCE_LINKADDR
*Jun 25 11:08:24.997: SISF[RAG]: Et0/2 vlan 1 Flood the RS
*Jun 25 11:08:24.999: SISF[RAG]: Et0/0 vlan 1 RA received by RA guard on Et0/0 from FE80::1
*Jun 25 11:08:24.999: SISF[RAG]: Et0/0 vlan 1 option 1 : ND_OPT_SOURCE_LINKADDR
*Jun 25 11:08:24.999: SISF[RAG]: Et0/0 vlan 1 option 3 : ND_OPT_PREFIX_INFORMATION
*Jun 25 11:08:25.000: SISF[RAG]: Et0/0 vlan 1 option 5 : ND_OPT_MTU
*Jun 25 11:08:25.000: SISF[RAG]: Et0/0 vlan 1 RA with prefix option 2001:DB8:1234:: len 64
As we can see the switch forwarded the RA successfully, so HOST 3 could obtain his IPv6 address using SLAAC. Now let's demonstrate what happens if the Attacker starts sending his RA messages to spoof the legitimate router:
ATTACKER(config)#ipv6 unicast-routing
ATTACKER(config)#int g0/0
ATTACKER(config-if)#ipv6 addr fe80::2 link-local
ATTACKER(config-if)#ipv6 addr 2001:db8:bad::2/64
I configured the Attacker the same way as the legitimate router, using the ipv6 unicast-router
command, it starts sending unsolicited RA messages. The switch detects it and drops these RA messages, the end hosts never get them:
*Jun 25 11:13:03.057: SISF[RAG]: Et0/1 vlan 1 RA received by RA guard on Et0/1 from FE80::2
*Jun 25 11:13:03.057: SISF[RAG]: Et0/1 vlan 1 option 1 : ND_OPT_SOURCE_LINKADDR
*Jun 25 11:13:03.057: SISF[RAG]: Et0/1 vlan 1 option 3 : ND_OPT_PREFIX_INFORMATION
*Jun 25 11:13:03.057: SISF[RAG]: Et0/1 vlan 1 option 5 : ND_OPT_MTU
*Jun 25 11:13:03.057: SISF[RAG]: Et0/1 vlan 1 !Not a router port: all router messages disallowed
*Jun 25 11:13:03.057: SISF[RAG]: Et0/1 vlan 1 ! DROP ROUTER-ADVERT src FE80::2 dst FF02::1 reason = 3
The switch detected that it received an RA message on a port which was configured for host devices, and it drops the RA message, the end hosts never get these RA massages.
Now let's change the prefix on the legitimate router:
ROUTER_R1(config-if)#no ipv6 addr 2001:db8:1234::1/64
ROUTER_R1(config-if)#ipv6 addr 2001:db8:bad0::1/64
According to the policy which we've just configured switch should drop these RA messages advertising the 2001:DB8:BAD0::/64 prefix as well: *Jun 25 11:15:59.393: SISF[RAG]: Et0/0 vlan 1 RA received by RA guard on Et0/0 from FE80::1
*Jun 25 11:15:59.393: SISF[RAG]: Et0/0 vlan 1 option 1 : ND_OPT_SOURCE_LINKADDR
*Jun 25 11:15:59.393: SISF[RAG]: Et0/0 vlan 1 option 3 : ND_OPT_PREFIX_INFORMATION
*Jun 25 11:15:59.393: SISF[RAG]: Et0/0 vlan 1 option 5 : ND_OPT_MTU
*Jun 25 11:15:59.393: SISF[RAG]: Et0/0 vlan 1 RA with prefix option 2001:DB8:BAD0:: len 64
*Jun 25 11:15:59.393: SISF[RAG]: Et0/0 vlan 1 Prefix-list RA_PREFIX deny implicitly RA prefix address 2001:DB8:BAD0::
*Jun 25 11:15:59.393: SISF[RAG]: Et0/0 vlan 1 ! DROP ROUTER-ADVERT src FE80::1 dst FF02::1 reason = 5
We can clearly see the reason in the debug messages: the prefix in the RA messages doesn't match the prefix which we've configured with the RA_PREFIX prefix-list. Let's test one more thing: I changed the preference in the RA messages to high:
ROUTER_R1(config-if)#ipv6 nd router-preference high

In the policy we've configured for the router, 'medium' is the highest preference allowed in the RA messages, so the switch drops these messages as well:
*Jun 25 11:17:01.572: SISF[RAG]: Et0/0 vlan 1 RA received by RA guard on Et0/0 from FE80::1
*Jun 25 11:17:01.572: SISF[RAG]: Et0/0 vlan 1 option 1 : ND_OPT_SOURCE_LINKADDR
*Jun 25 11:17:01.572: SISF[RAG]: Et0/0 vlan 1 option 3 : ND_OPT_PREFIX_INFORMATION
*Jun 25 11:17:01.572: SISF[RAG]: Et0/0 vlan 1 option 5 : ND_OPT_MTU
*Jun 25 11:17:01.572: SISF[RAG]: Et0/0 vlan 1 !Advertised default router-preference high is higher than the configured value
*Jun 25 11:17:01.572: SISF[RAG]: Et0/0 vlan 1 ! DROP ROUTER-ADVERT src FE80::1 dst FF02::1 reason = 12
IPv6 Snooping (Device Tracking)
Another IPv6 FHS feature is IPv6 Snooping or Device Tracking: it builds a binding table checking the NS and NA messages, but it doesn't drop actual data traffic. If the MAC address - IPv6 address combination doesn't match it discards the NA messages sent by the end hosts. Let's configure IPv6 Snooping which is now called Device Tracking in newer IOS versions using the same topology.
SW1(config)#device-tracking policy NODE
SW1(config-device-tracking)#tracking enable
SW1(config-device-tracking)#limit address-count 2
SW1(config-device-tracking)#device-role ?
node Attached device is a node (default)
router Attached device is a router
switch Attached device is a switch
SW1(config-device-tracking)#device-role node
Just as with RA Guard we create a separate policy for the end hosts and for the router. With the limit address-count
command we can limit how many IPv6 addresses can be associated with a single MAC address. In this example I set it to 2, so besides the link-local address only a single global unicast address is allowed for the end hosts.
SW1(config-device-tracking)#security-level ?
glean glean addresses passively
guard inspect and drop un-authorized messages (default)
inspect glean and Validate message
SW1(config-device-tracking)#security-level guard
With the security-level
command we can set what actions the switch should take in case of violation:
- glean: it doesn't do anything, only populates the binding table
- inspect: the same as glean, but it actually drops wrong NA messages as well
- guard (default): the same as inspect, but it also drops RA and DHCP server messages (it includes the RA Guard feature which we configured before)
Now let's apply the policy for VLAN 1 (which includes all devices):
SW1(config)#vlan configuration 1
SW1(config-vlan-config)#device-tracking attach-policy NODE
I configure the router the same way as before:
ROUTER_R1(config)#ipv6 unicast-routing
ROUTER_R1(config)#int g0/0
ROUTER_R1(config-if)#ipv6 addr fe80::1 link-local
ROUTER_R1(config-if)#ipv6 addr 2001:db8:1234::1/64
ROUTER_R1(config-if)#no shut
Because of the ipv6 unicast-routing
the router starts sending RA messages which are silently dropped by the switch because of the guard policy:
SW1#debug device-tracking
SW1#show device-tracking messages
[Wed Jun 25 11:41:04.000] VLAN 1, From Et0/0 NDP::NS, FE80::1,
[Wed Jun 25 11:41:05.000] VLAN 1, From Et0/0 MAC 5254.001a.359c: NDP::NA, FE80::1,
[Wed Jun 25 11:41:05.000] VLAN 1, From Et0/0 NDP::NS, 2001:DB8:1234::1,
[Wed Jun 25 11:41:05.000] VLAN 1, From Et0/0 MAC 5254.001a.359c: NDP::RA, FE80::1, Drop reason=Packet not authorized on port
[Wed Jun 25 11:41:06.000] VLAN 1, From Et0/0 MAC 5254.001a.359c: NDP::NA, 2001:DB8:1234::1,
So I configured a separate policy for the router: E0/0 is now a trusted-port
, the switch won't drop any control-plane packet from the router anymore. Again, the policy applied to the interface overwrites the policy 'NODE' which was applied to the whole VLAN because it's more specific.
SW1(config)#device-tracking policy ROUTER
SW1(config-device-tracking)#trusted-port
SW1(config)#int e0/0
SW1(config-if)#device-tracking attach-policy ROUTER
If a device sends NA messages, like HOST3 in this example:
HOST_R3(config)#int g0/0
HOST_R3(config-if)#ipv6 addr fe80::3 link-local
HOST_R3(config-if)#ipv6 addr autoconfig
The switch populates the binding table:
SW1#show device-tracking database
VPC role NONE VPC state CREATING
Binding Table has 3 entries, 3 dynamic (limit 200000)
Codes: L - Local, S - Static, ND - Neighbor Discovery, ARP - Address Resolution Protocol, DH4 - IPv4 DHCP, DH6 - IPv6 DHCP, PKT - Other Packet, API - API created
Preflevel flags (prlvl):
0001:MAC and LLA match 0002:Orig trunk 0004:Orig access
0008:Orig trusted trunk 0010:Orig trusted access 0020:DHCP assigned
0040:Cga authenticated 0080:Cert authenticated 0100:Statically assigned
Network Layer Address Link Layer Address Interface vlan/bd prlvl age state Time left
ND FE80::3 5254.001f.c7eb Et0/2 1 0005 108s REACHABLE 196 s
ND FE80::1 5254.001a.359c Et0/0 1 0011 107s REACHABLE 203 s
ND 2001:DB8:1234::3 5254.001f.c7eb Et0/2 1 0005 106s REACHABLE 205 s
What if the Attacker tries to use same IPv6 address?
ATTACKER(config)#int g0/0
ATTACKER(config-if)#ipv6 addr fe80::3 link-local
The switch drops the NA messages sent by the Attacker:
*Jun 25 12:00:17.817: SISF[BT ]: Et0/2 vlan 1 Duplicated IP address or possible IP THEFT attempt detected for: FE80::3 Mac: 5254.0017.9436, on I/f: Et0/1
*Jun 25 12:00:17.817: SISF[BT ]: Requester reset from type 10 for FE80::3 on Et0/1
And what if we exceed the maximum address count for HOST 3? I assigned another IPv6 address for the interface:
HOST_R3(config-if)#ipv6 addr 2011:bad0::33/64
And the switch drops the NA messages sent by HOST 3 for his new address:
*Jun 25 12:09:48.575: SISF[BT ]: Max dynamic entries per port for policy 2 reached
*Jun 25 12:09:49.575: SISF[BT ]: Max dynamic entries per port for policy 2 reached
Remember this feature only blocks control-plane messages (NDP NA/RA), it doesn't actually drops data packets. If we want to inspect data packets as well we need another IPv6 FHS feature called Source Guard.