In this post I will say something about FreeRadius config files, database connection, basic instruction how to insert user in database, etc. Before you step inside this post, I recommend reading part 1 and part 2.
I suppose you’re using RH based distros (Red Hat, CentOS, Fedora,..) and you already installed FreeRadius from source (config files are located in /usr/local/etc/raddb/). Now lets get back to FreeRadius source dir (the place where you extracted the tar.gz).
Inside redhat dir you can find freeradius-radiusd-init script which can be used for easy start/stop radiusd process. Copy this script to /etc/init.d/ dir
# cp freeradius-radiusd-init /etc/init.d/radiusd
Now open /etc/init.d/radiusd script and change the next lines
exec=${exec:=/usr/sbin/$prog}
config_dir=${config_dir:=/etc/raddb}
config=${config:=$config_dir/radiusd.conf}
pidfile=${pidfile:=/var/run/$prog/$prog.pid}
lockfile=${lockfile:=/var/lock/subsys/radiusd}
into
exec=${exec:=/usr/local/sbin/$prog}
config_dir=${config_dir:=/usr/local/etc/raddb}
config=${config:=$config_dir/radiusd.conf}
pidfile=${pidfile:=/usr/local/var/run/$prog/$prog.pid}
lockfile=${lockfile:=/var/lock/subsys/radiusd}
Save changes and exit from editor. (Notice above that we actually changed the path from / to /usr/local/)
Now you can easily start/stop radiusd process.
[root@ms /]# service radiusd
Usage: /etc/init.d/radiusd {start|stop|status|restart|condrestart|try-restart|reload|force-reload}
Also, you can exec chkconfig –level 235 radiusd on to start radiusd on boot.
Now lets get back to our setup.
I suppose you have at least one NAS (A Network Access Server (NAS) is a system that provides access to a network. In some cases also known as a Terminal Server or Remote Access Server (RAS).) NAS is a CLIENT for your radiusd server so please do not mess users and clients. Freeradius doesn’t interact with your users directly so “radius client” is another term for NAS.
The first step is to add your NAS to client list and to create a unique password. Inside clients.conf (/usr/local/etc/raddb/clients.conf) you can find the next lines
#client 192.168.0.0/24 {
# secret = testing123-1
# shortname = private-network-1
#}
Uncomment those lines and set up client IP address according to your addresses. In the example shown above, all IPs from 192.168.0.0/24 network will be able to use your radiusd server.
You can allow any IP with
client 0.0.0.0/0 {
secret = mysecret
shortname = myNAS
}
which means all IPs in the world can use my radius server (which is not recommended)…
To allow only one IP (in this case 192.168.0.15),
client 192.168.0.15 {
secret = mysecret
shortname = myNAS
}
Delete user Cleartext-Password := “password” line from users because we don’t need this any more.
Stop radiusd and start in debugging mode (radiusd -X).
You should see the similar lines
...............
radiusd: #### Loading Clients ####
client localhost {
ipaddr = 127.0.0.1
require_message_authenticator = no
secret = "testing123"
nastype = "other"
}
client 192.168.0.15 {
require_message_authenticator = no
secret = "mysecret"
shortname = "myNAS"
}
...........
This means that radiusd will allow NAS with IP address 192.168.0.15 and secret mysecret. Ctrl+C to stop radiusd.
In case you want to use MySQL with freeradius, you should do the next steps. Before anything, you need to create a database for freeradius.
Connect as root to your mysql and exec next queries.
CREATE USER 'radius'@'localhost' IDENTIFIED BY 'radpass';
GRANT USAGE ON * . * TO 'radius'@'localhost' IDENTIFIED BY 'radpass';
CREATE DATABASE IF NOT EXISTS `radius` ;
GRANT ALL PRIVILEGES ON `radius` . * TO 'radius'@'localhost';
Another option is to use admin.sql script from raddb/sql/mysql dir.
CREATE USER 'radius'@'localhost';
SET PASSWORD FOR 'radius'@'localhost' = PASSWORD('radpass');
GRANT SELECT ON radius.* TO 'radius'@'localhost';
GRANT ALL ON radius.radacct TO 'radius'@'localhost';
GRANT ALL ON radius.radpostauth TO 'radius'@'localhost';
This script will set a little bit safer permissions where radius will be able only to write radacct and radpostauth tables. (Do not forget to change default username/pass shown above).
The next step is to import default Freeradius tables (the sql files can be found inside raddb/sql/mysql dir). You should import nas.sql and schema.sql. The nas.sql will create a table for your NASes. It is much easier to maintain the NAS list inside database then inside clients.conf. Also, you can add more fields to nas table so you can do other operations with your NAS.
After this operations you should have something like:
[root@ms mysql]# mysql -u radius -p
Enter password:
Welcome TO the MySQL monitor. Commands END WITH ; OR \g.
Your MySQL connection id IS 23387
Server version: 5.0.77-log SOURCE distribution
TYPE 'help;' OR '\h' FOR help. TYPE '\c' TO clear the buffer.
mysql> USE radius;
Reading TABLE information FOR completion OF TABLE AND COLUMN names
You can turn off this feature TO GET a quicker startup WITH -A
DATABASE changed
mysql> SHOW TABLES;
+------------------+
| Tables_in_radius |
+------------------+
| nas |
| radacct |
| radcheck |
| radgroupcheck |
| radgroupreply |
| radpostauth |
| radreply |
| radusergroup |
+------------------+
8 ROWS IN SET (0.00 sec)
mysql>
Now we have a working database and we need to configure FreeRadius to use SQL.
radiusd.conf
Open radiusd.conf file (/usr/local/etc/raddb/radiusd.conf), and uncomment $INCLUDE sql.conf line inside modules section. Save changes and exit.
sql.conf
Open sql.conf and edit next lines
# Connection info:
server = "localhost"
#port = 3306
login = "radius"
password = "radpass"
# Database table configuration for everything except Oracle
radius_db = "radius"
to fit your settings (database name, username and password).
dialup.conf
Then open /usr/local/etc/raddb/sql/mysql/dialup.conf and find the next lines (near the end)
# Uncomment simul_count_query to enable simultaneous use checking
simul_count_query = "SELECT COUNT(*) \
FROM ${acct_table1} \
WHERE username = '%{SQL-User-Name}' \
AND acctstoptime IS NULL"
Sometimes you will need to check users for simultaneous use and uncommenting sql in session section and uncommenting the query shown above will help you to do this.
default
Now open /usr/local/etc/raddb/sites-available/default and uncomment sql lines inside authorize, accounting and session sections. You can uncomment sql inside post-auth section too if you want to log login attempts (notice that this is not recommended for production servers. Your database can grow and eat up all free space in case someone tries to brute force your NAS.).
Then comment the next lines: files inside authorize section, detail, unix and radutmp inside accounting section and radutmp inside session section.
Please note that those lines we commented above are not important for now and commenting those lines can improve performance. Also, note that detail should remain uncommented in case you want to create ‘detail’ed log of the packets for accounting requests. You will need this in case you want to proxy accounting to another server.
Then save the file and check your config with radiusd -X (debugging mode).
After this you should see something like
rlm_sql (sql): Driver rlm_sql_mysql (module rlm_sql_mysql) loaded and linked
rlm_sql (sql): Attempting to connect to radius@localhost:/radius
rlm_sql (sql): starting 0
rlm_sql (sql): Attempting to connect rlm_sql_mysql #0
rlm_sql_mysql: Starting connect to MySQL server for #0
rlm_sql (sql): Connected new DB handle, #0
rlm_sql (sql): starting 1
rlm_sql (sql): Attempting to connect rlm_sql_mysql #1
rlm_sql_mysql: Starting connect to MySQL server for #1
rlm_sql (sql): Connected new DB handle, #1
rlm_sql (sql): starting 2
rlm_sql (sql): Attempting to connect rlm_sql_mysql #2
rlm_sql_mysql: Starting connect to MySQL server for #2
rlm_sql (sql): Connected new DB handle, #2
rlm_sql (sql): starting 3
rlm_sql (sql): Attempting to connect rlm_sql_mysql #3
rlm_sql_mysql: Starting connect to MySQL server for #3
rlm_sql (sql): Connected new DB handle, #3
rlm_sql (sql): starting 4
rlm_sql (sql): Attempting to connect rlm_sql_mysql #4
rlm_sql_mysql: Starting connect to MySQL server for #4
rlm_sql (sql): Connected new DB handle, #4
which means your freeradius server successfully connected to MySQL database.
There are hundreds of options inside the files shown above and it is impossible to explain all of them. Read comments inside config files and try to figure yourself about them. If you’re using another database scheme, you will need to set up sql.conf and dialup.conf according to your tables. All parameters are editable and it is very easy to understand them. For example if you have a large number on users (1000-xxxx) open sql.conf and increase num_sql_socks from 5 to 15 or 20.
You should not change/delete any other lines in the config file without reading and understanding the comments!
Populating tables and testing
This is the most important part. Before you continue, you need to know what actually do you want from FreeRadius. Which kind of connection do you expect, etc. Also, you need to know something about tables, attributes, operators, etc.
This is it for now…. Next time we will add some users inside database and see what we can do.
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
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'
);
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)
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"
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');
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');
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');
Then we need to assign this user with created service (group)
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]#
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');
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
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');
Assigning with suspended group can be done with
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
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');
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');
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
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.
2 comments
If I put the table radusergroup one username any two other groups, so always loads only one and the other does not, what do they function both?
Thanks
You have to change authorize_group_reply_query in queries.conf like that;
authorize_group_reply_query = "\
SELECT id, GroupName, Attribute, Value, op \
FROM ${groupreply_table} \
WHERE GroupName in (SELECT GroupName FROM ${usergroup_table} WHERE UserName='%{SQL-User-Name}') \
ORDER BY id
Post a Comment