Syed Jahanzaib Personal Blog to Share Knowledge !

March 29, 2019

March 25, 2019

Mikrotik with Freeradius/mySQL # Part-21 – Weird Trigger for Duplicate Users

Filed under: Mikrotik Related, Radius Manager — Tags: , — Syed Jahanzaib / Pinochio~:) @ 11:13 AM

dup user.jpg

fre



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:

  • We have DMASOFTLAB radius manager installed as a billing system in Ubuntu 12.04 server
  • Mikrotik version 6.4x.x is acting as Hotspot NAS and connected with radius for AAA

Requirement: [A Weird one really]

As operator demanded

“We are running Hotspot on mikrotik, & client login to hotspot using his mobile/laptop. If logged-in client leaves his primary location without logout, & move to another location, & if he try to login from another device, his request will gets DENY because of Single user limit. We increased it to 2 by using SIM-USE=2 directive in user properties,It allows second session to login, but both sessions can use the bandwidth, therefore we want that once second session is established its old first live session should get kicked. If it was single Hotspot we could have used the script on LOGIN, but there are several NAS spreaded across various location using single radius.”

if the user uses same device then we could have used

if (User-Name){
if("%{sql:UPDATE radacct set AcctStopTime=ADDDATE(AcctStartTime,INTERVAL AcctSessionTime SECOND), AcctTerminateCause='Clear-Stale Session' WHERE UserName='%{User-Name}' and CallingStationId='%{Calling-Station-Id}' and AcctStopTime is NULL}"){
}
}

but things are different in hotspot as I have observed, if devices are different then it will give us already logged-in error, if we use sim-use=2 then second device can be logged-in but old session will also be alive and both ids will suck the bandwidth at a time.

Also using idle-timeout or keep-alive timeout is the simplest way to achieve this , but for some weird reasons and to avoid long arguments dueto accent issues, I made one customized solution for the operator.


Solution:

Login to mysql with root

mysql -uroot -pXXXX

and switch to radius database

use radius;

Now create new table that will hold duplicate users record

MYSQL Table to hold duplicate users list


--
-- Table structure for table `rm_dupusers`
--

DROP TABLE IF EXISTS `rm_dupusers`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `rm_dupusers` (
`dupid` int(9) NOT NULL AUTO_INCREMENT,
`datetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`username` varchar(64) NOT NULL,
`ip` varchar(16) NOT NULL,
`nas` varchar(16) NOT NULL,
`comments` varchar(64) DEFAULT NULL,
KEY `dupid` (`dupid`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `rm_dupusers`
--

MYSQL TRIGGER to check duplicate users sessions

Now we will create a new Trigger that will be executed when any record is inserted in radacct, it will check for existing duplicate session of user and if it found , it will add its entry in the mysql table of rm_dupusers

drop trigger chk_dup_user;
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER `chk_dup_user` BEFORE INSERT ON `radacct` FOR EACH ROW BEGIN
SET @dupuserchk = (SELECT count(*) from radacct where username=New.username and acctstoptime is NULL);
IF (@dupuserchk = 1) THEN
SET @dupusername = (SELECT username from radacct where username=New.username and acctstoptime is NULL);
SET @dupuserip = (SELECT framedipaddress from radacct where username=New.username and acctstoptime is NULL);
SET @dupusernas = (SELECT nasipaddress from radacct where username=New.username and acctstoptime is NULL);
INSERT into rm_dupusers (dupid,username,ip,nas,comments) values ('',@dupusername,@dupuserip,@dupusernas,'Duplicate User');
END IF;
END */;;
DELIMITER ;

Mysql Part is Done.

Now we will create a BASH script that will scheduled to run every minute.

BASH script !

Create bash script in desired folder, in this example I am using /temp folder as default

mkdir /temp
touch /temp/kickdupuser.sh
chmod +x /temp/kickdupuser.sh
nano /temp/kickdupuser.sh

& paste following, make sure to modify credentials

#!/bin/bash
#set -x
# Following script is made specifically for Dmasoftlab radius manager 4.1.x
# When any new user will login, it will simply check if exists session of same user found, it will kick previous session
# it requires custom trigger on radacct table, this script will be schedule to run every minute
# Created: 25-MARCH-2019
# Tested on Ubuntu OS Only
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
#################
# CHANGE these
HOSTNAME=`hostname`
SQLID="root"
SQLPASS="XXXXXX"
NAS_COA_PORT="1700"
DB="radius"
SRV="mysql"
DUP_TABLE="rm_dupusers"
INT="1"
RADCLIENT="/usr/local/bin/radclient"
#################
#DATE TIME FUNCTIONS
currenttime=$(date +%H:%M:%S)
# Add Script start execution entry in the /var/log/syslog to see if the script got executed or not
logger "Duplicate User poller script Started @ $currenttime by the CRON scheduler ... Powered by SYED.JAHANZAIB"
echo "- Script Start Time - $currenttime"
echo "- Checking Duplicate Users in $DUP_TABLE table ..."
export MYSQL_PWD=$SQLPASS
CMD="mysql -u$SQLID --skip-column-names -s -e"
#Table which contain main users information
TMPUSRINFO=/tmp/userpass.txt
TEMP="/temp"

# Checking if /temp folder is previously present or not . . .
{
if [ ! -d "$TEMP" ]; then
echo
echo "- INFO: $TEMP folder not found, Creating it now to store logs ..."
mkdir $TEMP
else
echo -e "- INFO: $TEMP folder is already present to store logs."
echo
fi
}

DUP_LIST_FILE=$TEMP/duplicate_users_list.txt
SYSLOG="/var/log/syslog"
> $TMPUSRINFO

# KANNEL DETAILS
KHOST="127.0.0.1:13013"
KID="kannel"
KPASS="KANNEL_PASSWORD"

IPADD=`ip route get 1 | awk '{print $NF;exit}'`
SRVSTATUS=`service $SRV status |grep running |wc -l`
if [ "$SRVSTATUS" -ne 1 ];
#if [ -z "$SRVSTATUS" ];
then
echo "- ALERT: $HOSTNAME - $IPADD - $SRV NOT RESPONDING CHECK - $DATE $DT .Exiting ..."
echo "- ALERT: $HOSTNAME - $IPADD - $SRV NOT RESPONDING CHECK - $DATE $DT .Exiting ..." >> $SYSLOG
echo "- ALERT:

- $HOSTNAME
- $IPADD
- $SRV not responding ***
- $currenttime

Exiting ..."
exit 1
else
echo "- INFO: $SRV service is accessible. Proceeding further ... OK"
fi

# Check if table exists
if [ $($CMD \
"select count(*) from information_schema.tables where \
table_schema='$DB' and table_name='$DUP_TABLE';") -eq 1 ]; then
echo "- INFO: $DUP_TABLE Table exists ..."
else
echo "- WARNING: $DUP_TABLE Table does not exists ..."
fi
########
########
# Enable following line so that it will update all users simultanous-use to '2' so that two sessions can be established
# $CMD "use $DB; UPDATE  radius.radcheck SET value = '2' where Attribute = 'Simultaneous-Use';
#######
#######
# pull user record
$CMD "use $DB; select username,ip,nas from $DUP_TABLE WHERE datetime >= NOW() - INTERVAL $INT MINUTE;" >> $TMPUSRINFO
if [ ! -s $TMPUSRINFO ]
then
endtime=$(date +%H:%M:%S)

echo "
- INFO: No Duplicate User found in DMA RADIUS MANAGER TABLE '$DUP_TABLE' , Sending EXIT signals ...

- Script Ends Here...
- EXITING peacefully...
- Script End Time - $endtime
"
exit 1
fi

# Apply Count Loop Formula while deleting first line which have junk text
num=0
cat $TMPUSRINFO | while read users
do
num=$[$num+1]
username=`echo $users | awk '{print $1}'`
USER_IP=`echo $users | awk '{print $2}'`
ACCTSESID=`$CMD "use $DB; select acctsessionid from radacct where framedipaddress ='$USER_IP' AND acctstoptime is NULL;"`
NAS_IP=`echo $users | awk '{print $3}'`
NAS_SECRET=`$CMD "use $DB; select secret from nas where nasname = '$NAS_IP' ;"`

# Print Info on screen
echo "Duplicate User Found: USER: $username , IP: $USER_IP, ID: $ACCTSESID, $NAS: $NAS+IP @ $currenttime ... KICKING him now ..."
echo "Duplicate User Found: USER: $username , IP: $USER_IP, ID: $ACCTSESID, $NAS: $NAS+IP @ $currenttime ... KICKING him now ..." >> $DUP_LIST_FILE
#echo User-Name=$USERNAME,Acct-Session-Id=$ACCTSESID,Framed-IP-Address=$USER_IP,Mikrotik-Rate-Limit=\"$DN_BWPKG\" | $RADCLIENT -q -c 1 $NAS_IP:$NAS_COA_PORT coa $NAS_SECRET
#for hotspot, enable following line
echo Framed-IP-Address=$USER_IP | radclient -x -c 1 $NAS_IP:$NAS_COA_PORT disconnect $NAS_SECRET
done
# once done, we should delete the tmp files to clear the garbage
rm $TMPUSRINFO

CRON scheduler to run the above script every minute. Edit crontab by

crontab -e

& add following entry

* * * * * /temp/kickdupuser.sh >/dev/null 2>&1

Testing …

Using same credentials, Login to first device, and then on second ,

& run this script,

root@radius:/temp# /temp/kickdupuser.sh
- Script Start Time - 10:52:03
- Checking Duplicate Users in rm_dupusers table ...
- INFO: /temp folder is already present to store logs.
- INFO: mysql service is accessible. Proceeding further ... OK
- INFO: rm_dupusers Table exists ...
Duplicate User Found: USER: test , IP: 172.16.0.253, ID: 81d00057, : +IP @ 10:52:03 ... KICKING him now ...
Sending Disconnect-Request of id 58 to 10.0.0.1 port 1700
Framed-IP-Address = 172.16.0.253
rad_recv: Disconnect-ACK packet from host 10.0.0.1 port 1700, id=58, length=32
NAS-Identifier = "ZAIB_CCR_GW"
root@radius:/temp#

older session will be removed

radclient dc the first user.PNG


Weirdo …. but its fun to learn !

TIPS:

Command to view duplicate users session in freeradius using CLI


mysql -uroot -pMYPASS --skip-column-names -e 'use radius; SELECT username FROM radacct WHERE acctstoptime IS NULL;' > 1.txt && sort 1.txt | uniq -cd

Regard’s
Syed Jahanzaib

%d bloggers like this: