Commit d82d2454 authored by Nigel Kukard's avatar Nigel Kukard

Merge branch 'FUP' into 'master'

Added FUP support

See merge request !425
parents 71f628a0 f24d760c
Pipeline #3767 passed with stages
in 4 minutes and 2 seconds
...@@ -27,7 +27,7 @@ Enhanced features: ...@@ -27,7 +27,7 @@ Enhanced features:
* Plugin: Topups * Plugin: Topups
* Plugin: Auto-topups * Plugin: Auto-topups
* Plugin: Usage/Time caps * Plugin: Usage/Time caps
* Plugin: Prepaid accounting based on usage/time * Plugin: Prepaid accounting based on usage/time
* Plugin: Creation of accounting START records when no START record has been received but an interim update has - helps on slow/lossly links * Plugin: Creation of accounting START records when no START record has been received but an interim update has - helps on slow/lossly links
* Plugin: Notifications, % based or approximate time based * Plugin: Notifications, % based or approximate time based
* Plugin: User blacklists * Plugin: User blacklists
......
...@@ -5,8 +5,7 @@ smradiusd: ...@@ -5,8 +5,7 @@ smradiusd:
* Create a raddbpath config option which is prepended to dict paths * Create a raddbpath config option which is prepended to dict paths
usage related queries: * Configurable 'use defaults for POD/CoA' we may not want to send these
* Use Math module to perform calculations
smadmin: smadmin:
* Ability to run smadmin before the end of current month and updating the records as necessary at a later stage * Ability to run smadmin before the end of current month and updating the records as necessary at a later stage
......
...@@ -199,13 +199,13 @@ CREATE TABLE @PREFIX@accounting ( ...@@ -199,13 +199,13 @@ CREATE TABLE @PREFIX@accounting (
ServiceType @INT_UNSIGNED@, ServiceType @INT_UNSIGNED@,
FramedProtocol @INT_UNSIGNED@, FramedProtocol @INT_UNSIGNED@,
NASPort VARCHAR(255), NASPort VARCHAR(255),
NASPortType @INT_UNSIGNED@, NASPortType @INT_UNSIGNED@,
CallingStationID VARCHAR(255), CallingStationID VARCHAR(255),
CalledStationID VARCHAR(255), CalledStationID VARCHAR(255),
...@@ -251,6 +251,9 @@ CREATE INDEX @PREFIX@accounting_idx2 ON @PREFIX@accounting (PeriodKey); ...@@ -251,6 +251,9 @@ CREATE INDEX @PREFIX@accounting_idx2 ON @PREFIX@accounting (PeriodKey);
CREATE INDEX @PREFIX@accounting_idx4 ON @PREFIX@accounting (Username,AcctSessionID,NASIPAddress,NASPort); CREATE INDEX @PREFIX@accounting_idx4 ON @PREFIX@accounting (Username,AcctSessionID,NASIPAddress,NASPort);
/* accounting_update_query */ /* accounting_update_query */
CREATE INDEX @PREFIX@accounting_idx5 ON @PREFIX@accounting (Username,AcctSessionID,NASIPAddress,NASPort,PeriodKey); CREATE INDEX @PREFIX@accounting_idx5 ON @PREFIX@accounting (Username,AcctSessionID,NASIPAddress,NASPort,PeriodKey);
/* Index for the EventTimestamp */
CREATE INDEX @PREFIX@accounting_idx7 ON @PREFIX@accounting (EventTimestamp);
CREATE INDEX @PREFIX@accounting_idx8 ON @PREFIX@accounting (Username,EventTimestamp);
...@@ -276,7 +279,7 @@ CREATE INDEX @PREFIX@accounting_summary_idx3 ON @PREFIX@accounting_summary (User ...@@ -276,7 +279,7 @@ CREATE INDEX @PREFIX@accounting_summary_idx3 ON @PREFIX@accounting_summary (User
/* Users data */ /* Users data */
CREATE TABLE @PREFIX@users_data ( CREATE TABLE @PREFIX@users_data (
ID @SERIAL_TYPE@, ID @SERIAL_TYPE@,
UserID @INT_UNSIGNED@, UserID @INT_UNSIGNED@,
...@@ -287,4 +290,4 @@ CREATE TABLE @PREFIX@users_data ( ...@@ -287,4 +290,4 @@ CREATE TABLE @PREFIX@users_data (
Value VARCHAR(255), Value VARCHAR(255),
UNIQUE (UserID,Name) UNIQUE (UserID,Name)
) @CREATE_TABLE_SUFFIX@; ) @CREATE_TABLE_SUFFIX@;
...@@ -81,6 +81,10 @@ my @attributeReplyIgnoreList = ( ...@@ -81,6 +81,10 @@ my @attributeReplyIgnoreList = (
'SMRadius-AutoTopup-Uptime-Notify', 'SMRadius-AutoTopup-Uptime-Notify',
'SMRadius-AutoTopup-Uptime-NotifyTemplate', 'SMRadius-AutoTopup-Uptime-NotifyTemplate',
'SMRadius-AutoTopup-Uptime-Threshold', 'SMRadius-AutoTopup-Uptime-Threshold',
'SMRadius-Config-Filter-Reply-Attribute',
'SMRadius-Config-Filter-Reply-VAttribute',
'SMRadius-FUP-Period',
'SMRadius-FUP-Traffic-Threshold',
); );
my @attributeVReplyIgnoreList = ( my @attributeVReplyIgnoreList = (
); );
...@@ -342,7 +346,7 @@ sub checkAuthAttribute ...@@ -342,7 +346,7 @@ sub checkAuthAttribute
# Always matches as a check item, and adds the current # Always matches as a check item, and adds the current
# attribute with value to the list of configuration items. # attribute with value to the list of configuration items.
# #
# As a reply item, it has an itendtical meaning, but the # As a reply item, it has an idendtical meaning, but the
# attribute is added to the reply items. # attribute is added to the reply items.
} elsif ($operator eq '+=') { } elsif ($operator eq '+=') {
...@@ -439,7 +443,7 @@ sub checkAcctAttribute ...@@ -439,7 +443,7 @@ sub checkAcctAttribute
# Always matches as a check item, and adds the current # Always matches as a check item, and adds the current
# attribute with value to the list of configuration items. # attribute with value to the list of configuration items.
# #
# As a reply item, it has an itendtical meaning, but the # As a reply item, it has an idendtical meaning, but the
# attribute is added to the reply items. # attribute is added to the reply items.
if ($operator eq '+=') { if ($operator eq '+=') {
...@@ -546,7 +550,7 @@ sub setReplyAttribute ...@@ -546,7 +550,7 @@ sub setReplyAttribute
# Always matches as a check item, and replaces in the configuration items any attribute of the same name. # Always matches as a check item, and replaces in the configuration items any attribute of the same name.
# If no attribute of that name appears in the request, then this attribute is added. # If no attribute of that name appears in the request, then this attribute is added.
# #
# As a reply item, it has an itendtical meaning, but for the reply items, instead of the request items. # As a reply item, it has an idendtical meaning, but for the reply items, instead of the request items.
} elsif ($attribute->{'Operator'} eq ':=') { } elsif ($attribute->{'Operator'} eq ':=') {
# Overwrite # Overwrite
...@@ -561,7 +565,7 @@ sub setReplyAttribute ...@@ -561,7 +565,7 @@ sub setReplyAttribute
# Always matches as a check item, and adds the current # Always matches as a check item, and adds the current
# attribute with value to the list of configuration items. # attribute with value to the list of configuration items.
# #
# As a reply item, it has an itendtical meaning, but the # As a reply item, it has an idendtical meaning, but the
# attribute is added to the reply items. # attribute is added to the reply items.
} elsif ($attribute->{'Operator'} eq '+=') { } elsif ($attribute->{'Operator'} eq '+=') {
...@@ -610,7 +614,7 @@ sub setReplyVAttribute ...@@ -610,7 +614,7 @@ sub setReplyVAttribute
@attrValues = ( $attribute->{'Value'} ); @attrValues = ( $attribute->{'Value'} );
} }
$server->log(LOG_DEBUG,"[VATTRIBUTES] Processing REPLY attribute: '". $server->log(LOG_DEBUG,"[VATTRIBUTES] Processing REPLY vattribute: '".
$attribute->{'Name'}."' ".$attribute->{'Operator'}." '".join("','",@attrValues)."'"); $attribute->{'Name'}."' ".$attribute->{'Operator'}." '".join("','",@attrValues)."'");
...@@ -640,7 +644,7 @@ sub setReplyVAttribute ...@@ -640,7 +644,7 @@ sub setReplyVAttribute
# Always matches as a check item, and replaces in the configuration items any attribute of the same name. # Always matches as a check item, and replaces in the configuration items any attribute of the same name.
# If no attribute of that name appears in the request, then this attribute is added. # If no attribute of that name appears in the request, then this attribute is added.
# #
# As a reply item, it has an itendtical meaning, but for the reply items, instead of the request items. # As a reply item, it has an idendtical meaning, but for the reply items, instead of the request items.
} elsif ($attribute->{'Operator'} eq ':=') { } elsif ($attribute->{'Operator'} eq ':=') {
# Overwrite # Overwrite
...@@ -655,7 +659,7 @@ sub setReplyVAttribute ...@@ -655,7 +659,7 @@ sub setReplyVAttribute
# Always matches as a check item, and adds the current # Always matches as a check item, and adds the current
# attribute with value to the list of configuration items. # attribute with value to the list of configuration items.
# #
# As a reply item, it has an itendtical meaning, but the # As a reply item, it has an idendtical meaning, but the
# attribute is added to the reply items. # attribute is added to the reply items.
} elsif ($attribute->{'Operator'} eq '+=') { } elsif ($attribute->{'Operator'} eq '+=') {
...@@ -707,7 +711,7 @@ sub processConfigAttribute ...@@ -707,7 +711,7 @@ sub processConfigAttribute
# Always matches as a check item, and adds the current # Always matches as a check item, and adds the current
# attribute with value to the list of configuration items. # attribute with value to the list of configuration items.
# #
# As a reply item, it has an itendtical meaning, but the # As a reply item, it has an idendtical meaning, but the
# attribute is added to the reply items. # attribute is added to the reply items.
if ($attribute->{'Operator'} eq '+=') { if ($attribute->{'Operator'} eq '+=') {
...@@ -720,7 +724,7 @@ sub processConfigAttribute ...@@ -720,7 +724,7 @@ sub processConfigAttribute
# Always matches as a check item, and replaces in the configuration items any attribute of the same name. # Always matches as a check item, and replaces in the configuration items any attribute of the same name.
# If no attribute of that name appears in the request, then this attribute is added. # If no attribute of that name appears in the request, then this attribute is added.
# #
# As a reply item, it has an itendtical meaning, but for the reply items, instead of the request items. # As a reply item, it has an idendtical meaning, but for the reply items, instead of the request items.
} elsif ($attribute->{'Operator'} eq ':=') { } elsif ($attribute->{'Operator'} eq ':=') {
@{$configAttributes->{$attribute->{'Name'}}} = @attrValues; @{$configAttributes->{$attribute->{'Name'}}} = @attrValues;
...@@ -790,7 +794,8 @@ sub processConditional ...@@ -790,7 +794,8 @@ sub processConditional
# Split off expression # Split off expression
my ($condition,$onTrue,$onFalse) = ($attrVal =~ /^([^\?]*)(?:\?\s*((?:\S+)?[^:]*)(?:\s*\:\s*(.*))?)?$/); # NK: This probably needs a bit of work
my ($condition,$onTrue,$onFalse) = ($attrVal =~ /^([^\?]*)(?:\?\s*((?:\S+)?[^:]*)(?:\:\s*(.*))?)?$/);
# If there is no condition we cannot really continue? # If there is no condition we cannot really continue?
if (!defined($condition)) { if (!defined($condition)) {
...@@ -838,6 +843,10 @@ sub processConditional ...@@ -838,6 +843,10 @@ sub processConditional
$res = 1; $res = 1;
} }
# Sanitize the output
$attribStr =~ s/^\s*//;
$attribStr =~ s/\s*$//;
$server->log(LOG_DEBUG,"[ATTRIBUTES] - Evaluated to '$res' returning '".(defined($attribStr) ? $attribStr : "-undef-")."'"); $server->log(LOG_DEBUG,"[ATTRIBUTES] - Evaluated to '$res' returning '".(defined($attribStr) ? $attribStr : "-undef-")."'");
# Loop with attributes: # Loop with attributes:
......
# Radius client # Radius client
# Copyright (C) 2007-2016, AllWorldIT # Copyright (C) 2007-2019, AllWorldIT
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
...@@ -44,11 +44,15 @@ if (!eval {require Config::IniFiles; 1;}) { ...@@ -44,11 +44,15 @@ if (!eval {require Config::IniFiles; 1;}) {
sub run sub run
{ {
my ($self,@methodArgs) = @_; my ($self,@methodArgs) = @_;
# Instantiate if we're not already instantiated # Instantiate if we're not already instantiated
$self = $self->new() if (!ref($self)); $self = $self->new() if (!ref($self));
# The hash we're going to return
my $ret = { };
print(STDERR "SMRadClient v$VERSION - Copyright (c) 2007-2016, AllWorldIT\n"); print(STDERR "SMRadClient v".VERSION." - Copyright (c) 2007-2019, AllWorldIT\n");
print(STDERR "\n"); print(STDERR "\n");
...@@ -67,10 +71,11 @@ sub run ...@@ -67,10 +71,11 @@ sub run
\%{$cmdline}, \%{$cmdline},
"config:s", "config:s",
"raddb:s", "raddb:s",
"listen:s",
"help", "help",
)) { )) {
print(STDERR "ERROR: Error parsing commandline arguments"); print(STDERR "ERROR: Error parsing commandline arguments");
return 1; return 1;
} }
# Check for some args # Check for some args
...@@ -190,13 +195,38 @@ sub run ...@@ -190,13 +195,38 @@ sub run
return 1; return 1;
} }
my $sock2;
# Check if we must listen on another IP/port
if (defined($cmdline->{'listen'}) && $cmdline->{'listen'} ne "") {
print(STDERR "Creating second socket\n");
# Check the details we were provided
my ($localAddr,$localPort) = split(/:/,$cmdline->{'listen'});
if (!defined($localPort)) {
print(STDERR "ERROR: The format for --listen is IP:Port\n");
return 1;
}
$sock2 = IO::Socket::INET->new(
LocalAddr => $localAddr,
LocalPort => $localPort,
Type => SOCK_DGRAM,
Proto => 'udp',
Timeout => $sockTimeout,
);
if (!$sock2) {
print(STDERR "ERROR: Failed to create second socket\n");
return 1;
}
}
# Check if we sent the packet... # Check if we sent the packet...
if (!$sock->send($udp_packet)) { if (!$sock->send($udp_packet)) {
print(STDERR "ERROR: Failed to send data on socket\n"); print(STDERR "ERROR: Failed to send data on socket\n");
return 1; return 1;
} }
# And time for the response # And time for the response
print(STDERR "\nResponse:\n"); print(STDERR "\nResponse:\n");
...@@ -216,7 +246,7 @@ sub run ...@@ -216,7 +246,7 @@ sub run
# Read packet # Read packet
$sock->recv($udp_packet, 65536); $sock->recv($udp_packet, 65536);
if (!$udp_packet) { if (!$udp_packet) {
print(STDERR "ERROR: Receive response data failed: $!\n"); print(STDERR "ERROR: Receive response data failed on socket: $!\n");
return 1; return 1;
} }
...@@ -225,13 +255,44 @@ sub run ...@@ -225,13 +255,44 @@ sub run
print(STDERR " > Authenticated: ". (defined(auth_req_verify($udp_packet,$self->{'secret'},$authen)) ? "yes" : "no") ."\n"); print(STDERR " > Authenticated: ". (defined(auth_req_verify($udp_packet,$self->{'secret'},$authen)) ? "yes" : "no") ."\n");
print(STDERR $pkt->str_dump()); print(STDERR $pkt->str_dump());
# Setup response
$ret->{'request'} = $self->hashedPacket($self->{'packet'});
$ret->{'response'} = $self->hashedPacket($pkt);
my $udp_packet2;
if (defined($sock2)) {
my $rsock2 = IO::Select->new($sock2);
if (!$rsock2) {
print(STDERR "ERROR: Failed to select response data on socket2\n");
return 1;
}
# Check if we can read a response after the select()
if (!$rsock2->can_read($sockTimeout)) {
print(STDERR "ERROR: Failed to receive response data on socket2\n");
return 1;
}
# Read packet
my $udp_packet2;
$sock2->recv($udp_packet2, 65536);
if (!$udp_packet2) {
print(STDERR "ERROR: Receive response data failed on socket2: $!\n");
return 1;
}
my $pkt2 = smradius::Radius::Packet->new($raddb,$udp_packet2);
print(STDERR $pkt2->str_dump());
# Save the packet we got
$ret->{'listen'}->{'response'} = $self->hashedPacket($pkt2);
}
# If we were called as a function, return hashed version of the response packet # If we were called as a function, return hashed version of the response packet
if (@methodArgs) { if (@methodArgs) {
return { return $ret;
'request' => $self->hashedPacket($self->{'packet'}),
'response' => $self->hashedPacket($pkt),
};
} }
return 0; return 0;
...@@ -261,7 +322,7 @@ sub hashedPacket ...@@ -261,7 +322,7 @@ sub hashedPacket
foreach my $attrName ($pkt->vsattributes($attrVendor)) { foreach my $attrName ($pkt->vsattributes($attrVendor)) {
$res->{'vattributes'}->{$attrVendor}->{$attrName} = $pkt->vsattr($attrVendor,$attrName); $res->{'vattributes'}->{$attrVendor}->{$attrName} = $pkt->vsattr($attrVendor,$attrName);
} }
} }
return $res; return $res;
} }
......
...@@ -20,14 +20,13 @@ ...@@ -20,14 +20,13 @@
## @class smradius::constants ## @class smradius::constants
# SMRadius constants package # SMRadius constants package
package smradius::constants; package smradius::constants;
use base qw(Exporter);
use strict; use strict;
use warnings; use warnings;
# Exporter stuff
use base qw(Exporter);
our (@EXPORT,@EXPORT_OK); our (@EXPORT,@EXPORT_OK);
@EXPORT = qw( @EXPORT = qw(
RES_OK RES_OK
...@@ -37,7 +36,7 @@ our (@EXPORT,@EXPORT_OK); ...@@ -37,7 +36,7 @@ our (@EXPORT,@EXPORT_OK);
MOD_RES_NACK MOD_RES_NACK
MOD_RES_SKIP MOD_RES_SKIP
UINT_MAX GIGAWORD_VALUE
); );
@EXPORT_OK = (); @EXPORT_OK = ();
...@@ -50,7 +49,7 @@ use constant { ...@@ -50,7 +49,7 @@ use constant {
MOD_RES_ACK => 1, MOD_RES_ACK => 1,
MOD_RES_NACK => 2, MOD_RES_NACK => 2,
UINT_MAX => 2**32 GIGAWORD_VALUE => 2**32,
}; };
......
This diff is collapsed.
# Capping support # Capping support
# Copyright (C) 2007-2017, AllWorldIT # Copyright (C) 2007-2019, AllWorldIT
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
...@@ -219,7 +219,7 @@ sub post_auth_hook ...@@ -219,7 +219,7 @@ sub post_auth_hook
# #
# Allow for capping overrides by client attribute # Allow for capping overrides by attribute
# #
if (defined($user->{'ConfigAttributes'}->{'SMRadius-Config-Capping-Uptime-Multiplier'})) { if (defined($user->{'ConfigAttributes'}->{'SMRadius-Config-Capping-Uptime-Multiplier'})) {
...@@ -231,7 +231,7 @@ sub post_auth_hook ...@@ -231,7 +231,7 @@ sub post_auth_hook
$uptimeLimitWithTopups = $newLimit; $uptimeLimitWithTopups = $newLimit;
$accountingUsage->{'TotalSessionTime'} = $newSessionTime; $accountingUsage->{'TotalSessionTime'} = $newSessionTime;
$server->log(LOG_INFO,"[MOD_FEATURE_CAPPING] Client uptime multiplier '$multiplier' changes ". $server->log(LOG_INFO,"[MOD_FEATURE_CAPPING] User uptime multiplier '$multiplier' changes ".
"uptime limit ('$uptimeLimitWithTopups' => '$newLimit'), ". "uptime limit ('$uptimeLimitWithTopups' => '$newLimit'), ".
"uptime usage ('".$accountingUsage->{'TotalSessionTime'}."' => '$newSessionTime')" "uptime usage ('".$accountingUsage->{'TotalSessionTime'}."' => '$newSessionTime')"
); );
...@@ -245,7 +245,7 @@ sub post_auth_hook ...@@ -245,7 +245,7 @@ sub post_auth_hook
$trafficLimitWithTopups = $newLimit; $trafficLimitWithTopups = $newLimit;
$accountingUsage->{'TotalDataUsage'} = $newDataUsage; $accountingUsage->{'TotalDataUsage'} = $newDataUsage;
$server->log(LOG_INFO,"[MOD_FEATURE_CAPPING] Client traffic multiplier '$multiplier' changes ". $server->log(LOG_INFO,"[MOD_FEATURE_CAPPING] User traffic multiplier '$multiplier' changes ".
"traffic limit ('$trafficLimitWithTopups' => '$newLimit'), ". "traffic limit ('$trafficLimitWithTopups' => '$newLimit'), ".
"traffic usage ('".$accountingUsage->{'TotalDataUsage'}."' => '$newDataUsage')" "traffic usage ('".$accountingUsage->{'TotalDataUsage'}."' => '$newDataUsage')"
); );
...@@ -346,7 +346,7 @@ sub post_acct_hook ...@@ -346,7 +346,7 @@ sub post_acct_hook
# Skip MAC authentication # Skip MAC authentication
return MOD_RES_SKIP if ($user->{'_UserDB'}->{'Name'} eq "SQL User Database (MAC authentication)"); return MOD_RES_SKIP if ($user->{'_UserDB'}->{'Name'} eq "SQL User Database (MAC authentication)");
# Exceeding maximum, must be disconnected # 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"); 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_CAPPING] POST ACCT HOOK"); $server->log(LOG_DEBUG,"[MOD_FEATURE_CAPPING] POST ACCT HOOK");
...@@ -440,20 +440,20 @@ sub post_acct_hook ...@@ -440,20 +440,20 @@ sub post_acct_hook
# #
# Allow for capping overrides by client attribute # Allow for capping overrides by user attribute
# #
if (defined($user->{'ConfigAttributes'}->{'SMRadius-Config-Capping-Uptime-Multiplier'})) { if (defined($user->{'ConfigAttributes'}->{'SMRadius-Config-Capping-Uptime-Multiplier'})) {
my $multiplier = pop(@{$user->{'ConfigAttributes'}->{'SMRadius-Config-Capping-Uptime-Multiplier'}}); my $multiplier = pop(@{$user->{'ConfigAttributes'}->{'SMRadius-Config-Capping-Uptime-Multiplier'}});
my $newLimit = $uptimeLimitWithTopups * $multiplier; my $newLimit = $uptimeLimitWithTopups * $multiplier;
$server->log(LOG_INFO,"[MOD_FEATURE_CAPPING] Client cap uptime multiplier '$multiplier' changes limit ". $server->log(LOG_INFO,"[MOD_FEATURE_CAPPING] User cap uptime multiplier '$multiplier' changes limit ".
"from '$uptimeLimitWithTopups' to '$newLimit'"); "from '$uptimeLimitWithTopups' to '$newLimit'");
$uptimeLimitWithTopups = $newLimit; $uptimeLimitWithTopups = $newLimit;
} }
if (defined($user->{'ConfigAttributes'}->{'SMRadius-Config-Capping-Traffic-Multiplier'})) { if (defined($user->{'ConfigAttributes'}->{'SMRadius-Config-Capping-Traffic-Multiplier'})) {
my $multiplier = pop(@{$user->{'ConfigAttributes'}->{'SMRadius-Config-Capping-Traffic-Multiplier'}}); my $multiplier = pop(@{$user->{'ConfigAttributes'}->{'SMRadius-Config-Capping-Traffic-Multiplier'}});
my $newLimit = $trafficLimitWithTopups * $multiplier; my $newLimit = $trafficLimitWithTopups * $multiplier;
$server->log(LOG_INFO,"[MOD_FEATURE_CAPPING] Client cap traffic multiplier '$multiplier' changes limit ". $server->log(LOG_INFO,"[MOD_FEATURE_CAPPING] User cap traffic multiplier '$multiplier' changes limit ".
"from '$trafficLimitWithTopups' to '$newLimit'"); "from '$trafficLimitWithTopups' to '$newLimit'");
$trafficLimitWithTopups = $newLimit; $trafficLimitWithTopups = $newLimit;
} }
...@@ -491,7 +491,7 @@ sub post_acct_hook ...@@ -491,7 +491,7 @@ sub post_acct_hook
## @internal ## @internal
# Code snippet to grab the current uptime limit by processing the user attributes # Code snippet to grab the current attribute key limit by processing the user attributes
sub _getAttributeKeyLimit sub _getAttributeKeyLimit
{ {
my ($server,$user,$attributeKey) = @_; my ($server,$user,$attributeKey) = @_;
......
# 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;