Thursday, December 29, 2011

DHCP Based Security Part 1: DHCP Snooping

There's 3 related switching security technologies for which I've had draft posts sitting around for some time now. I'm finally getting around to publishing them as I study away for my second lab attempt. I know it's the silly little technologies like these ones that can show up on a Lab and cause grief, so hopefully I don't forget all this come Jan 13th.

The first one we're going to look at is DHCP Snooping. 


DHCP Snooping is a security technology that network administrators can use combat the problem of rogue DHCP servers. With DHCP Snooping enabled switches are configured to only allow DHCP messages from ports that are defined as "trusted" while discarding messages received on all other ports.

And that's it.  Simple, yes?  But wait, there's more!

As a function of this snooping a DHCP Snooping enabled switch also creates a snooping binding database to store all the DHCP related information it sees. This snooping binding database can be leveraged by two more security technologies, IP Source Guard and Dynamic ARP Inspection, that I'll look at in this 3 post series.

But I think I'm getting a little too far ahead of myself.  Lets back up and look at DHCP Snooping in action, and then move outward from there.

For this series of Blog posts I'm going to be using this very simple topology. 


R6 will be our DHCP client, R7 is a DHCP relay agent configured with a helper-address, and R8 will be our DHCP server.  Cat2 is sitting between R6 and R7 and will be configured for DHCP Snooping. OSPF is running between R7 and R8 with all interfaces in area 0.

To configure DHCP Snooping on our switch we must first enable it globally, and then enable it on our target VLAN.  Finally, we specify which port(s) our DHCP server is connected to by marking them as trusted.

Cat2(config)#ip dhcp snooping
Cat2(config)#ip dhcp snooping vlan 67
Cat2(config)#interface FastEthernet0/7
Cat2(config-if)#ip dhcp snooping trust

And viola!  DHCP Snooping is now enabled. But what does this really mean?  And what have we gained?

Well, for starters, we have changed the behavior of this switch with regards to the way it now handles DHCP packets.  Let's look at the basic information:

Cat2#sh ip dhcp snooping
Switch DHCP snooping is enabled
DHCP snooping is configured on following VLANs:
67
DHCP snooping is operational on following VLANs:   
67
DHCP snooping is configured on the following L3 Interfaces:

Insertion of option 82 is enabled
   circuit-id format: vlan-mod-port
    remote-id format: MAC
Option 82 on untrusted port is not allowed
Verification of hwaddr field is enabled
Verification of giaddr field is enabled
DHCP snooping trust/rate is configured on the following Interfaces:

Interface                    Trusted     Rate limit (pps)
------------------------     -------     ----------------
FastEthernet0/7              yes         unlimited
Cat2#

We can see that snooping is enabled, and that it is configured and operational on VLAN 67.  We also see that insertion of option 82 is enabled, and the format used for the suboptions.  At the end we see that we have defined port F0/7 as trusted.

Let's give this a test now shall we? 

R6(config-if)#do sh run int f0/0
Building configuration...

Current configuration : 85 bytes
!
interface FastEthernet0/0
 ip address dhcp
 shutdown
 duplex auto
 speed auto
end

R6(config-if)#no shut

We should get an address pretty quickly...  I'm going to turn on 'debug dhcp' to watch...  I'm editing the output for brevity. Run your own debug to see the entire output.

*Dec 30 03:42:56.203: DHCP: DHCP client process started: 10
*Dec 30 03:42:56.207: DHCP: Waiting for 5 seconds on interface FastEthernet0/0 to come up
*Dec 30 03:42:58.199: %LINK-3-UPDOWN: Interface FastEthernet0/0, changed state to up
*Dec 30 03:42:59.199: %LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet0/0, changed state to up
*Dec 30 03:43:01.207: RAC: Starting DHCP discover on FastEthernet0/0
*Dec 30 03:43:01.207: DHCP: Try 1 to acquire address for FastEthernet0/0
...
*Dec 30 03:43:01.211: DHCP: SDiscover attempt # 1 for entry:
...
*Dec 30 03:43:05.191: DHCP: SDiscover attempt # 2 for entry:
...
*Dec 30 03:43:09.191: DHCP: SDiscover attempt # 3 for entry:
...
%Unknown DHCP problem.. No allocation possible
*Dec 30 03:43:21.691: DHCP: Waiting for 5 seconds on interface FastEthernet0/0
*Dec 30 03:43:26.691: DHCP: Try 2 to acquire address for FastEthernet0/0
...
*Dec 30 03:43:26.695: DHCP: SDiscover attempt # 1 for entry:
...
*Dec 30 03:43:30.191: DHCP: SDiscover attempt # 2 for entry:
...
*Dec 30 03:43:34.191: DHCP: SDiscover attempt # 3 for entry:
...
%Unknown DHCP problem.. No allocation possible
*Dec 30 03:43:47.175: DHCP: Waiting for 10 seconds on interface FastEthernet0/0
*Dec 30 03:43:57.175: DHCP: Try 3 to acquire address for FastEthernet0/0
...
*Dec 30 03:43:57.179: DHCP: SDiscover attempt # 1 for entry:
...
*Dec 30 03:44:00.191: DHCP: SDiscover attempt # 2 for entry:
...
*Dec 30 03:44:04.191: DHCP: SDiscover attempt # 3 for entry:
...
%Unknown DHCP problem.. No allocation possible
*Dec 30 03:44:17.659: DHCP: Waiting for 15 seconds on interface FastEthernet0/0

Looking at out timestamps we're over a minute waiting for DHCP to work.  This is not the way things should be working.  Before turning on DHCP snooping this did work, so why is it not now?  What's missing?

The answer is nothing is missing, and that's the problem! 

The reason why this is not working was shown to us above in the output of the 'show ip dhcp snooping' command.

Insertion of option 82 is enabled

Those cold, hard words have forced upon us a reality where the default setting for two different types of Cisco devices will simply not interoperate.  One says tomato, the other says tomato. 

(That doesn't really work in print as well as it does when spoken...)

What I'm taking my sweet time to get around to saying is that when we enabled DHCP Snooping on our switch we also enabled the behavior where the switch inserts option 82 into DHCP DISCOVER packets that traverse it.  The problem with this is that by default Cisco routers do not trust option 82 and if a DHCP relay sees an DHCP DISCOVER with the option 82 suboption of GIADDR set to all zeros then it will drop the packet!

The proof is in the pudding:

R7#deb ip dhcp server packet
DHCP server packet debugging is on.
R7#
*Dec 29 09:44:16.647: DHCPD: inconsistent relay information.
*Dec 29 09:44:16.647: DHCPD: relay information option exists, but giaddr is zero

This post is starting to read like a Tarantino film, what with everything out of order...  Let's back up (again) and look at DHCP Option 82.

DHCP Option 82 is designed to allow a DHCP server to know where a DHCP client actually connects to the network so it can allocate an address form the correct pool.  This scenario is important when you have a DHCP server that is not on the same segment as the DHCP clients, as is the case in many many networks.  There are 3 sub options inside option 82.  These are:

CicuitID
RemoteID
GIADDR

Option 82 is specified in RFC 3046, and if you wish to read up on the suboptions above, I encourage you to do so.  In our experiment the only suboption we're concerned with is GIADDR, and that's the only field I'm going to discuss here.

GIADDR means "gateway IP address", and this field is usually populated by DHCP relay agents with the IP of the interface that received the DHCP packet.  When the DHCP server receives a DISCOVER it looks at the GIADDR field and then compares that address to the pools it has configured to decide from which pool it should allocate an address from.  Basically this is saying that the DHCP server allocates an address from the same range of addresses that the GIADDR address is a part of.

Back to our little problem...  Let's look again at the relevant output of 'show ip dhcp snooping":

Insertion of option 82 is enabled
   circuit-id format: vlan-mod-port
   remote-id format: MAC
  
This is great...  But what about GIADDR?  Well, since it doesn't say I'll tell you.  The switch sets GIADDR to all zeros because it doesn't know what the GIADDR should be, and it has no way to know.  Option 82 must contain all three suboptions, and because we are inserting option 82 it uses the only value it can: all zeros.

Moving forward again to our default router behavior, a Cisco router will drop a DHCP packet with a GIADDR of all zeros.  Normally this is not a problem because most DHCP clients by default do not insert option 82, and therefore there is no GIADDR at all.  But when we enabled DHCP snooping on our switch, the switch, by default, inserts option 82 with a GIADDR of all zeros, and we now have the problem we are seeing.

There's 2 ways to fix this.  We can either tell the switch to not insert option 82, or we can tell the router to trust DHCP packets with a GIADDR of all zeros:

Cat2(config)#no ip dhcp snooping information option

Or

R7(config)#ip dhcp relay information trust-all

Either way our problem will be "fixed" and R6 will finally get an address:

%DHCP-6-ADDRESS_ASSIGN: Interface FastEthernet0/0 assigned DHCP address 10.6.7.1, mask 255.255.255.0, hostname R6

Yay!

Alright, so what else do we have here?  Well, we now have the beginnings of our DHCP snooping bindings database:

Cat2#sh ip dhcp snooping binding vlan 67
MacAddress          IpAddress        Lease(sec)  Type           VLAN  Interface
------------------  ---------------  ----------  -------------  ----  --------------------
00:0A:B8:1A:50:80   10.6.7.1         86277       dhcp-snooping   67    FastEthernet0/6
Total number of bindings: 1

This database is used to track which MAC address is assigned which IP address, and on what port is resides.  It also tracks the lease time, and the method which it knows about the binding (Type).  A switch can either learn about a binding via DHCP Snooping, or they can be statically defined by an administrator by using the following EXEC mode command:

Cat2#ip dhcp snooping binding AAAA.AAAA.AAAA vlan 67 1.1.1.1 interface f0/5 expiry 5000
Cat2#sh ip dhcp snooping binding
MacAddress          IpAddress        Lease(sec)  Type           VLAN  Interface
------------------  ---------------  ----------  -------------  ----  --------------------
00:0A:B8:1A:50:80   10.6.7.1         85717       dhcp-snooping   67    FastEthernet0/6
AA:AA:AA:AA:AA:AA   1.1.1.1          4995        dhcp-snooping   67    FastEthernet0/5
Total number of bindings: 2

The only other bit I should show you is what happens when we get a rogue DHCP server. To do that I'm going to add R2 on port f0/2 of Cat2, and fire up a DHCP server there without marking the port as trusted.  Here's the 'debug ip dhcp server' on R2:

R2#deb ip dhcp server packet
DHCP server packet debugging is on.
R2#

Yeh...  Pretty informational eh?  Well, the thing is that Cat2 doesn't even forward the DHCP DISCOVER to R2 since it's not connected to a trusted port.  In other words, our rogue DHCP server never gets a chance to respond to the DHCP request at all!

Just for kicks, here's the entire 'debug ip dhcp snooping' and 'debug ip dhcp snooping packet' output from Cat2 with the configuration we created above, and R2 connected as our rogue.  If you read through it you'll see all the neat little bits happening.

*Mar  1 02:06:06.440: %LINK-3-UPDOWN: Interface FastEthernet0/6, changed state to up
*Mar  1 02:06:07.446: %LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet0/6, changed state to up
*Mar  1 02:06:07.631: DHCPSNOOP(hlfm_set_if_input): Setting if_input to Fa0/6 for pak.  Was not set
*Mar  1 02:06:07.631: DHCPSNOOP(hlfm_set_if_input): Clearing if_input for pak.  Was Fa0/6
*Mar  1 02:06:07.631: DHCPSNOOP(hlfm_set_if_input): Setting if_input to Fa0/6 for pak.  Was not set
*Mar  1 02:06:07.631: DHCP_SNOOPING: received new DHCP packet from input interface (FastEthernet0/6)
*Mar  1 02:06:07.631: DHCP_SNOOPING: process new DHCP packet, message type: DHCPDISCOVER, input interface: Fa0/6, MAC da: ffff.ffff.ffff, MAC sa: 000a.b81a.5080, IP da: 255.255.255.255, IP sa: 0.0.0.0, DHCP ciaddr: 0.0.0.0, DHCP yiaddr: 0.0.0.0, DHCP siaddr: 0.0.0.0, DHCP giaddr: 0.0.0.0, DHCP chaddr: 000a.b81a.5080
*Mar  1 02:06:07.631: DHCP_SNOOPING_SW: bridge packet get invalid mat entry: FFFF.FFFF.FFFF, packet is flooded to ingress VLAN: (67)
*Mar  1 02:06:09.636: DHCPSNOOP(hlfm_set_if_input): Setting if_input to Fa0/7 for pak.  Was not set
*Mar  1 02:06:09.636: DHCPSNOOP(hlfm_set_if_input): Clearing if_input for pak.  Was Fa0/7
*Mar  1 02:06:09.636: DHCPSNOOP(hlfm_set_if_input): Setting if_input to Fa0/7 for pak.  Was not set
*Mar  1 02:06:09.636: DHCP_SNOOPING: received new DHCP packet from input interface (FastEthernet0/7)
*Mar  1 02:06:09.636: DHCP_SNOOPING: process new DHCP packet, message type: DHCPOFFER, input interface: Fa0/7, MAC da: ffff.ffff.ffff, MAC sa: 0013.8083.4750, IP da: 255.255.255.255, IP sa: 10.6.7.7, DHCP ciaddr: 0.0.0.0, DHCP yiaddr: 10.6.7.6, DHCP siaddr: 0.0.0.0, DHCP giaddr: 10.6.7.7, DHCP chaddr: 000a.b81a.5080
*Mar  1 02:06:09.636: DHCP_SNOOPING: direct forward dhcp reply to output port: FastEthernet0/6.
*Mar  1 02:06:09.636: DHCPSNOOP(hlfm_set_if_input): Setting if_input to Fa0/6 for pak.  Was not set
*Mar  1 02:06:09.636: DHCPSNOOP(hlfm_set_if_input): Clearing if_input for pak.  Was Fa0/6
*Mar  1 02:06:09.636: DHCPSNOOP(hlfm_set_if_input): Setting if_input to Fa0/6 for pak.  Was not set
*Mar  1 02:06:09.636: DHCP_SNOOPING: received new DHCP packet from input interface (FastEthernet0/6)
*Mar  1 02:06:09.636: DHCP_SNOOPING: process new DHCP packet, message type: DHCPREQUEST, input interface: Fa0/6, MAC da: ffff.ffff.ffff, MAC sa: 000a.b81a.5080, IP da: 255.255.255.255, IP sa: 0.0.0.0, DHCP ciaddr: 0.0.0.0, DHCP yiaddr: 0.0.0.0, DHCP siaddr: 0.0.0.0, DHCP giaddr: 0.0.0.0, DHCP chaddr: 000a.b81a.5080
*Mar  1 02:06:09.636: DHCP_SNOOPING_SW: bridge packet get invalid mat entry: FFFF.FFFF.FFFF, packet is flooded to ingress VLAN: (67)
*Mar  1 02:06:09.644: DHCPSNOOP(hlfm_set_if_input): Setting if_input to Fa0/7 for pak.  Was not set
*Mar  1 02:06:09.644: DHCPSNOOP(hlfm_set_if_input): Clearing if_input for pak.  Was Fa0/7
*Mar  1 02:06:09.644: DHCPSNOOP(hlfm_set_if_input): Setting if_input to Fa0/7 for pak.  Was not set
*Mar  1 02:06:09.644: DHCP_SNOOPING: received new DHCP packet from input interface (FastEthernet0/7)
*Mar  1 02:06:09.644: DHCP_SNOOPING: process new DHCP packet, message type: DHCPACK, input interface: Fa0/7, MAC da: ffff.ffff.ffff, MAC sa: 0013.8083.4750, IP da: 255.255.255.255, IP sa: 10.6.7.7, DHCP ciaddr: 0.0.0.0, DHCP yiaddr: 10.6.7.6, DHCP siaddr: 0.0.0.0, DHCP giaddr: 10.6.7.7, DHCP chaddr: 000a.b81a.5080
*Mar  1 02:06:09.644: DHCP_SNOOPING: add binding on port FastEthernet0/6.
*Mar  1 02:06:09.644: DHCP_SNOOPING: added entry to table (index 119)

*Mar  1 02:06:09.644: DHCP_SNOOPING: dump binding entry: Mac=00:0A:B8:1A:50:80 Ip=10.6.7.6 Lease=86400      Type=dhcp-snooping Vlan=67 If=FastEthernet0/6
*Mar  1 02:06:09.644: DHCP_SNOOPING_SW no entry found for 000a.b81a.5080 0.0.0.67 FastEthernet0/6
*Mar  1 02:06:09.644: DHCP_SNOOPING_SW host tracking not found for update add dynamic (10.6.7.6, 0.0.0.0, 000a.b81a.5080) vlan 67
*Mar  1 02:06:09.644: DHCP_SNOOPING: direct forward dhcp reply to output port: FastEthernet0/6.


And that's going to be it for DHCP Snooping. You can find the next two follow up posts using the following links:

http://blog.brokennetwork.ca/2011/09/dhcp-based-security-part-2-ip-source.html

http://blog.brokennetwork.ca/2011/09/dhcp-based-security-part-3-dynamic-arp.html

References:
http://www.cisco.com/en/US/partner/docs/switches/lan/catalyst3560/software/release/12.2_58_se/configuration/guide/swdhcp82.html#wp1058138
http://www.odva.org/Portals/0/Library/Publications_Numbered/PUB0088R0_ODVA_DHCP_Option_82v2.pdf

12 comments:

  1. excellent article, jason!
    good luck on the 13th!

    ReplyDelete
  2. can you please tell me how does switch differentiate between different dhcp packts. i mean switch is a layer 2 device and so it will look into frame only.
    does switch also do deep frame inspection on enabling dhcp snooping

    ReplyDelete
    Replies
    1. Hi Sameer,

      Switches forward based on Layer 2 information, true, but to say "it will look into frame only" is something that just is not true, and hasn't been for many years. Modern switches are capable of examining far more then the layer 2 headers. In the case of DHCP Snooping the switch does examine the DHCP protocol information contained within the packet. The same is true for other features such as IGMP Snooping. I suppose it could be considered a form of Deep Packet Inspection, though I'm not aware of any documentation for DHCP Snooping that actually refers to it as such.

      Delete
  3. Great explanation, simple but in-depth! What makes it so special is the experiment with a 'rogue' DHCP server on an untrusted port. All of the Cisco official CCNP learning materials (either SWITCH or TSHOOT) state that an untrusted port cannot accept ingress DHCP server responses, but NONE of them mentions that a DHCP snooping-enabled switch doesn't even forward DHCP client requests out of untrusted ports!!! Of course, such a behaviour is very logical, but it's not that obvious, since the emphasis is made on accepting or denying ingress DHCP packets. And the 'debug ip dhcp snooping' output saying that 'packet is flooded to ingress VLAN' is very deceptive - one may expect the packet really being flooded just as any Ethernet broadcast frame, but it is not so in reality, which may (and does!) complicate troubleshooting of DHCP-related issues.

    ReplyDelete
    Replies
    1. I've never looked at the SWITCH or TSHOOT material so I can't really comment on that, but I can say that it is the nuances like that that are important points to understand when you need to troubleshoot something. The subtle behaviors are the ones that will get you every time.

      Delete
  4. Спасибо большое. Твоя статься мне очень помогла. Молодец!

    ReplyDelete
    Replies
    1. Спасибо за любезные слова.

      Delete
  5. Thank you very much for this. Worked with TAC and they couldn't understand the issue after 3 hours. This saved me and us.
    Sincere thanks.
    Zac

    ReplyDelete