Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
S
smradius
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
shail
smradius
Commits
580204f6
Commit
580204f6
authored
15 years ago
by
Nigel Kukard
Browse files
Options
Downloads
Patches
Plain Diff
* Removed old code remains
parent
bbdaa4f7
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
acct-filter
+0
-893
0 additions, 893 deletions
acct-filter
auth-filter
+0
-459
0 additions, 459 deletions
auth-filter
with
0 additions
and
1352 deletions
acct-filter
deleted
100755 → 0
+
0
−
893
View file @
bbdaa4f7
#!/usr/bin/perl -w
# Author: Nigel Kukard <nkukard@lbsd.net>
# Date: 17/04/2007
# Desc: Accounting filter for GNU Radius
# License: GPL
use
strict
;
use
Benchmark
;
use
Getopt::
Long
;
use
DateTime
;
use
Time::
HiRes
qw( gettimeofday tv_interval )
;
use
MIME::
Lite
;
# Set library directory
use
lib
qw(../../)
;
use
sm::
config
;
use
sm::
dblayer
;
# Radius stuff
use
Authen::
Radius
;
# Common stuff
require
("
common.pm
");
use
Data::
Dumper
;
# Notify constants
use
constant
{
NOTIFY_CHECK
=>
1
,
NOTIFY_RESET
=>
2
,
};
my
%optctl
=
();
GetOptions
(
\
%optctl
,
"
help
");
# Check if user wants usage
if
(
defined
(
$optctl
{'
help
'}))
{
displayUsage
();
}
# Open up logfile
my
$logfile
=
"
/var/log/radius/acct-filter
";
open
(
FH
,"
>>
$logfile
")
or
die
"
Failed to open '
$logfile
': $!
";
# Load radius dictionaries
Authen::
Radius
->
load_dictionary
("
raddb/dictionary
");
# Databases
my
$dbh
;
# Authentication
my
$dbh_log
;
# Logs
# Get db handle
$dbh
=
sm::
dbilayer
->
new
(
$cfg_db_DSN
,
$cfg_db_Username
,
$cfg_db_Password
);
if
(
!
$dbh
)
{
print
(
STDERR
"
Error creating database object:
"
.
sm::
dbilayer
->
internalErr
());
exit
1
;
}
# Connect to database
if
(
$dbh
->
connect
()
!=
0
)
{
print
(
STDERR
"
Error connecting to database:
"
.
$dbh
->
err
);
exit
1
;
}
# Check if we must use split db's
if
(
defined
(
$cfg_radiuslog_db_DSN
))
{
# Get log db handle
$dbh_log
=
sm::
dbilayer
->
new
(
$cfg_radiuslog_db_DSN
,
$cfg_radiuslog_db_Username
,
$cfg_radiuslog_db_Password
);
if
(
!
$dbh_log
)
{
print
(
STDERR
"
Error creating database object:
"
.
sm::
dbilayer
->
internalErr
());
exit
1
;
}
# Connect to database
if
(
$dbh_log
->
connect
()
!=
0
)
{
print
(
STDERR
"
Error connecting to database:
"
.
$dbh_log
->
err
);
exit
1
;
}
# If not use the main DB
}
else
{
$dbh_log
=
$dbh
;
}
# Signal handler for dead children
use
POSIX
"
WNOHANG
";
sub
REAPER
{
my
$child
;
# If a second child dies while in the signal handler caused by the
# first death, we won't get another signal. So must loop here else
# we will leave the unreaped child as a zombie. And the next time
# two children die we get another zombie. And so on.
while
((
$child
=
waitpid
(
-
1
,
WNOHANG
))
>
0
)
{
# $Kid_Status{$child} = $?;
1
;
}
$SIG
{
CHLD
}
=
\
&REAPER
;
# still loathe sysV
}
$SIG
{
CHLD
}
=
\
&REAPER
;
# No buffering
select
((
select
(
FH
),
$|
=
1
)[
0
]);
select
((
select
(
STDOUT
),
$|
=
1
)[
0
]);
# Handled requests
my
$requests
=
0
;
# Loop with input
while
(
my
$line
=
<
STDIN
>
)
{
my
%acct
;
my
@acct
;
# Inc number of requests
$requests
++
;
# Munch off \n
chomp
(
$line
);
# Check number of results
if
((
@acct
=
split
/:/
,
$line
)
!=
21
)
{
print
(
FH
"
ERROR: Number of params from radiusd:
"
.
(
@acct
)
.
"
/
$line
\n
");
goto
END
;
}
# Pull in request
(
$acct
{'
User-Name
'},
$acct
{'
Status-Type
'},
$acct
{'
Acct-Session-Id
'},
$acct
{'
NAS-IP-Address
'},
$acct
{'
NAS-Port-Type
'},
$acct
{'
NAS-Port
'},
$acct
{'
Called-Station-Id
'},
$acct
{'
Calling-Station-Id
'},
$acct
{'
Delay
'},
$acct
{'
Acct-Session-Time
'},
$acct
{'
Acct-Input-Octets
'},
$acct
{'
Acct-Output-Octets
'},
$acct
{'
Acct-Input-Gigawords
'},
$acct
{'
Acct-Output-Gigawords
'},
$acct
{'
Ascend-Xmit-Rate
'},
$acct
{'
Ascend-Data-Rate
'},
$acct
{'
Framed-IP-Address
'},
$acct
{'
Connect-Info
'},
$acct
{'
Service-Type
'},
$acct
{'
Class
'},
$acct
{'
Acct-Terminate-Cause
'})
=
@acct
;
# Pull timestamp
my
$dt
=
DateTime
->
from_epoch
(
epoch
=>
time
()
);
$acct
{'
Timestamp
'}
=
$dt
->
strftime
('
%Y-%m-%d %H:%M:%S
');
my
$timer0
=
[
gettimeofday
];
# Grab user details
my
$userData
=
getUser
(
$dbh
,
$acct
{'
User-Name
'});
if
(
ref
$userData
ne
"
HASH
")
{
print
(
FH
"
ERROR:
$userData
\n
");
$userData
->
{'
AgentID
'}
=
0
;
$userData
->
{'
RadiusClassID
'}
=
0
;
$userData
->
{'
UsageCap
'}
=
0
;
}
printf
(
FH
'
ACCT - AgentID: %s, ClassID: %s, User-Name: %s, Status-Type: %s, Timestamp: %s, Acct-Session-Id: %s, NAS-IP-Address: %s, NAS-Port-Type: %s, NAS-Port: %s, Called-Station-Id: %s, Calling-Station-Id: %s, Delay: %s, Acct-Session-Time: %s, Acct-Input-Octets: %s, Acct-Output-Octets: %s, Acct-Input-Gigawords: %s, Acct-Output-Gigawords: %s, Ascend-Xmit-Rate: %s, Ascend-Data-Rate: %s, Framed-IP-Address: %s, Connect-Info: %s, Service-Type: %s, Class: %s, Acct-Terminate-Cause: %s
'
.
"
\n
",
$userData
->
{'
AgentID
'},
$userData
->
{'
RadiusClassID
'},
$acct
{'
User-Name
'},
$acct
{'
Status-Type
'},
$acct
{'
Timestamp
'},
$acct
{'
Acct-Session-Id
'},
$acct
{'
NAS-IP-Address
'},
$acct
{'
NAS-Port-Type
'},
$acct
{'
NAS-Port
'},
$acct
{'
Called-Station-Id
'},
$acct
{'
Calling-Station-Id
'},
$acct
{'
Delay
'},
$acct
{'
Acct-Session-Time
'},
$acct
{'
Acct-Input-Octets
'},
$acct
{'
Acct-Output-Octets
'},
$acct
{'
Acct-Input-Gigawords
'},
$acct
{'
Acct-Output-Gigawords
'},
$acct
{'
Ascend-Xmit-Rate
'},
$acct
{'
Ascend-Data-Rate
'},
$acct
{'
Framed-IP-Address
'},
$acct
{'
Connect-Info
'},
$acct
{'
Service-Type
'},
$acct
{'
Class
'},
$acct
{'
Acct-Terminate-Cause
'});
# IF ADSL (ADSL specific stuff)
if
(
$acct
{'
NAS-Port-Type
'}
eq
"
5
")
{
# Calculate dates
my
$date
=
DateTime
->
from_epoch
(
epoch
=>
time
()
);
my
$today
=
$date
->
ymd
();
$date
->
set_day
(
1
);
my
$thismonth
=
$date
->
ymd
();
$date
->
add
(
months
=>
1
);
my
$nextmonth
=
$date
->
ymd
();
my
$extraQuery
=
"";
# NULL - uncapped, no limits
if
(
!
defined
(
$userData
->
{'
UsageCap
'}))
{
$extraQuery
=
"
AND Timestamp >
"
.
$dbh
->
quote
(
$thismonth
)
.
"
AND Timestamp <
"
.
$dbh
->
quote
(
$nextmonth
);
# > 0 - normal cap, check usage for this month, check topups for this month
# Calculate cap user has (acctinputoctets + (2^32 * gigawords)) /1024 / 1024
# Calculate usage user has
}
elsif
(
$userData
->
{'
UsageCap
'}
>
0
)
{
$extraQuery
=
"
AND Timestamp >
"
.
$dbh
->
quote
(
$thismonth
)
.
"
AND Timestamp <
"
.
$dbh
->
quote
(
$nextmonth
);
# 0 - topup account
}
elsif
(
$userData
->
{'
UsageCap
'}
==
0
)
{
}
# Grab users usage
my
$usageData
=
getUsage
(
$dbh_log
,
$acct
{'
User-Name
'},
$extraQuery
);
if
(
ref
$usageData
ne
"
HASH
")
{
print
(
FH
"
ERROR:
$usageData
\n
");
# print(STDOUT "1\n");
goto
END
;
}
$userData
->
{'
TotalUsage
'}
=
$usageData
->
{'
Total
'};
# Only total up this month
$extraQuery
=
"";
if
(
defined
(
$userData
->
{'
UsageCap
'})
&&
$userData
->
{'
UsageCap
'}
>
0
)
{
$extraQuery
=
"
AND ValidFrom <=
"
.
$dbh
->
quote
(
$today
)
.
"
AND ValidTo >
"
.
$dbh
->
quote
(
$today
);
}
# Get how much we've been topped up
my
$topupData
=
getTopups
(
$dbh
,
$acct
{'
User-Name
'},
$extraQuery
);
if
(
ref
$topupData
ne
"
HASH
")
{
print
(
FH
"
ERROR:
$topupData
\n
");
# print(STDOUT "1\n");
goto
END
;
}
$userData
->
{'
Topups
'}
=
$topupData
->
{'
Total
'};
$userData
->
{'
SessUsage
'}
=
0
;
# If we updating or disconnecting, calculate the session usage so far
if
(
$acct
{'
Status-Type
'}
==
2
||
$acct
{'
Status-Type
'}
==
3
)
{
# Check how much data we used in this session
my
$sessUsage
=
0
;
if
(
defined
(
$acct
{'
Acct-Input-Octets
'})
&&
$acct
{'
Acct-Input-Octets
'}
>
0
)
{
$sessUsage
+=
$acct
{'
Acct-Input-Octets
'}
/ 1024 /
1024
;
}
if
(
defined
(
$acct
{'
Acct-Input-Gigawords
'})
&&
$acct
{'
Acct-Input-Gigawords
'}
>
0
)
{
$sessUsage
+=
$acct
{'
Acct-Input-Gigawords
'}
*
4096
;
}
# Add up output
if
(
defined
(
$acct
{'
Acct-Output-Octets
'})
&&
$acct
{'
Acct-Output-Octets
'}
>
0
)
{
$sessUsage
+=
$acct
{'
Acct-Output-Octets
'}
/ 1024 /
1024
;
}
if
(
defined
(
$acct
{'
Acct-Output-Gigawords
'})
&&
$acct
{'
Acct-Output-Gigawords
'}
>
0
)
{
$sessUsage
+=
$acct
{'
Acct-Output-Gigawords
'}
*
4096
;
}
$userData
->
{'
SessUsage
'}
=
ceil
(
$sessUsage
);
}
# Print usage stats
printf
(
FH
'
- Usage => Total: %s, Session: %s, Cap: %s, Topups: %s
'
.
"
\n
",
$userData
->
{'
TotalUsage
'},
$userData
->
{'
SessUsage
'},
defined
(
$userData
->
{'
UsageCap
'})
?
$userData
->
{'
UsageCap
'}
:
"
uncapped
",
$userData
->
{'
Topups
'},
);
# Capping & usage predictions
my
$totalCap
=
!
defined
(
$userData
->
{'
UsageCap
'})
?
0
:
$userData
->
{'
UsageCap
'}
+
$userData
->
{'
Topups
'};
if
(
defined
(
$userData
->
{'
UsageCap
'})
&&
$userData
->
{'
UsageCap
'}
>=
0
)
{
my
$exceeded
=
0
;
# Checking if we updating or stopping the session, if we are, check capping
if
(
$totalCap
<=
$userData
->
{'
TotalUsage
'}
&&
(
$acct
{'
Status-Type
'}
==
2
||
$acct
{'
Status-Type
'}
==
3
))
{
print
(
FH
"
- TEST: User has exceeded cap by
"
.
(
$userData
->
{'
TotalUsage
'}
-
$totalCap
)
.
"
Mbyte
\n
");
# If this is an update, user is still logged in, so disconnect them
if
(
$userData
->
{'
CappingType
'}
==
1
&&
$acct
{'
Status-Type
'}
==
3
)
{
print
(
FH
"
- TEST: User is still logged in, disconnecting
\n
");
disconnectUser
(
$dbh
,
\
*FH
,
$userData
,
\
%acct
);
# If user just got kicked off, notify them
}
elsif
(
$userData
->
{'
CappingType
'}
==
1
&&
$acct
{'
Status-Type
'}
==
2
)
{
print
(
FH
"
- TEST: Notifying user
\n
");
# We reset notifications, cause the user MUST get this and we dont mind updating him in future
notifyUser
(
$dbh
,
$dbh_log
,
\
*FH
,
$userData
,
NOTIFY_RESET
,
sprintf
('
Username %s has been capped, please contact your ISP should you need a topup
',
$userData
->
{'
Username
'}),
);
}
$exceeded
=
1
;
}
# Check if we may exceed the cap in the next hour, we need at least 1hrs of data for accuracy
if
(
!
$exceeded
&&
$acct
{'
Acct-Session-Time
'}
>
3600
)
{
my
$perSecUsage
=
$userData
->
{'
SessUsage
'}
/
$acct
{'
Acct-Session-Time
'};
my
$hrPredict
=
sprintf
('
%.2f
',(
$perSecUsage
*
3600
));
print
(
FH
"
- User is predicted to use
${hrPredict}
Mb in the next hour
\n
");
# If user is infact predicted to exceed, notify them
if
(
$totalCap
<=
$userData
->
{'
TotalUsage
'}
+
$hrPredict
)
{
print
(
FH
"
- This will exceed users cap, notifying user
\n
");
notifyUser
(
$dbh
,
$dbh_log
,
\
*FH
,
$userData
,
NOTIFY_CHECK
,
sprintf
('
Username %s may be capped in the next hour based on current usage stats, please contact your ISP should you need a topup
',
$userData
->
{'
Username
'}),
);
}
}
}
}
# START
if
(
$acct
{'
Status-Type
'}
==
1
)
{
# Start accounting
my
$res
=
$dbh_log
->
do
("
INSERT INTO radiusLogs
(
AgentID,
Username,
RadiusClassID,
UsageCap,
Topups,
Timestamp,
AcctDelayTime,
AcctSessionID,
NASIPAddress,
NASPortType,
NASPort,
CalledStationID,
CallingStationID,
ConnectInfo,
ServiceType,
Class,
FramedIPAddress,
Status
)
VALUES
(
"
.
$dbh_log
->
quote
(
$userData
->
{'
AgentID
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
User-Name
'})
.
"
,
"
.
$dbh_log
->
quote
(
$userData
->
{'
RadiusClassID
'})
.
"
,
"
.
$dbh_log
->
quote
(
$userData
->
{'
UsageCap
'})
.
"
,
"
.
$dbh_log
->
quote
(
$userData
->
{'
Topups
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Timestamp
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Delay
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Session-Id
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
NAS-IP-Address
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
NAS-Port-Type
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
NAS-Port
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Called-Station-Id
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Calling-Station-Id
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Connect-Info
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Service-Type
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Class
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Framed-IP-Address
'})
.
"
,
"
.
$dbh_log
->
quote
(
1
)
.
"
)
");
if
(
!
$res
)
{
print
(
FH
"
ERROR: Failed to insert radius auth fail data:
"
.
$dbh_log
->
err
.
"
\n
");
# print(STDOUT "1\n");
goto
END
;
}
# STOP
}
elsif
(
$acct
{'
Status-Type
'}
==
2
)
{
# Stop accounting
my
$res
=
$dbh_log
->
do
("
UPDATE radiusLogs
SET
Status =
"
.
$dbh_log
->
quote
(
3
)
.
"
,
NASTransmitRate =
"
.
$dbh_log
->
quote
(
$acct
{'
Ascend-Xmit-Rate
'})
.
"
,
NASReceiveRate =
"
.
$dbh_log
->
quote
(
$acct
{'
Ascend-Data-Rate
'})
.
"
,
AcctSessionTime =
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Session-Time
'})
.
"
,
AcctInputOctets =
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Input-Octets
'})
.
"
,
AcctOutputOctets =
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Output-Octets
'})
.
"
,
AcctInputGigawords =
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Input-Gigawords
'})
.
"
,
AcctOutputGigawords =
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Output-Gigawords
'})
.
"
,
ConnectTermReason =
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Terminate-Cause
'})
.
"
,
LastAccUpdate =
"
.
$dbh_log
->
quote
(
$acct
{'
Timestamp
'})
.
"
WHERE
Username =
"
.
$dbh_log
->
quote
(
$acct
{'
User-Name
'})
.
"
AND AcctSessionID =
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Session-Id
'})
.
"
AND NASIPAddress =
"
.
$dbh_log
->
quote
(
$acct
{'
NAS-IP-Address
'})
.
"
");
if
(
!
$res
)
{
print
(
FH
"
ERROR: Failed to update stop accounting data:
"
.
$dbh_log
->
err
.
"
\n
");
# print(STDOUT "1\n");
goto
END
;
}
$res
=
0
if
(
$res
eq
"
0E0
");
print
(
FH
"
- Rows updated:
$res
\n
");
# Check if we updated duplicates, if we did, fix them
if
(
$res
>
1
)
{
fixDuplicates
(
\
%acct
);
}
# UPDATE
}
elsif
(
$acct
{'
Status-Type
'}
==
3
)
{
# Update accounting
my
$res
=
$dbh_log
->
do
("
UPDATE radiusLogs
SET
Status =
"
.
$dbh_log
->
quote
(
2
)
.
"
,
NASTransmitRate =
"
.
$dbh_log
->
quote
(
$acct
{'
Ascend-Xmit-Rate
'})
.
"
,
NASReceiveRate =
"
.
$dbh_log
->
quote
(
$acct
{'
Ascend-Data-Rate
'})
.
"
,
AcctSessionTime =
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Session-Time
'})
.
"
,
AcctInputOctets =
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Input-Octets
'})
.
"
,
AcctOutputOctets =
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Output-Octets
'})
.
"
,
AcctInputGigawords =
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Input-Gigawords
'})
.
"
,
AcctOutputGigawords =
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Output-Gigawords
'})
.
"
,
ConnectTermReason =
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Terminate-Cause
'})
.
"
,
LastAccUpdate =
"
.
$dbh_log
->
quote
(
$acct
{'
Timestamp
'})
.
"
WHERE
Username =
"
.
$dbh_log
->
quote
(
$acct
{'
User-Name
'})
.
"
AND AcctSessionID =
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Session-Id
'})
.
"
AND NASIPAddress =
"
.
$dbh_log
->
quote
(
$acct
{'
NAS-IP-Address
'})
.
"
");
if
(
!
$res
)
{
print
(
FH
"
ERROR: Failed to update accounting data:
"
.
$dbh_log
->
err
.
"
\n
");
# print(STDOUT "1\n");
goto
END
;
}
$res
=
0
if
(
$res
eq
"
0E0
");
print
(
FH
"
- Rows updated:
$res
\n
");
# Create record as it doesn't exist!
if
(
$res
==
0
)
{
# Start accounting
my
$res
=
$dbh_log
->
do
("
INSERT INTO radiusLogs
(
AgentID,
Username,
RadiusClassID,
UsageCap,
Topups,
Timestamp,
AcctDelayTime,
AcctSessionID,
NASIPAddress,
NASPortType,
NASPort,
CalledStationID,
CallingStationID,
ConnectInfo,
ServiceType,
Class,
FramedIPAddress,
NASTransmitRate,
NASReceiveRate,
AcctSessionTime,
AcctInputOctets,
AcctOutputOctets,
AcctInputGigawords,
AcctOutputGigawords,
ConnectTermReason,
Status
)
VALUES
(
"
.
$dbh_log
->
quote
(
$userData
->
{'
AgentID
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
User-Name
'})
.
"
,
"
.
$dbh_log
->
quote
(
$userData
->
{'
RadiusClassID
'})
.
"
,
"
.
$dbh_log
->
quote
(
$userData
->
{'
UsageCap
'})
.
"
,
"
.
$dbh_log
->
quote
(
$userData
->
{'
Topups
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Timestamp
'}
-
defined
(
$acct
{'
Acct-Session-Time
'})
?
$acct
{'
Acct-Session-Time
'}
:
0
)
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Delay
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Session-Id
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
NAS-IP-Address
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
NAS-Port-Type
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
NAS-Port
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Called-Station-Id
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Calling-Station-Id
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Connect-Info
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Service-Type
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Class
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Framed-IP-Address
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Ascend-Xmit-Rate
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Ascend-Data-Rate
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Session-Time
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Input-Octets
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Output-Octets
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Input-Gigawords
'})
.
"
,
"
.
$dbh_log
->
quote
(
$acct
{'
Acct-Output-Gigawords
'})
.
"
,
"
.
$dbh_log
->
quote
(
0
)
.
"
,
"
.
$dbh_log
->
quote
(
1
)
.
"
)
");
if
(
!
$res
)
{
print
(
FH
"
ERROR: Failed to insert radius auth fail data:
"
.
$dbh_log
->
err
.
"
\n
");
# print(STDOUT "1\n");
goto
END
;
}
print
(
FH
"
- Lost accounting record created
\n
");
}
# Check if we updated duplicates, if we did, fix them
if
(
$res
>
1
)
{
fixDuplicates
(
\
%acct
);
}
}
my
$timer1
=
[
gettimeofday
];
my
$timediff
=
tv_interval
(
$timer0
,
$timer1
);
print
(
FH
"
Code execution took:
${timediff}
s
\n
");
END
:
# Check if we've handled enough requests
if
(
$requests
>=
1000
)
{
print
(
FH
"
Handled enough request, terminating
\n
");
last
;
}
# print(STDOUT "0\n");
}
close
(
FH
);
# Function to resolve duplicates
sub
fixDuplicates
{
my
(
$acct
)
=
@_
;
# Select duplicates
my
$sth
=
$dbh_log
->
select
("
SELECT ID
FROM
radiusLogs
WHERE
Username =
"
.
$dbh_log
->
quote
(
$acct
->
{'
User-Name
'})
.
"
AND NASIPAddress =
"
.
$dbh_log
->
quote
(
$acct
->
{'
NAS-IP-Address
'})
.
"
AND AcctSessionID =
"
.
$dbh_log
->
quote
(
$acct
->
{'
Acct-Session-Id
'})
.
"
ORDER BY ID
LIMIT 99 OFFSET 1
");
if
(
!
$sth
)
{
print
(
FH
"
ERROR: Selecting duplicates:
"
.
$dbh_log
->
err
.
"
\n
");
print
(
STDOUT
"
1
\n
");
return
;
}
# Return if no rows returned
return
if
(
$sth
->
rows
<
1
);
my
@IDs
=
();
# Pull in duplicates
while
(
my
$dup
=
$sth
->
fetchrow_hashref
())
{
push
(
@IDs
,
$dup
->
{'
ID
'});
}
$sth
->
finish
();
# Remove duplicates
my
$res
=
$dbh_log
->
do
("
DELETE FROM radiusLogs
WHERE
ID IN (
"
.
join
('
,
',
@IDs
)
.
"
)
");
if
(
!
$res
)
{
print
(
FH
"
ERROR: Failed to remove duplicates:
"
.
$dbh_log
->
err
.
"
\n
");
}
else
{
$res
=
0
if
(
$res
eq
"
0E0
");
print
(
FH
"
- Duplicates removed:
$res
\n
");
}
}
# Disconnect user
sub
disconnectUser
{
my
(
$dbh
,
$fh
,
$userData
,
$acct
)
=
@_
;
# If radius classID == 0, means we don't know about this user, just return, nothing we can do
if
(
$userData
->
{'
RadiusClassID
'}
==
0
)
{
print
(
$fh
"
- (D) Radius class ID is zero, cannot disconnect
\n
");
return
;
}
# Grab class data
my
$classData
=
getClass
(
$dbh
,
$userData
->
{'
RadiusClassID
'});
# Check if we got a hash, if not just return, error already reported in common.pm
if
(
ref
$classData
ne
"
HASH
")
{
print
(
$fh
"
- (D) No class data, cannot disconnect:
$classData
\n
");
return
;
}
# Check if we have POD server list, if not ... return
if
(
!
defined
(
$classData
->
{'
PODServers
'})
||
$classData
->
{'
PODServers
'}
eq
"")
{
print
(
$fh
"
- (D) No POD servers, cannot disconnect
\n
");
return
;
}
# Loop with POD servers and add to list
my
@podServers
;
foreach
my
$i
(
split
(
/,/
,
$classData
->
{'
PODServers
'}))
{
my
%server
;
# Pull out data we need
if
(
$i
=~
/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/([^:]+):(\d+)$/
)
{
(
$server
{'
IP
'},
$server
{'
Secret
'},
$server
{'
Port
'})
=
(
$
1
,
$
2
,
$
3
);
# If we didn't understand it, bitch
}
else
{
print
(
$fh
"
- (D) Did not understand POD server definition '
$i
'
\n
");
return
;
}
# Add to list
push
(
@podServers
,
\
%server
);
}
# Fork off notification handler
my
$child_pid
;
if
(
!
defined
(
$child_pid
=
fork
()))
{
print
(
$fh
"
- (D) ERROR: Cannot fork: $!
\n
");
}
elsif
(
$child_pid
)
{
# I'm the parent
return
;
}
else
{
# I'm the child
sleep
(
5
);
# Grab a server
foreach
my
$server
(
@podServers
)
{
# Fire up radius
my
$r
=
new
Authen::
Radius
(
Host
=>
$server
->
{'
IP
'}
.
'
:
'
.
$server
->
{'
Port
'},
Secret
=>
$server
->
{'
Secret
'},
Debug
=>
1
);
if
(
!
$r
)
{
print
(
$fh
"
FORK - (D)
"
.
$userData
->
{'
Username
'}
.
"
, failed to create radius object
\n
");
exit
;
}
# Set attributes
$r
->
add_attributes
(
{
Name
=>
'
User-Name
',
Value
=>
$userData
->
{'
Username
'}
},
{
Name
=>
'
Framed-IP-Address
',
Value
=>
$acct
->
{'
Framed-IP-Address
'}
},
{
Name
=>
'
NAS-IP-Address
',
Value
=>
$acct
->
{'
NAS-IP-Address
'}
},
);
# Send packet
my
$res
=
$r
->
send_packet
(
DISCONNECT_REQUEST
);
print
(
$fh
"
FORK - (D)
"
.
$userData
->
{'
Username
'}
.
"
, Result1:
"
.
Dumper
(
$res
)
.
"
\n
");
# Clear & grab result
$r
->
clear_attributes
();
$res
=
$r
->
recv_packet
();
# Disect packet and see whats going on
print
(
$fh
"
FORK - (D)
"
.
$userData
->
{'
Username
'}
.
"
, Result2:
"
.
Dumper
(
$res
)
.
"
\n
");
my
$value
=
$r
->
{'
attributes
'};
if
(
defined
(
$value
))
{
my
(
$v1
,
$v2
,
$v3
,
$v4
)
=
unpack
('
C C N
',
$value
);
printf
(
$fh
"
FORK - (D)
"
.
$userData
->
{'
Username
'}
.
"
, Got reply: v1=%s, v2=%s, v3=%s, v4=%s
\n
",
defined
(
$v1
)
?
$v1
:
'
<undef>
',
defined
(
$v2
)
?
$v2
:
'
<undef>
',
defined
(
$v3
)
?
$v3
:
'
<undef>
',
defined
(
$v4
)
?
$v4
:
'
<undef>
'
);
# Last it, as we got a reply
last
;
# This would mean a timeout?
}
else
{
print
(
$fh
"
FORK - (D)
"
.
$userData
->
{'
Username
'}
.
"
, Got reply: undefined
\n
");
}
}
}
}
# Notify user
sub
notifyUser
{
my
(
$dbh
,
$dbh_log
,
$fh
,
$userData
,
$action
,
$message
)
=
@_
;
# If no notification method is specified, just return
return
if
(
!
defined
(
$userData
->
{'
NotifyMethod
'})
||
$userData
->
{'
NotifyMethod
'}
eq
"");
# Get current notification status
my
$notifyStatus
=
getNotifyStatus
(
$dbh_log
,
$userData
);
if
(
ref
$notifyStatus
ne
"
HASH
")
{
print
(
$fh
"
- (N) No notify status:
$notifyStatus
\n
");
return
;
}
printf
(
$fh
'
- (N) Notify status, id = %s, lastupdate = %s, updateinterval = %s
'
.
"
\n
",
defined
(
$notifyStatus
->
{'
ID
'})
?
$notifyStatus
->
{'
ID
'}
:
'
new
',
$notifyStatus
->
{'
LastUpdate
'},
$notifyStatus
->
{'
UpdateInterval
'});
# Time now
my
$now
=
time
();
# Check if we should reset
if
(
$action
&
NOTIFY_RESET
==
NOTIFY_RESET
)
{
$notifyStatus
->
{'
UpdateInterval
'}
=
86400
;
# If we not resetting, check if we should do a check
}
else
{
# Calculate delta
my
$delta
=
((
$now
-
$notifyStatus
->
{'
LastUpdate
'})
+
$notifyStatus
->
{'
UpdateInterval
'})
/
2
;
$delta
=
86400
if
(
$delta
>
86400
);
# 1 day window only
print
(
$fh
"
- (N) Notify delta =
$delta
\n
");
# Check actions
if
(
$action
&
NOTIFY_CHECK
==
NOTIFY_CHECK
)
{
# Return if delta is less than half a day
return
if
(
$delta
<
43200
);
print
(
$fh
"
- (N) Notify check, succeeded
\n
");
}
$notifyStatus
->
{'
UpdateInterval
'}
=
$delta
;
}
$notifyStatus
->
{'
LastUpdate
'}
=
$now
;
my
$res
=
updateNotifyStatus
(
$dbh_log
,
$userData
,
$notifyStatus
);
if
(
!
$res
)
{
print
(
$fh
"
- (N) Notify data updated
\n
");
}
else
{
print
(
$fh
"
- (N) Notify update error:
$res
\n
");
}
# Get agent data
my
$agentData
=
getAgent
(
$dbh
,
$userData
->
{'
AgentID
'});
# Check if we got a hash, if not just return, error already reported in common.pm
if
(
ref
$agentData
ne
"
HASH
")
{
print
(
$fh
"
- (N) No agent data, cannot notify:
$agentData
\n
");
return
;
}
# Fork off notification handler
my
$child_pid
;
if
(
!
defined
(
$child_pid
=
fork
()))
{
print
(
$fh
"
- (N) ERROR: Cannot fork: $!
\n
");
}
elsif
(
$child_pid
)
{
# I'm the parent
return
;
}
else
{
# I'm the child
sleep
(
5
);
# Pull out notification email addy
my
@methods
=
split
/,/
,
$userData
->
{'
NotifyMethod
'};
print
(
$fh
"
FORK - (N) Resume for:
"
.
$userData
->
{'
Username
'}
.
"
\n
");
# Loop with notification methods
foreach
my
$method
(
@methods
)
{
# Check for email addy
if
(
$method
=~
/^\S+@\S+$/
)
{
print
(
$fh
"
FORK - (N) Its an email addy:
$method
\n
");
# Create message
my
$msg
=
MIME::
Lite
->
new
(
From
=>
$agentData
->
{'
ContactEmail
'},
To
=>
$method
,
Bcc
=>
$agentData
->
{'
ContactEmail
'},
Subject
=>
"
ADSL user
"
.
$userData
->
{'
Username
'},
Type
=>
'
multipart/mixed
'
);
# Attach body
$msg
->
attach
(
Type
=>
'
TEXT
',
Encoding
=>
'
quoted-printable
',
Data
=>
$message
,
);
# Send
if
(
!
(
my
$res
=
$msg
->
send
()))
{
print
(
$fh
"
FORK - (N) Failed to send email
\n
");
}
# First character can only be 1-9, next char is second part of country code, then 9 digit phone number (without 0)
}
elsif
(
$method
=~
/^\+([1-9][0-9]{0,1})([1-9][0-9]{8})$/
)
{
my
$country
=
$
1
;
my
$number
=
$
2
;
use
URI::
Escape
;
my
$cmd
=
"
echo '
"
.
uri_escape
(
$message
,"
\x00
-
\x1f\x7f
-
\xff\"\
'
")
.
"
' | /usr/local/sitemanager-trunk/scripts/sms/sendsms --send-to='
$country$number
'
";
if
(
$country
eq
"
27
")
{
print
(
$fh
"
FORK - (N) Its a cellphone in allowed country
$country
:
$method
\n
");
open
(
LOG
,"
>> /var/log/radius/sms.log
");
printf
(
LOG
'
%s:SENT:%s:%s:%s%s
',
$userData
->
{'
AgentID
'},
$country
.
$number
,
$userData
->
{'
Username
'},
$cmd
,
"
\n
");
close
(
LOG
);
print
(
$fh
"
FORK - (N) Going to run command:
$cmd
\n
");
system
(
$cmd
);
if
(
$?
==
-
1
)
{
print
(
$fh
"
FORK - (N) Failed to execute: $!
\n
");
}
elsif
(
$?
&
127
)
{
printf
(
$fh
"
FORK - (N) Child died with signal %d
\n
",(
$?
&
127
));
}
else
{
printf
(
$fh
"
FORK - (N) Child exited with value %d
\n
",
$?
>>
8
);
}
}
else
{
print
(
$fh
"
FORK - (N) Its a cellphone in dis-allowed country
$country
:
$method
\n
");
open
(
LOG
,"
>> /var/log/radius/sms.log
");
printf
(
LOG
'
%s:REJECT:%s:%s:%s%s
',
$userData
->
{'
AgentID
'},
$country
.
$number
,
$userData
->
{'
Username
'},
$cmd
,
"
\n
");
close
(
LOG
);
}
# Not understood
}
else
{
print
(
$fh
"
FORK - (N) I DO NOT UNDERSTAND NOTIFY METHOD => '
$method
'
\n
");
}
}
exit
;
}
}
# Function to get a notification status
sub
getNotifyStatus
{
my
(
$dbh
,
$userData
)
=
@_
;
my
%notifyStatus
;
# Select tracking information
my
$sth
=
$dbh
->
select
("
SELECT
ID, Username, LastUpdate, UpdateInterval, LastValue
FROM
radiusNotifyTrack
WHERE
Username =
"
.
$dbh
->
quote
(
$userData
->
{'
Username
'})
.
"
");
if
(
!
$sth
)
{
return
"
Database error:
"
.
$dbh
->
err
;
}
# Tracking info exists
if
(
$sth
->
rows
==
1
)
{
# Pull data
my
$data
=
$sth
->
fetchrow_hashref
();
$sth
->
finish
();
# Sanity check
return
"
Undefined data!
"
if
(
ref
$data
ne
"
HASH
");
$notifyStatus
{'
ID
'}
=
$data
->
{'
ID
'};
$notifyStatus
{'
LastUpdate
'}
=
$data
->
{'
LastUpdate
'};
$notifyStatus
{'
UpdateInterval
'}
=
$data
->
{'
UpdateInterval
'};
$notifyStatus
{'
LastValue
'}
=
$data
->
{'
LastValue
'};
# No tracking info
}
elsif
(
$sth
->
rows
==
0
)
{
$sth
->
finish
();
$notifyStatus
{'
LastUpdate
'}
=
0
;
$notifyStatus
{'
UpdateInterval
'}
=
86400
;
# Insert record seeing as it doesn't exist
my
$res
=
$dbh
->
do
("
INSERT INTO radiusNotifyTrack
(
Username,
LastUpdate,
UpdateInterval
)
VALUES
(
"
.
$dbh
->
quote
(
$userData
->
{'
Username
'})
.
"
,
"
.
$dbh
->
quote
(
$notifyStatus
{'
LastUpdate
'})
.
"
,
"
.
$dbh
->
quote
(
$notifyStatus
{'
UpdateInterval
'})
.
"
)
");
return
"
Failed to insert radius tracking data:
"
.
$dbh
->
err
if
(
!
$res
);
# Wth happened here?
}
else
{
my
$msg
=
"
Unknown number of rows returned for radius tracking:
"
.
$sth
->
rows
;
$sth
->
finish
();
return
$msg
;
}
return
\
%notifyStatus
;
}
# Function to update users notify status
sub
updateNotifyStatus
{
my
(
$dbh
,
$userData
,
$notifyStatus
)
=
@_
;
# Update accounting
my
$res
=
$dbh
->
do
("
UPDATE radiusNotifyTrack
SET
LastUpdate =
"
.
$dbh
->
quote
(
$notifyStatus
->
{'
LastUpdate
'})
.
"
,
UpdateInterval =
"
.
$dbh
->
quote
(
$notifyStatus
->
{'
UpdateInterval
'})
.
"
WHERE
Username =
"
.
$dbh
->
quote
(
$userData
->
{'
Username
'})
.
"
");
if
(
!
$res
)
{
return
"
Failed to update notify tracking data:
"
.
$dbh
->
err
;
}
return
;
}
# Display usage
sub
displayUsage
{
print
("
Usage: $0 [--quiet]
\n
");
exit
0
;
}
# vim: ts=4
This diff is collapsed.
Click to expand it.
auth-filter
deleted
100755 → 0
+
0
−
459
View file @
bbdaa4f7
#!/usr/bin/perl -w
# Author: Nigel Kukard <nkukard@lbsd.net>
# Date: 12/04/2007
# Desc: Authentication filter for GNU Radius
# License: GPL
use
strict
;
use
Benchmark
;
use
Getopt::
Long
;
use
DateTime
;
use
Time::
HiRes
qw( gettimeofday tv_interval )
;
# Set library directory
use
lib
qw(../../)
;
use
sm::
config
;
use
sm::
dblayer
;
require
("
common.pm
");
my
%optctl
=
();
GetOptions
(
\
%optctl
,
"
help
");
# Check if user wants usage
if
(
defined
(
$optctl
{'
help
'}))
{
displayUsage
();
}
# Open up logfile
my
$logfile
=
"
/var/log/radius/auth-filter
";
open
(
FH
,"
>>
$logfile
")
or
die
"
Failed to open '
$logfile
': $!
";
# Databases
my
$dbh
;
# Authentication
my
$dbh_log
;
# Logs
# Get db handle
$dbh
=
sm::
dbilayer
->
new
(
$cfg_db_DSN
,
$cfg_db_Username
,
$cfg_db_Password
);
if
(
!
$dbh
)
{
print
(
STDERR
"
Error creating database object:
"
.
sm::
dbilayer
->
internalErr
());
exit
1
;
}
# Connect to database
if
(
$dbh
->
connect
()
!=
0
)
{
print
(
STDERR
"
Error connecting to database:
"
.
$dbh
->
err
);
exit
1
;
}
# Check if we must use split db's
if
(
defined
(
$cfg_radiuslog_db_DSN
))
{
# Get log db handle
$dbh_log
=
sm::
dbilayer
->
new
(
$cfg_radiuslog_db_DSN
,
$cfg_radiuslog_db_Username
,
$cfg_radiuslog_db_Password
);
if
(
!
$dbh_log
)
{
print
(
STDERR
"
Error creating database object:
"
.
sm::
dbilayer
->
internalErr
());
exit
1
;
}
# Connect to database
if
(
$dbh_log
->
connect
()
!=
0
)
{
print
(
STDERR
"
Error connecting to database:
"
.
$dbh_log
->
err
);
exit
1
;
}
# If not use the main DB
}
else
{
$dbh_log
=
$dbh
;
}
# No buffering
select
((
select
(
FH
),
$|
=
1
)[
0
]);
select
((
select
(
STDOUT
),
$|
=
1
)[
0
]);
# Loop with input
while
(
my
$line
=
<
STDIN
>
)
{
my
%request
;
my
@request
;
my
%accessAttribs
;
my
%replyAttribs
;
# Munch off \n
chomp
(
$line
);
# Check number of results
if
((
@request
=
split
/:/
,
$line
)
<
6
)
{
print
(
FH
"
ERROR: Number of params from radiusd:
"
.
(
@request
)
.
"
/
$line
\n
");
print
(
STDOUT
"
1
\n
");
next
;
}
# Pull in request
(
$request
{'
User-Name
'},
$request
{'
NAS-IP-Address
'},
$request
{'
NAS-Port-Type
'},
$request
{'
NAS-Port
'},
$request
{'
Connect-Info
'},
$request
{'
Service-Type
'})
=
@request
;
my
$dt
=
DateTime
->
from_epoch
(
epoch
=>
time
()
);
$request
{'
Timestamp
'}
=
$dt
->
strftime
('
%Y-%m-%d %H:%M:%S
');
# If this is a auth mechanism that called us, allow
if
(
$request
{'
NAS-Port-Type
'}
eq
"
0
"
&&
$request
{'
NAS-Port
'}
eq
"
0
"
&&
$request
{'
Service-Type
'}
eq
"
0
")
{
print
(
STDOUT
"
0
\n
");
next
;
}
my
$timer0
=
[
gettimeofday
];
# Grab user details
my
$userData
=
getUser
(
$dbh
,
$request
{'
User-Name
'});
if
(
ref
$userData
ne
"
HASH
")
{
print
(
FH
"
ERROR:
$userData
\n
");
print
(
STDOUT
"
1
\n
");
next
;
}
printf
(
FH
'
INFO: User-Name: %s, Timestamp: %s, NAS-IP-Address: %s, NAS-Port-Type: %s, NAS-Port: %s, Connect-Info: %s, Service-Type: %s, CappingType: %s, UsageCap: %s, AgentDisabled: %s
'
.
"
\n
",
$request
{'
User-Name
'},
$request
{'
Timestamp
'},
$request
{'
NAS-IP-Address
'},
$request
{'
NAS-Port-Type
'},
$request
{'
NAS-Port
'},
$request
{'
Connect-Info
'},
$request
{'
Service-Type
'},
$userData
->
{'
CappingType
'},
defined
(
$userData
->
{'
UsageCap
'})
?
$userData
->
{'
UsageCap
'}
:
"
uncapped
",
$userData
->
{'
AgentDisabled
'}
);
# Check user active, else insert into auth fail
if
(
$userData
->
{'
AgentDisabled
'}
eq
"
1
")
{
print
(
FH
"
- Agent disabled
\n
");
print
(
STDOUT
"
1 Reply-Message =
\"
Your account is currently deactivated. Please, contact your ISP.
\"\n
");
authFail
(
\
%request
,
1
);
next
;
}
# Pull in class attribs & check
my
$sth
=
$dbh
->
select
("
SELECT
Attr, OP, Value
FROM
radiusClassAttribs
WHERE
RadiusClassID =
"
.
$dbh
->
quote
(
$userData
->
{'
RadiusClassID
'})
.
"
AND OP IS NOT NULL
");
if
(
!
$sth
)
{
print
(
FH
"
ERROR: Selecting class attributes:
"
.
$dbh
->
err
.
"
\n
");
print
(
STDOUT
"
1
\n
");
next
;
}
# Loop with class attribs and push
while
(
my
$item
=
$sth
->
fetchrow_hashref
())
{
push
(
@
{
$accessAttribs
{
$item
->
{'
Attr
'}}{
$item
->
{'
OP
'}}},
$item
->
{'
Value
'});
}
$sth
->
finish
();
# Pull in user attribs & check
$sth
=
$dbh
->
select
("
SELECT
Attr, OP, Value
FROM
radiusAttribs
WHERE
RadiusUserID =
"
.
$dbh
->
quote
(
$userData
->
{'
ID
'})
.
"
AND OP IS NOT NULL
");
if
(
!
$sth
)
{
print
(
FH
"
ERROR: Selecting class attributes:
"
.
$dbh
->
err
.
"
\n
");
print
(
STDOUT
"
1
\n
");
next
;
}
# Loop with class attribs and push
while
(
my
$item
=
$sth
->
fetchrow_hashref
())
{
push
(
@
{
$accessAttribs
{
$item
->
{'
Attr
'}}{
$item
->
{'
OP
'}}},
$item
->
{'
Value
'});
}
$sth
->
finish
();
# Loop with access attribs and push
my
$rejectAttrs
=
0
;
foreach
my
$attr
(
keys
%accessAttribs
)
{
my
$ok
=
0
;
# Check if we missing something in the request
if
(
!
defined
(
$request
{
$attr
}))
{
printf
(
FH
"
- WARNING: Attribute '
$attr
' was in accessAttribs, but not request
\n
");
next
;
}
# Loop with attrib op's and check them out
foreach
my
$op
(
keys
%
{
$accessAttribs
{
$attr
}})
{
printf
(
FH
'
- Checking %s, request="%s", op="%s", attr="%s":
',
$attr
,
$request
{
$attr
},
$op
,
join
('
,
',
@
{
$accessAttribs
{
$attr
}{
$op
}})
);
# Check value against operator
foreach
my
$val
(
@
{
$accessAttribs
{
$attr
}{
$op
}})
{
# Equal
if
(
$op
eq
"
=
")
{
if
(
$request
{
$attr
}
eq
$val
)
{
print
(
FH
"
matched '
$val
'
\n
");
$ok
=
1
;
last
;
}
}
}
# Check if we ok, if not continue
if
(
$ok
==
0
)
{
print
(
FH
"
no match
\n
");
}
else
{
last
}
}
# Check if we ok, if not we've been violated
if
(
$ok
==
0
)
{
print
(
FH
"
- Class attribute violation: '
$attr
'
\n
");
$rejectAttrs
=
1
;
last
;
}
}
# Check if something didn't match up
if
(
$rejectAttrs
==
1
)
{
print
(
STDOUT
"
1 Reply-Message =
\"
Connection attribute mismatch. Please, contact your ISP.
\"\n
");
authFail
(
\
%request
,
5
);
next
;
}
# Check user type vs. adsl & analogue/isdn
# IF ADSL
if
(
$request
{'
NAS-Port-Type
'}
eq
"
5
")
{
# Calculate dates
my
$date
=
DateTime
->
from_epoch
(
epoch
=>
time
()
);
my
$today
=
$date
->
ymd
();
$date
->
set_day
(
1
);
my
$thismonth
=
$date
->
ymd
();
$date
->
add
(
months
=>
1
);
my
$nextmonth
=
$date
->
ymd
();
# Extra query for selects
my
$extraQuery
=
"";
# Check port locking, else insert into auth fail
$sth
=
$dbh
->
select
("
SELECT
NASPort
FROM
radiusPortLocks
WHERE
RadiusUserID =
"
.
$dbh
->
quote
(
$userData
->
{'
ID
'})
.
"
AND AgentDisabled = 0
");
if
(
!
$sth
)
{
print
(
FH
"
ERROR: Selecting NAS ports:
"
.
$dbh
->
err
.
"
\n
");
print
(
STDOUT
"
1
\n
");
next
;
}
# Check rows
if
(
$sth
->
rows
>
0
)
{
my
$found
=
0
;
# Loop with port locks
while
(
my
$portLock
=
$sth
->
fetchrow_hashref
())
{
# Check if we found port locking
if
(
$request
{'
NAS-Port
'}
eq
$portLock
->
{'
NASPort
'})
{
$found
=
1
;
last
;
}
}
# Check if we found it
if
(
$found
==
0
)
{
print
(
FH
"
- Port locked
\n
");
print
(
STDOUT
"
1 Reply-Message =
\"
Connection from unauthorized port. Please, contact your ISP.
\"\n
");
authFail
(
\
%request
,
4
);
$sth
->
finish
();
next
;
}
}
$sth
->
finish
();
# NULL - uncapped, no limits
if
(
!
defined
(
$userData
->
{'
UsageCap
'}))
{
$extraQuery
=
"
AND Timestamp >
"
.
$dbh
->
quote
(
$thismonth
)
.
"
AND Timestamp <
"
.
$dbh
->
quote
(
$nextmonth
);
# > 0 - normal cap, check usage for this month, check topups for this month
# Calculate cap user has (acctinputoctets + (2^32 * gigawords)) /1024 / 1024
# Calculate usage user has
}
elsif
(
$userData
->
{'
UsageCap
'}
>
0
)
{
$extraQuery
=
"
AND Timestamp >
"
.
$dbh
->
quote
(
$thismonth
)
.
"
AND Timestamp <
"
.
$dbh
->
quote
(
$nextmonth
);
# 0 - topup account
}
elsif
(
$userData
->
{'
UsageCap
'}
==
0
)
{
}
# Grab users usage
my
$usageData
=
getUsage
(
$dbh_log
,
$request
{'
User-Name
'},
$extraQuery
);
if
(
ref
$usageData
ne
"
HASH
")
{
print
(
FH
"
ERROR:
$usageData
\n
");
print
(
STDOUT
"
1
\n
");
next
;
}
my
$totalUsage
=
$usageData
->
{'
Total
'};
# If we a normal or topup, check topups
if
(
defined
(
$userData
->
{'
UsageCap
'})
&&
(
$userData
->
{'
UsageCap
'}
>
0
||
$userData
->
{'
UsageCap
'}
==
0
))
{
# Prepare
$extraQuery
=
"";
# Only total up this month
if
(
$userData
->
{'
UsageCap
'}
>
0
)
{
$extraQuery
=
"
AND ValidFrom <=
"
.
$dbh
->
quote
(
$today
)
.
"
AND ValidTo >=
"
.
$dbh
->
quote
(
$today
);
}
# Get how much we've been topped up
my
$topupData
=
getTopups
(
$dbh
,
$request
{'
User-Name
'},
$extraQuery
);
if
(
ref
$topupData
ne
"
HASH
")
{
print
(
FH
"
ERROR:
$topupData
\n
");
print
(
STDOUT
"
1
\n
");
next
;
}
my
$topupBw
=
$topupData
->
{'
Total
'};
# Check capping, else insert into auth fail
print
(
FH
"
- Usage
$totalUsage
(Cap:
"
.
$userData
->
{'
UsageCap
'}
.
"
+Topup:
$topupBw
)
\n
");
# Check capping
if
(
$userData
->
{'
CappingType
'}
==
1
&&
(
$userData
->
{'
UsageCap
'}
+
$topupBw
)
<=
$totalUsage
)
{
print
(
FH
"
- User capped
\n
");
print
(
STDOUT
"
1 Reply-Message =
\"
Your account is has been capped. Please, contact your ISP.
\"\n
");
authFail
(
\
%request
,
2
);
next
;
}
}
# IF ANALOGUE
}
elsif
(
$request
{'
NAS-Port-Type
'}
eq
"
0
")
{
# IF ISDN
}
elsif
(
$request
{'
NAS-Port-Type
'}
eq
"
2
")
{
}
else
{
print
(
FH
"
ERROR: Unknown NAS-Port-Type:
"
.
$request
{'
NAS-Port-Type
'}
.
"
\n
");
}
# Pull in class attribs
$sth
=
$dbh
->
select
("
SELECT
Attr, Value
FROM
radiusClassAttribs
WHERE
RadiusClassID =
"
.
$dbh
->
quote
(
$userData
->
{'
RadiusClassID
'})
.
"
AND OP IS NULL
");
if
(
!
$sth
)
{
print
(
FH
"
ERROR: Selecting class attributes:
"
.
$dbh
->
err
.
"
\n
");
print
(
STDOUT
"
1
\n
");
next
;
}
# Loop with class attribs
while
(
my
$item
=
$sth
->
fetchrow_hashref
())
{
$replyAttribs
{
$item
->
{'
Attr
'}}
=
$item
->
{'
Value
'};
}
$sth
->
finish
();
# Pull in user attribs
$sth
=
$dbh
->
select
("
SELECT
Attr, Value
FROM
radiusAttribs
WHERE
RadiusUserID =
"
.
$dbh
->
quote
(
$userData
->
{'
ID
'})
.
"
AND OP IS NULL
");
if
(
!
$sth
)
{
print
(
FH
"
ERROR: Selecting user attributes:
"
.
$dbh
->
err
.
"
\n
");
print
(
STDOUT
"
1
\n
");
next
;
}
# Loop with user attribs
while
(
my
$item
=
$sth
->
fetchrow_hashref
())
{
$replyAttribs
{
$item
->
{'
Attr
'}}
=
$item
->
{'
Value
'};
}
$sth
->
finish
();
# Build up our attrib pairs
my
@replyAttribs
;
foreach
my
$key
(
keys
%replyAttribs
)
{
push
(
@replyAttribs
,
sprintf
('
%s = %s
',
$key
,
$replyAttribs
{
$key
}));
}
my
$timer1
=
[
gettimeofday
];
my
$timediff
=
tv_interval
(
$timer0
,
$timer1
);
printf
(
FH
'
- Attributes => %s
'
.
"
\n
",
join
("
,
",
@replyAttribs
));
print
(
FH
"
Code execution took:
${timediff}
s
\n
");
# Reply with positive status plus , separated list of attribs
printf
(
STDOUT
'
0 %s
'
.
"
\n
",
join
("
,
",
@replyAttribs
));
}
close
(
FH
);
# Log failed authentication
sub
authFail
{
my
(
$request
,
$reason
)
=
@_
;
# Insert entry into auth fail table
my
$sth
=
$dbh_log
->
do
("
INSERT INTO radiusAuthFail
(
Username,
Timestamp,
NASIPAddress,
NASPortType,
NASPort,
ConnectInfo,
ServiceType,
Reason
)
VALUES
(
"
.
$dbh
->
quote
(
$request
->
{'
User-Name
'})
.
"
,
"
.
$dbh
->
quote
(
$request
->
{'
Timestamp
'})
.
"
,
"
.
$dbh
->
quote
(
$request
->
{'
NAS-IP-Address
'})
.
"
,
"
.
$dbh
->
quote
(
$request
->
{'
NAS-Port-Type
'})
.
"
,
"
.
$dbh
->
quote
(
$request
->
{'
NAS-Port
'})
.
"
,
"
.
$dbh
->
quote
(
$request
->
{'
Connect-Info
'})
.
"
,
"
.
$dbh
->
quote
(
$request
->
{'
Service-Type
'})
.
"
,
"
.
$dbh
->
quote
(
$request
->
{'
Reason
'})
.
"
)
");
if
(
!
$sth
)
{
print
(
FH
"
ERROR: Failed to insert radius auth fail data:
"
.
$dbh_log
->
err
.
"
\n
");
}
}
# Display usage
sub
displayUsage
{
print
("
Usage: $0 [--quiet]
\n
");
exit
0
;
}
# vim: ts=4
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment