Using Freeradius to proxy and filter Radius accounting traffic

Posted on Sun 21 March 2021 in Networking

I have recently resolved a situation where the Wi-Fi Access Points(APs) at work were generating a very large amount of radius accounting packets due to devices frequently roaming between APs.

Every time a device would roam from one AP to another, it causes the AP to send a radius Start packet when the device connects and a Stop packet when the device disconnects. These packets are sent to the firewall to map the username to the IP address of the device and to allow internet access with the appropriate level of filtering (this is in a school environment).

Due to the AP deployment, there are areas of the site where devices end up roaming between APs way too much, causing excessive Radius accounting packets to be generated which overwhelm the firewall as it tries to keep up with logging users in and out for sessions that only last a few seconds.

Due to the age of the Wi-Fi deployment and the changes to the use of the network, the real fix will be to re-evaluate the AP deployment to match the new requirements of the school. However, this won't happen until summer 2022 at the earliest, so until then I needed to come up with a way to reduce the amount of radius traffic being sent to the firewall.

The solution was to setup a Linux server with Freeradius to act as a proxy for the radius accounting traffic, which could then filter out the unnecessary traffic and only forward on the needed packets to the firewall.

The School was already using Microsoft NPS for radius authentication and proxying of accounting packets, but it lacks the ability to do the kind of filtering needed for this, which is why freeradius was chosen to act as the proxy.

After analysing the radius accounting packets being sent to the firewall, I concluded that the following packets could be filtered out to achieve the desired outcome of students being able to use the internet on their own devices reliably:

  • Anything missing a Framed-IP-Address attribute
    • This is how the firewall knows the IP address of device connected to the Wi-Fi and if it is missing, then the firewall cannot do anything with the packet. Filtering here saves the firewall having to process these.
  • Any stop packet with that has a Acct-Session-Time less than 90 seconds
    • This does mean that some IP addresses will stay logged in as we will miss stop packets, but in this particular environment, we are more concerned with making sure the firewall sees the Start packets to enable students to access the internet. By favouring the Start packets, any changes to IP addresses that get issued will always get picked up, correctly matching the student to the IP.
  • Any Stop packet that arrives later than the current minute
    • This is to filter out any stop packets that get re-sent by the APs when they don't get a response from the firewall.

Filering packets matching the above criteria resulted in ~80% reduction of radius accounting packets being passed on to the firewall and resulted in students being to reliably access the internet again.

Freeradius setup

NOTE: These instructions assume you are installing on Ubuntu 20.4 LTS

On your server install Freeradius:

sudo apt install freeradius

Say yes when prompted to install.

Create a new site config for our proxying setup:

sudo nano /etc/freeradius/3.0/sites-available/filteredProxy

In this file enter the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
server default {

# Listen for the accouting packets
listen {
    ipaddr = *
    port = 0
    type = acct

}

preacct {
    preprocess
    acct_unique
    suffix
}

accounting {
    # Log the packets for debuging
    # Comment this out for production
    detail
    attr_filter.accounting_response

}

session {
    radutmp
}

pre-proxy {

    # This is where we define the rules that will reject packets
    # from being proxied to the firewall.

    # Reject packets missing Framed-IP-Address 
    if (! &Framed-IP-Address) {
        reject
    }

    # Reject stop packets with Acct-Session-Time less that 90s
    if ((&Acct-Status-Type == Stop) && (&Acct-Session-Time < 90)) {
        reject
    }

    # Reject stop packets that arrive outside of the current minute
    if ((&Acct-Status-Type == Stop) && (! &Event-Timestamp =~ /.+%H\:%G.+/)) {
        reject
    }
}

post-proxy {
    # If proxying fails ignore it and return ok
    Post-Proxy-Type Fail-Accouting {
        ok
    }
}

}

# Server you are proxying to
# Replace the 10.0.0.1 with the IP address of the destination for the proxied packets
# Replace yourSharedSecret with the radius secret you are using with the
# destination server
home_server firewall.example.com {
    type = acct
    ipaddr = 10.0.0.1
    port = 1813
    secret = yourSharedSecret
    status_check = status-server

}

# Specify the pool of servers we are proxying to
# In this case we are only using one    
home_server_pool acct_pool.example.com {
    type = fail-over
    home_server = firewall.example.com
}

# Specify the realm we are interested in. In this particular setup
# there is no realm in the username, so we use NULL
realm NULL {
    acct_pool = acct_pool.example.com
}

Open the clients.conf file to add your radius accounting sources.

sudo nano /etc/freeradius/3.0/clients.conf

At the end of the file, add one of the following for each of your radius accounting sources. In the example below we specify one specific server and one subnet.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Config for a specific server
client specificServer {
    ipaddr = 10.0.0.2
    proto = *
    secret = yourSharedSecret
    require_message_authenticator = no
    nas_type = other
}

# Config for a subnet
client specificSubnet {
    ipaddr = 10.0.1.0/24
    proto = *
    secret = yourSharedSecret
    require_message_authenticator = no
    nas_type = other
}

Now add the new config to the enabled sites and remove the default config:

1
2
3
4
5
6
7
sudo -i
cd /etc/freeradius/3.0/sites-enabled
ln -s ../sites-available/filteredProxy ./
rm default
rm inner-tunnel
rm ../mods-enabled/eap
exit

Start the Freeradius service

sudo /etc/init.d/freeradius start

Set the service to start automatically on boot

sudo systemctl enable freeradius.service

You can now start to migrate your APs to use the newly created server as the destination for their accounting packets. The server will proxy them onto the destination server, filtering out any packets that match the defined rules in the pre-proxy section of the filteredProxy config file.