PacketFence Revisited
In our initial PacketFence article in the April 2007 issue of LJ, we introduced the great network access control (NAC) solution that rivals the best ones on the market. On that occasion, we covered ARP-based isolation, which works relatively well for small networks.
Unfortunately, ARP-based isolation can't really scale to many thousands of nodes and is relatively easy to bypass with a simple static ARP table. Thus, we, at Inverse, decided to improve PacketFence by adding a VLAN-based isolation mode. This addition, combined with other enhancements, makes the solution suitable for large-scale networks.
The purpose of PacketFence's VLAN isolation is to assign any device connected to the network to an appropriate VLAN based on its MAC, registration and violation status. A simple scenario would be that every new device belongs to a registration VLAN, a registered and violation-free device belongs to a “normal” VLAN and a device with open violations belongs to an isolation VLAN. If the isolation and registration VLANs are not routed to the “normal” VLAN, PacketFence fully isolates the new device, and any device that violates network policy, from the regular network, efficiently preventing any attack or virus propagation. Of course, real networks are a bit more complicated, and VoIP phones may not end up in the same VLAN as regular computers or servers. But, whatever your network's VLAN design, PacketFence is up to the task.
In order for the VLAN isolation code to work properly, you must use manageable switches. In particular, the switches must provide a means to change a port's VLAN remotely and must be able to send SNMP (Simple Network Management Protocol) traps to PacketFence. SNMP traps include the switch's IP address; the port number and, depending on the trap type, could include the port status (for example, “up” when a device has been connected and “down” when disconnected); the MAC address of the device (mostly for MAC notification and security violation traps); the number of MACs connected to the switch port and so on.
When a switch sends an SNMP trap to PacketFence, the snmptrapd dæmon receives it and writes it to the log file /usr/local/pf/contrib/log/snmptrapd.log. PacketFence's setVlanOnTrapd dæmon continuously reads this log file and, for every new trap, determines whether it needs to change a port's VLAN. If this is the case, it sends the appropriate SNMP commands to the switch.
A crucial part of VLAN isolation is knowing when a device connects to or disconnects from the network. In early 2006, we started the development of the VLAN isolation code by supporting two very basic SNMP traps: linkup and linkdown traps. The vast majority of switch vendors support these two traps, which made our implementation immediately usable on a wide variety of networking hardware. Unfortunately, simply relying on linkup and linkdown traps has its downsides, from both a performance and a functional perspective, including:
Because a switch needs to see some network traffic on a port to determine the MAC address of the connecting device, linkup traps cannot include any MAC address. PacketFence's setVlanOnTrapd must, therefore, repeatedly query the switch after every linkup trap in order to determine the MAC address of the newly connected device, which introduces some overhead.
Most VoIP phones contain a built-in switch to connect a PC. The switch sends the linkup trap when you connect the phone; when you connect the PC to the phone, the switch won't send a second linkup trap. Therefore, in this deployment scenario, relying solely on linkup and linkdown traps does not provide enough information to setVlanOnTrapd to work correctly.
One possible solution to address these issues is MAC notification traps. Every time a switch learns a MAC address on a port, it sends a “MAC learned” trap that includes the MAC address. And, of course, PacketFence now also supports MAC notification traps.
In addition to assigning an appropriate VLAN to devices when they connect to the network, PacketFence also isolates devices already connected to the network when they violate the network policy. Two different options are available:
PacketFence can briefly disconnect a device from the network by administratively shutting down the switch port and re-opening it soon after. In this case, the switch sends a linkdown, followed by a linkup trap. When PacketFence receives the linkup trap, it determines that the device has an open violation and switches the port to the isolation VLAN. On the computer side, the network adapter notices that the network link went down and automatically renews its IP address—this time in the isolation VLAN. PacketFence's captive portal then informs the user that he or she has been isolated.
Administratively shutting down a switch port can be problematic when using VoIP phones, as doing so might end a call. If PacketFence has access to the isolation VLAN, you don't actually need to shut down the port. Changing the port's VLAN and doing some ARP spoofing generally are sufficient to make the captive portal available to the user.
So far, we've mentioned only the registration and isolation VLANs, but PacketFence uses a third VLAN, the MAC detection VLAN. This VLAN, which is the default one of every port, must not contain access to any DHCP server and could be seen as an “empty” VLAN. It exists to allow the switch to learn the MAC address of a newly connected device before it obtains an answer from a DHCP server.
Install PacketFence 1.7 from www.packetfence.org. If you are using Red Hat EL5 or CentOS5, the easiest way to do so is to install the official RPM.
In this example, we set up VLAN isolation on a Cisco Catalyst 2960 switch (IP address 192.168.0.3). The PacketFence server's IP address is 192.168.0.10. Let's further assume that you are using the following VLANs and that these already have been created on your switch:
“normal” VLAN
isolation VLAN
registration VLAN
MAC detection VLAN
Enable the SNMP traps globally on the switch with the following commands:
snmp-server enable traps snmp authentication linkdown linkup snmp-server enable traps mac-notification snmp-server host 192.168.0.10 version 2c public mac-notification snmp mac-address-table notification interval 0 mac-address-table notification mac-address-table aging-time 300
Then, configure every access port PacketFence should be handling with the following:
switchport access vlan 4 switchport mode access snmp trap mac-notification added spanning-tree portfast
Edit the VLAN isolation configuration file /usr/local/pf/conf/switches.conf, so that it contains the correct SNMP community strings. Then, adjust the VLAN definition as follows:
vlans = 1,2,3,4 normalVlan = 1 isolationVlan = 2 registrationVlan = 3 macDetectionVlan = 4
And, finally, add a new section for your switch:
[192.168.0.3] ip = 192.168.0.3 type = Cisco::Catalyst_2960 mode = production uplink = 23,24
Next, you can do a communication test between PacketFence and the switch:
/usr/local/pf/bin/pfcmd_vlan -getVlan -switch 192.168.0.3 -ifIndex 10001
The next test is to determine whether the switch can send SNMP traps to PacketFence. Start snmptrapd:
service snmptrapd start
and observe the log file:
tail -f /usr/local/pf/logs/snmptrapd.log
Every time a device connects to and disconnects from the network, you should see a new line in the log file.
Now, configure PacketFence's access to VLAN 1, 2 and 3. Set the configuration of the switch port that PacketFence plugs into to “trunk mode”, and allow packets in VLAN 1 to pass through the switch without tagging. On the PacketFence server, add two new NICs that read and write 802.1q tagged packets for VLAN 2 and 3. Don't forget to add these new NICs to your configuration file /usr/local/pf/conf/pf.conf.
To simplify the installation, configure a DHCP service on the PacketFence box for VLANs 2 and 3. The DHCP server should return its own (VLAN-specific) IP address as both the gateway and the DNS server. Last but not least, set up a “fake” DNS service for VLANs 2 and 3 that responds to all queries with its own IP address. Now, verify that a host connected to the registration VLAN is able to obtain an IP address and that whatever DNS query it sends, PacketFence answers with its own IP.
If all these tests work fine, you can start setVlanOnTrapd:
service setVlanOnTrapd start
and look at the log file to verify that your devices, upon connection to the switch, are assigned to the correct VLAN:
tail -f /usr/local/pf/logs/setvlanontrapd.log
This setup should be transparent for already-registered devices, because they end up in the “normal” VLAN; unregistered devices will be assigned to the registration VLAN where all they can access is the PacketFence server that will show the captive portal with the registration screen.
PacketFence also integrates very well with wireless networks. As for its wired counterpart, the switch, a wireless Access Point (AP) needs to implement some specific features in order for the integration to work perfectly. In particular, the AP needs to support the following:
Several SSIDs with several VLANs inside each SSID.
Authentication against a RADIUS server.
Dynamic VLAN assignment (through RADIUS attributes).
SNMP deauthentication traps.
The deauthentication of an associated station.
We then can configure two SSIDs on the AP, the first one reserved for visitors and unregistered clients. In this SSID, communications will not be encrypted, and users will connect either to the registration VLAN or the visitor's VLAN (depending on their registration status). The second SSID will allow encrypted communications for registered users. The VLANs here are the “normal” VLAN and the isolation VLAN (if ever there are open violations for the MAC).
In this example, we configure a Cisco 1242 AP (IP address 192.168.0.4). Configuration of other vendors' APs is similar. First, define the normal, isolation, registration and visitor VLANs on the AP, together with the appropriate wired and wireless interfaces as shown for the isolation VLAN:
dot11 vlan-name isolation vlan 2 interface FastEthernet0.2 encapsulation dot1Q 2 no ip route-cache bridge-group 253 no bridge-group 253 source-learning bridge-group 253 spanning-disabled interface Dot11Radio0.2 encapsulation dot1Q 2 no ip route-cache bridge-group 253 bridge-group 253 subscriber-loop-control bridge-group 253 block-unknown-source no bridge-group 253 source-learning no bridge-group 253 unicast-flooding bridge-group 253 spanning-disabled
Then, create the two SSIDs:
dot11 ssid WPA2 vlan 2 backup normal authentication open eap eap_methods authentication key-management wpa accounting acct-methods mbssid guest-mode dot11 ssid MACauth vlan 3 backup visitor authentication open mac-address mac_methods accounting acct_methods mbssid guest-mode
Configure the RADIUS server (we assume here that the FreeRADIUS server and the PacketFence server are located on the same box):
radius-server host 192.168.0.10 auth-port 1812 ↪acct-port 1813 key secretKey aaa group server radius rad_eap server 192.168.0.10 auth-port 1812 acct-port 1813 aaa authentication login eap_methods group rad_eap aaa group server radius rad_mac server 192.168.0.10 auth-port 1812 acct-port 1813 aaa authentication login mac_methods group rad_mac
Enable the SNMP deauthentication traps:
snmp-server enable traps deauthenticate snmp-server host 192.168.0.10 public deauthenticate
Finally, activate the SSIDs on the radio:
interface Dot11Radio0 encryption vlan 1 mode ciphers aes-ccm encryption vlan 2 mode ciphers aes-ccm ssid WPA2 ssid MACauth
Now, check with a Wi-Fi card that you actually can see the two new SSIDs. You can't connect to them yet because the RADIUS server is not up and running.
Start configuring the FreeRADIUS server by adding the following lines at the end of /etc/raddb/clients.conf:
client 192.168.0.3 { secret = secretKey shortname = AP1242 }
In /etc/raddb/eap.conf, set the default eap type to peap at the beginning of the eap {} section:
default_eap_type = peap
And, set up your cryptographic keys in the tls {} section.
Then, update /etc/raddb/radiusd.conf, first by adding the following lines to the modules {} section:
perl { module = ${confdir}/rlm_perl_packetfence.pl }
Then, add “perl” at the end of the authorize {} section. The script /etc/raddb/rlm_perl_packetfence.pl uses the Calling-Station-Id RADIUS request attribute, containing the MAC of the wireless station to determine its registration and violation status. Based on this information, it sets the Tunnel-Medium-Type, Tunnel-Type and Tunnel-Private-Group-ID RADIUS reply attributes. The AP, upon reception of these three attributes, then confines the wireless station into the specified VLAN.
The last file to edit is /etc/raddb/users to define that non-EAP messages should, by default, lead to an authentication acceptance:
DEFAULT EAP-Message !* "", Auth-Type := Accept
Then, add a local test user with:
testUser User-Password == "testPwd"
Now, start FreeRADIUS in debug mode:
radiusd -x
Try to connect to one of the two new SSIDs with your Wi-Fi card, and you'll see the packets received by FreeRADIUS with the generated responses.
It also is noteworthy that the concepts you've learned here on using PacketFence with wireless networks are identical to using 802.1x on a wired network, which of course, is supported by PacketFence.
We designed the VLAN isolation feature from the beginning with extensibility in mind. All supported switches are represented through Perl objects, and we make extensive use of inheritance. For example:
At the highest level, you have the pf::SNMP object that defines general functions, such as SNMP session creation and deletion, database connections and some standardized SNMP queries.
At the next level are the vendor-specific objects, such as pf::SNMP::Cisco and pf::SNMP::Nortel. They include the necessary functions to parse SNMP traps and, most of the time, to read and write a port's VLAN assignment.
Finally, at the lowest level, are the model-specific objects, containing only the model-specific code.
This architecture simplifies adding the support for a new product from an already-supported vendor; it comes down to redefining only a very limited number of methods and can be done in a matter of hours.
As you've seen in this article, PacketFence secures both wired and wireless networks in an efficient way. Offering the same level of security and using the same NAC solution on both networks make PacketFence one of the most essential security tools to have.
Resources
“PacketFence” by Ludovic Marcotte and Dominik Gehl, LJ, April 2007: www.linuxjournal.com/article/9551
PacketFence: www.packetfence.org
Inverse—PacketFence VLAN-Based Isolation Mode: www.inverse.ca/contributions/packetfence.html
Net-SNMP—snmptrapd Dæmon: www.net-snmp.org
The FreeRADIUS Project: www.freeradius.org
Regis Balzard (rbalzard@inverse.ca) holds a Computer Engineering degree from the Ecole Superieure d'Ingenieurs en Genie Electrique (ESIGELEC) in Rouen, France. He is currently a systems architect for Inverse, Inc., an IT consulting company located in downtown Montréal that specializes in the deployment of infrastructures based on free and open-source components like PacketFence and SOGo.
Dominik Gehl (dgehl@inverse.ca) holds a Master's degree in Computer Science from the University of Montréal. He is currently a systems architect for Inverse, Inc., an IT consulting company located in downtown Montréal that specializes in the deployment of infrastructures based on free and open-source components like PacketFence and SOGo.