Scenario:
- Dmasoftlab Radius Manager 4.1 with multiple services. Some of services have dynamic dynamic bandwidth scheduling for day & night. Example some services have double up mode for day , some for evening, and some for night.
- Mikrotik 6.42.7 server with hotspot or pppoe authentication services for LAN users
Problem:
DMA Radius Manager 4.1 ‘s API functionality is broken for Mikrotikr RouterOS newwer versions. The 4.1 code is relying on modifying dynamic queues which had worked on 5.x version (& in some 6.2x seriesas well e.g: v6.29) . Any circumstances where that was doable were bugs that MikroTik has since fixed. And relying on bugs is generally a bad practice. This can be solved by using CoA instead of modifying dynamic queues which I have used in this post.
It is highly recommended that you must upgrade radius manager to latest 4.2 version which works good with new ROS.
Workaround for RM 4.1:
If for some reasons you want to stick with 4.1 version for whatsoever reason, example 4.2 version have some strict licensing policies, and some other things that we cannot mention here & still wants to use ROS latest series like 6.42.7 (as of writing this post) , , & if you still wants to avail dynamic bandwidth changes on the fly for particular services , you can schedule following script which will run on hourly basis and will send bandwidth change request to mikrotik according to the service time.
Limitations of the Script:
- This is a lab testing version of the script. You must modify and tune it for production use. Example the script is doing lots of sql queries, you can minimize it by creating single combined query to fetch all data from the tables, and then read values in next cmd from local file which will be much faster then querying from Mysql.
- The service must have single time schedule. example from 0800 to 1800. Multiple times for single service is not supported.
- Script will run as per cron schedule , despite you have selected specific days or not.
- In lab I have configured it to run every hour , It will query services and its associated users. If the Start time matches , it will send bandwidth change request to the NAS, and if end time matches it will send user original package values to NAS. You can overcome repeating issue by adding additional column in the respective table and update it every time script runs which will check if it have already sent or not.
- You should disable echoing the outputs, it will save some resources.
the Script!
#!/bin/bash # Following script is made specifically for Dmasoftlab radius manager 4.x . It will check "rm_specperbw" table, and if found any servic entry, # It will query that service and make list of users attached to this service, # Then it will query next package , start/end time, and will perform actions accordingly # Syed Jahanzaib # Created: 6-SEP-2018 # Last Modified: 9-SEP-2019 #set -x ####################### # CHANGE these SQLID="root" SQLPASS="SQLROOTPASS" NAS_COA_PORT="1700" ###################### # Script starts here export MYSQL_PWD=$SQLPASS CMD="mysql -u$SQLID --skip-column-names -s -e" DB="radius" #Table which contain main users information USER_TABLE="rm_users" SRV_BW_DB="rm_services" #Table which contains service name id which will be scanned for user and packages DYN_BW_TABLE="rm_specperbw" USER_SERVICE_TABLE="rm_services" # Temp file where services/users list will be saved TMP1="/tmp/bwsch_srv.txt" TMP2="/tmp/bwsch_users.txt" TMP3="/tmp/bwsch_users_final.txt" > $TMP1 > $TMP2 #DATE TIME FUNCTIONS currenttime=$(date +%H:%M:%S) # Look for services that have Dynamic bandwidth change (and remove duplicate entries as well becasue of multipel time definitiosn ins ingle service) $CMD "use $DB; select srvid from $DYN_BW_TABLE" | sort -u >> $TMP1 TOTSRV=`cat $TMP1 | wc -l` echo "Total number of services with Dynamic bandwidth enabled = $TOTSRV / No.s" if [ ! -s $TMP1 ] then echo "No SERVICES found to check for bandwdith changing in $DYN_BW_TABLE , 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 TOTUSR=`cat $TMP2 | wc -l` echo "Total number of users with Dynamic bandwidth enabled = $TOTUSR / No.s" sleep 5 # Remove duplicate users , If any (it was dueto the fact if the service have multiple time defined) #sort -u $TMP2 > $TMP3 if [ ! -s $TMP2 ] then echo "No User found for bandwidth upgrade $DYN_BW_TABLE , exit" exit 1 fi # Run loop forumla to run CMD for single or multi usernames echo "Checking for Dynamic Bandwidth Policies and implemnt change on the fly for online users , if any ..." 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';"` DN_ST=`$CMD "use $DB; select starttime from $DYN_BW_TABLE where srvid ='$SRVID';" |awk 'FNR == 1'` DN_ET=`$CMD "use $DB; select endtime from $DYN_BW_TABLE where srvid ='$SRVID';" |awk 'FNR == 1'` #If time matches if [[ "$currenttime" > "$DN_ST" ]] && [[ "$currenttime" < "$DN_ET" ]]; then ####################### ##### UP-GRADE SECTION ####################### # If user is Online UPGRADE its package ACCTSESID=`$CMD "use $DB; select acctsessionid from radacct where username ='$USERNAME' AND acctstoptime is NULL;"` if [ ! -z "$ACCTSESID" ]; 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' ;"` USER_IP=`$CMD "use $DB; select framedipaddress from radacct where username ='$USERNAME' AND acctstoptime is NULL;"` dlrate_c=`$CMD "use $DB; select dlrate from $DYN_BW_TABLE where srvid ='$SRVID';" |awk 'FNR == 1'` ulrate_c=`$CMD "use $DB; select ulrate from $DYN_BW_TABLE where srvid ='$SRVID';"|awk 'FNR == 1'` ulrate=$(echo $(( $ulrate_c / 1024 )))k dlrate=$(echo $(( $dlrate_c / 1024 )))k DN_BWPKG="$ulrate/$dlrate" echo "UPGRADE ***** USER - $USERNAME / $USER_IP / $ACCTSESID is online, and eligible for package UPGRAD to new package $DN_BWPKG @ $currenttime ..." #for pppoe #echo User-Name=$USERNAME,Acct-Session-Id=$ACCTSESID,Framed-IP-Address=$USER_IP,Mikrotik-Rate-Limit=\"$DN_BWPKG\" | radclient -q -x $NAS_IP:$NAS_COA_PORT coa $NAS_SECRET #for hotspot echo Framed-IP-Address=$USER_IP,Mikrotik-Rate-Limit=\"$DN_BWPKG\" | radclient -q -x $NAS_IP:$NAS_COA_PORT coa $NAS_SECRET #sleep 3 fi else ####################### ##### DOWNGRADE SECTION ####################### # If package DOWNgrade time is matched in services & packages have not changed already, then do it now - zaib ACCTSESID=`$CMD "use $DB; select acctsessionid from radacct where username ='$USERNAME' AND acctstoptime is NULL;"` if [ ! -z "$ACCTSESID" ]; 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' ;"` USER_IP=`$CMD "use $DB; select framedipaddress from radacct where username ='$USERNAME' AND acctstoptime is NULL;"` dlrate_c=`$CMD "use $DB; select downrate from $USER_SERVICE_TABLE where srvid ='$SRVID';" |awk 'FNR == 1'` ulrate_c=`$CMD "use $DB; select uprate from $USER_SERVICE_TABLE where srvid ='$SRVID';"|awk 'FNR == 1'` ulrate=$(echo $(( $ulrate_c / 1024 )))k dlrate=$(echo $(( $dlrate_c / 1024 )))k DN_BWPKG="$ulrate/$dlrate" echo "DOWNGRADE ***** USER - $USERNAME / $USER_IP / $ACCTSESID is online, and eligible for package DOWNGRADE to old package $DN_BWPKG @ $currenttime ..." #for pppoe #echo User-Name=$USERNAME,Acct-Session-Id=$ACCTSESID,Framed-IP-Address=$USER_IP,Mikrotik-Rate-Limit=\"$DN_BWPKG\" | radclient -q -x $NAS_IP:$NAS_COA_PORT coa $NAS_SECRET #for hotspot echo Framed-IP-Address=$USER_IP,Mikrotik-Rate-Limit=\"$DN_BWPKG\" | radclient -q -x $NAS_IP:$NAS_COA_PORT coa $NAS_SECRET #sleep 3 fi fi done # Script Ends Here # Syed Jahanzaib
Regard’s
Syed Jahanzaib