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:

IPv6 FHS 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-routercommand, 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

RA sent by the legitimate router with 'high' preference, the switch will drop these RA messages
RA sent by the legitimate router with 'high' preference, the switch will drop these RA messages

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.