FREERADIUS WITH MIKROTIK – Part #1 – General Tip’s Click here to read more on FR tutorials …
Disclaimer! This is important!
Every Network is different , so one solution cannot be applied to all. Therefore try to understand logic & create your own solution as per your network scenario. Just dont follow copy paste.
If anybody here thinks I am an expert on this stuff, I am NOT certified in anything Mikrotik/Cisco/Linux or Windows. However I have worked with some core networks and I read , research & try stuff all of the time. So I am not speaking/posting about stuff I am formerly trained in, I pretty much go with experience and what I have learned on my own. And , If I don’t know something then I read & learn all about it.
So , please don’t hold me/my-postings to be always 100 percent correct. I make mistakes just like everybody else. However – I do my best, learn from my mistakes and always try to help others.
Regard's Syed Jahanzaib~
Scenario:
In freeradius , we have to add NAS client entries either in clients.conf
or in nas
table to allow communication from NAS with freeradius services (for AAA requests). This is good from security perspective to allow only specific IP addresses, BUT what if your NASes are spreaded across different location (geographically different places) and have dynamic IP addresses like DSL , 3G/4G etc.
As a workaround we can setup a vpn server on our central location and connect all remote NAS (es) to this vpn server but this requires additional configuration at server end and all client end’s as well.
Another workaround is to ALLOW all ip addresses to communicate with FR service which is really a BAD idea from security perspective As ALAN once said:
Are you willing to let anyone on the net send RADIUS packets to your RADIUS server?
Another workaround is to allow only specific IP subnet range , for this you have to inquire about the IP range that ISP is assigning to that particular NAS
& allow this range in your clients.conf
.
1# Howto enable freeradius to inquire about NAS clients using SQL NAS table
To enable freeradius to read clients details from NAS table in SQL, We need to modify in sql.conf
file …
Edit following file /etc/freeradius/sql.conf
nano /etc/freeradius/sql.conf file
Uncomment the following
readclients = yes
So after modifications some portion of the file may look like following …
# Connection info: server = "localhost" #port = 3306 login = "radius" password = "zaib1234" readclients = yes
Now add one entry in this table & restart your Freeradius service.
mysql> select * from nas; +---+---------------+------------+-------+------+------------+------+------+---------------+------+ | 1 | 101.11.11.255 | testmk | other | NULL | testing123 | NULL | NULL | RADIUS Client | 3799 | +---+---------------+------------+-------+------+------------+------+------+---------------+------+ 1 rows in set (0.00 sec)
This table contains data about your NASes (like mikrotik etc). It is more convenient to to maintain the NAS details in the database.
NOTE: Whenever you add / edit / remove any entry in clients.conf or NAS table, you must restart freeradius service by following cmd
service freeradius restart
You can use following NAS table also, adding just for reference purposes …
-- phpMyAdmin SQL Dump -- version 4.5.4.1deb2ubuntu2 -- http://www.phpmyadmin.net -- -- Host: localhost -- Generation Time: Jun 29, 2018 at 03:25 PM -- Server version: 5.7.21-0ubuntu0.16.04.1-log -- PHP Version: 7.0.22-0ubuntu0.16.04.1 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; SET time_zone = "+00:00"; /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8mb4 */; -- -- Database: `radius` -- -- -------------------------------------------------------- -- -- Table structure for table `nas` -- CREATE TABLE `nas` ( `id` int(10) NOT NULL, `nasname` varchar(128) NOT NULL, `shortname` varchar(32) DEFAULT NULL, `type` varchar(30) DEFAULT 'other', `ports` int(5) DEFAULT NULL, `secret` varchar(60) NOT NULL DEFAULT 'secret', `server` varchar(64) DEFAULT NULL, `community` varchar(50) DEFAULT NULL, `description` varchar(200) DEFAULT 'RADIUS Client', `nas_coa_port` int(32) NOT NULL DEFAULT '3799' ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Dumping data for table `nas` -- INSERT INTO `nas` (`id`, `nasname`, `shortname`, `type`, `ports`, `secret`, `server`, `community`, `description`, `nas_coa_port`) VALUES (1, '10.0.0.3', 'ZAIB_CCR_GW', 'other', NULL, 'testing123', NULL, NULL, 'RADIUS Client', 3799); -- -- Indexes for dumped tables -- -- -- Indexes for table `nas` -- ALTER TABLE `nas` ADD PRIMARY KEY (`id`), ADD KEY `nasname` (`nasname`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `nas` -- ALTER TABLE `nas` MODIFY `id` int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
2# Adding NAS Clients entries in CLIENTS.CONF file
In /etc/freeradius/clients.conf
use below format to allow either single ip, subnet, or Allow ANY IP (all all ip’s is is not recommended*)
# To allow specific NAS single IP only
# To allow ONLY specific NAS via clients.conf client 92.168.10.1 { secret = testing123 shortname = Mikrotik }
# To allow specific SUBNET ip (example if remote NAS have dynamic public ip but the ip remains from specific subnet range)
client test_subnet_nas { ipaddr = 192.168.10.0 secret = testing123 netmask = 24 }
To allow ANY ip to send request to freeradius server (not recommended)
# To allow ANY NAS client which is not recommended* client 0.0.0.0/0 { secret = testing123 shortname = Mikrotik }
3# Allow NAS AAA Requests based on NAS-IDENTIFIER
In Some situations we would like to authenticate user only if its coming from SPECIFIC NAS only (not by ip, but by NAS-Identifier attribute).
Example if client request coming from NAS which have system identifiaction of ZAIB_CCR_GW , then process authentication request further ELSE REJECT !
First you need to allow NAS requests from ALL or Subnet range IP.
# To allow ANY NAS client which is not recommended* client 0.0.0.0/0 { secret = testing123 shortname = Mikrotik }
Users Table Sample !
We have a user table which contains a column nas_id
. We will add a SQL IF statement which will check the the connecting user NAS-Identifier
& match it with users allowed nas_id in the user’s table.
-- -- Table structure for table `users` -- CREATE TABLE `users` ( `id` int(10) NOT NULL, `username` varchar(128) NOT NULL, `password` varchar(32) NOT NULL, `firstname` text NOT NULL, `lastname` text NOT NULL, `email` text NOT NULL, `mobile` text NOT NULL, `cnic` text NOT NULL, `srvname` text NOT NULL, `srvid` int(3) NOT NULL, `expiration` date DEFAULT NULL, `mac` varchar(30) NOT NULL, `macvendor` varchar(128) NOT NULL, `bwpkg` varchar(256) NOT NULL, `pool` varchar(128) DEFAULT 'other', `is_enabled` int(1) NOT NULL, `is_days_expired` int(1) NOT NULL, `is_qt_expired` int(1) NOT NULL, `is_uptime_expired` int(1) NOT NULL, `qt_total` varchar(32) NOT NULL, `qt_used` varchar(20) NOT NULL, `uptime_limit` varchar(20) NOT NULL, `uptime_used` varchar(32) NOT NULL, `owner` text NOT NULL, `vlanid` varchar(32) NOT NULL, `nas_id` varchar(32) DEFAULT NULL, `createdon` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- -- Dumping data for table `users` --
Now we will add a USERS entry as sample …
INSERT INTO `users` (`id`, `username`, `password`, `firstname`, `lastname`, `email`, `mobile`, `cnic`, `srvname`, `srvid`, `expiration`, `mac`, `macvendor`, `bwpkg`, `pool`, `is_enabled`, `is_days_expired`, `is_qt_expired`, `is_uptime_expired`, `qt_total`, `qt_used`, `uptime_limit`, `uptime_used`, `owner`, `vlanid`, `nas_id`, `createdon`) VALUES (1, 'zaib', 'zaib', 'OK', 'jahanzaib', 'aacableAThotmailDOTcom', '03333021909', '1234567890-1-1', '1mb', 9, '2018-01-04', '00:0C:29:B9:D8:A0', '', '1024k/1024k', 'public-pool', 1, 0, 0, 0, '0', '2933559', '0', '', 'xxxxxx', 'ether1-LAN-DUMMY', 'someinvalid_CCR_GW', '2018-06-29 11:06:52');
Now we will add the SQL IF statement that will actually check every incoming Authentication request for matching NAS-IDENTIFIER with nas_id
column in users
table.
Edit Default Sites-Enabled
file,
nano /etc/freeradius/sites-enabled/default
& paste following in `Authorize` Section
if ("%{sql: select nas_id from users where username = '%{User-Name}'}" != "%{NAS-Identifier}") { update reply { Reply-Message = 'Error: You are not allowed to connect form this NAS ! Bingo - zaib' } update control { Auth-Type := "Reject" } }
Save & Exit.
Now reload Freeradius
in Debug Mode (by freeradius -X
) & monitor the debugging.
If user will connect from another NAS (which is not matched in with nas_id column in the USERS
table , he will get denied with the message.
Note: For testing purposes . I have added dummy entry in user’s nas_id
column.
############################################### # Showing relevant data only for demo purposes - Syed Jahanzaib - 29-JUN-2018 ############################################### rad_recv: Access-Request packet from host 10.0.0.1 port 49453, id=150, length=124 Service-Type = Framed-User Framed-Protocol = PPP NAS-Port = 15729249 NAS-Port-Type = Ethernet User-Name = "zaib" Calling-Station-Id = "24:26:42:D4:BC:43" Called-Station-Id = "service1" NAS-Port-Id = "ether10" User-Password = "zaib" NAS-Identifier = "ZAIB_CCR_GW" NAS-IP-Address = 10.0.0.1 # Executing section authorize from file /etc/freeradius/sites-enabled/default ++? if ("%{sql: select nas_id from users where username = '%{User-Name}'}" != "%{NAS-Identifier}") sql_xlat expand: %{User-Name} -> zaib sql_set_user escaped user --> 'zaib' expand: select nas_id from users where username = '%{User-Name}' -> select nas_id from users where username = 'zaib' rlm_sql (sql): Reserving sql socket id: 25 sql_xlat finished rlm_sql (sql): Released sql socket id: 25 expand: %{sql: select nas_id from users where username = '%{User-Name}'} -> ZAIB_CCR_GW1 expand: %{NAS-Identifier} -> ZAIB_CCR_GW ? Evaluating ("%{sql: select nas_id from users where username = '%{User-Name}'}" != "%{NAS-Identifier}") -> TRUE ++? if ("%{sql: select nas_id from users where username = '%{User-Name}'}" != "%{NAS-Identifier}") -> TRUE ++if ("%{sql: select nas_id from users where username = '%{User-Name}'}" != "%{NAS-Identifier}") { +++update reply { +++} # update reply = noop +++update control { +++} # update control = noop ++} # if ("%{sql: select nas_id from users where username = '%{User-Name}'}" != "%{NAS-Identifier}") = noop Found Auth-Type = Reject Auth-Type = Reject, rejecting user Failed to authenticate the user. Using Post-Auth-Type Reject # Executing group from file /etc/freeradius/sites-enabled/default +group REJECT { ++update reply { ++} # update reply = noop [sql] expand: %{User-Name} -> zaib [sql] sql_set_user escaped user --> 'zaib' [sql] expand: INSERT into radpostauth (username, pass, mac, nasipaddress, reply, authdate, reason) values ('%{User-Name}', '%{User-Password:-Pap-Password}', '%{Calling-Station-Id}', '%{NAS-IP-Address}', '%{reply:Packet-Type}', NOW(), '%{reply:Reply-Message}') -> INSERT into radpostauth (username, pass, mac, nasipaddress, reply, authdate, reason) values ('zaib', 'zaib', '24:26:42:D4:BC:43', '10.0.0.1', 'Access-Reject', NOW(), 'Error: You are not allowed to connect form this NAS =21') rlm_sql (sql) in sql_postauth: query is INSERT into radpostauth (username, pass, mac, nasipaddress, reply, authdate, reason) values ('zaib', 'zaib', '24:26:42:D4:BC:43', '10.0.0.1', 'Access-Reject', NOW(), 'Error: You are not allowed to connect form this NAS =21') rlm_sql (sql): Reserving sql socket id: 24 rlm_sql (sql): Released sql socket id: 24 ++[sql] = ok [attr_filter.access_reject] expand: %{User-Name} -> zaib attr_filter: Matched entry DEFAULT at line 11 ++[attr_filter.access_reject] = updated +} # group REJECT = updated Delaying reject of request 3 for 1 seconds Going to the next request Waking up in 0.9 seconds. Sending delayed reject for request 3 Sending Access-Reject of id 150 to 10.0.0.1 port 49453 Reply-Message = "Error: You are not allowed to connect form this NAS !" Waking up in 4.9 seconds. Cleaning up request 3 ID 150 with timestamp +104 Ready to process requests.
.
& if the users request matches , he will be granted access (off course after all other checks)
Regard’s
Syed Jahanzaib