SMUS Wireless Configuration: Difference between revisions

From SMUSwiki
Jump to navigation Jump to search
(Created page with "== Introduction == == Prerequisites == == Software Used == == Hardware Used == == Firewall and NAT == == Freeradius Configuration == === Virtual Hosts === === Certificates...")
 
 
(30 intermediate revisions by the same user not shown)
Line 1: Line 1:
== Introduction ==
== Introduction ==
This page will discuss the backend for the SMUS wireless configuration.
This document is made available under the [http://creativecommons.org/licenses/by-sa/2.5/ca/ Creative Commons Attribution ShareAlike 2.5 Canada] license.


== Prerequisites ==
== Prerequisites ==
Our requirements for wireless on campus are fairly complex.  We decided on several prerequisites, for a variety of reasons.
=== 802.1x ===
We wanted staff and students to be able to sign into the wireless system themselves without any help from the MIS department.  Several implementations use a captive portal mechanism to do this, but that results in an SSID with no encryption.  By using 802.1x, we can use WPA2-Enterprise encryption on the SSIDs, and staff and students can still configure the connection themselves.
=== Active Directory Integration ===
Wherever possible, we have staff and students use their active directory credentials to log into whatever they're trying to access.  We wanted this system to also use the active directory credentials.  The AD server had preexisting groups we wanted to take advantage of as well, and we added more groups later to further separate out our users.
=== Different Student and Staff IP addresses ===
Students on our campus are subject to bandwidth limitations and packet shaping.  We do not want to apply these restrictions to staff members.  Our packet shaper uses a simple IP range to track which machines to apply restrictions to, so we needed our students to be assigned a different set of IP addresses than our staff.
=== VLANs for mobile labs ===
Our mobile laptop labs also need different IP ranges.  As we have a senior and middle school, we apply different web filtering to each set of computers.  We achieved this using VLAN assignments in freeradius after the machines logged in, based on a regular expression check on the computer name.
=== Single simultaneous login for students ===
This is no longer a requirement for our system, so we have removed the sections containing simultaneous use from this document.  See the document history from January 3 2012 or earlier to see how we did simultaneous use (although it wasn't fully working).
=== Login times by grade ===
We apply different login hours by grade.  Grade 12s can use the wireless longer into the evening than grade 11s, which can use it longer than grade 10s, etc.  We accomplish this by assigning different VLANs per grade and boarder/day status.  This results in different IP ranges that we can apply time-based firewalling on through our PFSense router.
=== Guest logins ===
As there are frequently parents and other guests on campus, we wanted it to be fairly simple for them to get their wireless device onto our network.  These devices are sometimes not as secure as other devices, so they are separated out onto their own network, and we check their computers for up-to-date antivirus protection through a captive portal before allowing them to login.  Antivirus protection is not checked on smartphones and similar devices, only full computers.


== Software Used ==
== Software Used ==
We use a combination of Freeradius (to do radius authentication), and Samba (for active directory integration) on the backend.  The wireless access points are configured using the Meraki cloud controller, although other wifi systems can also tap into the same radius configuration (we tested with Dlink access points as well).  Whatever wifi system is selected must support 802.1x authentication through WPA2-Enterprise encryption.
Bug-free support for the functions we're using arrived recently to Samba and Freeradius, and older versions definitely don't work properly.  We are running Debian 6 with the stock versions of all packages.  We were previously running Ubuntu 10.04 and the versions included there did not work.  Freeradius 2.1.10 and Samba 3.5.6 are included with Debian 6, so those are the recommended versions.
Our VLANs are routed through a PFSense 2.0.1 virtual machine.  This VM can apply firewalls to any combination of subnet connections, and has good performance for the throughput we need.  It also supports time-based firewalling so we can block access to the Internet at specific times per VLAN.  Routing and firewalling can also be done through a dedicated router.


== Hardware Used ==
== Hardware Used ==


== Firewall and NAT ==
Our radius server runs as a VMWare ESXi 5.1 virtual machine.  It has a single virtual processor (2.53 GHz) with 512 MB of ram.  This is more than sufficient to handle our incoming connections.
 
We use Meraki MR16 access points.
 
Clients we have successfully authenticated on this network include Windows XP, Vista, and 7; Mac OS X; Android, Blackberry, and iOS smartphones; etc.  Through MAC address whitelisting, we have also put other devices onto the guest network.
 
== Samba Configuration ==
 
Samba must be installed and the Linux machine must be joined to the active directory domain before radius can do NTLM authentication.
 
sudo apt-get install samba winbind smbclient krb5-user
sudo vi /etc/krb5.conf
 
* Ensure default realm is set to your active directory DNS name (ours is SMUS.LOCAL)
* Under realms, add a section:
 
<pre>
        SMUS.LOCAL = {
                kdc = <domain controller DNS name>
                kdc = <backup domain controller DNS name>
                admin_server = <domain controller DNS name>
        }
</pre>
 
* Now test that your Kerberos settings are correct
 
sudo kinit Administrator
 
* Enter your domain administrator password, and if it comes back without any errors you've set up Kerberos correctly
* Now configure Samba
 
sudo vi /etc/samba/smb.conf
 
* Change workgroup to your active directory short name (Ours is "SMUSLOCAL")
* Add a new line underneath with your Kerberos realm/Active Directory DNS name:
 
realm = <AD DNS name>
 
* Uncomment "security = user" and change to "security = ads"
* Immediately underneath, add the following lines:
 
password server = <domain controller DNS name>
 
Now join the Active Directory domain:
 
sudo net ads join -U Administrator
 
Then restart Samba and Winbind so that you can authenticate against the AD domain:
 
sudo /etc/init.d/samba stop; sudo /etc/init.d/winbind stop
sudo /etc/init.d/samba start; sudo /etc/init.d/winbind start


== Freeradius Configuration ==
== Freeradius Configuration ==
=== Installation ===
sudo apt-get install freeradius freeradius-ldap
* Allow the freerad user access to query winbind
sudo adduser freerad winbindd_priv
=== Clients ===
We must set up clients that are allowed to authenticate via radius.  We have set up one client definition for senior/middle school Meraki access points, another definition for junior school Meraki access points, and a several definitions for the Meraki cloud controller, which does the guest authentication.
<pre>
client <ip range>/24 {
        secret = <radius secret>
        shortname = meraki_ap
        nastype    = other
}
client <ip range>/24 {
        secret = <radius secret>
        shortname = meraki_jr_ap
        nastype    = other
}
client 64.156.192.220/32 {
        secret = <radius secret>
        shortname = meraki_cloud1
        nastype    = other
}
client 64.156.192.245/32 {
        secret = <radius secret>
        shortname = meraki_cloud2
        nastype    = other
}
client 74.50.51.16/32 {
        secret = <radius secret>
        shortname = meraki_cloud3
        nastype    = other
}
client 74.50.53.101/32 {
        secret = <radius secret>
        shortname = meraki_cloud4
        nastype    = other
}
</pre>
=== Policies ===
Add each of these policies under /etc/freeradius/policy.conf
==== Require_staff Policy ====
This ensures that the Huntgroup-Name variable is set when we actually authenticate the user later.
<pre>
        require_staff {
                update request {
                        Huntgroup-Name := "<staff group name>"
                }
        }
</pre>
==== Require_student Policy ====
This ensures that the Huntgroup-Name variable is set when we actually authenticate the user later.  We also update any replies to indicate that the student's session timeout is 5 minutes to force them to reauthenticate every 5 minutes.
<pre>
        require_student {
                update request {
                        Huntgroup-Name := "<student group name>"
                }
        }
</pre>
==== Require_guest Policy ====
Guests are authenticated differently because they are not doing 802.1x EAP/MSCHAP authentication.  Instead, they use NTLM authentication (a username and cleartext password).  As these passwords are transmitted cleartext over the Internet, it is wise to rotate the passwords often, and also to not use privileged accounts.  The accounts we set up for guest wireless access are not allowed to log into school computers, or access any resources other than wireless.
We will set up the actual auth module later.
<pre>
        require_guest {
                update request {
                        Huntgroup-Name := "<guest group name>"
                }
                update control {
                        Auth-Type := "ntlm_auth_guest"
                }
        }
</pre>
==== Special_vlan Policy ====
When we authenticate computers, we also check to see if the machine should go onto a special VLAN.  We check computer names for the computer lab VLANs, and we also check which access point they're binding to to check for Junior School machines, which are assigned different VLANs as they are a separate campus.
<pre>
        check_unified_vlan {
                update reply {
                        # default settings
                        Tunnel-Private-Group-ID = 104
                        Tunnel-Type = "VLAN"
                        Tunnel-Medium-Type = "IEEE-802"
                }
                ### computer name policies ###
                if ("%{User-Name}" =~ /D7-BROW-MIS-E/i) {
                        update reply {
                                Tunnel-Private-Group-ID := 1
                        }
                }
                elsif ("%{User-Name}" =~ /D7-CROT-303-/i) {
                        update reply {
                                # Crothall South Lab
                                Tunnel-Private-Group-ID := 150
                        }
                }
...
                ### staff group policies ###
                elsif (Ldap-Group == "staffnt") {
                        update reply {
                                Tunnel-Private-Group-ID := 104
                        }
                }
                ### student grade group policies ###
                elsif (Ldap-Group == "Grade 12 Board") {
                        update reply {
                                Tunnel-Private-Group-ID := 112
                        }
                }
                elsif (Ldap-Group == "Grade 12 Day") {
                        update reply {
                                Tunnel-Private-Group-ID := 114
                        }
                }
...
                ### junior school ###
                if ("%{Client-Shortname}" == "meraki_jr_ap") {
                        # authenticating from JR school, change up the VLAN numbers
                        if (Ldap-Group == "studentsnt") {
                                # was going to be on student VLAN, put on JR student VLAN
                                update reply {
                                        Tunnel-Private-Group-ID := 204
                                }
                        }
                        else {
                                # otherwise put on JR staff VLAN
                                update reply {
                                        Tunnel-Private-Group-ID := 200
                                }
                        }
                }
        }
</pre>


=== Virtual Hosts ===
=== Virtual Hosts ===
We use virtual hosts so that there are different radius servers available to authenticate staff, students, and guests.
sudo vi /etc/freeradius/radiusd.conf
* Comment out all of the listen blocks, as we will be setting these up for each virtualhost
* Now set up your virtualhosts
cd /etc/freeradius/sites-available
cp default staff
cp default student
cp default guest
cd /etc/freeradius/sites-enabled
rm default
ln -s ../sites-available/staff .
ln -s ../sites-available/student .
ln -s ../sites-available/guest .
==== Staff Virtual Host ====
sudo vi /etc/freeradius/sites-enabled/staff
* Wrap the entire config file into a block.  At the top of the file, add "server staff {" and at the bottom, add "}".  For ease of readability, you can indent the contents of the block one tab so that you can tell it's part of the "server staff {" block.
* Add a listen block immediately under "server staff {"
** The port is set to 0 as that makes it the default (1812 for radius and 1813 for accounting)
** Note that the staff server handles the radius accounting for all IP addresses, but you can configure them separately if desired
<pre>
        listen {
                port = 0
                type = auth
                ipaddr = <ip address>
        }
        listen {
                port = 0
                type = acct
                ipaddr = *
        }
</pre>
* Update the authorize block so that it has the following items:
<pre>
preprocess
require_staff
suffix
eap {
  ok = return
}
files
</pre>
* Update the authentication block so that it has the following items:
<pre>
eap
</pre>
* Update the preacct block so that it has the following items:
<pre>
preprocess
acct_unique
suffix
</pre>
* Update the accounting block so that it has the following items:
<pre>
attr_filter.accounting_response
</pre>
* Update the post-auth block so that it has the following items:
<pre>
check_unified_vlan
exec
Post-Auth-Type REJECT {
  attr_filter.access_reject
}
</pre>
* Update the post-proxy block so that it has the following items:
<pre>
eap
</pre>
==== Student Virtual Host ====
sudo vi /etc/freeradius/sites-enabled/student
* Wrap the entire config file into a block. At the top of the file, add "server student {" and at the bottom, add "}". For ease of readability, you can indent the contents of the block one tab so that you can tell it's part of the "server student {" block.
* Add a listen block immediately under "server student {"
** The port is set to 0 as that makes it the default (1812 for radius and 1813 for accounting)
<pre>
        listen {
                port = 0
                type = auth
                ipaddr = <ip address>
        }
</pre>
* Update the authorize block so that it has the following items:
<pre>
preprocess
ldap
require_student
suffix
eap {
  ok = return
}
files
expiration
</pre>
* Update the authentication block so that it has the following items:
<pre>
eap
</pre>
* Comment out the preacct and accounting blocks, as they are not used
* Update the post-auth block so that it has the following items:
<pre>
check_unified_vlan
exec
Post-Auth-Type REJECT {
  attr_filter.access_reject
}
</pre>
* Update the post-proxy block so that it has the following items:
<pre>
eap
</pre>
==== Guest Virtual Host ====
sudo vi /etc/freeradius/sites-enabled/guest
* Wrap the entire config file into a block. At the top of the file, add "server guest {" and at the bottom, add "}". For ease of readability, you can indent the contents of the block one tab so that you can tell it's part of the "server guest {" block.
* Add a listen block immediately under "server guest {"
** The port is set to 0 as that makes it the default (1812 for radius and 1813 for accounting)
<pre>
        listen {
                port = 0
                type = auth
                ipaddr = <ip address>
        }
</pre>
* Update the authorize block so that it has the following items:
<pre>
preprocess
require_guest
suffix
eap {
  ok = return
}
files
</pre>
* Update the authentication block so that it has the following items:
<pre>
ntlm_auth_guest
</pre>
* Comment out the preacct and accounting blocks as they are not used
* Update the post-auth block so that it has the following items:
<pre>
check_unified_vlan
exec
Post-Auth-Type REJECT {
  attr_filter.access_reject
}
</pre>
* Update the post-proxy block so that it has the following items:
<pre>
eap
</pre>
==== Inner-Tunnel Virtual Host ====
The inner-tunnel vhost should already be mostly set up, as it's generally included with Freeradius' default configuration.  If it's not, symlink it from the sites-available:
sudo ln -s /etc/freeradius/sites-available/inner-tunnel /etc/freeradius/sites-enabled
Now start editing:
sudo vi /etc/freeradius/sites-enabled/inner-tunnel
* Update the authorize block so that it has the following items:
<pre>
chap
mschap
suffix
update control {
  Proxy-To-Realm := LOCAL
}
eap {
  ok = return
}
files
expiration
pap
</pre>
* Update the authentication block so that it has the following items.  Note that if mschap authentication fails (this means that the user isn't a member of the huntgroup we set earlier), we also check whether mschap_computers authenticates the user correctly.
<pre>
Auth-Type PAP {
  pap
}
Auth-Type CHAP {
  chap
}
Auth-Type MS-CHAP {
  mschap {
    reject = 2
  }
  if (reject) {
    mschap_computers
  }
}
unix
eap
</pre>
* Comment out the accounting, preacct, and session blocks, as they are not used
* Update the post-auth block so that it has the following items:
<pre>
Post-Auth-Type REJECT {
  attr_filter.access_reject
}
</pre>
* Update the post-proxy block so that it has the following items:
<pre>
eap
</pre>


=== Certificates ===
=== Certificates ===
We need to generate a CSR and get a real certificate for this server.  Here are the steps from memory, so they may not be 100% correct.
cd /etc/freeradius/certs
openssl req -out <server_name>.csr -new -newkey rsa:2048 -nodes -keyout <server_name>.key
Now send the CSR to a certificate authority and get it signed.  If the CA uses a certificate chain, you need to put all of the certificates into one file, with the server's certificate at the top, then the CA that signed that cert, then the next CA up the chain, etc.  Upload the resulting certificate file as <server_name>.crt .


=== EAP ===
=== EAP ===


=== Radius Accounting ===
Now configure EAP to use the certificate along with other parameters.
 
sudo vi /etc/freeradius/eap.conf
 
Inside the eap block, set the following:
 
default_eap_type = peap
Inside the eap/tls block, set the following:
 
private_key_password =
private_key_file = ${certdir}/<server_name>.key
certificate_file = ${certdir}/<server_name>.crt


=== SQL Connection ===
Inside the eap/tls/cache block, set the following:
 
enable = yes
lifetime = 4 # hours
max_entries = 1000


=== LDAP Connection ===
=== LDAP Connection ===


=== Logintime Policy ===
sudo vi /etc/freeradius/modules/ldap
 
* Configure TLS if desired under the ldap/tls block
* Set the following values in the ldap block:
 
server = "<domain controller>:3268"
identity = "<domain query user, for example cn=ldap_user,cn=users,dc=...>"
password = "<domain query user AD password>"
basedn = "<AD base DN>"
filter = "(samAccountName=%{%{mschap:User-Name}:-%{User-Name}})"
groupname_attribute = cn
groupmembership_filter = "(&(objectClass=group)(member=%{control:Ldap-UserDn}))"
groupmembership_attribute = memberOf
chase_referrals = yes
rebind = yes
 
=== MSCHAP module ===
 
sudo vi /etc/freeradius/modules/mschap
 
* Set the following values under the mschap block:
 
with_ntdomain_hack = yes
ntlm_auth = "/usr/bin/ntlm_auth --request-nt-key --challenge=%{mschap:Challenge:-00} --nt-response=%{mschap:NT-Response:-00} --domain=<Domain short name> --username=%{Stripped-User-Name:-%{mschap:User-Name}} --require-membership-of=<Domain short name>\\\\%{outer.request:Huntgroup-Name}"
 
=== MSCHAP_Computers module ===
 
sudo cp /etc/freeradius/modules/mschap /etc/freeradius/modules/mschap_computers
 
* Change the block from "mschap {" to "mschap mschap_computers {"
* Change the following values under the mschap mschap_computers block:
 
ntlm_auth = "/usr/bin/ntlm_auth --request-nt-key --challenge=%{mschap:Challenge:-00} --nt-response=%{mschap:NT-Response:-00} --domain=<Domain short name> --username=%{Stripped-User-Name:-%{mschap:User-Name}} --require-membership-of=<Domain short name>\\\\Domain\\ Computers"
 
=== NTLM_Auth_Guest module ===
 
sudo cp /etc/freeradius/modules/ntlm_auth /etc/freeradius/modules/ntlm_auth_guest
 
* Change the block from "exec ntlm_auth {" to "exec ntlm_auth_guest {"
* Change the following values under the exec ntlm_auth_guest block:
 
program = "/usr/bin/ntlm_auth --request-nt-key --domain=<AD domain> --username=%{mschap:User-Name} --password=%{User-Password} --require-membership-of=<AD domain>\\\\%{request:Huntgroup-Name}"
 
=== Restart freeradius and pray ===
 
This starts Freeradius in debug mode.  You should watch this fly by and verify that all of the configuration you have done above worked properly.  If it didn't, Freeradius will complain and then exit.  Then, try to get something to actually authenticate (follow the Meraki configuration in the next step to get it using your radius server).
 
sudo /etc/init.d/freeradius stop
sudo freeradius -X
 
To start radius for real, CTRL+C your debug session, then run:
 
sudo /etc/init.d/freeradius start
 
== Meraki configuration to use radius server ==
 
Note that while this configuration is specific to the Meraki cloud controller, it is also possible to set up 802.1x authentication through radius with other wireless systems.
 
=== Staff SSID ===
 
* Go to Configure -> Overview and enable a new SSID.  We named ours AirSMUS-staff.
* Go to Configure -> Access control, and set up the following details:
 
Network Access, Association Requirements -> WPA2-Enterprise with 802.1x authentication
Network Access, Network sign-on method -> Direct access
Network Access, Authentication server -> Use my radius server, host <ip>, port 1812, secret <radius_secret>
Addressing and traffic, Client IP assignment -> Bridge mode
VLAN setup, VLAN tagging: Use VLAN Tagging
VLAN setup, VLAN ID: JR tag -> 200, all other APs -> 112
VLAN setup, Radius override -> radius response can override VLAN tag
Wireless options, Band selection -> dual band operation (2.4 GHz and 5 GHz)
Wireless options, Legacy 11b operation -> Disable legacy 11b bitrates (1, 2, & 5.5 Mbps)
 
We noticed on our network that if "Dual band operation with Band Steering" was selected, some older wireless cards did not see the SSID at all.  We resolved the issue by just using Dual Band with no Band Steering.
 
=== Student SSID ===
 
* Go to Configure -> Overview and enable a new SSID.  We named ours AirSMUS-student.
* Go to Configure -> Access control, and set up the following details:
 
Network Access, Association Requirements -> WPA2-Enterprise with 802.1x authentication
Network Access, Network sign-on method -> Direct access
Network Access, Authentication server -> Use my radius server, host <ip2>, port 1812, secret <radius_secret>
Addressing and traffic, Client IP assignment -> Bridge mode
VLAN setup, VLAN tagging: Use VLAN Tagging
VLAN setup, VLAN ID: JR tag -> 204, all other APs -> 104
VLAN setup, Radius override -> radius response can override VLAN tag
Wireless options, Band selection -> dual band operation (2.4 GHz and 5 GHz)
Wireless options, Legacy 11b operation -> Disable legacy 11b bitrates (1, 2, & 5.5 Mbps)
 
=== Guest SSID ===
 
* Go to Configure -> Overview and enable a new SSID.  We named ours AirSMUS-guest.
* Go to Configure -> Access control, and set up the following details:
 
Network Access, Association Requirements -> Open (no encryption)
Network Access, Network sign-on method -> Sign-on splash page
Network access, Network access control -> Enabled: check clients for antivirus software
Network access, Remediation -> Send users to the standard remediation site
Network Access, Captive portal strength -> Block all access until sign-on is complete
Network Access, Walled garden -> Walled garden is disabled
Network Access, Authentication server -> Use my radius server, host <external_ip_address>, port 1812, secret <radius_secret>
Network Access, Failover policy -> Deny access
Network Access, Simultaneous logins -> Allow simultaneous devices per user
Addressing and traffic, Client IP assignment -> Bridge mode
VLAN setup, VLAN tagging: Use VLAN Tagging
VLAN setup, VLAN ID: JR tag -> 200, all other APs -> 100
Wireless options, Band selection -> dual band operation (2.4 GHz and 5 GHz)
Wireless options, Legacy 11b operation -> Disable legacy 11b bitrates (1, 2, & 5.5 Mbps)
 
Note: make sure you have set up firewall exceptions and IP forwarding through to the external IP address you have configured here.
 
== Additional Information ==
 
=== P2P blocking through Meraki ===
 
On our guest wifi network, we block P2P traffic.
 
Under Configure -> Firewall & Traffic Shaping, we added a Layer 7 firewall rule denying P2P traffic.
 
=== Packetshaper Integration ===
 
We use an application called Penaltybox: http://sourceforge.net/projects/penaltybox/ in combination with our packet shaper in order to restrict students to 10 GB of traffic per week.  After this amount of traffic, the student is restricted to 64 Kbit/sec down and 64 Kbit/sec up for 7 days.
 
In order to get this to work, you must set up port mirroring to a physical server that listens to the traffic in promiscuous mode.  It then records how much bandwidth is used by each IP address in the eligible range and applies restrictions when thresholds are met.
 
In order to compile the penaltybox application on our Debian 6 server and have it support our (newer) packetshaper, we had to apply the following patch:
 
<pre>
diff -ur penaltybox/src/benconfig/configexception.h penaltybox.new/src/benconfig/configexception.h
--- penaltybox/src/benconfig/configexception.h  2006-08-23 10:29:54.000000000 -0700
+++ penaltybox.new/src/benconfig/configexception.h      2010-12-23 11:09:18.000000000 -0800
@@ -10,6 +10,7 @@
#ifndef __CONFIGEXCEPTION_H
#define __CONFIGEXCEPTION_H
#include <string>
+#include <cstdio>
#include "configtypes.h"
using namespace std;
 
diff -ur penaltybox/src/benconfig/configloader.cpp penaltybox.new/src/benconfig/configloader.cpp
--- penaltybox/src/benconfig/configloader.cpp  2007-01-17 12:07:13.000000000 -0800
+++ penaltybox.new/src/benconfig/configloader.cpp      2010-12-23 11:10:06.000000000 -0800
@@ -25,6 +25,8 @@
#include "configloader.h"
#include <iostream>
#include <cmath>
+#include <stdio.h>
+#include <stdlib.h>
#include <assert.h>
#include "trimstring.h"
using namespace std;
diff -ur penaltybox/src/capture/Capture.cpp penaltybox.new/src/capture/Capture.cpp
--- penaltybox/src/capture/Capture.cpp  2006-12-13 00:53:56.000000000 -0800
+++ penaltybox.new/src/capture/Capture.cpp      2010-12-23 11:11:27.000000000 -0800
@@ -21,6 +21,10 @@
  *************************************************************************/
#include "Capture.h"
#include <pbconfigloader.h>
+#include <string>
+#include <sstream>
+#include <cstring>
+
 
#include <iostream>
using namespace std;
diff -ur penaltybox/src/host/DayTotal.cpp penaltybox.new/src/host/DayTotal.cpp
--- penaltybox/src/host/DayTotal.cpp    2006-12-11 00:20:51.000000000 -0800
+++ penaltybox.new/src/host/DayTotal.cpp        2010-12-23 11:12:53.000000000 -0800
@@ -24,6 +24,7 @@
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
+#include <strings.h>
#include <string>
 
using namespace std;
diff -ur penaltybox/src/host/HostList.cpp penaltybox.new/src/host/HostList.cpp
--- penaltybox/src/host/HostList.cpp    2006-12-13 01:13:37.000000000 -0800
+++ penaltybox.new/src/host/HostList.cpp        2010-12-23 11:12:25.000000000 -0800
@@ -31,6 +31,8 @@
#include "../pbconfigloader.h"
#include <errno.h>
#include <time.h>
+#include <cstring>
+#include <strings.h>
using namespace std;
using namespace Config;
 
diff -ur penaltybox/src/host/HostNode.cpp penaltybox.new/src/host/HostNode.cpp
--- penaltybox/src/host/HostNode.cpp    2006-08-22 15:45:19.000000000 -0700
+++ penaltybox.new/src/host/HostNode.cpp        2010-12-23 11:12:40.000000000 -0800
@@ -22,6 +22,7 @@
 
#include "HostNode.h"
#include <iostream>
+#include <strings.h>
using namespace std;
#include <stdio.h>
#include <assert.h>
diff -ur penaltybox/src/limiter/Packeteer.cpp penaltybox.new/src/limiter/Packeteer.cpp
--- penaltybox/src/limiter/Packeteer.cpp        2006-12-15 18:59:04.000000000 -0800
+++ penaltybox.new/src/limiter/Packeteer.cpp    2010-12-23 11:14:01.000000000 -0800
@@ -26,6 +26,9 @@
#include "../benconfig/trimstring.h"
#include "../pbconfigloader.h"
#include <assert.h>
+#include <string>
+#include <cstring>
+#include <sstream>
 
#include <openssl/md5.h>
#include <fstream>
@@ -35,6 +38,7 @@
 
const int Inbound = 0;
const int Outbound = 1;
+long int ClassID = 1234567;
const char * folder[] = { "Inbound/students", "Outbound/students" };
 
 
@@ -201,11 +205,17 @@
        string entryStartTagEnd  = "/pb-" + h->GetIp().toString() + "\">\n";
        string entryFootTag      = " </entry>\n</add-delete-schema-objects>\n";
 
-      string data = " <objectclass><oc-value>iqosTrafficClass</oc-value></objectclass>\n";
+      string s;
+      stringstream st;
+
+      string data = " <objectclass><oc-value>iqosTrafficClass</oc-value></objectclass>\n";
        data      += " <attr name=\"iqosInsideHost\"><value>" + h->GetIp().toString() + "</value></attr>\n";
        data      += xmlpartition;
        data      += " <attr name=\"iqosProtocolName\"><value>IP</value></attr>\n";
-
+      ClassID += 1;
+      st << ClassID;
+      data      += " <attr name=\"iqosClassID\"><value>" + st.str() + "</value></attr>\n";
+
 
        return entryStartTagBegin + entryStartTagEnd + data + entryFootTag ;
}
@@ -259,12 +269,12 @@
                xml = xmlhead;
                xml += this->DeleteXml(*r, folder[x]);
                xml += xmlfoot;
-
-              sprintf(message, "+Adding Class: %s/pb-%s\n",
+
+              sprintf(message, "+Adding Class: %s/pb-%s\n",
                                folder[x],
                                (*r).c_str());
 
-              pb_log_debug(message);
+              pb_log_debug(message);
                SendRequest(xml);
        }
        r++;
@@ -378,11 +388,12 @@
 
void Packeteer::UploadNotify() {
        list<string>::iterator p = hostsToNotify.begin();
-      string xml  = xmlhead + "<add-delete-schema-objects>\n<entry dn=\"" + HostListName + "\">\n";
+      // string xml  = xmlhead + "<add-delete-schema-objects>\n<entry dn=\"" + HostListName + "\">\n";
+      string xml  = xmlhead + "<add-delete-schema-objects>\n<entry dn=\"" + "penaltybox" + "\">\n";
              xml += "<objectclass><oc-value>iqosHostList</oc-value></objectclass>\n";
 
        while (p != hostsToNotify.end()) {
-              pb_log_debug("Adding " + *p + " to redirect\n");
+              pb_log_debug("Adding R2 " + *p + " to redirect\n");
                xml += "<attr name=\"iqosHostListNames\"><value>" + *p + "</value></attr>\n";
                p++;
        }
diff -ur penaltybox/src/pb.cpp penaltybox.new/src/pb.cpp
--- penaltybox/src/pb.cpp      2007-01-11 16:24:48.000000000 -0800
+++ penaltybox.new/src/pb.cpp  2010-12-23 11:17:48.000000000 -0800
@@ -23,6 +23,10 @@
#include <iostream>
#include <fstream>
#include <string>
+#include <cstring>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdio.h>
 
#include <pbconfigloader.h>
#include <pbversion.h>
diff -ur penaltybox/src/socket/http.cpp penaltybox.new/src/socket/http.cpp
--- penaltybox/src/socket/http.cpp      2006-06-30 19:39:54.000000000 -0700
+++ penaltybox.new/src/socket/http.cpp  2010-12-23 11:14:26.000000000 -0800
@@ -20,6 +20,7 @@
  * Written By Benjamin Wilder <mrcawfee@sfsu.edu>
  *************************************************************************/
#include "http.h"
+#include <strings.h>
#include <iostream>
using namespace std;
 
diff -ur penaltybox/src/socket/url.cpp penaltybox.new/src/socket/url.cpp
--- penaltybox/src/socket/url.cpp      2006-06-30 19:39:54.000000000 -0700
+++ penaltybox.new/src/socket/url.cpp  2010-12-23 11:14:58.000000000 -0800
@@ -21,6 +21,7 @@
  *************************************************************************/
#include "url.h"
#include <stdio.h>
+#include <cstring>
 
string urlencode(string s) {
  string result;
</pre>

Latest revision as of 10:02, 10 October 2012

Introduction

This page will discuss the backend for the SMUS wireless configuration.

This document is made available under the Creative Commons Attribution ShareAlike 2.5 Canada license.

Prerequisites

Our requirements for wireless on campus are fairly complex. We decided on several prerequisites, for a variety of reasons.

802.1x

We wanted staff and students to be able to sign into the wireless system themselves without any help from the MIS department. Several implementations use a captive portal mechanism to do this, but that results in an SSID with no encryption. By using 802.1x, we can use WPA2-Enterprise encryption on the SSIDs, and staff and students can still configure the connection themselves.

Active Directory Integration

Wherever possible, we have staff and students use their active directory credentials to log into whatever they're trying to access. We wanted this system to also use the active directory credentials. The AD server had preexisting groups we wanted to take advantage of as well, and we added more groups later to further separate out our users.

Different Student and Staff IP addresses

Students on our campus are subject to bandwidth limitations and packet shaping. We do not want to apply these restrictions to staff members. Our packet shaper uses a simple IP range to track which machines to apply restrictions to, so we needed our students to be assigned a different set of IP addresses than our staff.

VLANs for mobile labs

Our mobile laptop labs also need different IP ranges. As we have a senior and middle school, we apply different web filtering to each set of computers. We achieved this using VLAN assignments in freeradius after the machines logged in, based on a regular expression check on the computer name.

Single simultaneous login for students

This is no longer a requirement for our system, so we have removed the sections containing simultaneous use from this document. See the document history from January 3 2012 or earlier to see how we did simultaneous use (although it wasn't fully working).

Login times by grade

We apply different login hours by grade. Grade 12s can use the wireless longer into the evening than grade 11s, which can use it longer than grade 10s, etc. We accomplish this by assigning different VLANs per grade and boarder/day status. This results in different IP ranges that we can apply time-based firewalling on through our PFSense router.

Guest logins

As there are frequently parents and other guests on campus, we wanted it to be fairly simple for them to get their wireless device onto our network. These devices are sometimes not as secure as other devices, so they are separated out onto their own network, and we check their computers for up-to-date antivirus protection through a captive portal before allowing them to login. Antivirus protection is not checked on smartphones and similar devices, only full computers.

Software Used

We use a combination of Freeradius (to do radius authentication), and Samba (for active directory integration) on the backend. The wireless access points are configured using the Meraki cloud controller, although other wifi systems can also tap into the same radius configuration (we tested with Dlink access points as well). Whatever wifi system is selected must support 802.1x authentication through WPA2-Enterprise encryption.

Bug-free support for the functions we're using arrived recently to Samba and Freeradius, and older versions definitely don't work properly. We are running Debian 6 with the stock versions of all packages. We were previously running Ubuntu 10.04 and the versions included there did not work. Freeradius 2.1.10 and Samba 3.5.6 are included with Debian 6, so those are the recommended versions.

Our VLANs are routed through a PFSense 2.0.1 virtual machine. This VM can apply firewalls to any combination of subnet connections, and has good performance for the throughput we need. It also supports time-based firewalling so we can block access to the Internet at specific times per VLAN. Routing and firewalling can also be done through a dedicated router.

Hardware Used

Our radius server runs as a VMWare ESXi 5.1 virtual machine. It has a single virtual processor (2.53 GHz) with 512 MB of ram. This is more than sufficient to handle our incoming connections.

We use Meraki MR16 access points.

Clients we have successfully authenticated on this network include Windows XP, Vista, and 7; Mac OS X; Android, Blackberry, and iOS smartphones; etc. Through MAC address whitelisting, we have also put other devices onto the guest network.

Samba Configuration

Samba must be installed and the Linux machine must be joined to the active directory domain before radius can do NTLM authentication.

sudo apt-get install samba winbind smbclient krb5-user
sudo vi /etc/krb5.conf
  • Ensure default realm is set to your active directory DNS name (ours is SMUS.LOCAL)
  • Under realms, add a section:
        SMUS.LOCAL = {
                kdc = <domain controller DNS name>
                kdc = <backup domain controller DNS name>
                admin_server = <domain controller DNS name>
        }
  • Now test that your Kerberos settings are correct
sudo kinit Administrator
  • Enter your domain administrator password, and if it comes back without any errors you've set up Kerberos correctly
  • Now configure Samba
sudo vi /etc/samba/smb.conf
  • Change workgroup to your active directory short name (Ours is "SMUSLOCAL")
  • Add a new line underneath with your Kerberos realm/Active Directory DNS name:
realm = <AD DNS name>
  • Uncomment "security = user" and change to "security = ads"
  • Immediately underneath, add the following lines:
password server = <domain controller DNS name>

Now join the Active Directory domain:

sudo net ads join -U Administrator

Then restart Samba and Winbind so that you can authenticate against the AD domain:

sudo /etc/init.d/samba stop; sudo /etc/init.d/winbind stop
sudo /etc/init.d/samba start; sudo /etc/init.d/winbind start

Freeradius Configuration

Installation

sudo apt-get install freeradius freeradius-ldap
  • Allow the freerad user access to query winbind
sudo adduser freerad winbindd_priv

Clients

We must set up clients that are allowed to authenticate via radius. We have set up one client definition for senior/middle school Meraki access points, another definition for junior school Meraki access points, and a several definitions for the Meraki cloud controller, which does the guest authentication.

client <ip range>/24 {
        secret = <radius secret>
        shortname = meraki_ap
        nastype     = other
}

client <ip range>/24 {
        secret = <radius secret>
        shortname = meraki_jr_ap
        nastype     = other
}

client 64.156.192.220/32 {
        secret = <radius secret>
        shortname = meraki_cloud1
        nastype     = other
}

client 64.156.192.245/32 {
        secret = <radius secret>
        shortname = meraki_cloud2
        nastype     = other
}

client 74.50.51.16/32 {
        secret = <radius secret>
        shortname = meraki_cloud3
        nastype     = other
}

client 74.50.53.101/32 {
        secret = <radius secret>
        shortname = meraki_cloud4
        nastype     = other
}

Policies

Add each of these policies under /etc/freeradius/policy.conf

Require_staff Policy

This ensures that the Huntgroup-Name variable is set when we actually authenticate the user later.

        require_staff {
                update request {
                        Huntgroup-Name := "<staff group name>"
                }
        }

Require_student Policy

This ensures that the Huntgroup-Name variable is set when we actually authenticate the user later. We also update any replies to indicate that the student's session timeout is 5 minutes to force them to reauthenticate every 5 minutes.

        require_student {
                update request {
                        Huntgroup-Name := "<student group name>"
                }
        }

Require_guest Policy

Guests are authenticated differently because they are not doing 802.1x EAP/MSCHAP authentication. Instead, they use NTLM authentication (a username and cleartext password). As these passwords are transmitted cleartext over the Internet, it is wise to rotate the passwords often, and also to not use privileged accounts. The accounts we set up for guest wireless access are not allowed to log into school computers, or access any resources other than wireless.

We will set up the actual auth module later.

        require_guest {
                update request {
                        Huntgroup-Name := "<guest group name>"
                }
                update control {
                        Auth-Type := "ntlm_auth_guest"
                }
        }

Special_vlan Policy

When we authenticate computers, we also check to see if the machine should go onto a special VLAN. We check computer names for the computer lab VLANs, and we also check which access point they're binding to to check for Junior School machines, which are assigned different VLANs as they are a separate campus.

        check_unified_vlan {
                update reply {
                        # default settings
                        Tunnel-Private-Group-ID = 104
                        Tunnel-Type = "VLAN"
                        Tunnel-Medium-Type = "IEEE-802"
                }

                ### computer name policies ###
                if ("%{User-Name}" =~ /D7-BROW-MIS-E/i) {
                        update reply {
                                Tunnel-Private-Group-ID := 1
                        }
                }
                elsif ("%{User-Name}" =~ /D7-CROT-303-/i) {
                        update reply {
                                # Crothall South Lab
                                Tunnel-Private-Group-ID := 150
                        }
                }
...
                ### staff group policies ###
                elsif (Ldap-Group == "staffnt") {
                        update reply {
                                Tunnel-Private-Group-ID := 104
                        }
                }

                ### student grade group policies ###
                elsif (Ldap-Group == "Grade 12 Board") {
                        update reply {
                                Tunnel-Private-Group-ID := 112
                        }
                }
                elsif (Ldap-Group == "Grade 12 Day") {
                        update reply {
                                Tunnel-Private-Group-ID := 114
                        }
                }
...
                ### junior school ###
                if ("%{Client-Shortname}" == "meraki_jr_ap") {
                        # authenticating from JR school, change up the VLAN numbers
                        if (Ldap-Group == "studentsnt") {
                                # was going to be on student VLAN, put on JR student VLAN
                                update reply {
                                        Tunnel-Private-Group-ID := 204
                                }
                        }
                        else {
                                # otherwise put on JR staff VLAN
                                update reply {
                                        Tunnel-Private-Group-ID := 200
                                }
                        }
                }
        }

Virtual Hosts

We use virtual hosts so that there are different radius servers available to authenticate staff, students, and guests.

sudo vi /etc/freeradius/radiusd.conf
  • Comment out all of the listen blocks, as we will be setting these up for each virtualhost
  • Now set up your virtualhosts
cd /etc/freeradius/sites-available
cp default staff
cp default student
cp default guest
cd /etc/freeradius/sites-enabled
rm default
ln -s ../sites-available/staff .
ln -s ../sites-available/student .
ln -s ../sites-available/guest .

Staff Virtual Host

sudo vi /etc/freeradius/sites-enabled/staff
  • Wrap the entire config file into a block. At the top of the file, add "server staff {" and at the bottom, add "}". For ease of readability, you can indent the contents of the block one tab so that you can tell it's part of the "server staff {" block.
  • Add a listen block immediately under "server staff {"
    • The port is set to 0 as that makes it the default (1812 for radius and 1813 for accounting)
    • Note that the staff server handles the radius accounting for all IP addresses, but you can configure them separately if desired
        listen {
                port = 0
                type = auth
                ipaddr = <ip address>
        }

        listen {
                port = 0
                type = acct
                ipaddr = *
        }
  • Update the authorize block so that it has the following items:
preprocess
require_staff
suffix
eap {
  ok = return
}
files
  • Update the authentication block so that it has the following items:
eap
  • Update the preacct block so that it has the following items:
preprocess
acct_unique
suffix
  • Update the accounting block so that it has the following items:
attr_filter.accounting_response
  • Update the post-auth block so that it has the following items:
check_unified_vlan
exec
Post-Auth-Type REJECT {
  attr_filter.access_reject
}
  • Update the post-proxy block so that it has the following items:
eap

Student Virtual Host

sudo vi /etc/freeradius/sites-enabled/student
  • Wrap the entire config file into a block. At the top of the file, add "server student {" and at the bottom, add "}". For ease of readability, you can indent the contents of the block one tab so that you can tell it's part of the "server student {" block.
  • Add a listen block immediately under "server student {"
    • The port is set to 0 as that makes it the default (1812 for radius and 1813 for accounting)
        listen {
                port = 0
                type = auth
                ipaddr = <ip address>
        }
  • Update the authorize block so that it has the following items:
preprocess
ldap
require_student
suffix
eap {
  ok = return
}
files
expiration
  • Update the authentication block so that it has the following items:
eap
  • Comment out the preacct and accounting blocks, as they are not used
  • Update the post-auth block so that it has the following items:
check_unified_vlan
exec
Post-Auth-Type REJECT {
  attr_filter.access_reject
}
  • Update the post-proxy block so that it has the following items:
eap

Guest Virtual Host

sudo vi /etc/freeradius/sites-enabled/guest
  • Wrap the entire config file into a block. At the top of the file, add "server guest {" and at the bottom, add "}". For ease of readability, you can indent the contents of the block one tab so that you can tell it's part of the "server guest {" block.
  • Add a listen block immediately under "server guest {"
    • The port is set to 0 as that makes it the default (1812 for radius and 1813 for accounting)
        listen {
                port = 0
                type = auth
                ipaddr = <ip address>
        }
  • Update the authorize block so that it has the following items:
preprocess
require_guest
suffix
eap {
  ok = return
}
files
  • Update the authentication block so that it has the following items:
ntlm_auth_guest
  • Comment out the preacct and accounting blocks as they are not used
  • Update the post-auth block so that it has the following items:
check_unified_vlan
exec
Post-Auth-Type REJECT {
  attr_filter.access_reject
}
  • Update the post-proxy block so that it has the following items:
eap

Inner-Tunnel Virtual Host

The inner-tunnel vhost should already be mostly set up, as it's generally included with Freeradius' default configuration. If it's not, symlink it from the sites-available:

sudo ln -s /etc/freeradius/sites-available/inner-tunnel /etc/freeradius/sites-enabled

Now start editing:

sudo vi /etc/freeradius/sites-enabled/inner-tunnel
  • Update the authorize block so that it has the following items:
chap
mschap
suffix
update control {
  Proxy-To-Realm := LOCAL
}
eap {
  ok = return
}
files
expiration
pap
  • Update the authentication block so that it has the following items. Note that if mschap authentication fails (this means that the user isn't a member of the huntgroup we set earlier), we also check whether mschap_computers authenticates the user correctly.
Auth-Type PAP {
  pap
}
Auth-Type CHAP {
  chap
}
Auth-Type MS-CHAP {
  mschap {
    reject = 2
  }
  if (reject) {
    mschap_computers
  }
}
unix
eap
  • Comment out the accounting, preacct, and session blocks, as they are not used
  • Update the post-auth block so that it has the following items:
Post-Auth-Type REJECT {
  attr_filter.access_reject
}
  • Update the post-proxy block so that it has the following items:
eap

Certificates

We need to generate a CSR and get a real certificate for this server. Here are the steps from memory, so they may not be 100% correct.

cd /etc/freeradius/certs
openssl req -out <server_name>.csr -new -newkey rsa:2048 -nodes -keyout <server_name>.key

Now send the CSR to a certificate authority and get it signed. If the CA uses a certificate chain, you need to put all of the certificates into one file, with the server's certificate at the top, then the CA that signed that cert, then the next CA up the chain, etc. Upload the resulting certificate file as <server_name>.crt .

EAP

Now configure EAP to use the certificate along with other parameters.

sudo vi /etc/freeradius/eap.conf

Inside the eap block, set the following:

default_eap_type = peap

Inside the eap/tls block, set the following:

private_key_password =
private_key_file = ${certdir}/<server_name>.key
certificate_file = ${certdir}/<server_name>.crt

Inside the eap/tls/cache block, set the following:

enable = yes
lifetime = 4 # hours
max_entries = 1000

LDAP Connection

sudo vi /etc/freeradius/modules/ldap

  • Configure TLS if desired under the ldap/tls block
  • Set the following values in the ldap block:
server = "<domain controller>:3268"
identity = "<domain query user, for example cn=ldap_user,cn=users,dc=...>"
password = "<domain query user AD password>"
basedn = "<AD base DN>"
filter = "(samAccountName=%{%{mschap:User-Name}:-%{User-Name}})"
groupname_attribute = cn
groupmembership_filter = "(&(objectClass=group)(member=%{control:Ldap-UserDn}))"
groupmembership_attribute = memberOf
chase_referrals = yes
rebind = yes

MSCHAP module

sudo vi /etc/freeradius/modules/mschap
  • Set the following values under the mschap block:
with_ntdomain_hack = yes
ntlm_auth = "/usr/bin/ntlm_auth --request-nt-key --challenge=%{mschap:Challenge:-00} --nt-response=%{mschap:NT-Response:-00} --domain=<Domain short name> --username=%{Stripped-User-Name:-%{mschap:User-Name}} --require-membership-of=<Domain short name>\\\\%{outer.request:Huntgroup-Name}"

MSCHAP_Computers module

sudo cp /etc/freeradius/modules/mschap /etc/freeradius/modules/mschap_computers
  • Change the block from "mschap {" to "mschap mschap_computers {"
  • Change the following values under the mschap mschap_computers block:
ntlm_auth = "/usr/bin/ntlm_auth --request-nt-key --challenge=%{mschap:Challenge:-00} --nt-response=%{mschap:NT-Response:-00} --domain=<Domain short name> --username=%{Stripped-User-Name:-%{mschap:User-Name}} --require-membership-of=<Domain short name>\\\\Domain\\ Computers"

NTLM_Auth_Guest module

sudo cp /etc/freeradius/modules/ntlm_auth /etc/freeradius/modules/ntlm_auth_guest
  • Change the block from "exec ntlm_auth {" to "exec ntlm_auth_guest {"
  • Change the following values under the exec ntlm_auth_guest block:
program = "/usr/bin/ntlm_auth --request-nt-key --domain=<AD domain> --username=%{mschap:User-Name} --password=%{User-Password} --require-membership-of=<AD domain>\\\\%{request:Huntgroup-Name}"

Restart freeradius and pray

This starts Freeradius in debug mode. You should watch this fly by and verify that all of the configuration you have done above worked properly. If it didn't, Freeradius will complain and then exit. Then, try to get something to actually authenticate (follow the Meraki configuration in the next step to get it using your radius server).

sudo /etc/init.d/freeradius stop
sudo freeradius -X

To start radius for real, CTRL+C your debug session, then run:

sudo /etc/init.d/freeradius start

Meraki configuration to use radius server

Note that while this configuration is specific to the Meraki cloud controller, it is also possible to set up 802.1x authentication through radius with other wireless systems.

Staff SSID

  • Go to Configure -> Overview and enable a new SSID. We named ours AirSMUS-staff.
  • Go to Configure -> Access control, and set up the following details:
Network Access, Association Requirements -> WPA2-Enterprise with 802.1x authentication
Network Access, Network sign-on method -> Direct access
Network Access, Authentication server -> Use my radius server, host <ip>, port 1812, secret <radius_secret>
Addressing and traffic, Client IP assignment -> Bridge mode
VLAN setup, VLAN tagging: Use VLAN Tagging
VLAN setup, VLAN ID: JR tag -> 200, all other APs -> 112
VLAN setup, Radius override -> radius response can override VLAN tag
Wireless options, Band selection -> dual band operation (2.4 GHz and 5 GHz)
Wireless options, Legacy 11b operation -> Disable legacy 11b bitrates (1, 2, & 5.5 Mbps)

We noticed on our network that if "Dual band operation with Band Steering" was selected, some older wireless cards did not see the SSID at all. We resolved the issue by just using Dual Band with no Band Steering.

Student SSID

  • Go to Configure -> Overview and enable a new SSID. We named ours AirSMUS-student.
  • Go to Configure -> Access control, and set up the following details:
Network Access, Association Requirements -> WPA2-Enterprise with 802.1x authentication
Network Access, Network sign-on method -> Direct access
Network Access, Authentication server -> Use my radius server, host <ip2>, port 1812, secret <radius_secret>
Addressing and traffic, Client IP assignment -> Bridge mode
VLAN setup, VLAN tagging: Use VLAN Tagging
VLAN setup, VLAN ID: JR tag -> 204, all other APs -> 104
VLAN setup, Radius override -> radius response can override VLAN tag
Wireless options, Band selection -> dual band operation (2.4 GHz and 5 GHz)
Wireless options, Legacy 11b operation -> Disable legacy 11b bitrates (1, 2, & 5.5 Mbps)

Guest SSID

  • Go to Configure -> Overview and enable a new SSID. We named ours AirSMUS-guest.
  • Go to Configure -> Access control, and set up the following details:
Network Access, Association Requirements -> Open (no encryption)
Network Access, Network sign-on method -> Sign-on splash page
Network access, Network access control -> Enabled: check clients for antivirus software
Network access, Remediation -> Send users to the standard remediation site
Network Access, Captive portal strength -> Block all access until sign-on is complete
Network Access, Walled garden -> Walled garden is disabled
Network Access, Authentication server -> Use my radius server, host <external_ip_address>, port 1812, secret <radius_secret>
Network Access, Failover policy -> Deny access
Network Access, Simultaneous logins -> Allow simultaneous devices per user
Addressing and traffic, Client IP assignment -> Bridge mode
VLAN setup, VLAN tagging: Use VLAN Tagging
VLAN setup, VLAN ID: JR tag -> 200, all other APs -> 100
Wireless options, Band selection -> dual band operation (2.4 GHz and 5 GHz)
Wireless options, Legacy 11b operation -> Disable legacy 11b bitrates (1, 2, & 5.5 Mbps)

Note: make sure you have set up firewall exceptions and IP forwarding through to the external IP address you have configured here.

Additional Information

P2P blocking through Meraki

On our guest wifi network, we block P2P traffic.

Under Configure -> Firewall & Traffic Shaping, we added a Layer 7 firewall rule denying P2P traffic.

Packetshaper Integration

We use an application called Penaltybox: http://sourceforge.net/projects/penaltybox/ in combination with our packet shaper in order to restrict students to 10 GB of traffic per week. After this amount of traffic, the student is restricted to 64 Kbit/sec down and 64 Kbit/sec up for 7 days.

In order to get this to work, you must set up port mirroring to a physical server that listens to the traffic in promiscuous mode. It then records how much bandwidth is used by each IP address in the eligible range and applies restrictions when thresholds are met.

In order to compile the penaltybox application on our Debian 6 server and have it support our (newer) packetshaper, we had to apply the following patch:

diff -ur penaltybox/src/benconfig/configexception.h penaltybox.new/src/benconfig/configexception.h
--- penaltybox/src/benconfig/configexception.h  2006-08-23 10:29:54.000000000 -0700
+++ penaltybox.new/src/benconfig/configexception.h      2010-12-23 11:09:18.000000000 -0800
@@ -10,6 +10,7 @@
 #ifndef __CONFIGEXCEPTION_H
 #define __CONFIGEXCEPTION_H
 #include <string>
+#include <cstdio>
 #include "configtypes.h"
 using namespace std;

diff -ur penaltybox/src/benconfig/configloader.cpp penaltybox.new/src/benconfig/configloader.cpp
--- penaltybox/src/benconfig/configloader.cpp   2007-01-17 12:07:13.000000000 -0800
+++ penaltybox.new/src/benconfig/configloader.cpp       2010-12-23 11:10:06.000000000 -0800
@@ -25,6 +25,8 @@
 #include "configloader.h"
 #include <iostream>
 #include <cmath>
+#include <stdio.h>
+#include <stdlib.h>
 #include <assert.h>
 #include "trimstring.h"
 using namespace std;
diff -ur penaltybox/src/capture/Capture.cpp penaltybox.new/src/capture/Capture.cpp
--- penaltybox/src/capture/Capture.cpp  2006-12-13 00:53:56.000000000 -0800
+++ penaltybox.new/src/capture/Capture.cpp      2010-12-23 11:11:27.000000000 -0800
@@ -21,6 +21,10 @@
  *************************************************************************/
 #include "Capture.h"
 #include <pbconfigloader.h>
+#include <string>
+#include <sstream>
+#include <cstring>
+

 #include <iostream>
 using namespace std;
diff -ur penaltybox/src/host/DayTotal.cpp penaltybox.new/src/host/DayTotal.cpp
--- penaltybox/src/host/DayTotal.cpp    2006-12-11 00:20:51.000000000 -0800
+++ penaltybox.new/src/host/DayTotal.cpp        2010-12-23 11:12:53.000000000 -0800
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <time.h>
 #include <stdlib.h>
+#include <strings.h>
 #include <string>

 using namespace std;
diff -ur penaltybox/src/host/HostList.cpp penaltybox.new/src/host/HostList.cpp
--- penaltybox/src/host/HostList.cpp    2006-12-13 01:13:37.000000000 -0800
+++ penaltybox.new/src/host/HostList.cpp        2010-12-23 11:12:25.000000000 -0800
@@ -31,6 +31,8 @@
 #include "../pbconfigloader.h"
 #include <errno.h>
 #include <time.h>
+#include <cstring>
+#include <strings.h>
 using namespace std;
 using namespace Config;

diff -ur penaltybox/src/host/HostNode.cpp penaltybox.new/src/host/HostNode.cpp
--- penaltybox/src/host/HostNode.cpp    2006-08-22 15:45:19.000000000 -0700
+++ penaltybox.new/src/host/HostNode.cpp        2010-12-23 11:12:40.000000000 -0800
@@ -22,6 +22,7 @@

 #include "HostNode.h"
 #include <iostream>
+#include <strings.h>
 using namespace std;
 #include <stdio.h>
 #include <assert.h>
diff -ur penaltybox/src/limiter/Packeteer.cpp penaltybox.new/src/limiter/Packeteer.cpp
--- penaltybox/src/limiter/Packeteer.cpp        2006-12-15 18:59:04.000000000 -0800
+++ penaltybox.new/src/limiter/Packeteer.cpp    2010-12-23 11:14:01.000000000 -0800
@@ -26,6 +26,9 @@
 #include "../benconfig/trimstring.h"
 #include "../pbconfigloader.h"
 #include <assert.h>
+#include <string>
+#include <cstring>
+#include <sstream>

 #include <openssl/md5.h>
 #include <fstream>
@@ -35,6 +38,7 @@

 const int Inbound = 0;
 const int Outbound = 1;
+long int ClassID = 1234567;
 const char * folder[] = { "Inbound/students", "Outbound/students" };


@@ -201,11 +205,17 @@
        string entryStartTagEnd   = "/pb-" + h->GetIp().toString() + "\">\n";
        string entryFootTag       = " </entry>\n</add-delete-schema-objects>\n";

-       string data = " <objectclass><oc-value>iqosTrafficClass</oc-value></objectclass>\n";
+       string s;
+       stringstream st;
+
+       string data = " <objectclass><oc-value>iqosTrafficClass</oc-value></objectclass>\n";
        data       += " <attr name=\"iqosInsideHost\"><value>" + h->GetIp().toString() + "</value></attr>\n";
        data       += xmlpartition;
        data       += " <attr name=\"iqosProtocolName\"><value>IP</value></attr>\n";
-
+       ClassID += 1;
+       st << ClassID;
+       data       += " <attr name=\"iqosClassID\"><value>" + st.str() + "</value></attr>\n";
+

        return entryStartTagBegin + entryStartTagEnd + data + entryFootTag ;
 }
@@ -259,12 +269,12 @@
                xml = xmlhead;
                xml += this->DeleteXml(*r, folder[x]);
                xml += xmlfoot;
-
-               sprintf(message, "+Adding Class: %s/pb-%s\n",
+
+               sprintf(message, "+Adding Class: %s/pb-%s\n",
                                folder[x],
                                (*r).c_str());

-               pb_log_debug(message);
+               pb_log_debug(message);
                SendRequest(xml);
        }
        r++;
@@ -378,11 +388,12 @@

 void Packeteer::UploadNotify() {
        list<string>::iterator p = hostsToNotify.begin();
-       string xml  = xmlhead + "<add-delete-schema-objects>\n<entry dn=\"" + HostListName + "\">\n";
+       // string xml  = xmlhead + "<add-delete-schema-objects>\n<entry dn=\"" + HostListName + "\">\n";
+       string xml  = xmlhead + "<add-delete-schema-objects>\n<entry dn=\"" + "penaltybox" + "\">\n";
               xml += "<objectclass><oc-value>iqosHostList</oc-value></objectclass>\n";

        while (p != hostsToNotify.end()) {
-               pb_log_debug("Adding " + *p + " to redirect\n");
+               pb_log_debug("Adding R2 " + *p + " to redirect\n");
                xml += "<attr name=\"iqosHostListNames\"><value>" + *p + "</value></attr>\n";
                p++;
        }
diff -ur penaltybox/src/pb.cpp penaltybox.new/src/pb.cpp
--- penaltybox/src/pb.cpp       2007-01-11 16:24:48.000000000 -0800
+++ penaltybox.new/src/pb.cpp   2010-12-23 11:17:48.000000000 -0800
@@ -23,6 +23,10 @@
 #include <iostream>
 #include <fstream>
 #include <string>
+#include <cstring>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdio.h>

 #include <pbconfigloader.h>
 #include <pbversion.h>
diff -ur penaltybox/src/socket/http.cpp penaltybox.new/src/socket/http.cpp
--- penaltybox/src/socket/http.cpp      2006-06-30 19:39:54.000000000 -0700
+++ penaltybox.new/src/socket/http.cpp  2010-12-23 11:14:26.000000000 -0800
@@ -20,6 +20,7 @@
  * Written By Benjamin Wilder <mrcawfee@sfsu.edu>
  *************************************************************************/
 #include "http.h"
+#include <strings.h>
 #include <iostream>
 using namespace std;

diff -ur penaltybox/src/socket/url.cpp penaltybox.new/src/socket/url.cpp
--- penaltybox/src/socket/url.cpp       2006-06-30 19:39:54.000000000 -0700
+++ penaltybox.new/src/socket/url.cpp   2010-12-23 11:14:58.000000000 -0800
@@ -21,6 +21,7 @@
  *************************************************************************/
 #include "url.h"
 #include <stdio.h>
+#include <cstring>

 string urlencode(string s) {
   string result;