Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
smradius
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
1
Issues
1
List
Boards
Labels
Service Desk
Milestones
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
smradius
smradius
Commits
bcaa1e81
Commit
bcaa1e81
authored
May 15, 2019
by
Nigel Kukard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
FEATURE: FUP
parent
2dc0563d
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
457 additions
and
2 deletions
+457
-2
lib/smradius/daemon.pm
lib/smradius/daemon.pm
+7
-0
lib/smradius/modules/features/mod_feature_fup.pm
lib/smradius/modules/features/mod_feature_fup.pm
+355
-0
smradiusd.conf
smradiusd.conf
+1
-0
t/200-dbtests.t
t/200-dbtests.t
+94
-2
No files found.
lib/smradius/daemon.pm
View file @
bcaa1e81
...
...
@@ -903,6 +903,13 @@ sub process_request {
# We don't care if it fails
}
}
# TEST START
my
$coaReq
=
smradius::Radius::
Packet
->
new
(
$self
->
{'
radius
'}
->
{'
dictionary
'});
# Process the reply attributes
$self
->
_processReplyAttributes
(
$request
,
$user
,
$coaReq
);
# TEST END
# Check if we must POD the user
if
(
$PODUser
)
{
...
...
lib/smradius/modules/features/mod_feature_fup.pm
0 → 100644
View file @
bcaa1e81
# FUP support
# Copyright (C) 2007-2019, AllWorldIT
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
package
smradius::modules::features::
mod_feature_fup
;
use
strict
;
use
warnings
;
# Modules we need
use
smradius::
attributes
;
use
smradius::
constants
;
use
smradius::
logging
;
use
smradius::
util
;
use
AWITPT::
Util
;
use
List::
Util
qw( min )
;
use
MIME::
Lite
;
use
POSIX
qw( floor )
;
# Set our version
our
$VERSION
=
"
0.0.1
";
# Load exporter
use
base
qw(Exporter)
;
our
@EXPORT
=
qw(
)
;
our
@EXPORT_OK
=
qw(
)
;
# Plugin info
our
$pluginInfo
=
{
Name
=>
"
User FUP Feature
",
Init
=>
\
&init
,
# Authentication hook
'
Feature_Post-Authentication_hook
'
=>
\
&post_auth_hook
,
# Accounting hook
'
Feature_Post-Accounting_hook
'
=>
\
&post_acct_hook
,
};
# Some constants
my
$FUP_PERIOD_ATTRIBUTE
=
'
SMRadius-FUP-Period
';
my
$FUP_TRAFFIC_THRESHOLD_ATTRIBUTE
=
'
SMRadius-FUP-Traffic-Threshold
';
my
$config
;
## @internal
# Initialize module
sub
init
{
my
$server
=
shift
;
my
$scfg
=
$server
->
{'
inifile
'};
# Defaults
$config
->
{'
enable_mikrotik
'}
=
0
;
# Setup SQL queries
if
(
defined
(
$scfg
->
{'
mod_feature_fup
'}))
{
# Check if option exists
if
(
defined
(
$scfg
->
{'
mod_feature_fup
'}{'
enable_mikrotik
'}))
{
# Pull in config
if
(
defined
(
my
$val
=
isBoolean
(
$scfg
->
{'
mod_feature_fup
'}{'
enable_mikrotik
'})))
{
if
(
$val
)
{
$server
->
log
(
LOG_NOTICE
,"
[MOD_FEATURE_FUP] Mikrotik-specific vendor return attributes ENABLED
");
$config
->
{'
enable_mikrotik
'}
=
$val
;
}
}
else
{
$server
->
log
(
LOG_NOTICE
,"
[MOD_FEATURE_FUP] Value for 'enable_mikrotik' is invalid
");
}
}
}
return
;
}
## @post_auth_hook($server,$user,$packet)
# Post authentication hook
#
# @param server Server object
# @param user User data
# @param packet Radius packet
#
# @return Result
sub
post_auth_hook
{
my
(
$server
,
$user
,
$packet
)
=
@_
;
# Skip MAC authentication
return
MOD_RES_SKIP
if
(
$user
->
{'
_UserDB
'}
->
{'
Name
'}
eq
"
SQL User Database (MAC authentication)
");
$server
->
log
(
LOG_DEBUG
,"
[MOD_FEATURE_FUP] POST AUTH HOOK
");
#
# Get threshold from attributes
#
my
$fupPeriod
=
_getAttributeKeyNumeric
(
$server
,
$user
,
$FUP_PERIOD_ATTRIBUTE
);
my
$trafficThreshold
=
_getAttributeKeyNumeric
(
$server
,
$user
,
$FUP_TRAFFIC_THRESHOLD_ATTRIBUTE
);
# If we have no FUP period, skip
if
(
!
defined
(
$fupPeriod
))
{
return
MOD_RES_SKIP
;
};
# If we have no traffic threshold, display an info message and skip
if
(
!
defined
(
$trafficThreshold
))
{
$server
->
log
(
LOG_INFO
,"
[MOD_FEATURE_FUP] User has a '
$FUP_PERIOD_ATTRIBUTE
' defined, but NOT a
"
.
"
'
$FUP_TRAFFIC_THRESHOLD_ATTRIBUTE
' attribute, aborting FUP checks.
");
return
MOD_RES_SKIP
;
};
#
# Get current traffic and uptime usage
#
my
$accountingUsage
=
_getAccountingUsage
(
$server
,
$user
,
$packet
,
$fupPeriod
);
if
(
!
defined
(
$accountingUsage
))
{
return
MOD_RES_SKIP
;
}
#
# Display our FUP info
#
_logUsage
(
$server
,
$fupPeriod
,
$accountingUsage
->
{'
TotalDataUsage
'},
$trafficThreshold
);
#
# Check if the user has exceeded the FUP
#
my
$fupExceeded
=
(
$accountingUsage
->
{'
TotalDataUsage
'}
>
$trafficThreshold
)
?
1
:
0
;
#
# Add conditional variables
#
addAttributeConditionalVariable
(
$user
,"
SMRadius_FUP
",
$fupExceeded
);
return
MOD_RES_ACK
;
}
## @post_acct_hook($server,$user,$packet)
# Post authentication hook
#
# @param server Server object
# @param user User data
# @param packet Radius packet
#
# @return Result
sub
post_acct_hook
{
my
(
$server
,
$user
,
$packet
)
=
@_
;
# We cannot cap a user if we don't have a UserDB module can we? no userdb, no cap?
return
MOD_RES_SKIP
if
(
!
defined
(
$user
->
{'
_UserDB
'}
->
{'
Name
'}));
# Skip MAC authentication
return
MOD_RES_SKIP
if
(
$user
->
{'
_UserDB
'}
->
{'
Name
'}
eq
"
SQL User Database (MAC authentication)
");
# User is either connecting 'START' or disconnecting 'STOP'
return
MOD_RES_SKIP
if
(
$packet
->
rawattr
('
Acct-Status-Type
')
ne
"
1
"
&&
$packet
->
rawattr
('
Acct-Status-Type
')
ne
"
3
");
$server
->
log
(
LOG_DEBUG
,"
[MOD_FEATURE_FUP] POST ACCT HOOK
");
#
# Get threshold from attributes
#
my
$fupPeriod
=
_getAttributeKeyNumeric
(
$server
,
$user
,
$FUP_PERIOD_ATTRIBUTE
);
my
$trafficThreshold
=
_getAttributeKeyNumeric
(
$server
,
$user
,
$FUP_TRAFFIC_THRESHOLD_ATTRIBUTE
);
# If we have no FUP period, skip
if
(
!
defined
(
$fupPeriod
))
{
return
MOD_RES_SKIP
;
};
# If we have no traffic threshold, display an info message and skip
if
(
!
defined
(
$trafficThreshold
))
{
$server
->
log
(
LOG_INFO
,"
[MOD_FEATURE_FUP] User has a '
$FUP_PERIOD_ATTRIBUTE
' defined, but NOT a
"
.
"
'
$FUP_TRAFFIC_THRESHOLD_ATTRIBUTE
' attribute, aborting FUP checks.
");
return
MOD_RES_SKIP
;
};
#
# Get current traffic and uptime usage
#
my
$accountingUsage
=
_getAccountingUsage
(
$server
,
$user
,
$packet
,
$fupPeriod
);
if
(
!
defined
(
$accountingUsage
))
{
return
MOD_RES_SKIP
;
}
#
# Display our FUP info
#
_logUsage
(
$server
,
$fupPeriod
,
$accountingUsage
->
{'
TotalDataUsage
'},
$trafficThreshold
);
#
# Check if the user has exceeded the FUP
#
my
$fupExceeded
=
(
$accountingUsage
->
{'
TotalDataUsage
'}
>
$trafficThreshold
)
?
1
:
0
;
#
# Add conditional variables
#
addAttributeConditionalVariable
(
$user
,"
SMRadius_FUP
",
$fupExceeded
);
return
MOD_RES_ACK
;
}
## @internal
# Code snippet to grab the current uptime limit by processing the user attributes
sub
_getAttributeKeyNumeric
{
my
(
$server
,
$user
,
$attributeKey
)
=
@_
;
# Short circuit return if we don't have the uptime key set
return
if
(
!
defined
(
$user
->
{'
Attributes
'}
->
{
$attributeKey
}));
# Short circuit if we do not have a valid attribute operator: ':='
if
(
!
defined
(
$user
->
{'
Attributes
'}
->
{
$attributeKey
}
->
{'
:=
'}))
{
$server
->
log
(
LOG_NOTICE
,"
[MOD_FEATURE_FUP] No valid operators for attribute '
"
.
$user
->
{'
Attributes
'}
->
{
$attributeKey
}
.
"
'
");
return
;
}
$server
->
log
(
LOG_DEBUG
,"
[MOD_FEATURE_FUP] Attribute '
"
.
$attributeKey
.
"
' is defined
");
# Check for valid attribute value
if
(
!
defined
(
$user
->
{'
Attributes
'}
->
{
$attributeKey
}
->
{'
:=
'}
->
{'
Value
'})
||
$user
->
{'
Attributes
'}
->
{
$attributeKey
}
->
{'
:=
'}
->
{'
Value
'}
!~
/^\d+$/
)
{
$server
->
log
(
LOG_NOTICE
,"
[MOD_FEATURE_FUP] Attribute '
"
.
$user
->
{'
Attributes
'}
->
{
$attributeKey
}
->
{'
:=
'}
->
{'
Value
'}
.
"
' is NOT a numeric value
");
return
;
}
return
$user
->
{'
Attributes
'}
->
{
$attributeKey
}
->
{'
:=
'}
->
{'
Value
'};
}
## @internal
# Code snippet to grab the accounting usage of a user for a specific period
sub
_getAccountingUsage
{
my
(
$server
,
$user
,
$packet
,
$period
)
=
@_
;
foreach
my
$module
(
@
{
$server
->
{'
module_list
'}})
{
# Do we have the correct plugin?
if
(
defined
(
$module
->
{'
Accounting_getUsage
'}))
{
$server
->
log
(
LOG_INFO
,"
[MOD_FEATURE_FUP] Found plugin: '
"
.
$module
->
{'
Name
'}
.
"
'
");
# Fetch users session uptime & bandwidth used for a specific period
if
(
my
$res
=
$module
->
{'
Accounting_getUsage
'}(
$server
,
$user
,
$packet
,
$period
))
{
return
$res
;
}
$server
->
log
(
LOG_ERR
,"
[MOD_FEATURE_FUP] No usage data found for user '
"
.
$user
->
{'
Username
'}
.
"
'
");
}
}
return
;
}
## @internal
# Code snippet to log our FUP information
sub
_logUsage
{
my
(
$server
,
$period
,
$total
,
$threshold
)
=
@_
;
$server
->
log
(
LOG_INFO
,"
[MOD_FEATURE_FUP] FUP information [period: %s days, total: %s, threshold: %s]
",
$period
,
$total
,
$threshold
);
return
;
}
## @internal
# Function snippet to return a attribute
sub
_getAttribute
{
my
(
$server
,
$user
,
$attributeName
)
=
@_
;
# Check the attribute exists
return
if
(
!
defined
(
$user
->
{'
Attributes
'}
->
{
$attributeName
}));
$server
->
log
(
LOG_DEBUG
,"
[MOD_FEATURE_CAPPING] User attribute '
"
.
$attributeName
.
"
' is defined
");
# Check the required operator is present in this case :=
if
(
!
defined
(
$user
->
{'
Attributes
'}
->
{
$attributeName
}
->
{'
:=
'}))
{
$server
->
log
(
LOG_NOTICE
,"
[MOD_FEATURE_CAPPING] User attribute '
"
.
$attributeName
.
"
' has no ':=' operator
");
return
;
}
# Check the operator value is defined...
if
(
!
defined
(
$user
->
{'
Attributes
'}
->
{
$attributeName
}
->
{'
:=
'}
->
{'
Value
'}))
{
$server
->
log
(
LOG_NOTICE
,"
[MOD_FEATURE_CAPPING] User attribute '
"
.
$attributeName
.
"
' has no value
");
return
;
}
return
$user
->
{'
Attributes
'}
->
{
$attributeName
}
->
{'
:=
'}
->
{'
Value
'};
}
1
;
# vim: ts=4
smradiusd.conf
View file @
bcaa1e81
...
...
@@ -163,6 +163,7 @@ mod_feature_capping
mod_feature_user_stats
mod_feature_update_user_stats_sql
mod_feature_validity
mod_feature_fup
EOT
...
...
t/200-dbtests.t
View file @
bcaa1e81
...
...
@@ -752,8 +752,6 @@ if ($child = fork()) {
my
$session3_ID
=
9858240
;
my
$session3_Timestamp
=
time
();
my
$session3_Timestamp_str
=
DateTime
->
from_epoch
(
epoch
=>
$session3_Timestamp
,
time_zone
=>
'
UTC
')
->
strftime
('
%Y-%m-%d %H:%M:%S
');
$res
=
smradius::
client
->
run
(
"
--raddb
","
dicts
",
...
...
@@ -811,6 +809,100 @@ if ($child = fork()) {
);
#
# Check that if we send an accounting ALIVE we trigger the FUP
#
my
$user5_ID
=
testDBInsert
("
Create user 'testuser5'
",
"
INSERT INTO users (UserName,Disabled) VALUES ('testuser5',0)
"
);
my
$user5attr1_ID
=
testDBInsert
("
Create user 'testuser5' attribute 'User-Password'
",
"
INSERT INTO user_attributes (UserID,Name,Operator,Value,Disabled) VALUES (?,?,?,?,0)
",
$user5_ID
,'
User-Password
','
==
','
test456
'
);
my
$user5attr2_ID
=
testDBInsert
("
Create user 'testuser5' attribute 'SMRadius-FUP-Period'
",
"
INSERT INTO user_attributes (UserID,Name,Operator,Value,Disabled) VALUES (?,?,?,?,0)
",
$user5_ID
,'
SMRadius-FUP-Period
','
:=
','
1
'
);
my
$user5attr3_ID
=
testDBInsert
("
Create user 'testuser5' attribute 'SMRadius-FUP-Traffic-Threshold'
",
"
INSERT INTO user_attributes (UserID,Name,Operator,Value,Disabled) VALUES (?,?,?,?,0)
",
$user5_ID
,'
SMRadius-FUP-Traffic-Threshold
','
:=
',
800
);
# Add an attribute so we can check the FUP match results
my
$user5attr4_ID
=
testDBInsert
("
Create user 'testuser5' attribute 'SMRadius-Evaluate'
",
"
INSERT INTO user_attributes (UserID,Name,Operator,Value,Disabled) VALUES (?,?,?,?,0)
",
$user5_ID
,'
SMRadius-Evaluate
','
||+=
',"
SMRadius_FUP > 0 ? [14988:Mikrotik-Rate-Limit] = 1638k/8m
"
);
my
$session4_ID
=
9858240
;
my
$session4_Timestamp
=
time
()
-
3600
;
$res
=
smradius::
client
->
run
(
"
--raddb
","
dicts
",
"
127.0.0.1
",
"
acct
",
"
secret123
",
'
User-Name=testuser5
',
'
NAS-IP-Address=10.0.0.1
',
'
Acct-Delay-Time=12
',
'
NAS-Identifier=Test-NAS2
',
'
Acct-Status-Type=Interim-Update
',
'
Acct-Output-Packets=786933
',
'
Acct-Output-Gigawords=0
',
'
Acct-Output-Octets=708163705
',
'
Acct-Input-Packets=670235
',
'
Acct-Input-Gigawords=0
',
'
Acct-Input-Octets=102600046
',
'
Acct-Session-Time=800
',
'
Event-Timestamp=
'
.
$session4_Timestamp
,
'
Framed-IP-Address=10.0.1.1
',
'
Acct-Session-Id=
'
.
$session4_ID
,
'
NAS-Port-Id=wlan1
',
'
Called-Station-Id=testservice2
',
'
Calling-Station-Id=00:00:0C:EE:47:BF
',
'
NAS-Port-Type=Ethernet
',
'
NAS-Port=15729175
',
'
Framed-Protocol=PPP
',
'
Service-Type=Framed-User
',
);
is
(
ref
(
$res
),"
HASH
","
smradclient should return a HASH
");
my
$session4_Timestamp2
=
time
();
$res
=
smradius::
client
->
run
(
"
--raddb
","
dicts
",
"
127.0.0.1
",
"
acct
",
"
secret123
",
'
User-Name=testuser5
',
'
NAS-IP-Address=10.0.0.1
',
'
Acct-Delay-Time=8
',
'
NAS-Identifier=Test-NAS2
',
'
Acct-Status-Type=Interim-Update
',
'
Acct-Output-Packets=700000
',
'
Acct-Output-Gigawords=0
',
'
Acct-Output-Octets=850000000
',
'
Acct-Input-Packets=100000
',
'
Acct-Input-Gigawords=0
',
'
Acct-Input-Octets=100000000
',
'
Acct-Session-Time=1000
',
'
Event-Timestamp=
'
.
$session4_Timestamp2
,
'
Framed-IP-Address=10.0.1.1
',
'
Acct-Session-Id=
'
.
$session4_ID
,
'
NAS-Port-Id=wlan1
',
'
Called-Station-Id=testservice2
',
'
Calling-Station-Id=00:00:0C:EE:47:BF
',
'
NAS-Port-Type=Ethernet
',
'
NAS-Port=15729175
',
'
Framed-Protocol=PPP
',
'
Service-Type=Framed-User
',
);
is
(
ref
(
$res
),"
HASH
","
smradclient should return a HASH
");
sleep
(
5
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment