This page will discuss the following:
There are many public areas served with Internet Hotspots. These hotspots typically makes use of a captive portal to authenticate the users
The hotspots then makes use of a RADIUS server to authenticate the users and also to keep count of the usage (AAA).
When these hotspots sit behind a NATed firewall there is a potential problem since most of these connections comes from a DHCP assigned public IP Address.
RADIUS unfortunately requires a known IP Address for each client connecting. This makes configurations that use DHCP assigned public IP Addresses difficult to handle. Fortunately the authors of FreeRADIUS supplied us a way to handle this problem.
In the above schematic we see that all three Access Points will appear as though they originate from the same source. This is because of the NAT which allow all three devices to share a single IP Address.
In the schematic above we see that when a request comes to FreeRADIUS it first check if it knows the client before further handling the request.
The source IP Address of a client who wants to connect is compared to a known list of pre-defined clients. If there is a match the request is further taken care of.
If there is no match, we can either add the client's detail dynamically and further process the request, or silently discard the request.
In order for FreeRADIUS to know about a client that will connect to it, the following is required:
Item
Description
IP Address
The IP Address which the client will contact the RADIUS server with
Shared secret
A shared secret between the client and the server
Lets see how normal clients are defined:
In FreeRADIUS, clients are defined in two places.
Although the contents of the SQL database appear to be dynamic, FreeRADIUS only reads all the client definitions into memory during start-up and not again there after.
This makes the definition of NAS devices with IP Addresses that changes impossible. For this we can use two options.
With dynamic clients the FreeRADIUS server dynamically add the client just before the request is further processed by FreeRADIUS server.
In order for this to happen, the contents of a few control attributes has to be populated. These attributes can be dynamically populated by using a few external sources.
FreeRADIUS includes a sample dynamic client server. Under the sites-available directory is a file called dynamic-clients. This sample consist of the following:
We will use a catch all client definition:
There is a special directive called dynamic_clients which is used to specify a virtual server that should be used to add the clients dynamically.
Once the client is added (and as long as the IP Address does not change), the clients dynamic created detail will remain cached for the time specified in the lifetime directive.
After that time the detail expires and has to be again dynamically added as soon as the first request after expiration arrives.
Clients does not have to only defined in the clients.conf file. In the dynamic-clients file we see one defined together with a virtual server.
We define a special virtual server for the dynamic clients. This virtual has the following characteristics:
The virtual server essentially populate the client definition of a client dynamically when the client first connects.
How the client detail is obtained is up to the person configuring FreeRADIUS.
If the client's detail could be populated, the authorize section should return ok to allow further processing of the request.
The following client detail should be populated. (This is done using internal attributes added to the control attribute list.
Internal Attribute
Comments
FreeRADIUS-Client-IP-Address
This is usually replaced with the only available attribute called Packet-Src-IP-Address
FreeRADIUS-Client-Require-MA
Specify if request from client should include Message-Authenticator attribute
FreeRADIUS-Client-Secret
Specify the secret that is shared between the client and server
FreeRADIUS-Client-Shortname
Short descriptive name for client
FreeRADIUS-Client-NAS-Type
Specify the type of NAS
If you are familiar with defining NASes in the clients.conf file or in SQL, you will note that these are the standard type of info we provide when defining a NAS.
In order for us to populate the values of these control attributes there are two xlat strings which we can make use of.
Unfortunately as stated before, the only attribute that 'bleeds' through to the virtual server is the IP Address of the client that tries to connect (Packet-Src-IP-Address).
If we want to learn of any of the other attributes in the request, we have to make use of the rlm_raw module.
THE ONLY WAY TO GET TO THE ATTRIBUTES INSIDE THE REQUEST OF THE DYNAMIC CLIENT VIRTUAL SERVER IS BY USING rlm_raw!!!'''
This module does not come standard with FreeRADIUS. This means FreeRADIUS first has be be patched to include it and then compiled and installed from source before we can use it.
The reason we would want to use rlm_raw to get the value of certain attributes from the request is that we can then in turn compare it with some info stored in a database table and then based on the outcome decide if we want to dynamically add the client to the list of known clients.
We can now for instance check the presence and value of Called-Station-Id (A MAC address) and compare it with a SQL table containing MAC addresses of devices we know.
We can use the analogy of someone from the post office arriving with a packet at your doorstep. You know it's from the post office (Packet-Src-IP-Address) but but first want to make sure the packet is safe or from someone you know. This is where rlm_raw comes in. We use rlm_raw to look into the packet for certain attributes and once we are satisfied with the values of those attributes we accept the packet.
If you read some of the FreeRADIUS documentation or even some of the replies on the FreeRADIUS mailing lists people sometimes refer to xlat strings.
The SQL module now supports SQL queries in xlat strings.
or
The ldap module now supports LDAP URLs in xlat strings.
To catch up with the FreeRADIUS lingo we ask google what XLAT means:
XLAT â€" TransLATe There may be many popular meanings for XLAT with the most popular definition being that of TransLATe
xlat strings are typically used in unlang. xlat strings can be categorized into two categories:
These strings will either start with the original module name like sql or ldap, or the instance name of the module, if there are a few instances defined and you want to use one.
sql: This tells us that the text which follows sql: should be something which the sql module understands (This is typically a SQL statement).
"%{sql:SELECT mytable.field1 FROM `mytable` WHERE 1}" "%{sql_clients:SELECT mytable.field1 FROM `mytable` WHERE 1}"
ldap: This tells us the text that follows ldap: should be something which the ldap module understands (This is typically a LDAP query).
"%{ldap:ldap:///dc=company,dc=com?uid?sub?uid=%u}" "%{ldap_company1:ldap:///dc=company1,dc=com?uid?sub?uid=%u}"
raw: The raw module. This module contains a list of incoming raw attributes which can be fetched.
"%{raw:User-Name}"
Attributes in FreeRADIUS belongs to one of three possible lists. To identify the list in which an attribute is located, we specify it with an xlat string.
request: The request attribute list.
"%{request:User-Name}"
control: The control attribute list.
"%{control:Auth-Type}"
reply: The reply attribute list.
"%{reply:Reply-Message := 'Long Time'}"
So in terms of FreeRADIUS and xlat strings, we can say that we specify a module or an attribute list that we want to address (eg sql:), and then we continue with something the module or attribute list understands.
Everything following the module or attribute list we specified, should be understood by the module or attribute list
The sql xlat string is the most complicated, other xlat strings are usually simply the value of an attribute in that module or list that we want.
After you extracted the patch look for the following:
+ xlat_unregister(data->xlat_name, raw_xlat);
Change it to the following:
+ xlat_unregister(data->xlat_name, raw_xlat, instance);
With all this background knowledge it is time to see how dynamic clients can be implemented with YFi Hotspot Manager.
Extract the tar file
tar -xzvf freeradius-server-2.1.12.tar.gz
Apply the rlm_raw patch
gunzip rlm_raw_patch.gz mv rlm_raw_patch freeradius-server-2.1.12 cd freeradius-server-2.1.12 patch -p1 < rlm_raw_patch
If all goes according to plan the following output should show on your screen:
system@ubuntu-32:~/Documents/raw/freeradius-server-2.1.12$ patch -p1 < rlm_raw_patch patching file src/modules/rlm_raw/config.h.in patching file src/modules/rlm_raw/configure patching file src/modules/rlm_raw/configure.in patching file src/modules/rlm_raw/Makefile.in patching file src/modules/rlm_raw/rlm_raw.c patching file src/modules/stable Hunk #1 FAILED at 39. 1 out of 1 hunk FAILED -- saving rejects to file src/modules/stable.rej
This simply means the last part of the patch did not happen. You can manually fix it by adding the following to the bottom of the src/modules/stable file.
rlm_raw
This will cause FreeRADIUS to be build with the raw module since we tell it that rlm_raw is a stable module.
* Build and install FreeRADIUS as normal.
./configure | tee config_out.txt make sudo make install sudo ldconfig
Confirm rlm_raw in installed. (Should list rlm_raw.a rlm_raw.so and rlm_raw.la)
ls /usr/local/lib/rlm_raw.*
Because of the Non-standard place we put the YFi attributes (BAD YFi), we have to add the YFi attributes again after the patched version of FreeRADIUS has been installed. See this link to change the dictionary:
Modify the rights again as required for YFi
sudo chown root.www-data /usr/local/etc/raddb/proxy.conf sudo chmod 664 /usr/local/etc/raddb/proxy.conf sudo chmod 644 /usr/local/etc/raddb/dictionary sudo ldconfig
As a final test issue the following command and ensure no errors are present.
sudo /usr/local/sbin/radiusd -X
Modify the /usr/local/etc/raddb/sites-available/dynamic-clients file to have the following:
#Define a client that has a 'catch all' client dymamic { ipaddr = 0.0.0.0 netmask = 0 #We spacify the virtual server that will be used for client verification dynamic_clients = dynamic_client_server lifetime = 86400 } server dynamic_client_server { authorize { #With YFi we mis-use the optional Community field in the NAS table to specify the value of an attribute that the raw module should read #In this sample we use the MAC address of the Device running Coova Chilli, but you can use any of the attributes inside the request. #The mac is then added as the value of the Community optional field in YFi to create a match #rlm_raw: Called-Station-Id = 08-00-27-56-22-0B #Test to see if our required raw attribute exists if("%{raw:Called-Station-Id}"){ #Test to see if it is in the DB if ("%{sql: select count(*) from nas where community='%{raw:Called-Station-Id}'}" == 1) { update control { FreeRADIUS-Client-IP-Address = "%{Packet-Src-IP-Address}" FreeRADIUS-Client-Require-MA = no FreeRADIUS-Client-Secret = "%{sql: select nas.secret from nas where nas.community='%{raw:Called-Station-Id}'}" FreeRADIUS-Client-Shortname = "%{sql: select shortname from nas where community='%{raw:Called-Station-Id}'}" FreeRADIUS-Client-NAS-Type = "other" #Optional Virtual server #FreeRADIUS-Client-Virtual-Server = "dynamic_server" } ok } } } }
Activate the dynamic-clients virtual server.
sudo su cd /usr/local/etc/raddb/sites-enabled ln -s ../sites-available/dynamic-clients ./
Create a raw module in file /usr/local/etc/raddb/modules/raw (empty definition)
raw { }
Tell FreeRADIUS to instantiate the raw module upon start-up. Edit the /usr/local/etc/raddb/radiusd.conf file and ensure raw is added to the instantiate section:
instantiate { ..... raw ..... }
Restart the FreeRADIUS server and do an authentication attempt to see if the dynamic clients work as intended. Here's the feedback from my system where I'm just using dynamic client definitions.
rad_recv: Access-Request packet from host 127.0.0.1 port 48312, id=44, length=282 server dynamic_client_server { rlm_raw: Called-Station-Id = 08-00-27-56-22-0B rlm_raw: Called-Station-Id = 08-00-27-56-22-0B rlm_sql (sql): Reserving sql socket id: 4 rlm_sql (sql): Released sql socket id: 4 rlm_raw: Called-Station-Id = 08-00-27-56-22-0B rlm_sql (sql): Reserving sql socket id: 3 rlm_sql (sql): Released sql socket id: 3 rlm_raw: Called-Station-Id = 08-00-27-56-22-0B rlm_sql (sql): Reserving sql socket id: 2 rlm_sql (sql): Released sql socket id: 2 } # server dynamic_client_server - Added client 127.0.0.1 with shared secret testing123 rad_recv: Access-Request packet from host 127.0.0.1 port 48312, id=44, length=282 ChilliSpot-Version = "1.2.5" User-Name = "dvdwalt@ri" User-Password = "dvdwalt@ri" Service-Type = Login-User Acct-Session-Id = "4ebe4ab100000001" Framed-IP-Address = 10.1.0.2 NAS-Port-Type = Wireless-802.11 NAS-Port = 1 NAS-Port-Id = "00000001" Calling-Station-Id = "08-00-27-83-EB-FB" Called-Station-Id = "08-00-27-56-22-0B" NAS-IP-Address = 127.0.0.1 NAS-Identifier = "Residence_Inn" WISPr-Location-ID = "isocc=,cc=,ac=,network=Coova," WISPr-Location-Name = "My_HotSpot" WISPr-Logoff-URL = "http://10.1.0.1:3990/logoff" Message-Authenticator = 0x3e2ec225667630119ddd2f1b612c6f0e # Executing section authorize from file /usr/local/etc/raddb/sites-enabled/default
You will note that on subsequent request the first lookup and registration does not happen again due to the cached values specified by the lifetime directive in the client's definition.
Here's why
Wiki: Home
Wiki: YfiTechBeta6VM
Wiki: YfiTechOpenMeshHeartbeat