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.
This particular script was tested in Virtual environment only, therefore consider this posting as an reference only, donot use it in production environment.
Regard's Syed Jahanzaib~
Scenario:
We have a generic FreeRADIUS Version 2.2.8 based billing system in Ubuntu 16.04.3 LTS Server. Users are authenticating to NAS (Mikrotik) which is using Freeradius as its AAA Server.
Requirement:
Currently users packages are flat 1mb, 2mb and so on. We would like to introduce different bandwidth for day and night for specific services. Upgrade/Downgrade of user package should be done by dynamically with COA, so that package changes must be done on the fly without disconnecting user.
I made a simple bash script to perform the job, but that required different cron jobs to start/end the packages, also if the server was powered off on that particular time then schedule will be missed till next run. This was major PITA. Therefore I added few more checks and balances so that if the job misses its schedule time, it will execute it self BUT avoiding re-running of same action.
Its a bit complicated piece of BASH scripting , but so far doing its job.
Software / Hardware Components Used:
- NAS: Mikrotik CCR1036 / Firmware: 6.42.1
- Radius: Ubuntu 16.04.3 LTS Server Edition / 64bit
- FreeRADIUS Version: 2.2.8 using apt-get installation
SERVICES Table!
/*!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 `services` CREATE TABLE `services` ( `srvid` int(10) NOT NULL, `srvname` varchar(128) NOT NULL, `descr` varchar(128) DEFAULT NULL, `enabled` varchar(1) NOT NULL DEFAULT '1', `expdays` int(4) NOT NULL DEFAULT '0', `dlimit` varchar(32) NOT NULL DEFAULT '0', `ulimit` varchar(32) NOT NULL DEFAULT '0', `qt_enabled` tinyint(1) NOT NULL, `tot_qt` int(32) NOT NULL DEFAULT '0', `free_quota_enabled` tinyint(1) NOT NULL DEFAULT '0', `free_qt_start_time` time NOT NULL, `free_qt_end_time` time NOT NULL, `dyn_bw_change` int(1) NOT NULL DEFAULT '0', `dn_bwpkg` varchar(16) NOT NULL DEFAULT '0', `dn_st_time` time NOT NULL, `dn_et_time` time NOT NULL, `dn_st_exec` int(1) NOT NULL DEFAULT '0', `dn_et_exec` int(1) NOT NULL DEFAULT '0', `ippool` varchar(64) NOT NULL, `createdon` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=latin1; -- Dumping data for table `services` INSERT INTO `services` (`srvid`, `srvname`, `descr`, `enabled`, `expdays`, `dlimit`, `ulimit`, `qt_enabled`, `tot_qt`, `free_quota_enabled`, `free_qt_start_time`, `free_qt_end_time`, `dyn_bw_change`, `dn_bwpkg`, `dn_st_time`, `dn_et_time`, `dn_st_exec`, `dn_et_exec`, `ippool`, `createdon`) VALUES (9, '1mb', '1mb 30 days expity', '1', 30, '1024k', '1024k', 1, 1024, 1, '00:00:00', '00:00:00', 1, '2048k/2048k', '13:00:00', '23:00:00', 0, 1, 'public-pool', '2018-06-27 12:13:04'); -- Indexes for dumped tables -- Indexes for table `services` ALTER TABLE `services` ADD PRIMARY KEY (`srvid`), ADD KEY `nasname` (`srvname`); -- AUTO_INCREMENT for dumped tables -- AUTO_INCREMENT for table `services` ALTER TABLE `services` MODIFY `srvid` int(10) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=10; /*!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 */;
the Script !
Following is bash script which will query different tables and take action according to the results. Scheduled to run hourly (or decide as per network load)
#!/bin/bash # Following script will check specific table, and if found any servic entry (ID), # It will query that service and make list of users attached to this service, # Then it will query next pacakge , start/end time, and will perform actions accordingly # It will also check if package change is already done, then ignore as per condition # Syed Jahanzaib # Created: 25-Jun=2018 # Last Modified: 27-Jun-2018 # set -x SQLID="SQLID" SQLPASS="SQLPASSWORD" export MYSQL_PWD=$SQLPASS CMD="mysql -u$SQLID --skip-column-names -s -e" DB="radius" #Table which contain main users information USER_TABLE="users" #Table which contains users name which will be scanned for quota SRV_BW_DB="services" #Log table in which few actions will be logged USER_TABLE_LOG="log" #Rad-user group in which we will update user profile like from 1mb to different pacake as per service GROUP="radgroupreply" # Temp file where user list will be saved TMP1="/tmp/bwsch_srv.txt" TMP2="/tmp/bwsch_users.txt" #DATE TIME FUNCTIONS currenttime=$(date +%H:%M:%S) # Look for services that have Dynamic bandwidth change $CMD "use $DB; select srvid from $SRV_BW_DB where dyn_bw_change ='1';" > $TMP1 if [ ! -s $TMP1 ] then echo "No SERVICES found to check for bandwdith changing in $SRV_BW_DB , exit" exit 1 fi # If required service found then look for Users num=0 cat $TMP1 | while read srvid do num=$[$num+1] SRVID=`echo $srvid |awk '{print $1}'` $CMD "use $DB; select username from $USER_TABLE where srvid ='$SRVID';" > $TMP2 done if [ ! -s $TMP2 ] then echo "No User found for bandwidth upgrade $SRV_BW_DB , exit" exit 1 fi # Run loop forumla to run CMD for single or multi usernames num=0 cat $TMP2 | while read users do num=$[$num+1] USERNAME=`echo $users |awk '{print $1}'` SRVID=`$CMD "use $DB; select srvid from $USER_TABLE where username ='$USERNAME';"` SRVNAME=`$CMD "use $DB; select srvname from services where srvid = '$SRVID';"` DLIMIT=`$CMD "use $DB; select dlimit from services where srvid ='$SRVID';"` ULIMIT=`$CMD "use $DB; select ulimit from services where srvid ='$SRVID';"` DN_BWPKG=`$CMD "use $DB; select dn_bwpkg from services where srvid ='$SRVID';"` DN_ST=`$CMD "use $DB; select dn_st_time from services where srvid ='$SRVID';"` DN_ET=`$CMD "use $DB; select dn_et_time from services where srvid ='$SRVID';"` DN_ST_EXEC=`$CMD "use $DB; select dn_st_exec from services where srvid ='$SRVID';"` DN_ET_EXEC=`$CMD "use $DB; select dn_et_exec from services where srvid ='$SRVID';"` GRPNAME=`$CMD "use $DB; select groupname from radgroupreply where groupname ='$SRVNAME';"` # If package UPgrade time is matched in services & packages have not changed already, then do it now - zaib echo "* Checking for Dynamic Bandwidth Changing. Match Start/End time, Check if upgrade/downgrade is already done etc," if [[ "$currenttime" > "$DN_ST" ]] && [[ "$currenttime" < "$DN_ET" ]]; then # Avoid recurrence for same if [ "$DN_ST_EXEC" -eq 0 ]; then # Update User group for bandwidth change $CMD "use $DB; update $GROUP set value= '$DN_BWPKG' where groupname ='$GRPNAME';" NAS_IP=`$CMD "use $DB; select nasipaddress from radacct where username ='$USERNAME' AND acctstoptime is NULL;"` NAS_SECRET=`$CMD "use $DB; select secret from nas where nasname = '$NAS_IP' ;"` NAS_COA_PORT=`$CMD "use $DB; select nas_coa_port from nas where nasname = '$NAS_IP';"` ACCTSESID=`$CMD "use $DB; select acctsessionid from radacct where username ='$USERNAME' AND acctstoptime is NULL;"` $CMD "use $DB; update services set dn_st_exec= '1' where srvid ='$SRVID';" $CMD "use $DB; update services set dn_et_exec= '0' where srvid ='$SRVID';" echo "************** Bandwidht Packages UPgraded to New as per time **************" fi # If user is Online if [ ! -z "$ACCTSESID" ]; then echo User-Name=zaib,Mikrotik-Rate-Limit=\"$DN_BWPKG\" | radclient -x $NAS_IP:$NAS_COA_PORT coa $NAS_SECRET fi else # If package DOWNgrade time is matched in services & packages have not changed already, then do it now - zaib # BUT Avoid recurrence for same if [ "$DN_ET_EXEC" -eq 0 ]; then NAS_IP=`$CMD "use $DB; select nasipaddress from radacct where username ='$USERNAME' AND acctstoptime is NULL;"` NAS_SECRET=`$CMD "use $DB; select secret from nas where nasname = '$NAS_IP' ;"` NAS_COA_PORT=`$CMD "use $DB; select nas_coa_port from nas where nasname = '$NAS_IP';"` ACCTSESID=`$CMD "use $DB; select acctsessionid from radacct where username ='$USERNAME' AND acctstoptime is NULL;"` $CMD "use $DB; update $GROUP set value= '$DLIMIT/$ULIMIT' where groupname ='$GRPNAME';" $CMD "use $DB; update services set dn_st_exec= '0' where srvid ='$SRVID';" $CMD "use $DB; update services set dn_et_exec= '1' where srvid ='$SRVID';" echo "************** Bandwidht Packages Downgraded to original packages **************" fi if [ ! -z "$ACCTSESID" ]; then echo User-Name=zaib,Mikrotik-Rate-Limit=\"$DLIMIT/$ULIMIT\" | radclient -x $NAS_IP:$NAS_COA_PORT coa $NAS_SECRET fi fi done
Result:
When bandwidth time change starts …
root@radius:/temp# ./bwsch.sh * Checking for Dynamic Bandwidth Changing. Match Start/End time, Check if upgrade/downgrade is already done etc, ************** Bandwidht Packages UPgraded to New as per time ************** Sending CoA-Request of id 94 to 10.0.0.6 port 3799 User-Name = "zaib" Mikrotik-Rate-Limit = "2048k/2048k" rad_recv: CoA-ACK packet from host 10.0.0.6 port 3799, id=94, length=38 NAS-Identifier = "_CCR_GW" NAS-IP-Address = 10.0.0.6 root@radius:/temp# root@radius:/temp# ./bwsch.sh * Checking for Dynamic Bandwidth Changing. Match Start/End time, Check if upgrade/downgrade is already done etc, root@radius:/temp# ********************************** root@radius:/temp# ./bwsch.sh * Checking for Dynamic Bandwidth Changing. Match Start/End time, Check if upgrade/downgrade is already done etc, ************** Bandwidht Packages Downgraded to original packages ************** Sending CoA-Request of id 54 to 10.0.0.6 port 3799 User-Name = "zaib" Mikrotik-Rate-Limit = "1024k/1024k" rad_recv: CoA-ACK packet from host 10.0.0.6 port 3799, id=54, length=38 NAS-Identifier = "_CCR_GW" NAS-IP-Address = 10.0.0.6 root@radius:/temp# ./bwsch.sh * Checking for Dynamic Bandwidth Changing. Match Start/End time, Check if upgrade/downgrade is already done etc, root@radius:/temp#
BEFORE
AFTER
When bandwidth time change ends … return pkg to normal