Menu

YfiTechDynamicClients

Anonymous

Dynamic Clients

This page will discuss the following:

  • The problem we have with DHCP public IP Addresses as clients of FreeRADIUS
  • A solution FreeRADIUS has to offer us.
  • Configuring FreeRADIUS to handle dynamic IP Addresses.

Acknowledgements

  • Many of the info on this page actually comes from a discussion on the FreeRADIUS mailing list:

http://freeradius.1045715.n5.nabble.com/Authorising-Clients-by-Calling-Station-ID-Not-IP-tc4883866.html

Introduction


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.


How FreeRADIUS does it

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.

What is required

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:

Defining Clients

In FreeRADIUS, clients are defined in two places.

  • clients.conf: This text file contains various client definitions.
  • sql: The nas table in the SQL database can contain various client definitions.

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.

  • VPN: We can create a VPN connection from the client to the FreeRADIUS server and make use of known private range of IP's and direct the RADIUS traffic over this VPN.
  • FreeRADIUS Dynamic Clients: FreeRADIUS now includes a nice option to add clients dynamically upon first contact of the RADIUS server.

Dynamic Clients

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.


Dynamic Clients -> Background

FreeRADIUS includes a sample dynamic client server. Under the sites-available directory is a file called dynamic-clients. This sample consist of the following:

  • client: A client definition. This is almost the same as the client definitions in the clients.conf file aside from a few specifics discussed here.
  • virtual server: A special virtual server specified to be used by the client defined in the same file.

Client definition

We will use a catch all client definition:

  • ipaddr: A value of 0.0.0.0 will include any IP Address
  • netmask: Together with the ipaddr we also need to specify a netmask. 0 is used to include any IP Address.

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.

Virtual server definition

We define a special virtual server for the dynamic clients. This virtual has the following characteristics:

  • It only contains an authorize section.
  • The authorize section only has one request attribute available to evaluate. This is the source IP Address of the request called Packet-Src-IP-Address.
  • It is called by the dynamic client defined in the same virtual server file (dynamic-clients).

What the virtual server does

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.

Determining the client detail

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.

  • sql: This is handy to obtain information from a database table
  • raw: This module does not come standard with FreeRADIUS but has to be patched and compiled before we can use it.

In awe of rlm_raw

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.

Explaining XLAT strings

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.

XLAT definition

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

Usage of xlat strings

xlat strings are typically used in unlang. xlat strings can be categorized into two categories:

  • xlat strings related to modules
  • xlat strings related to attribute lists.

Module xlat strings

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}"
    

Attribute list xlat strings

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'}"
    

In closing on xlat

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.


Dynamic Clients -> YFi Implementation

NOTE: FreeRADIUS 2.2.0

  • The xlat_unregister function call changed in this version and you have to patch the patch :-)
  • 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);
    

Compiling a patched version of FreeRADIUS

With all this background knowledge it is time to see how dynamic clients can be implemented with YFi Hotspot Manager.

  • Download the latest source file for FreeRADIUS (2.1.12 at the time of this writing).
  • Download the rlm_raw patch from this page.
  • 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:

https://sourceforge.net/apps/trac/hotcakes/wiki/yfi_setup_FreeRADIUS#Activateandchangechillispotdictionary

  • 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
    

Add dynamic clients virtual server

  • 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.

  • You will also note that after the registration of the dynamic client, the request continues in the same way that a normal request would have been processed.
  • You will note that the value of NAS-IP-Address is usually the same as the value of the Packet-Src-IP-Address. This is not a requirement and the value of NAS-IP-Address can actually be something different just used as a place holder value. So when you define a dynamic client (NAS device) in YFi, simply supply a place holder IP Address for the dynamic client.

The value of the shared secret

  • If you have a few NAS devices behind one NAT firewall and implemented Dynamic Clients on FreeRADIUS, remember that all the NAS devices should have the same shared secret.
  • It is advisable to have a common shared secret used by all NAS devices deployed behind NATed connections.

Here's why

  • DSL connection get DHCP IP Address X.
  • The NAS devices behind it contact a FreeRADIUS that implemented Dynamic Clients.
  • FreeRADIUS dynamically adds IP Address X (with the group of NAS devices using the same shared secret).
  • Later the DHCP lease for the IP Address X expires.
  • DSL modem now get IP Address Y.
  • Another DSL modem get IP Address X.
  • There could also be a NAS device behind the other DSL modem.
  • If this NAS happens to contact the FreeRADIUS server using a different shared secret, you are in for a nasty surprise.

Accounting Records

  • Although a few devices may share a common public IP Address, one should still be able to differentiate between them in the accounting data.
  • Simply ensure each supply a different value for the incoming NAS-IP-Address AVP.

Related

Wiki: Home
Wiki: YfiTechBeta6VM
Wiki: YfiTechOpenMeshHeartbeat