In the last article about FreeRadius (Here), I wrote about basic settings and now I’ll write something about inserting users into database (MySQL).
The FreeRadius database schema contains several tables:
nas
This table contains data about NASes (radius clients) and it is a “replacement” for clients.conf file. It is much easier to maintain the clients in the database than inside config file. If you want to use database for NAS list, skip the step in the last howto (the part about clients.conf). Also, in case you want to keep your NASes in the nas table, you’ll need to uncomment the readclients = yes inside sql.conf.
# Set to 'yes' to read radius clients from the database ('nas' table)
# Clients will ONLY be read on server startup. For performance
# and security reasons, finding clients via SQL queries CANNOT
# be done "live" while the server is running.
#
readclients = yes |
# Set to 'yes' to read radius clients from the database ('nas' table)
# Clients will ONLY be read on server startup. For performance
# and security reasons, finding clients via SQL queries CANNOT
# be done "live" while the server is running.
#
readclients = yes
As you can see from the comment, you will need to restart radiusd process to allow/disallow specific NAS.
nas table schema is located inside raddb/sql/mysql/nas.sql
To add IP 192.168.0.15 inside nas table, exec next query:
INSERT INTO nas VALUES (NULL , '192.168.0.15', 'myNAS', 'other', NULL , 'mysecret', NULL , NULL , 'RADIUS Client'
); |
INSERT INTO nas VALUES (NULL , '192.168.0.15', 'myNAS', 'other', NULL , 'mysecret', NULL , NULL , 'RADIUS Client'
);
and you will have
mysql> select * from nas;
+----+--------------+-----------+-------+-------+----------+--------+-----------+---------------+
| id | nasname | shortname | type | ports | secret | server | community | description |
+----+--------------+-----------+-------+-------+----------+--------+-----------+---------------+
| 1 | 192.168.0.15 | myNAS | other | NULL | mysecret | NULL | NULL | RADIUS Client |
+----+--------------+-----------+-------+-------+----------+--------+-----------+---------------+
1 row in set (0.00 sec) |
mysql> select * from nas;
+----+--------------+-----------+-------+-------+----------+--------+-----------+---------------+
| id | nasname | shortname | type | ports | secret | server | community | description |
+----+--------------+-----------+-------+-------+----------+--------+-----------+---------------+
| 1 | 192.168.0.15 | myNAS | other | NULL | mysecret | NULL | NULL | RADIUS Client |
+----+--------------+-----------+-------+-------+----------+--------+-----------+---------------+
1 row in set (0.00 sec)
radacct
This table is used for accounting data. In case you want to collect traffic stats, you will need to uncomment sql inside accounting {} section in /usr/local/etc/raddb/sites-available/default. The same table can be used for simultaneous use checking which is faster than radutmp. All you need to do is to uncomment sql inside session {} section inside /usr/local/etc/raddb/sites-available/default and uncomment simul_count_query inside /usr/local/etc/raddb/sql/mysql/dialup.conf
radcheck
This table keeps the check attributes for users (User-Password, Cleartext-Password, Expiration, Simultaneous-Use, Auth-Type, …)
radreply
Is used for reply attributes for specific user. For example Framed-IP-Address, upload and download speed, etc…
radgroupcheck
This table keeps the check attributes for groups (which means, all users inside specific group will be checked against this attributes).
radgroupreply
The same like radreply but for groups. (all users in specific group will get the same speed, etc). Also, Framed-Pool attribute goes here.
radpostauth
This table is used for logging failed login attempts. To use this, you’ll need to uncomment sql inside postauth section (/usr/local/etc/raddb/sites-available/default.). Think twice before you enable this option because it can overload your server with constant inserts. Your customers will probably spend their money on wireless or wired routers so the logging attempts will come over and over.
radusergroup
This table keeps relation between username and specific group and group priority. In Freeradius 1.x this table was named “usergroup” so in case you have your own billing which is made for old schema, rename this table to usergroup
# Table to keep group info
usergroup_table = "radusergroup" |
# Table to keep group info
usergroup_table = "radusergroup"
Examples
We will create a sample service with the next attributes:
– 512kbps download speed
– 128kbps upload speed
– we will use PPPoE – Point to Point Protocol Over Ethernet
– we will assign dynamic IP addresses to our clients from “internet” IP pool
INSERT INTO `radgroupreply` (`id` ,`groupname` ,`attribute` ,`op` ,`value` )
VALUES (NULL , 'testservice', 'Ascend-Xmit-Rate', ':=', '524288'),
(NULL , 'testservice', 'Ascend-Data-Rate', ':=', '131072'),
(NULL , 'testservice', 'Framed-Pool', ':=', 'internet'); |
INSERT INTO `radgroupreply` (`id` ,`groupname` ,`attribute` ,`op` ,`value` )
VALUES (NULL , 'testservice', 'Ascend-Xmit-Rate', ':=', '524288'),
(NULL , 'testservice', 'Ascend-Data-Rate', ':=', '131072'),
(NULL , 'testservice', 'Framed-Pool', ':=', 'internet');
As you can see the speed is converted to bps.

After you created the service, lets create a sample user (assigned with created service).
As I noticed above, check attributes should be placed inside radcheck table.
INSERT INTO `radcheck` (`id` ,`username` ,`attribute` ,`op` ,`value` )
VALUES (NULL , 'testuser', 'User-Password', ':=', 'testpassword'),
(NULL , 'testuser', 'Simultaneous-Use', ':=', '1'); |
INSERT INTO `radcheck` (`id` ,`username` ,`attribute` ,`op` ,`value` )
VALUES (NULL , 'testuser', 'User-Password', ':=', 'testpassword'),
(NULL , 'testuser', 'Simultaneous-Use', ':=', '1');
In this sample, the password is in plain text format which is not reccommended. Insted User-Password (which is alternative to Cleartext-Password for Mikrotik) better option is to use MD5-Password but keep in mind that you won’t be able to use CHAP.
INSERT INTO `radcheck` (`id` ,`username` ,`attribute` ,`op` ,`value` )
VALUES (NULL , 'testuser', 'MD5-Password', ':=', MD5( 'testpassword' ) ),
(NULL , 'testuser', 'Simultaneous-Use', ':=', '1'); |
INSERT INTO `radcheck` (`id` ,`username` ,`attribute` ,`op` ,`value` )
VALUES (NULL , 'testuser', 'MD5-Password', ':=', MD5( 'testpassword' ) ),
(NULL , 'testuser', 'Simultaneous-Use', ':=', '1');

Then we need to assign this user with created service (group)
INSERT INTO `radusergroup` (`username` ,`groupname` ,`priority` )
VALUES ('testuser', 'testservice', '1'); |
INSERT INTO `radusergroup` (`username` ,`groupname` ,`priority` )
VALUES ('testuser', 'testservice', '1');

After those inserts, lets test
[root@ns2 raddb]# radtest testuser testpassword 127.0.0.1 0 testing123
Sending Access-Request of id 228 to 127.0.0.1 port 1812
User-Name = "testuser"
User-Password = "testpassword"
NAS-IP-Address = 192.168.0.10
NAS-Port = 0
Message-Authenticator = 0x00000000000000000000000000000000
rad_recv: Access-Accept packet from host 127.0.0.1 port 1812, id=228, length=54
Ascend-Xmit-Rate = 524288
Ascend-Data-Rate = 131072
Framed-Pool = "internet"
[root@ns2 raddb]# |
[root@ns2 raddb]# radtest testuser testpassword 127.0.0.1 0 testing123
Sending Access-Request of id 228 to 127.0.0.1 port 1812
User-Name = "testuser"
User-Password = "testpassword"
NAS-IP-Address = 192.168.0.10
NAS-Port = 0
Message-Authenticator = 0x00000000000000000000000000000000
rad_recv: Access-Accept packet from host 127.0.0.1 port 1812, id=228, length=54
Ascend-Xmit-Rate = 524288
Ascend-Data-Rate = 131072
Framed-Pool = "internet"
[root@ns2 raddb]#
As you can see, the username/password combination is valid and RADIUS server returned all attributes assigned with user’s group.
To suspend user’s account you can insert Auth-Type := Reject for user.
INSERT INTO `radcheck` (`id` ,`username` ,`attribute` ,`op` ,`value` )
VALUES (NULL , 'testuser', 'Auth-Type', ':=', 'Reject'); |
INSERT INTO `radcheck` (`id` ,`username` ,`attribute` ,`op` ,`value` )
VALUES (NULL , 'testuser', 'Auth-Type', ':=', 'Reject');
and we have
[root@ns2 raddb]# radtest testuser testpassword 127.0.0.1 0 testing123
.....
rad_recv: Access-Reject packet from host 127.0.0.1 port 1812, id=145, length=20 |
[root@ns2 raddb]# radtest testuser testpassword 127.0.0.1 0 testing123
.....
rad_recv: Access-Reject packet from host 127.0.0.1 port 1812, id=145, length=20
Another option for disabling users is assigning with specific group which has Auth-Type := Reject inside radgroupcheck
INSERT INTO `radgroupcheck` (`id` ,`groupname` ,`attribute` ,`op` ,`value` )
VALUES (NULL , 'suspended', 'Auth-Type', ':=', 'Reject'); |
INSERT INTO `radgroupcheck` (`id` ,`groupname` ,`attribute` ,`op` ,`value` )
VALUES (NULL , 'suspended', 'Auth-Type', ':=', 'Reject');
Assigning with suspended group can be done with
UPDATE `radusergroup`
SET `groupname` = 'suspended'
WHERE `username` = 'testuser'
AND `priority` = 1; |
UPDATE `radusergroup`
SET `groupname` = 'suspended'
WHERE `username` = 'testuser'
AND `priority` = 1;

and we have
rad_recv: Access-Reject packet from host 127.0.0.1 port 1812, id=198, length=20 |
rad_recv: Access-Reject packet from host 127.0.0.1 port 1812, id=198, length=20
Also, keep in mind that routers will try to connect again and again so you will have a big problems in case you have thousands of users. Another option is to assign users with specific group which doesn’t have Auth-Type attribute. Instead rejecting you can assign internal IPs and redirect them to suspended page.
Many questions on FreeRadius mailing list are about Simultaneus-Use. Solution to this problem is very simple and it is very rude to ask this question again and again…
All you need to do is to insert Simultaneous-Use := 1 for specific user (radcheck table) or inside radgroupcheck if you want to limit all users inside specific group.
INSERT INTO `radgroupcheck` (`id` ,`groupname` ,`attribute` ,`op` ,`value` )
VALUES (NULL , 'testservice', 'Simultaneous-Use', ':=', '1'); |
INSERT INTO `radgroupcheck` (`id` ,`groupname` ,`attribute` ,`op` ,`value` )
VALUES (NULL , 'testservice', 'Simultaneous-Use', ':=', '1');
In case you want to set Expiration attribute you can insert the date and the time inside radcheck table.
INSERT INTO `radcheck` (`id` ,`username` ,`attribute` ,`op` ,`value` )
VALUES (NULL , 'testuser', 'Expiration', '==', 'November 30 2011 00:00:00'); |
INSERT INTO `radcheck` (`id` ,`username` ,`attribute` ,`op` ,`value` )
VALUES (NULL , 'testuser', 'Expiration', '==', 'November 30 2011 00:00:00');
then we have
[root@ns2 raddb]# radtest testuser testpassword 127.0.0.1 0 testing123
Sending Access-Request of id 28 to 127.0.0.1 port 1812
User-Name = "testuser"
User-Password = "testpassword"
NAS-IP-Address = 192.168.0.10
NAS-Port = 0
Message-Authenticator = 0x00000000000000000000000000000000
rad_recv: Access-Accept packet from host 127.0.0.1 port 1812, id=28, length=60
Ascend-Xmit-Rate = 524288
Ascend-Data-Rate = 131072
Framed-Pool = "internet"
Session-Timeout = 670889 |
[root@ns2 raddb]# radtest testuser testpassword 127.0.0.1 0 testing123
Sending Access-Request of id 28 to 127.0.0.1 port 1812
User-Name = "testuser"
User-Password = "testpassword"
NAS-IP-Address = 192.168.0.10
NAS-Port = 0
Message-Authenticator = 0x00000000000000000000000000000000
rad_recv: Access-Accept packet from host 127.0.0.1 port 1812, id=28, length=60
Ascend-Xmit-Rate = 524288
Ascend-Data-Rate = 131072
Framed-Pool = "internet"
Session-Timeout = 670889
You can note Session-Timeout attribute which contains the time in seconds between this moment and the date inside Expiration field. According to this value, the NAS will auto disconnect user when this time expire (in our case 670889 seconds). In case you set the time which already passed (for example yesterdays date) the user will be rejected.
Please keep in mind that this date format works for Mikrotik. I didn’t have chance to test it with other NASes.
If you want to reconnect users at regular intervals (for example every 24 hours – 86400 seconds) you can insert Session-Timeout inside radreply table (because it isn’t check attribute).
To recconect every user inside specific group, add this attribute inside radgroupreply table.
To assign a static IP for specific user insert Framed-IP-Address attribute inside radreply table where Value will be that IP address. Operator should be :=.
Please keep in mind that all inserts inside those tables are visible to radius server right after insert. Only inserts inside nas table won’t be until the restart (service radiusd restart)
I hope this post will help you to set up your own RADIUS server. Also, keep in mind that this is just an example and all this can done in many other ways.
In case you find a spelling errors please contact me so I can fix them.