# Accounting and Post-Auth Queries
#######################################################################
# These queries insert/update accounting and authentication records.
-# The query to use is determined by the value of 'reference'.
-# This value is used as a configuration path and should resolve to exactly
-# one query.
+# The query to use is determined by the name of the section the module
+# is called from.
+#
+# e.g. when called from `accouting Start`, the contents of
+#
+# accounting {
+# start {}
+# }
+#
+# will be read, and the "query" entry found will be used.
#
# Unlike other SQL drivers, the rlm_cassandra driver will always
# indicate a single row was updated. This is because the updates aren't
# as INSERTS are really UPSERTS so we can work around it.
#######################################################################
accounting {
- reference = "%tolower(type.%{Acct-Status-Type}.query)"
-
# Write SQL queries to a logfile. This is potentially useful for bulk inserts
# when used with the rlm_sql_null driver.
# logfile = ${logdir}/accounting.sql
- type {
- #
- # Because cassandra doesn't allow secondary indexes to be used in update statements
- # applying acct on/off packets must be done outside of the server, by a script that
- # first performs a SELECT to identify candidate rows, then closes out the sessions.
- #
- accounting-on {
- query = "\
- INSERT INTO radnasreboot (nasipaddress, timestamp) \
- VALUES ('%{NAS-IP-Address}', ${....event_timestamp});"
- }
+ #
+ # Because cassandra doesn't allow secondary indexes to be used in update statements
+ # applying acct on/off packets must be done outside of the server, by a script that
+ # first performs a SELECT to identify candidate rows, then closes out the sessions.
+ #
+ accounting-on {
+ query = "\
+ INSERT INTO radnasreboot (nasipaddress, timestamp) \
+ VALUES ('%{NAS-IP-Address}', ${...event_timestamp});"
+ }
- accounting-off {
- query = "${..accounting-on.query}"
- }
+ accounting-off {
+ query = "${..accounting-on.query}"
+ }
- start {
- #
- # Insert a new record into the sessions table
- #
- query = "\
- INSERT INTO ${....acct_table1} ( \
- acctuniqueid, \
- acctsessionid, \
- username, \
- realm, \
- nasipaddress, \
- nasportid, \
- nasporttype, \
- acctstarttime, \
- acctupdatetime, \
- acctstoptime, \
- acctauthentic, \
- connectinfo_start, \
- acctinputoctets, \
- acctoutputoctets, \
- calledstationid, \
- callingstationid, \
- servicetype, \
- framedprotocol, \
- framedipaddress, \
- framedipv6address, \
- framedipv6prefix, \
- framedinterfaceid, \
- delegatedipv6prefix, \
- class
- ) VALUES ( \
- '%{Acct-Unique-Session-Id}', \
- '%{Acct-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{&NAS-Port-Id || &NAS-Port}', \
- '%{NAS-Port-Type}', \
- ${....event_timestamp}, \
- ${....event_timestamp}, \
- null, \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- 0, \
- 0, \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '%{Framed-IPv6-Address}', \
- '%{Framed-IPv6-Prefix}', \
- '%{Framed-Interface-Id}', \
- '%{Delegated-IPv6-Prefix}', \
- '%{Class}'
- );"
- }
+ start {
+ #
+ # Insert a new record into the sessions table
+ #
+ query = "\
+ INSERT INTO ${...acct_table1} ( \
+ acctuniqueid, \
+ acctsessionid, \
+ username, \
+ realm, \
+ nasipaddress, \
+ nasportid, \
+ nasporttype, \
+ acctstarttime, \
+ acctupdatetime, \
+ acctstoptime, \
+ acctauthentic, \
+ connectinfo_start, \
+ acctinputoctets, \
+ acctoutputoctets, \
+ calledstationid, \
+ callingstationid, \
+ servicetype, \
+ framedprotocol, \
+ framedipaddress, \
+ framedipv6address, \
+ framedipv6prefix, \
+ framedinterfaceid, \
+ delegatedipv6prefix, \
+ class
+ ) VALUES ( \
+ '%{Acct-Unique-Session-Id}', \
+ '%{Acct-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{&NAS-Port-Id || &NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ ${...event_timestamp}, \
+ ${...event_timestamp}, \
+ null, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ 0, \
+ 0, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '%{Class}'
+ );"
+ }
- interim-update {
- query = "\
- BEGIN BATCH \
- INSERT INTO ${....acct_table1} ( \
- acctuniqueid, \
- acctstarttime \
- ) VALUES ( \
- '%{Acct-Unique-Session-Id}', \
- %{(${....event_timestamp_epoch} - &Acct-Session-Time) * 1000} \
- ) IF NOT EXISTS; \
- INSERT INTO ${....acct_table1} ( \
- acctuniqueid, \
- acctsessionid, \
- username, \
- realm, \
- nasipaddress, \
- nasportid, \
- nasporttype, \
- acctupdatetime, \
- acctstoptime, \
- acctauthentic, \
- connectinfo_start, \
- acctinputoctets, \
- acctoutputoctets, \
- calledstationid, \
- callingstationid, \
- servicetype, \
- framedprotocol, \
- framedipaddress, \
- framedipv6address, \
- framedipv6prefix, \
- framedinterfaceid, \
- delegatedipv6prefix, \
- class \
- ) VALUES ( \
- '%{Acct-Unique-Session-Id}', \
- '%{Acct-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{&NAS-Port-Id || &NAS-Port}', \
- '%{NAS-Port-Type}', \
- ${....event_timestamp}, \
- null, \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
- %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '%{Framed-IPv6-Address}', \
- '%{Framed-IPv6-Prefix}', \
- '%{Framed-Interface-Id}', \
- '%{Delegated-IPv6-Prefix}', \
- '%{Class}' \
- ); \
- APPLY BATCH;"
- }
+ interim-update {
+ query = "\
+ BEGIN BATCH \
+ INSERT INTO ${...acct_table1} ( \
+ acctuniqueid, \
+ acctstarttime \
+ ) VALUES ( \
+ '%{Acct-Unique-Session-Id}', \
+ %{(${...event_timestamp_epoch} - &Acct-Session-Time) * 1000} \
+ ) IF NOT EXISTS; \
+ INSERT INTO ${...acct_table1} ( \
+ acctuniqueid, \
+ acctsessionid, \
+ username, \
+ realm, \
+ nasipaddress, \
+ nasportid, \
+ nasporttype, \
+ acctupdatetime, \
+ acctstoptime, \
+ acctauthentic, \
+ connectinfo_start, \
+ acctinputoctets, \
+ acctoutputoctets, \
+ calledstationid, \
+ callingstationid, \
+ servicetype, \
+ framedprotocol, \
+ framedipaddress, \
+ framedipv6address, \
+ framedipv6prefix, \
+ framedinterfaceid, \
+ delegatedipv6prefix, \
+ class \
+ ) VALUES ( \
+ '%{Acct-Unique-Session-Id}', \
+ '%{Acct-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{&NAS-Port-Id || &NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ ${...event_timestamp}, \
+ null, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
+ %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '%{Class}' \
+ ); \
+ APPLY BATCH;"
+ }
- stop {
- query = "\
- BEGIN BATCH \
- INSERT INTO ${....acct_table1} ( \
- acctuniqueid, \
- acctstarttime \
- ) VALUES ( \
- '%{Acct-Unique-Session-Id}', \
- %{(${....event_timestamp_epoch} - &Acct-Session-Time) * 1000} \
- ) IF NOT EXISTS; \
- INSERT INTO ${....acct_table1} ( \
- acctuniqueid, \
- acctsessionid, \
- username, \
- realm, \
- nasipaddress, \
- nasportid, \
- nasporttype, \
- acctupdatetime, \
- acctstoptime, \
- acctauthentic, \
- connectinfo_stop, \
- acctinputoctets, \
- acctoutputoctets, \
- calledstationid, \
- callingstationid, \
- servicetype, \
- framedprotocol, \
- framedipaddress, \
- framedipv6address, \
- framedipv6prefix, \
- framedinterfaceid, \
- delegatedipv6prefix, \
- acctterminatecause, \
- class \
- ) VALUES ( \
- '%{Acct-Unique-Session-Id}', \
- '%{Acct-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{&NAS-Port-Id || &NAS-Port}', \
- '%{NAS-Port-Type}', \
- ${....event_timestamp}, \
- ${....event_timestamp}, \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
- %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '%{Framed-IPv6-Address}', \
- '%{Framed-IPv6-Prefix}', \
- '%{Framed-Interface-Id}', \
- '%{Delegated-IPv6-Prefix}', \
- '%{Acct-Terminate-Cause}', \
- '%{Class}' \
- ); \
- APPLY BATCH;"
- }
+ stop {
+ query = "\
+ BEGIN BATCH \
+ INSERT INTO ${...acct_table1} ( \
+ acctuniqueid, \
+ acctstarttime \
+ ) VALUES ( \
+ '%{Acct-Unique-Session-Id}', \
+ %{(${...event_timestamp_epoch} - &Acct-Session-Time) * 1000} \
+ ) IF NOT EXISTS; \
+ INSERT INTO ${...acct_table1} ( \
+ acctuniqueid, \
+ acctsessionid, \
+ username, \
+ realm, \
+ nasipaddress, \
+ nasportid, \
+ nasporttype, \
+ acctupdatetime, \
+ acctstoptime, \
+ acctauthentic, \
+ connectinfo_stop, \
+ acctinputoctets, \
+ acctoutputoctets, \
+ calledstationid, \
+ callingstationid, \
+ servicetype, \
+ framedprotocol, \
+ framedipaddress, \
+ framedipv6address, \
+ framedipv6prefix, \
+ framedinterfaceid, \
+ delegatedipv6prefix, \
+ acctterminatecause, \
+ class \
+ ) VALUES ( \
+ '%{Acct-Unique-Session-Id}', \
+ '%{Acct-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{&NAS-Port-Id || &NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ ${...event_timestamp}, \
+ ${...event_timestamp}, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
+ %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Class}' \
+ ); \
+ APPLY BATCH;"
}
}
#######################################################################
# Authentication Logging Queries
#######################################################################
-# postauth_query - Insert some info after authentication
+# send queries - Insert some info after authentication
#######################################################################
-post-auth {
+send {
# Write SQL queries to a logfile. This is potentially useful for bulk inserts
# when used with the rlm_sql_null driver.
# logfile = ${logdir}/post-auth.sql
- query = "\
- INSERT INTO ${..postauth_table} \
- (username, pass, reply, authdate, class) \
- VALUES ( \
- '%{SQL-User-Name}', \
- '%{&User-Password || &Chap-Password}', \
- '%{reply.Packet-Type}', \
- '%{%l * 1000 + %M / 1000}', \
- '%{reply.Class}')"
+ access-accept {
+ query = "\
+ INSERT INTO ${...postauth_table} \
+ (username, pass, reply, authdate, class) \
+ VALUES ( \
+ '%{SQL-User-Name}', \
+ '%{&User-Password || &Chap-Password}', \
+ '%{reply.Packet-Type}', \
+ '%{%l * 1000 + %M / 1000}', \
+ '%{reply.Class}')"
+ }
+
+ access-reject {
+ query = "${..access-accept.query}"
+ }
}
ORDER BY priority"
#######################################################################
-# Accounting and Post-Auth Queries
+# Accounting and Send Queries
#######################################################################
# These queries insert/update accounting and authentication records.
-# The query to use is determined by the value of 'reference'.
-# This value is used as a configuration path and should resolve to one
-# or more 'query's. If reference points to multiple queries, and a query
-# fails, the next query is executed.
+# The query to use is determined by the name of the section the module
+# is called from.
#
-# Behaviour is identical to the old 1.x/2.x module, except we can now
-# fail between N queries, and query selection can be based on any
-# combination of attributes, or custom 'Acct-Status-Type' values.
+# e.g. when called from `accouting Start`, the contents of
+#
+# accounting {
+# start {}
+# }
+#
+# will be read, and any "query" entries will be run in sequence
+# until one returns a positive number of modified rows.
#######################################################################
accounting {
- reference = "%tolower(type.%{Acct-Status-Type}.query)"
-
# Write SQL queries to a logfile. This is potentially useful for bulk inserts
# when used with the rlm_sql_null driver.
# logfile = ${logdir}/accounting.sql
- type {
- accounting-on {
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- AcctStopTime=${....event_timestamp}, \
- AcctSessionTime=${....event_timestamp_epoch} - \
- DATEDIFF(SS, '1970-01-01', AcctStartTime), \
- AcctTerminateCause='%{&Acct-Terminate-Cause || \'NAS-Reboot\'}', \
- AcctStopDelay = %{&Acct-Delay-Time || 0} \
- WHERE AcctStopTime = 0 \
- AND NASIPAddress = '%{NAS-IP-Address}' \
- AND AcctStartTime <= ${....event_timestamp}"
+ accounting-on {
+ query = "\
+ UPDATE ${...acct_table1} \
+ SET \
+ AcctStopTime=${...event_timestamp}, \
+ AcctSessionTime=${...event_timestamp_epoch} - \
+ DATEDIFF(SS, '1970-01-01', AcctStartTime), \
+ AcctTerminateCause='%{&Acct-Terminate-Cause || 'NAS-Reboot'}', \
+ AcctStopDelay = %{&Acct-Delay-Time || 0} \
+ WHERE AcctStopTime = 0 \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStartTime <= ${...event_timestamp}"
- #
- # If there are no open user sessions, then the previous query
- # will return "no rows updated". The server will then fall through
- # to the next query, which is just "yes, that's fine".
- #
- query = "SELECT true"
- }
+ #
+ # If there are no open user sessions, then the previous query
+ # will return "no rows updated". The server will then fall through
+ # to the next query, which is just "yes, that's fine".
+ #
+ query = "SELECT true"
+ }
- accounting-off {
- query = "${..accounting-on.query}"
+ accounting-off {
+ query = "${..accounting-on.query}"
- query = "SELECT true"
- }
+ query = "SELECT true"
+ }
- start {
- query = "\
- INSERT INTO ${....acct_table1} ( \
- AcctSessionId, \
- AcctUniqueId, \
- UserName, \
- Realm, \
- NASIPAddress, \
- NASPortId, \
- NASPortType, \
- AcctStartTime, \
- AcctSessionTime, \
- AcctAuthentic, \
- ConnectInfo_start, \
- ConnectInfo_stop, \
- AcctInputOctets, \
- AcctOutputOctets, \
- CalledStationId, \
- CallingStationId, \
- AcctTerminateCause, \
- ServiceType, \
- FramedProtocol, \
- FramedIPAddress, \
- FramedIPv6Address, \
- FramedIPv6Prefix, \
- FramedInterfaceId, \
- DelegatedIPv6Prefix, \
- AcctStartDelay, \
- AcctStopDelay, \
- Class) \
- VALUES(\
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{&NAS-Port-ID || &NAS-Port}', \
- '%{NAS-Port-Type}', \
- ${....event_timestamp}, \
- '0', \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- '', \
- '0', \
- '0', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '%{Framed-IPv6-Address}', \
- '%{Framed-IPv6-Prefix}', \
- '%{Framed-Interface-Id}', \
- '%{Delegated-IPv6-Prefix}', \
- '%{Acct-Delay-Time}', \
- '0', \
- '%{Class}')"
+ start {
+ query = "\
+ INSERT INTO ${...acct_table1} ( \
+ AcctSessionId, \
+ AcctUniqueId, \
+ UserName, \
+ Realm, \
+ NASIPAddress, \
+ NASPortId, \
+ NASPortType, \
+ AcctStartTime, \
+ AcctSessionTime, \
+ AcctAuthentic, \
+ ConnectInfo_start, \
+ ConnectInfo_stop, \
+ AcctInputOctets, \
+ AcctOutputOctets, \
+ CalledStationId, \
+ CallingStationId, \
+ AcctTerminateCause, \
+ ServiceType, \
+ FramedProtocol, \
+ FramedIPAddress, \
+ FramedIPv6Address, \
+ FramedIPv6Prefix, \
+ FramedInterfaceId, \
+ DelegatedIPv6Prefix, \
+ AcctStartDelay, \
+ AcctStopDelay, \
+ Class) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{&NAS-Port-ID || &NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ ${...event_timestamp}, \
+ '0', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '0', \
+ '0', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '%{Acct-Delay-Time}', \
+ '0', \
+ '%{Class}')"
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- AcctStartTime = ${....event_timestamp}, \
- AcctStartDelay = '%{&Acct-Delay-Time || 0}', \
- ConnectInfo_start = '%{Connect-Info}' \
- WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
- AND AcctStopTime = 0"
- }
+ query = "\
+ UPDATE ${...acct_table1} \
+ SET \
+ AcctStartTime = ${...event_timestamp}, \
+ AcctStartDelay = '%{&Acct-Delay-Time || 0}', \
+ ConnectInfo_start = '%{Connect-Info}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
+ AND AcctStopTime = 0"
+ }
- interim-update {
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- AcctInterval = DATEDIFF(second, CASE WHEN AcctUpdateTime > 0 THEN AcctUpdateTime ELSE AcctStartTime END, ${....event_timestamp}), \
- AcctUpdateTime = ${....event_timestamp}, \
- AcctSessionTime = '%{Acct-Session-Time}', \
- AcctInputOctets = convert(bigint, '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}'), \
- AcctOutputOctets = convert(bigint, '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}'), \
- FramedIPAddress = '%{Framed-IP-Address}', \
- FramedIPv6Address = '%{Framed-IPv6-Address}', \
- FramedIPv6Prefix = '%{Framed-IPv6-Prefix}', \
- FramedInterfaceId = '%{Framed-Interface-Id}', \
- DelegatedIPv6Prefix = '%{Delegated-IPv6-Prefix}', \
- Class = '%{Class}' \
- WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
- AND AcctStopTime = 0"
+ interim-update {
+ query = "\
+ UPDATE ${...acct_table1} \
+ SET \
+ AcctInterval = DATEDIFF(second, CASE WHEN AcctUpdateTime > 0 THEN AcctUpdateTime ELSE AcctStartTime END, ${...event_timestamp}), \
+ AcctUpdateTime = ${...event_timestamp}, \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = convert(bigint, '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}'), \
+ AcctOutputOctets = convert(bigint, '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}'), \
+ FramedIPAddress = '%{Framed-IP-Address}', \
+ FramedIPv6Address = '%{Framed-IPv6-Address}', \
+ FramedIPv6Prefix = '%{Framed-IPv6-Prefix}', \
+ FramedInterfaceId = '%{Framed-Interface-Id}', \
+ DelegatedIPv6Prefix = '%{Delegated-IPv6-Prefix}', \
+ Class = '%{Class}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
+ AND AcctStopTime = 0"
- query = "\
- INSERT INTO ${....acct_table1} ( \
- AcctSessionId, \
- AcctUniqueId, \
- UserName, \
- Realm, \
- NASIPAddress, \
- NASPortId, \
- NASPortType, \
- AcctStartTime, \
- AcctUpdateTime, \
- AcctSessionTime, \
- AcctAuthentic, \
- ConnectInfo_start, \
- AcctInputOctets, \
- AcctOutputOctets, \
- CalledStationId, \
- CallingStationId, \
- ServiceType, \
- FramedProtocol, \
- FramedIPAddress, \
- FramedIPv6Address, \
- FramedIPv6Prefix, \
- FramedInterfaceId, \
- DelegatedIPv6Prefix, \
- AcctStartDelay, \
- Class) \
- VALUES(\
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{&NAS-Port-ID || &NAS-Port}', \
- '%{NAS-Port-Type}', \
- ${....event_timestamp}, \
- ${....event_timestamp}, \
- '%{Acct-Session-Time}', \
- '%{Acct-Authentic}', \
- '', \
- '%{Acct-Input-Octets}', \
- '%{Acct-Output-Octets}', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '%{Framed-IPv6-Address}', \
- '%{Framed-IPv6-Prefix}', \
- '%{Framed-Interface-Id}', \
- '%{Delegated-IPv6-Prefix}', \
- '0' \
- '%{Class}')"
- }
+ query = "\
+ INSERT INTO ${...acct_table1} ( \
+ AcctSessionId, \
+ AcctUniqueId, \
+ UserName, \
+ Realm, \
+ NASIPAddress, \
+ NASPortId, \
+ NASPortType, \
+ AcctStartTime, \
+ AcctUpdateTime, \
+ AcctSessionTime, \
+ AcctAuthentic, \
+ ConnectInfo_start, \
+ AcctInputOctets, \
+ AcctOutputOctets, \
+ CalledStationId, \
+ CallingStationId, \
+ ServiceType, \
+ FramedProtocol, \
+ FramedIPAddress, \
+ FramedIPv6Address, \
+ FramedIPv6Prefix, \
+ FramedInterfaceId, \
+ DelegatedIPv6Prefix, \
+ AcctStartDelay, \
+ Class) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{&NAS-Port-ID || &NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ ${...event_timestamp}, \
+ ${...event_timestamp}, \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Acct-Input-Octets}', \
+ '%{Acct-Output-Octets}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '0' \
+ '%{Class}')"
+ }
- stop {
- query = "\
- UPDATE ${....acct_table2} \
- SET \
- AcctStopTime = ${....event_timestamp}, \
- AcctSessionTime = '%{Acct-Session-Time}', \
- AcctInputOctets = convert(bigint, '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}'), \
- AcctOutputOctets = convert(bigint, '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}'), \
- AcctTerminateCause = '%{Acct-Terminate-Cause}', \
- AcctStopDelay = '%{&Acct-Delay-Time || 0}', \
- ConnectInfo_stop = '%{Connect-Info}', \
- Class = '%{Class}' \
- WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
- AND AcctStopTime = 0"
+ stop {
+ query = "\
+ UPDATE ${...acct_table2} \
+ SET \
+ AcctStopTime = ${...event_timestamp}, \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = convert(bigint, '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}'), \
+ AcctOutputOctets = convert(bigint, '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}'), \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ AcctStopDelay = '%{&Acct-Delay-Time || 0}', \
+ ConnectInfo_stop = '%{Connect-Info}', \
+ Class = '%{Class}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
+ AND AcctStopTime = 0"
- query = "\
- INSERT into ${....acct_table2} (\
- AcctSessionId, \
- AcctUniqueId, \
- UserName, \
- Realm, \
- NASIPAddress, \
- NASPortId, \
- NASPortType, \
- AcctStopTime, \
- AcctSessionTime, \
- AcctAuthentic, \
- ConnectInfo_start, \
- ConnectInfo_stop, \
- AcctInputOctets, \
- AcctOutputOctets, \
- CalledStationId, \
- CallingStationId, \
- AcctTerminateCause, \
- ServiceType, \
- FramedProtocol, \
- FramedIPAddress, \
- FramedIPv6Address, \
- FramedIPv6Prefix, \
- FramedInterfaceId, \
- DelegatedIPv6Prefix, \
- AcctStartDelay, \
- AcctStopDelay, \
- Class) \
- VALUES(\
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{&NAS-Port-ID || &NAS-Port}', \
- '%{NAS-Port-Type}', \
- ${....event_timestamp}, \
- '%{Acct-Session-Time}', \
- '%{Acct-Authentic}', \
- '', \
- '%{Connect-Info}', \
- NULL, \
- convert(bigint, '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}'), \
- convert(bigint, '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}'), \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Acct-Terminate-Cause}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '%{Framed-IPv6-Address}', \
- '%{Framed-IPv6-Prefix}', \
- '%{Framed-Interface-Id}', \
- '%{Delegated-IPv6-Prefix}', \
- '0', \
- '%{&Acct-Delay-Time || 0}', \
- '%{Class}')"
- }
+ query = "\
+ INSERT into ${...acct_table2} (\
+ AcctSessionId, \
+ AcctUniqueId, \
+ UserName, \
+ Realm, \
+ NASIPAddress, \
+ NASPortId, \
+ NASPortType, \
+ AcctStopTime, \
+ AcctSessionTime, \
+ AcctAuthentic, \
+ ConnectInfo_start, \
+ ConnectInfo_stop, \
+ AcctInputOctets, \
+ AcctOutputOctets, \
+ CalledStationId, \
+ CallingStationId, \
+ AcctTerminateCause, \
+ ServiceType, \
+ FramedProtocol, \
+ FramedIPAddress, \
+ FramedIPv6Address, \
+ FramedIPv6Prefix, \
+ FramedInterfaceId, \
+ DelegatedIPv6Prefix, \
+ AcctStartDelay, \
+ AcctStopDelay, \
+ Class) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{&NAS-Port-ID || &NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ ${...event_timestamp}, \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Connect-Info}', \
+ NULL, \
+ convert(bigint, '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}'), \
+ convert(bigint, '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}'), \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '0', \
+ '%{&Acct-Delay-Time || 0}', \
+ '%{Class}')"
}
}
-post-auth {
+
+send {
# Write SQL queries to a logfile. This is potentially useful for bulk inserts
# when used with the rlm_sql_null driver.
# logfile = ${logdir}/post-auth.sql
- query = "\
- INSERT INTO ${..postauth_table} \
- (userName, pass, reply, authdate, class) \
- VALUES(\
- '%{User-Name}', \
- '%{&User-Password || CHAP-PASSWORD}', \
- '%{reply.Packet-Type}', \
- '%S.%{%M / 1000}', \
- '%{reply.Class}')"
+ access-accept {
+ query = "\
+ INSERT INTO ${...postauth_table} \
+ (userName, pass, reply, authdate, class) \
+ VALUES(\
+ '%{User-Name}', \
+ '%{&User-Password || CHAP-PASSWORD}', \
+ '%{reply.Packet-Type}', \
+ '%S.%{%M / 1000}', \
+ '%{reply.Class}')"
+ }
+
+ access-reject {
+ query = "${..access-accept.query}"
+ }
}
# Accounting and Post-Auth Queries
#######################################################################
# These queries insert/update accounting and authentication records.
-# The query to use is determined by the value of 'reference'.
-# This value is used as a configuration path and should resolve to one
-# or more 'query's. If reference points to multiple queries, and a query
-# fails, the next query is executed.
+# The query to use is determined by the name of the section the module
+# is called from.
#
-# Behaviour is identical to the old 1.x/2.x module, except we can now
-# fail between N queries, and query selection can be based on any
-# combination of attributes, or custom 'Acct-Status-Type' values.
+# e.g. when called from `accouting Start`, the contents of
+#
+# accounting {
+# start {}
+# }
+#
+# will be read, and any "query" entries will be run in sequence
+# until one returns a positive number of modified rows.
#######################################################################
accounting {
- reference = "%tolower(type.%{Acct-Status-Type}.query)"
-
# Write SQL queries to a logfile. This is potentially useful for bulk inserts
# when used with the rlm_sql_null driver.
# logfile = ${logdir}/accounting.sql
framedipaddress, framedipv6address, framedipv6prefix, \
framedinterfaceid, delegatedipv6prefix, class"
- type {
- accounting-on {
-
- #
- # "Bulk update" Accounting-On/Off strategy.
- #
- # Immediately terminate all sessions associated with a
- # given NAS.
- #
- # Note: If a large number of sessions require closing
- # then the bulk update may be take a long time to run
- # and lock an excessive number of rows. See the
- # strategy below for an alternative approach that does
- # not touch the radacct session data.
- #
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- acctstoptime = ${....event_timestamp}, \
- acctsessiontime = '${....event_timestamp_epoch}' \
- - UNIX_TIMESTAMP(acctstarttime), \
- acctterminatecause = '%{&Acct-Terminate-Cause || \'NAS-Reboot\'}' \
- WHERE acctstoptime IS NULL \
- AND nasipaddress = '%{NAS-IP-Address}' \
- AND acctstarttime <= ${....event_timestamp}"
-
- #
- # "Lightweight" Accounting-On/Off strategy.
- #
- # Record the reload time of the NAS and let the
- # administrator actually close the sessions in radacct
- # out-of-band, if desired.
- #
- # Implementation advice, together with a stored
- # procedure for closing sessions and a view showing
- # the effective stop time of each session is provided
- # in process-radacct.sql.
- #
- # To enable this strategy, just change the previous
- # query to "-query", and this one to "query". The
- # previous one will be ignored, and this one will be
- # enabled.
- #
- -query = "\
- INSERT INTO nasreload \
- SET \
- nasipaddress = '%{NAS-IP-Address}', \
- reloadtime = ${....event_timestamp} \
- ON DUPLICATE KEY UPDATE reloadtime = ${....event_timestamp}"
-
- # If there are no open user sessions, then the previous query
- # will return "no rows updated". The server will then fall through
- # to the next query, which is just "yes, that's fine".
- #
- query = "SELECT true"
-
- }
-
- accounting-off {
- query = "${..accounting-on.query}"
-
- query = "SELECT true"
- }
-
- start {
- #
- # Insert a new record into the sessions table
- #
- query = "\
- INSERT INTO ${....acct_table1} \
- (${...column_list}) \
- VALUES \
- ('%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{&NAS-Port-ID || &NAS-Port}', \
- '%{NAS-Port-Type}', \
- ${....event_timestamp}, \
- ${....event_timestamp}, \
- NULL, \
- '0', \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- '', \
- '0', \
- '0', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '%{Framed-IPv6-Address}', \
- '%{Framed-IPv6-Prefix}', \
- '%{Framed-Interface-Id}', \
- '%{Delegated-IPv6-Prefix}', \
- '%{Class}')"
-
- #
- # Key constraints prevented us from inserting a new session,
- # use the alternate query to update an existing session.
- #
- query = "\
- UPDATE ${....acct_table1} SET \
- acctstarttime = ${....event_timestamp}, \
- acctupdatetime = ${....event_timestamp}, \
- connectinfo_start = '%{Connect-Info}', \
- class = '%{Class}' \
- WHERE acctuniqueid = '%{Acct-Unique-Session-Id}'"
- }
-
- interim-update {
- #
- # Update an existing session and calculate the interval
- # between the last data we received for the session and this
- # update. This can be used to find stale sessions.
- #
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- acctupdatetime = (@acctupdatetime_old:=acctupdatetime), \
- acctupdatetime = ${....event_timestamp}, \
- acctinterval = ${....event_timestamp_epoch} - \
- UNIX_TIMESTAMP(@acctupdatetime_old), \
- framedipaddress = '%{Framed-IP-Address}', \
- framedipv6address = '%{Framed-IPv6-Address}', \
- framedipv6prefix = '%{Framed-IPv6-Prefix}', \
- framedinterfaceid = '%{Framed-Interface-Id}', \
- delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \
- acctsessiontime = %{&Acct-Session-Time || \'NULL\'}, \
- acctinputoctets = %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
- acctoutputoctets = %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
- class = '%{Class}' \
- WHERE acctuniqueid = '%{Acct-Unique-Session-Id}'"
-
- #
- # The update condition matched no existing sessions. Use
- # the values provided in the update to create a new session.
- #
- query = "\
- INSERT INTO ${....acct_table1} \
- (${...column_list}) \
- VALUES \
- ('%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{&NAS-Port-ID || &NAS-Port}', \
- '%{NAS-Port-Type}', \
- FROM_UNIXTIME(${....event_timestamp_epoch} - %{&Acct-Session-Time || 0}), \
- ${....event_timestamp}, \
- NULL, \
- %{&Acct-Session-Time || \'NULL\'}, \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- '', \
- '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}', \
- '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '%{Framed-IPv6-Address}', \
- '%{Framed-IPv6-Prefix}', \
- '%{Framed-Interface-Id}', \
- '%{Delegated-IPv6-Prefix}', \
- '%{Class}')"
- }
-
- stop {
- #
- # Session has terminated, update the stop time and statistics.
- #
- query = "\
- UPDATE ${....acct_table2} SET \
- acctstoptime = ${....event_timestamp}, \
- acctsessiontime = %{&Acct-Session-Time || \'NULL\'}, \
- acctinputoctets = '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}', \
- acctoutputoctets = '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}', \
- acctterminatecause = '%{Acct-Terminate-Cause}', \
- connectinfo_stop = '%{Connect-Info}', \
- class = '%{Class}' \
- WHERE acctuniqueid = '%{Acct-Unique-Session-Id}'"
-
- #
- # The update condition matched no existing sessions. Use
- # the values provided in the update to create a new session.
- #
- query = "\
- INSERT INTO ${....acct_table2} \
- (${...column_list}) \
- VALUES \
- ('%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{&NAS-Port-ID || &NAS-Port}', \
- '%{NAS-Port-Type}', \
- FROM_UNIXTIME(${....event_timestamp_epoch} - %{&Acct-Session-Time || 0}), \
- ${....event_timestamp}, \
- ${....event_timestamp}, \
- %{&Acct-Session-Time || \'NULL\'}, \
- '%{Acct-Authentic}', \
- '', \
- '%{Connect-Info}', \
- '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}', \
- '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Acct-Terminate-Cause}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '%{Framed-IPv6-Address}', \
- '%{Framed-IPv6-Prefix}', \
- '%{Framed-Interface-Id}', \
- '%{Delegated-IPv6-Prefix}', \
- '%{Class}')"
- }
+ accounting-on {
+
+ #
+ # "Bulk update" Accounting-On/Off strategy.
+ #
+ # Immediately terminate all sessions associated with a
+ # given NAS.
+ #
+ # Note: If a large number of sessions require closing
+ # then the bulk update may be take a long time to run
+ # and lock an excessive number of rows. See the
+ # strategy below for an alternative approach that does
+ # not touch the radacct session data.
+ #
+ query = "\
+ UPDATE ${...acct_table1} \
+ SET \
+ acctstoptime = ${...event_timestamp}, \
+ acctsessiontime = '${...event_timestamp_epoch}' \
+ - UNIX_TIMESTAMP(acctstarttime), \
+ acctterminatecause = '%{&Acct-Terminate-Cause || \'NAS-Reboot\'}' \
+ WHERE acctstoptime IS NULL \
+ AND nasipaddress = '%{NAS-IP-Address}' \
+ AND acctstarttime <= ${...event_timestamp}"
+
+ #
+ # "Lightweight" Accounting-On/Off strategy.
+ #
+ # Record the reload time of the NAS and let the
+ # administrator actually close the sessions in radacct
+ # out-of-band, if desired.
+ #
+ # Implementation advice, together with a stored
+ # procedure for closing sessions and a view showing
+ # the effective stop time of each session is provided
+ # in process-radacct.sql.
+ #
+ # To enable this strategy, just change the previous
+ # query to "-query", and this one to "query". The
+ # previous one will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ INSERT INTO nasreload \
+ SET \
+ nasipaddress = '%{NAS-IP-Address}', \
+ reloadtime = ${...event_timestamp} \
+ ON DUPLICATE KEY UPDATE reloadtime = ${...event_timestamp}"
+
+ # If there are no open user sessions, then the previous query
+ # will return "no rows updated". The server will then fall through
+ # to the next query, which is just "yes, that's fine".
+ #
+ query = "SELECT true"
+
+ }
+
+ accounting-off {
+ query = "${..accounting-on.query}"
+
+ query = "SELECT true"
+ }
+
+ start {
+ #
+ # Insert a new record into the sessions table
+ #
+ query = "\
+ INSERT INTO ${...acct_table1} \
+ (${..column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{&NAS-Port-ID || &NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ ${...event_timestamp}, \
+ ${...event_timestamp}, \
+ NULL, \
+ '0', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '0', \
+ '0', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '%{Class}')"
+
+ #
+ # Key constraints prevented us from inserting a new session,
+ # use the alternate query to update an existing session.
+ #
+ query = "\
+ UPDATE ${...acct_table1} SET \
+ acctstarttime = ${...event_timestamp}, \
+ acctupdatetime = ${...event_timestamp}, \
+ connectinfo_start = '%{Connect-Info}', \
+ class = '%{Class}' \
+ WHERE acctuniqueid = '%{Acct-Unique-Session-Id}'"
+ }
+
+ interim-update {
+ #
+ # Update an existing session and calculate the interval
+ # between the last data we received for the session and this
+ # update. This can be used to find stale sessions.
+ #
+ query = "\
+ UPDATE ${...acct_table1} \
+ SET \
+ acctupdatetime = (@acctupdatetime_old:=acctupdatetime), \
+ acctupdatetime = ${...event_timestamp}, \
+ acctinterval = ${...event_timestamp_epoch} - \
+ UNIX_TIMESTAMP(@acctupdatetime_old), \
+ framedipaddress = '%{Framed-IP-Address}', \
+ framedipv6address = '%{Framed-IPv6-Address}', \
+ framedipv6prefix = '%{Framed-IPv6-Prefix}', \
+ framedinterfaceid = '%{Framed-Interface-Id}', \
+ delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \
+ acctsessiontime = %{&Acct-Session-Time || 'NULL'}, \
+ acctinputoctets = %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
+ acctoutputoctets = %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
+ class = '%{Class}' \
+ WHERE acctuniqueid = '%{Acct-Unique-Session-Id}'"
+
+ #
+ # The update condition matched no existing sessions. Use
+ # the values provided in the update to create a new session.
+ #
+ query = "\
+ INSERT INTO ${...acct_table1} \
+ (${..column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{&NAS-Port-ID || &NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ FROM_UNIXTIME(${...event_timestamp_epoch} - %{&Acct-Session-Time || 0}), \
+ ${...event_timestamp}, \
+ NULL, \
+ %{&Acct-Session-Time || 'NULL'}, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}', \
+ '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '%{Class}')"
+ }
+
+ stop {
+ #
+ # Session has terminated, update the stop time and statistics.
+ #
+ query = "\
+ UPDATE ${...acct_table2} SET \
+ acctstoptime = ${...event_timestamp}, \
+ acctsessiontime = %{&Acct-Session-Time || 'NULL'}, \
+ acctinputoctets = '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}', \
+ acctoutputoctets = '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}', \
+ acctterminatecause = '%{Acct-Terminate-Cause}', \
+ connectinfo_stop = '%{Connect-Info}', \
+ class = '%{Class}' \
+ WHERE acctuniqueid = '%{Acct-Unique-Session-Id}'"
+
+ #
+ # The update condition matched no existing sessions. Use
+ # the values provided in the update to create a new session.
+ #
+ query = "\
+ INSERT INTO ${...acct_table2} \
+ (${..column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{&NAS-Port-ID || &NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ FROM_UNIXTIME(${...event_timestamp_epoch} - %{&Acct-Session-Time || 0}), \
+ ${...event_timestamp}, \
+ ${...event_timestamp}, \
+ %{&Acct-Session-Time || 'NULL'}, \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Connect-Info}', \
+ '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}', \
+ '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '%{Class}')"
}
}
#######################################################################
# Authentication Logging Queries
#######################################################################
-# postauth_query - Insert some info after authentication
+# send queries - Insert some info after authentication
#######################################################################
-post-auth {
+send {
# Write SQL queries to a logfile. This is potentially useful for bulk inserts
# when used with the rlm_sql_null driver.
# logfile = ${logdir}/post-auth.sql
- query = "\
- INSERT INTO ${..postauth_table} \
- (username, pass, reply, authdate, class) \
- VALUES ( \
- '%{SQL-User-Name}', \
- '%{&User-Password || &Chap-Password}', \
- '%{reply.Packet-Type}', \
- '%S.%M', \
- '%{reply.Class}')"
+ access-accept {
+ query = "\
+ INSERT INTO ${...postauth_table} \
+ (username, pass, reply, authdate, class) \
+ VALUES ( \
+ '%{SQL-User-Name}', \
+ '%{&User-Password || &Chap-Password}', \
+ '%{reply.Packet-Type}', \
+ '%S.%M', \
+ '%{reply.Class}')"
+ }
+
+ access-reject {
+ query = "${..access-accept.query}"
+ }
}
# Accounting and Post-Auth Queries
#######################################################################
# These queries insert/update accounting and authentication records.
-# The query to use is determined by the value of 'reference'.
-# This value is used as a configuration path and should resolve to one
-# or more 'query's. If reference points to multiple queries, and a query
-# fails, the next query is executed.
+# The query to use is determined by the name of the section the module
+# is called from.
#
-# Behaviour is identical to the old 1.x/2.x module, except we can now
-# fail between N queries, and query selection can be based on any
-# combination of attributes, or custom 'Acct-Status-Type' values.
+# e.g. when called from `accouting Start`, the contents of
+#
+# accounting {
+# start {}
+# }
+#
+# will be read, and any "query" entries will be run in sequence
+# until one returns a positive number of modified rows.
#######################################################################
accounting {
- reference = "%tolower(type.%{Acct-Status-Type}.query)"
-
# Write SQL queries to a logfile. This is potentially useful for bulk inserts
# when used with the rlm_sql_null driver.
-# logfile = ${logdir}/accounting.sql
-
- type {
- accounting-on {
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- AcctStopTime = ${....event_timestamp}, \
- AcctSessionTime = ROUND((${....event_timestamp} - \
- TO_DATE(TO_CHAR(acctstarttime, 'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24:mi:ss'))*86400), \
- AcctTerminateCause='%{&Acct-Terminate-Cause || \'NAS-Reboot\'}', \
- AcctStopDelay = %{&Acct-Delay-Time || 0}, \
- Class = '%{Class}' \
- WHERE AcctStopTime IS NULL \
- AND NASIPAddress = '%{NAS-IP-Address}' \
- AND AcctStartTime <= ${....event_timestamp}"
+# logfile = ${logdir}/accounting.sql
- #
- # If there are no open user sessions, then the previous query
- # will return "no rows updated". The server will then fall through
- # to the next query, which is just "yes, that's fine".
- #
- query = "SELECT 1 from dual"
- }
+ accounting-on {
+ query = "\
+ UPDATE ${...acct_table1} \
+ SET \
+ AcctStopTime = ${...event_timestamp}, \
+ AcctSessionTime = ROUND((${...event_timestamp} - \
+ TO_DATE(TO_CHAR(acctstarttime, 'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24:mi:ss'))*86400), \
+ AcctTerminateCause='%{&Acct-Terminate-Cause || \'NAS-Reboot\'}', \
+ AcctStopDelay = %{&Acct-Delay-Time || 0}, \
+ Class = '%{Class}' \
+ WHERE AcctStopTime IS NULL \
+ AND NASIPAddress = '%{NAS-IP-Address}' \
+ AND AcctStartTime <= ${...event_timestamp}"
- accounting-off {
- query = "${..accounting-on.query}"
+ #
+ # If there are no open user sessions, then the previous query
+ # will return "no rows updated". The server will then fall through
+ # to the next query, which is just "yes, that's fine".
+ #
+ query = "SELECT 1 from dual"
+ }
- query = "SELECT 1 from dual"
- }
+ accounting-off {
+ query = "${..accounting-on.query}"
- start {
- query = "\
- INSERT INTO ${....acct_table1} (\
- RadAcctId, \
- AcctSessionId, \
- AcctUniqueId, \
- UserName, \
- Realm, \
- NASIPAddress, \
- NASPortId, \
- NASPortType, \
- AcctStartTime, \
- AcctStopTime, \
- AcctSessionTime, \
- AcctAuthentic, \
- ConnectInfo_start, \
- ConnectInfo_stop, \
- AcctInputOctets, \
- AcctOutputOctets, \
- CalledStationId, \
- CallingStationId, \
- AcctTerminateCause, \
- ServiceType, \
- FramedProtocol, \
- FramedIPAddress, \
- FramedIPv6Address, \
- FramedIPv6Prefix, \
- FramedInterfaceId, \
- DelegatedIPv6Prefix, \
- AcctStartDelay, \
- AcctStopDelay, \
- Class) \
- VALUES(\
- '', \
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{&NAS-Port-ID || &NAS-Port}', \
- '%{NAS-Port-Type}', \
- ${....event_timestamp}, \
- NULL, \
- '0', \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- '', \
- '0', \
- '0', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '%{Framed-IPv6-Address}', \
- '%{Framed-IPv6-Prefix}', \
- '%{Framed-Interface-Id}', \
- '%{Delegated-IPv6-Prefix}', \
- '%{Acct-Delay-Time}', \
- '0', \
- '%{Class}')"
+ query = "SELECT 1 from dual"
+ }
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- AcctStartTime = ${....event_timestamp}, \
- AcctStartDelay = '%{&Acct-Delay-Time || 0}', \
- ConnectInfo_start = '%{Connect-Info}' \
- WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
- AND AcctStopTime IS NULL"
- }
+ start {
+ query = "\
+ INSERT INTO ${...acct_table1} (\
+ RadAcctId, \
+ AcctSessionId, \
+ AcctUniqueId, \
+ UserName, \
+ Realm, \
+ NASIPAddress, \
+ NASPortId, \
+ NASPortType, \
+ AcctStartTime, \
+ AcctStopTime, \
+ AcctSessionTime, \
+ AcctAuthentic, \
+ ConnectInfo_start, \
+ ConnectInfo_stop, \
+ AcctInputOctets, \
+ AcctOutputOctets, \
+ CalledStationId, \
+ CallingStationId, \
+ AcctTerminateCause, \
+ ServiceType, \
+ FramedProtocol, \
+ FramedIPAddress, \
+ FramedIPv6Address, \
+ FramedIPv6Prefix, \
+ FramedInterfaceId, \
+ DelegatedIPv6Prefix, \
+ AcctStartDelay, \
+ AcctStopDelay, \
+ Class) \
+ VALUES(\
+ '', \
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{&NAS-Port-ID || &NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ ${...event_timestamp}, \
+ NULL, \
+ '0', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '0', \
+ '0', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '%{Acct-Delay-Time}', \
+ '0', \
+ '%{Class}')"
- interim-update {
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- FramedIPAddress = NULLIF('%{Framed-IP-Address}', ''), \
- FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', ''), \
- FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', ''), \
- FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
- DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', ''), \
- AcctSessionTime = '%{Acct-Session-Time}', \
- AcctInputOctets = %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
- AcctOutputOctets = %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
- Class = '%{Class}' \
- WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
- AND AcctStopTime IS NULL"
+ query = "\
+ UPDATE ${...acct_table1} \
+ SET \
+ AcctStartTime = ${...event_timestamp}, \
+ AcctStartDelay = '%{&Acct-Delay-Time || 0}', \
+ ConnectInfo_start = '%{Connect-Info}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
+ AND AcctStopTime IS NULL"
+ }
- query = "\
- INSERT into ${....acct_table1} (\
- RadAcctId, \
- AcctSessionId, \
- AcctUniqueId, \
- UserName, \
- Realm, \
- NASIPAddress, \
- NASPortId, \
- NASPortType, \
- AcctStartTime, \
- AcctSessionTime, \
- AcctAuthentic, \
- ConnectInfo_start, \
- AcctInputOctets, \
- AcctOutputOctets, \
- CalledStationId, \
- CallingStationId, \
- ServiceType, \
- FramedProtocol, \
- FramedIPAddress, \
- AcctStartDelay, \
- Class) \
- VALUES(\
- '', \
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{&NAS-Port-ID || &NAS-Port}', \
- '%{NAS-Port-Type}', \
- NULL, \
- '%{Acct-Session-Time}', \
- '%{Acct-Authentic}', \
- '', \
- '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}', \
- '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '0', \
- '%{Class}')"
- }
+ interim-update {
+ query = "\
+ UPDATE ${...acct_table1} \
+ SET \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', ''), \
+ FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', ''), \
+ FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', ''), \
+ FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
+ DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', ''), \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
+ AcctOutputOctets = %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
+ Class = '%{Class}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
+ AND AcctStopTime IS NULL"
- stop {
- query = "\
- UPDATE ${....acct_table2} \
- SET \
- AcctStopTime = ${....event_timestamp}, \
- AcctSessionTime = '%{Acct-Session-Time}', \
- AcctInputOctets = '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}', \
- AcctOutputOctets = '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}', \
- AcctTerminateCause = '%{Acct-Terminate-Cause}', \
- AcctStopDelay = '%{&Acct-Delay-Time || 0}', \
- ConnectInfo_stop = '%{Connect-Info}', \
- Class = '%{Class}' \
- WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
- AND AcctStopTime IS NULL"
+ query = "\
+ INSERT into ${...acct_table1} (\
+ RadAcctId, \
+ AcctSessionId, \
+ AcctUniqueId, \
+ UserName, \
+ Realm, \
+ NASIPAddress, \
+ NASPortId, \
+ NASPortType, \
+ AcctStartTime, \
+ AcctSessionTime, \
+ AcctAuthentic, \
+ ConnectInfo_start, \
+ AcctInputOctets, \
+ AcctOutputOctets, \
+ CalledStationId, \
+ CallingStationId, \
+ ServiceType, \
+ FramedProtocol, \
+ FramedIPAddress, \
+ AcctStartDelay, \
+ Class) \
+ VALUES(\
+ '', \
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{&NAS-Port-ID || &NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ NULL, \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}', \
+ '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '0', \
+ '%{Class}')"
+ }
- query = "\
- INSERT into ${....acct_table2} (\
- RadAcctId, \
- AcctSessionId, \
- AcctUniqueId, \
- UserName, \
- Realm, \
- NASIPAddress, \
- NASPortId, \
- NASPortType, \
- AcctStartTime, \
- AcctStopTime, \
- AcctSessionTime, \
- AcctAuthentic, \
- ConnectInfo_start, \
- ConnectInfo_stop, \
- AcctInputOctets, \
- AcctOutputOctets, \
- CalledStationId, \
- CallingStationId, \
- AcctTerminateCause, \
- ServiceType, \
- FramedProtocol, \
- FramedIPAddress, \
- AcctStartDelay, \
- AcctStopDelay, \
- Class) \
- VALUES(\
- '', \
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{&NAS-Port-ID || &NAS-Port}', \
- '%{NAS-Port-Type}', \
- NULL, \
- ${....event_timestamp}, \
- '%{Acct-Session-Time}', \
- '%{Acct-Authentic}', \
- '', \
- '%{Connect-Info}', \
- NULL, \
- '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}', \
- '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Acct-Terminate-Cause}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '0', \
- '%{&Acct-Delay-Time || 0}', \
- '%{Class}')"
- }
+ stop {
+ query = "\
+ UPDATE ${...acct_table2} \
+ SET \
+ AcctStopTime = ${...event_timestamp}, \
+ AcctSessionTime = '%{Acct-Session-Time}', \
+ AcctInputOctets = '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}', \
+ AcctOutputOctets = '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}', \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ AcctStopDelay = '%{&Acct-Delay-Time || 0}', \
+ ConnectInfo_stop = '%{Connect-Info}', \
+ Class = '%{Class}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-ID}' \
+ AND AcctStopTime IS NULL"
- #
- # No Acct-Status-Type == ignore the packet
- #
- accounting {
- query = "SELECT 1 from dual"
- }
+ query = "\
+ INSERT into ${...acct_table2} (\
+ RadAcctId, \
+ AcctSessionId, \
+ AcctUniqueId, \
+ UserName, \
+ Realm, \
+ NASIPAddress, \
+ NASPortId, \
+ NASPortType, \
+ AcctStartTime, \
+ AcctStopTime, \
+ AcctSessionTime, \
+ AcctAuthentic, \
+ ConnectInfo_start, \
+ ConnectInfo_stop, \
+ AcctInputOctets, \
+ AcctOutputOctets, \
+ CalledStationId, \
+ CallingStationId, \
+ AcctTerminateCause, \
+ ServiceType, \
+ FramedProtocol, \
+ FramedIPAddress, \
+ AcctStartDelay, \
+ AcctStopDelay, \
+ Class) \
+ VALUES(\
+ '', \
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{&NAS-Port-ID || &NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ NULL, \
+ ${...event_timestamp}, \
+ '%{Acct-Session-Time}', \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Connect-Info}', \
+ NULL, \
+ '%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}', \
+ '%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '0', \
+ '%{&Acct-Delay-Time || 0}', \
+ '%{Class}')"
}
}
#######################################################################
# Authentication Logging Queries
#######################################################################
-# postauth_query - Insert some info after authentication
+# send queries - Insert some info after authentication
#######################################################################
-post-auth {
+send {
# Write SQL queries to a logfile. This is potentially useful for bulk inserts
# when used with the rlm_sql_null driver.
# logfile = ${logdir}/post-auth.sql
- query = "\
- INSERT INTO ${..postauth_table} \
- (username, pass, reply, authdate, class) \
- VALUES (\
- '%{User-Name}', \
- '%{&User-Password || &Chap-Password}', \
- '%{reply.Packet-Type}', \
- TO_TIMESTAMP('%S.%M','YYYY-MM-DDHH24:MI:SS.FF'), \
- '%{reply.Class}')"
+
+ access-accept {
+ query = "\
+ INSERT INTO ${...postauth_table} \
+ (username, pass, reply, authdate, class) \
+ VALUES (\
+ '%{User-Name}', \
+ '%{&User-Password || &Chap-Password}', \
+ '%{reply.Packet-Type}', \
+ TO_TIMESTAMP('%S.%M','YYYY-MM-DDHH24:MI:SS.FF'), \
+ '%{reply.Class}')"
+ }
+
+ access-reject {
+ query = "${..access-accept.query}"
+ }
}
# Accounting and Post-Auth Queries
#######################################################################
# These queries insert/update accounting and authentication records.
-# The query to use is determined by the value of 'reference'.
-# This value is used as a configuration path and should resolve to one
-# or more 'query's. If reference points to multiple queries, and a query
-# fails, the next query is executed.
+# The query to use is determined by the name of the section the module
+# is called from.
#
-# Behaviour is identical to the old 1.x/2.x module, except we can now
-# fail between N queries, and query selection can be based on any
-# combination of attributes, or custom 'Acct-Status-Type' values.
+# e.g. when called from `accouting Start`, the contents of
+#
+# accounting {
+# start {}
+# }
+#
+# will be read, and any "query" entries will be run in sequence
+# until one returns a positive number of modified rows.
#######################################################################
accounting {
- reference = "%tolower(type.%{&Acct-Status-Type || 'none'}.query)"
-
# Write SQL queries to a logfile. This is potentially useful for bulk inserts
# when used with the rlm_sql_null driver.
# logfile = ${logdir}/accounting.sql
DelegatedIpv6Prefix, \
Class"
- type {
- accounting-on {
-
- #
- # "Bulk update" Accounting-On/Off strategy.
- #
- # Immediately terminate all sessions associated with a
- # given NAS.
- #
- # Note: If a large number of sessions require closing
- # then the bulk update may be take a long time to run
- # and lock an excessive number of rows. See the
- # strategy below for an alternative approach that does
- # not touch the radacct session data.
- #
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- AcctStopTime = ${....event_timestamp}, \
- AcctUpdateTime = ${....event_timestamp}, \
- AcctSessionTime = (${....event_timestamp_epoch} - EXTRACT(EPOCH FROM(AcctStartTime))), \
- AcctTerminateCause = '%{&Acct-Terminate-Cause || \'NAS-Reboot\'}', \
- Class = '%{Class}' \
- WHERE AcctStopTime IS NULL \
- AND NASIPAddress= '%{&NAS-IPv6-Address || &NAS-IP-Address}' \
- AND AcctStartTime <= ${....event_timestamp}"
-
- #
- # "Lightweight" Accounting-On/Off strategy.
- #
- # Record the reload time of the NAS and let the
- # administrator actually close the sessions in radacct
- # out-of-band, if desired.
- #
- # Implementation advice, together with a stored
- # procedure for closing sessions and a view showing
- # the effective stop time of each session is provided
- # in process-radacct.sql.
- #
- # To enable this strategy, just change the previous
- # query to "-query", and this one to "query". The
- # previous one will be ignored, and this one will be
- # enabled.
- #
- -query = "\
- INSERT INTO nasreload (NASIPAddress, ReloadTime) \
- VALUES ('%{NAS-IP-Address}', ${....event_timestamp}) \
- ON CONFLICT ON (NASIPAddress) \
- DO UPDATE SET \
- ReloadTime = ${....event_timestamp}"
-
- # If there are no open user sessions, then the previous query
- # will return "no rows updated". The server will then fall through
- # to the next query, which is just "yes, that's fine".
- #
- query = "SELECT true"
-
- }
-
- accounting-off {
- query = "${..accounting-on.query}"
-
- query = "SELECT true"
- }
-
- start {
- query = "\
- INSERT INTO ${....acct_table1} \
- (${...column_list}) \
- VALUES(\
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- NULLIF('%{Realm}', ''), \
- '%{&NAS-IPv6-Address || &NAS-IP-Address}', \
- NULLIF('%{&NAS-Port-ID || &NAS-Port}', ''), \
- '%{NAS-Port-Type}', \
- ${....event_timestamp}, \
- ${....event_timestamp}, \
- NULL, \
- 0, \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- NULL, \
- 0, \
- 0, \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- NULL, \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- NULLIF('%{Framed-IP-Address}', '')::inet, \
- NULLIF('%{Framed-IPv6-Address}', '')::inet, \
- NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
- NULLIF('%{Framed-Interface-Id}', ''), \
- NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
- '%{Class}') \
- ON CONFLICT (AcctUniqueId) \
- DO UPDATE \
- SET \
- AcctStartTime = ${....event_timestamp}, \
- AcctUpdateTime = ${....event_timestamp}, \
- ConnectInfo_start = '%{Connect-Info}', \
- Class = '%{Class}' \
- WHERE ${....acct_table1}.AcctUniqueId = '%{Acct-Unique-Session-Id}' \
- AND ${....acct_table1}.AcctStopTime IS NULL"
-
- # and again where we don't have "AND AcctStopTime IS NULL"
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- AcctStartTime = ${....event_timestamp}, \
- AcctUpdateTime = ${....event_timestamp}, \
- ConnectInfo_start = '%{Connect-Info}', \
- Class = '%{Class}' \
- WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
- }
-
- interim-update {
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
- FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', '')::inet, \
- FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
- FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
- DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
- AcctSessionTime = %{&Acct-Session-Time || \'NULL\'}, \
- AcctInterval = (${....event_timestamp_epoch} - EXTRACT(EPOCH FROM (COALESCE(AcctUpdateTime, AcctStartTime)))), \
- AcctUpdateTime = ${....event_timestamp}, \
- AcctInputOctets = %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
- AcctOutputOctets = %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
- Class = '%{Class}' \
- WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}' \
- AND AcctStopTime IS NULL"
-
- query = "\
- INSERT INTO ${....acct_table1} \
- (${...column_list}) \
- VALUES(\
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- NULLIF('%{Realm}', ''), \
- '%{&NAS-IPv6-Address || &NAS-IP-Address}', \
- NULLIF('%{&NAS-Port-ID || &NAS-Port}', ''), \
- '%{NAS-Port-Type}', \
- ${....event_timestamp}, \
- ${....event_timestamp}, \
- NULL, \
- %{&Acct-Session-Time || \'NULL\'}, \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- NULL, \
- (%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets})::bigint, \
- (%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets})::bigint, \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- NULL, \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- NULLIF('%{Framed-IP-Address}', '')::inet, \
- NULLIF('%{Framed-IPv6-Address}', '')::inet, \
- NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
- NULLIF('%{Framed-Interface-Id}', ''), \
- NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
- '%{Class}') \
- ON CONFLICT (AcctUniqueId) \
- DO NOTHING"
- }
-
- stop {
- query = "\
- UPDATE ${....acct_table2} \
- SET \
- AcctStopTime = ${....event_timestamp}, \
- AcctUpdateTime = ${....event_timestamp}, \
- AcctSessionTime = COALESCE(%{&Acct-Session-Time || \'NULL\'}, \
- (${....event_timestamp_epoch} - EXTRACT(EPOCH FROM(AcctStartTime)))), \
- AcctInputOctets = %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
- AcctOutputOctets = %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
- AcctTerminateCause = '%{Acct-Terminate-Cause}', \
- FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
- FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', '')::inet, \
- FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
- FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
- DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
- ConnectInfo_stop = '%{Connect-Info}', \
- Class = '%{Class}' \
- WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}' \
- AND AcctStopTime IS NULL"
-
- query = "\
- INSERT INTO ${....acct_table1} \
- (${...column_list}) \
- VALUES(\
- '%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- NULLIF('%{Realm}', ''), \
- '%{&NAS-IPv6-Address || &NAS-IP-Address}', \
- NULLIF('%{&NAS-Port-ID || &NAS-Port}', ''), \
- '%{NAS-Port-Type}', \
- TO_TIMESTAMP(${....event_timestamp_epoch} - %{&Acct-Session-Time || 0}), \
- ${....event_timestamp}, \
- ${....event_timestamp}, \
- NULLIF('%{Acct-Session-Time}', '')::bigint, \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- NULL, \
- (%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets})::bigint, \
- (%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets})::bigint, \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Acct-Terminate-Cause}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- NULLIF('%{Framed-IP-Address}', '')::inet, \
- NULLIF('%{Framed-IPv6-Address}', '')::inet, \
- NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
- NULLIF('%{Framed-Interface-Id}', ''), \
- NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
- '%{Class}') \
- ON CONFLICT (AcctUniqueId) \
- DO NOTHING"
-
- # and again where we don't have "AND AcctStopTime IS NULL"
- query = "\
- UPDATE ${....acct_table2} \
- SET \
- AcctStopTime = ${....event_timestamp}, \
- AcctUpdateTime = ${....event_timestamp}, \
- AcctSessionTime = COALESCE(%{&Acct-Session-Time || \'NULL\'}, \
- (${....event_timestamp_epoch} - EXTRACT(EPOCH FROM(AcctStartTime)))), \
- AcctInputOctets = (%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets})::bigint, \
- AcctOutputOctets = (%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets})::bigint, \
- AcctTerminateCause = '%{Acct-Terminate-Cause}', \
- FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
- FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', '')::inet, \
- FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
- FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
- DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
- ConnectInfo_stop = '%{Connect-Info}', \
- Class = '%{Class}' \
- WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
- }
+ accounting-on {
#
- # No Acct-Status-Type == ignore the packet
+ # "Bulk update" Accounting-On/Off strategy.
+ #
+ # Immediately terminate all sessions associated with a
+ # given NAS.
+ #
+ # Note: If a large number of sessions require closing
+ # then the bulk update may be take a long time to run
+ # and lock an excessive number of rows. See the
+ # strategy below for an alternative approach that does
+ # not touch the radacct session data.
+ #
+ query = "\
+ UPDATE ${...acct_table1} \
+ SET \
+ AcctStopTime = ${...event_timestamp}, \
+ AcctUpdateTime = ${...event_timestamp}, \
+ AcctSessionTime = (${...event_timestamp_epoch} - EXTRACT(EPOCH FROM(AcctStartTime))), \
+ AcctTerminateCause = '%{&Acct-Terminate-Cause || \'NAS-Reboot\'}', \
+ Class = '%{Class}' \
+ WHERE AcctStopTime IS NULL \
+ AND NASIPAddress= '%{&NAS-IPv6-Address || &NAS-IP-Address}' \
+ AND AcctStartTime <= ${...event_timestamp}"
+
#
- none {
- query = "SELECT true"
- }
+ # "Lightweight" Accounting-On/Off strategy.
+ #
+ # Record the reload time of the NAS and let the
+ # administrator actually close the sessions in radacct
+ # out-of-band, if desired.
+ #
+ # Implementation advice, together with a stored
+ # procedure for closing sessions and a view showing
+ # the effective stop time of each session is provided
+ # in process-radacct.sql.
+ #
+ # To enable this strategy, just change the previous
+ # query to "-query", and this one to "query". The
+ # previous one will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ INSERT INTO nasreload (NASIPAddress, ReloadTime) \
+ VALUES ('%{NAS-IP-Address}', ${...event_timestamp}) \
+ ON CONFLICT ON (NASIPAddress) \
+ DO UPDATE SET \
+ ReloadTime = ${...event_timestamp}"
+
+ # If there are no open user sessions, then the previous query
+ # will return "no rows updated". The server will then fall through
+ # to the next query, which is just "yes, that's fine".
+ #
+ query = "SELECT true"
+
+ }
+
+ accounting-off {
+ query = "${..accounting-on.query}"
+
+ query = "SELECT true"
+ }
+
+ start {
+ query = "\
+ INSERT INTO ${...acct_table1} \
+ (${..column_list}) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ NULLIF('%{Realm}', ''), \
+ '%{&NAS-IPv6-Address || &NAS-IP-Address}', \
+ NULLIF('%{&NAS-Port-ID || &NAS-Port}', ''), \
+ '%{NAS-Port-Type}', \
+ ${...event_timestamp}, \
+ ${...event_timestamp}, \
+ NULL, \
+ 0, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ NULL, \
+ 0, \
+ 0, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ NULL, \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ NULLIF('%{Framed-IP-Address}', '')::inet, \
+ NULLIF('%{Framed-IPv6-Address}', '')::inet, \
+ NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
+ NULLIF('%{Framed-Interface-Id}', ''), \
+ NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
+ '%{Class}') \
+ ON CONFLICT (AcctUniqueId) \
+ DO UPDATE \
+ SET \
+ AcctStartTime = ${...event_timestamp}, \
+ AcctUpdateTime = ${...event_timestamp}, \
+ ConnectInfo_start = '%{Connect-Info}', \
+ Class = '%{Class}' \
+ WHERE ${...acct_table1}.AcctUniqueId = '%{Acct-Unique-Session-Id}' \
+ AND ${...acct_table1}.AcctStopTime IS NULL"
+
+ # and again where we don't have "AND AcctStopTime IS NULL"
+ query = "\
+ UPDATE ${...acct_table1} \
+ SET \
+ AcctStartTime = ${...event_timestamp}, \
+ AcctUpdateTime = ${...event_timestamp}, \
+ ConnectInfo_start = '%{Connect-Info}', \
+ Class = '%{Class}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
+ }
+
+ interim-update {
+ query = "\
+ UPDATE ${...acct_table1} \
+ SET \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
+ FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', '')::inet, \
+ FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
+ FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
+ DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
+ AcctSessionTime = %{&Acct-Session-Time || 'NULL'}, \
+ AcctInterval = (${...event_timestamp_epoch} - EXTRACT(EPOCH FROM (COALESCE(AcctUpdateTime, AcctStartTime)))), \
+ AcctUpdateTime = ${...event_timestamp}, \
+ AcctInputOctets = %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
+ AcctOutputOctets = %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
+ Class = '%{Class}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}' \
+ AND AcctStopTime IS NULL"
+
+ query = "\
+ INSERT INTO ${...acct_table1} \
+ (${..column_list}) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ NULLIF('%{Realm}', ''), \
+ '%{&NAS-IPv6-Address || &NAS-IP-Address}', \
+ NULLIF('%{&NAS-Port-ID || &NAS-Port}', ''), \
+ '%{NAS-Port-Type}', \
+ ${...event_timestamp}, \
+ ${...event_timestamp}, \
+ NULL, \
+ %{&Acct-Session-Time || 'NULL'}, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ NULL, \
+ (%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets})::bigint, \
+ (%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets})::bigint, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ NULL, \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ NULLIF('%{Framed-IP-Address}', '')::inet, \
+ NULLIF('%{Framed-IPv6-Address}', '')::inet, \
+ NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
+ NULLIF('%{Framed-Interface-Id}', ''), \
+ NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
+ '%{Class}') \
+ ON CONFLICT (AcctUniqueId) \
+ DO NOTHING"
+ }
+
+ stop {
+ query = "\
+ UPDATE ${...acct_table2} \
+ SET \
+ AcctStopTime = ${...event_timestamp}, \
+ AcctUpdateTime = ${...event_timestamp}, \
+ AcctSessionTime = COALESCE(%{&Acct-Session-Time || 'NULL'}, \
+ (${...event_timestamp_epoch} - EXTRACT(EPOCH FROM(AcctStartTime)))), \
+ AcctInputOctets = %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
+ AcctOutputOctets = %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
+ FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', '')::inet, \
+ FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
+ FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
+ DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
+ ConnectInfo_stop = '%{Connect-Info}', \
+ Class = '%{Class}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}' \
+ AND AcctStopTime IS NULL"
+
+ query = "\
+ INSERT INTO ${...acct_table1} \
+ (${..column_list}) \
+ VALUES(\
+ '%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ NULLIF('%{Realm}', ''), \
+ '%{&NAS-IPv6-Address || &NAS-IP-Address}', \
+ NULLIF('%{&NAS-Port-ID || &NAS-Port}', ''), \
+ '%{NAS-Port-Type}', \
+ TO_TIMESTAMP(${...event_timestamp_epoch} - %{&Acct-Session-Time || 0}), \
+ ${...event_timestamp}, \
+ ${...event_timestamp}, \
+ NULLIF('%{Acct-Session-Time}', '')::bigint, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ NULL, \
+ (%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets})::bigint, \
+ (%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets})::bigint, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ NULLIF('%{Framed-IP-Address}', '')::inet, \
+ NULLIF('%{Framed-IPv6-Address}', '')::inet, \
+ NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
+ NULLIF('%{Framed-Interface-Id}', ''), \
+ NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
+ '%{Class}') \
+ ON CONFLICT (AcctUniqueId) \
+ DO NOTHING"
+
+ # and again where we don't have "AND AcctStopTime IS NULL"
+ query = "\
+ UPDATE ${...acct_table2} \
+ SET \
+ AcctStopTime = ${...event_timestamp}, \
+ AcctUpdateTime = ${...event_timestamp}, \
+ AcctSessionTime = COALESCE(%{&Acct-Session-Time || 'NULL'}, \
+ (${...event_timestamp_epoch} - EXTRACT(EPOCH FROM(AcctStartTime)))), \
+ AcctInputOctets = (%{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets})::bigint, \
+ AcctOutputOctets = (%{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets})::bigint, \
+ AcctTerminateCause = '%{Acct-Terminate-Cause}', \
+ FramedIPAddress = NULLIF('%{Framed-IP-Address}', '')::inet, \
+ FramedIPv6Address = NULLIF('%{Framed-IPv6-Address}', '')::inet, \
+ FramedIPv6Prefix = NULLIF('%{Framed-IPv6-Prefix}', '')::inet, \
+ FramedInterfaceId = NULLIF('%{Framed-Interface-Id}', ''), \
+ DelegatedIPv6Prefix = NULLIF('%{Delegated-IPv6-Prefix}', '')::inet, \
+ ConnectInfo_stop = '%{Connect-Info}', \
+ Class = '%{Class}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
}
}
#######################################################################
# Authentication Logging Queries
#######################################################################
-# postauth_query - Insert some info after authentication
+# send queries - Insert some info after authentication
#######################################################################
-post-auth {
+send {
# Write SQL queries to a logfile. This is potentially useful for bulk inserts
# when used with the rlm_sql_null driver.
# logfile = ${logdir}/post-auth.sql
- query = "\
- INSERT INTO ${..postauth_table} \
- (username, pass, reply, authdate, class) \
- VALUES(\
- '%{User-Name}', \
- '%{&User-Password || &Chap-Password}', \
- '%{reply.Packet-Type}', \
- '%S.%M', \
- '%{reply.Class}')"
+ access-accept {
+ query = "\
+ INSERT INTO ${...postauth_table} \
+ (username, pass, reply, authdate, class) \
+ VALUES(\
+ '%{User-Name}', \
+ '%{&User-Password || &Chap-Password}', \
+ '%{reply.Packet-Type}', \
+ '%S.%M', \
+ '%{reply.Class}')"
+ }
+
+ access-reject {
+ query = "${..access-accept.query}"
+ }
}
ORDER BY id"
#######################################################################
-# Accounting and Post-Auth Queries
+# Accounting and Send Queries
#######################################################################
# These queries insert/update accounting and authentication records.
-# The query to use is determined by the value of 'reference'.
-# This value is used as a configuration path and should resolve to one
-# or more 'query's. If reference points to multiple queries, and a query
-# fails, the next query is executed.
+# The query to use is determined by the name of the section the module
+# is called from.
#
-# Behaviour is identical to the old 1.x/2.x module, except we can now
-# fail between N queries, and query selection can be based on any
-# combination of attributes, or custom 'Acct-Status-Type' values.
+# e.g. when called from `accouting Start`, the contents of
+#
+# accounting {
+# start {}
+# }
+#
+# will be read, and any "query" entries will be run in sequence
+# until one returns a positive number of modified rows.
#######################################################################
accounting {
- reference = "%tolower(type.%{Acct-Status-Type}.query)"
-
# Write SQL queries to a logfile. This is potentially useful for bulk inserts
# when used with the rlm_sql_null driver.
# logfile = ${logdir}/accounting.sql
delegatedipv6prefix, \
class"
- type {
- accounting-on {
-
- #
- # "Bulk update" Accounting-On/Off strategy.
- #
- # Immediately terminate all sessions associated with a
- # given NAS.
- #
- # Note: If a large number of sessions require closing
- # then the bulk update may be take a long time to run
- # and lock an excessive number of rows. See the
- # strategy below for an alternative approach that does
- # not touch the radacct session data.
- #
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- acctstoptime = ${....event_timestamp}, \
- acctsessiontime = \
- (${....event_timestamp_epoch} \
- - acctstarttime), \
- acctterminatecause = '%{Acct-Terminate-Cause}', \
- class = '%{Class}' \
- WHERE acctstoptime IS NULL \
- AND nasipaddress = '%{NAS-IP-Address}' \
- AND acctstarttime <= ${....event_timestamp}"
-
- # "Lightweight" Accounting-On/Off strategy.
- #
- # Record the reload time of the NAS and let the
- # administrator actually close the sessions in radacct
- # out-of-band, if desired.
- #
- # Implementation advice, together with a stored
- # procedure for closing sessions and a view showing
- # the effective stop time of each session is provided
- # in process-radacct.sql.
- #
- # To enable this strategy, just change the previous
- # query to "-query", and this one to "query". The
- # previous one will be ignored, and this one will be
- # enabled.
- #
- -query = "\
- INSERT OR REPLACE INTO nasreload (nasipaddress, reloadtime) \
- VALUES ('%{NAS-IP-Address}', ${....event_timestamp})"
-
- #
- # If there are no open user sessions, then the previous query
- # will return "no rows updated". The server will then fall through
- # to the next query, which is just "yes, that's fine".
- #
- query = "SELECT true"
-
- }
-
- accounting-off {
- query = "${..accounting-on.query}"
-
- query = "SELECT true"
- }
-
- start {
- #
- # Insert a new record into the sessions table
- #
- query = "\
- INSERT INTO ${....acct_table1} \
- (${...column_list}) \
- VALUES \
- ('%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{&NAS-Port-ID || &NAS-Port}', \
- '%{NAS-Port-Type}', \
- ${....event_timestamp}, \
- ${....event_timestamp}, \
- NULL, \
- '0', \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- '', \
- '0', \
- '0', \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '%{Framed-IPv6-Address}', \
- '%{Framed-IPv6-Prefix}', \
- '%{Framed-Interface-Id}', \
- '%{Delegated-IPv6-Prefix}', \
- '%{Class}')"
-
- #
- # Key constraints prevented us from inserting a new session,
- # use the alternate query to update an existing session.
- #
- query = "\
- UPDATE ${....acct_table1} SET \
- acctstarttime = ${....event_timestamp}, \
- acctupdatetime = ${....event_timestamp}, \
- connectinfo_start = '%{Connect-Info}', \
- class = '%{Class}' \
- WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
- }
-
- interim-update {
- #
- # Update an existing session and calculate the interval
- # between the last data we received for the session and this
- # update. This can be used to find stale sessions.
- #
- query = "\
- UPDATE ${....acct_table1} \
- SET \
- acctupdatetime = ${....event_timestamp}, \
- acctinterval = 0, \
- framedipaddress = '%{Framed-IP-Address}', \
- framedipv6address = '%{Framed-IPv6-Address}', \
- framedipv6prefix = '%{Framed-IPv6-Prefix}', \
- framedinterfaceid = '%{Framed-Interface-Id}', \
- delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \
- acctsessiontime = %{&Acct-Session-Time || \'NULL\'}, \
- class = '%{Class}' \
- WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
-
- #
- # The update condition matched no existing sessions. Use
- # the values provided in the update to create a new session.
- #
- query = "\
- INSERT INTO ${....acct_table1} \
- (${...column_list}) \
- VALUES \
- ('%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{&NAS-Port-ID || &NAS-Port}', \
- '%{NAS-Port-Type}', \
- (${....event_timestamp_epoch} - %{&Acct-Session-Time || 0}), \
- ${....event_timestamp}, \
- NULL, \
- %{&Acct-Session-Time || \'NULL\'}, \
- '%{Acct-Authentic}', \
- '%{Connect-Info}', \
- '', \
- %{&Acct-Input-Gigawords || 0} << 32 | %{&Acct-Input-Octets || 0}, \
- %{&Acct-Output-Gigawords || 0} << 32 | %{&Acct-Output-Octets || 0}, \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '%{Framed-IPv6-Address}', \
- '%{Framed-IPv6-Prefix}', \
- '%{Framed-Interface-Id}', \
- '%{Delegated-IPv6-Prefix}', \
- '%{Class}')"
- }
-
- stop {
- #
- # Session has terminated, update the stop time and statistics.
- #
- query = "\
- UPDATE ${....acct_table2} SET \
- acctstoptime = ${....event_timestamp}, \
- acctsessiontime = %{&Acct-Session-Time || \'NULL\'}, \
- acctinputoctets = %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
- acctoutputoctets = %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
- acctterminatecause = '%{Acct-Terminate-Cause}', \
- connectinfo_stop = '%{Connect-Info}', \
- class = '%{Class}' \
- WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
-
- #
- # The update condition matched no existing sessions. Use
- # the values provided in the update to create a new session.
- #
- query = "\
- INSERT INTO ${....acct_table2} \
- (${...column_list}) \
- VALUES \
- ('%{Acct-Session-Id}', \
- '%{Acct-Unique-Session-Id}', \
- '%{SQL-User-Name}', \
- '%{Realm}', \
- '%{NAS-IP-Address}', \
- '%{&NAS-Port-ID || &NAS-Port}', \
- '%{NAS-Port-Type}', \
- (${....event_timestamp_epoch} - %{&Acct-Session-Time || 0}), \
- ${....event_timestamp}, \
- ${....event_timestamp}, \
- %{&Acct-Session-Time || \'NULL\'}, \
- '%{Acct-Authentic}', \
- '', \
- '%{Connect-Info}', \
- %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
- %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
- '%{Called-Station-Id}', \
- '%{Calling-Station-Id}', \
- '%{Acct-Terminate-Cause}', \
- '%{Service-Type}', \
- '%{Framed-Protocol}', \
- '%{Framed-IP-Address}', \
- '%{Framed-IPv6-Address}', \
- '%{Framed-IPv6-Prefix}', \
- '%{Framed-Interface-Id}', \
- '%{Delegated-IPv6-Prefix}', \
- '%{Class}')"
- }
+ accounting-on {
+
+ #
+ # "Bulk update" Accounting-On/Off strategy.
+ #
+ # Immediately terminate all sessions associated with a
+ # given NAS.
+ #
+ # Note: If a large number of sessions require closing
+ # then the bulk update may be take a long time to run
+ # and lock an excessive number of rows. See the
+ # strategy below for an alternative approach that does
+ # not touch the radacct session data.
+ #
+ query = "\
+ UPDATE ${...acct_table1} \
+ SET \
+ acctstoptime = ${...event_timestamp}, \
+ acctsessiontime = \
+ (${...event_timestamp_epoch} \
+ - acctstarttime), \
+ acctterminatecause = '%{Acct-Terminate-Cause}', \
+ class = '%{Class}' \
+ WHERE acctstoptime IS NULL \
+ AND nasipaddress = '%{NAS-IP-Address}' \
+ AND acctstarttime <= ${...event_timestamp}"
+
+ # "Lightweight" Accounting-On/Off strategy.
+ #
+ # Record the reload time of the NAS and let the
+ # administrator actually close the sessions in radacct
+ # out-of-band, if desired.
+ #
+ # Implementation advice, together with a stored
+ # procedure for closing sessions and a view showing
+ # the effective stop time of each session is provided
+ # in process-radacct.sql.
+ #
+ # To enable this strategy, just change the previous
+ # query to "-query", and this one to "query". The
+ # previous one will be ignored, and this one will be
+ # enabled.
+ #
+ -query = "\
+ INSERT OR REPLACE INTO nasreload (nasipaddress, reloadtime) \
+ VALUES ('%{NAS-IP-Address}', ${...event_timestamp})"
+
+ #
+ # If there are no open user sessions, then the previous query
+ # will return "no rows updated". The server will then fall through
+ # to the next query, which is just "yes, that's fine".
+ #
+ query = "SELECT true"
+
+ }
+
+ accounting-off {
+ query = "${..accounting-on.query}"
+
+ query = "SELECT true"
+ }
+
+ start {
+ #
+ # Insert a new record into the sessions table
+ #
+ query = "\
+ INSERT INTO ${...acct_table1} \
+ (${..column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{&NAS-Port-ID || &NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ ${...event_timestamp}, \
+ ${...event_timestamp}, \
+ NULL, \
+ '0', \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ '0', \
+ '0', \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '%{Class}')"
+
+ #
+ # Key constraints prevented us from inserting a new session,
+ # use the alternate query to update an existing session.
+ #
+ query = "\
+ UPDATE ${...acct_table1} SET \
+ acctstarttime = ${...event_timestamp}, \
+ acctupdatetime = ${...event_timestamp}, \
+ connectinfo_start = '%{Connect-Info}', \
+ class = '%{Class}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
+ }
+
+ interim-update {
+ #
+ # Update an existing session and calculate the interval
+ # between the last data we received for the session and this
+ # update. This can be used to find stale sessions.
+ #
+ query = "\
+ UPDATE ${...acct_table1} \
+ SET \
+ acctupdatetime = ${...event_timestamp}, \
+ acctinterval = 0, \
+ framedipaddress = '%{Framed-IP-Address}', \
+ framedipv6address = '%{Framed-IPv6-Address}', \
+ framedipv6prefix = '%{Framed-IPv6-Prefix}', \
+ framedinterfaceid = '%{Framed-Interface-Id}', \
+ delegatedipv6prefix = '%{Delegated-IPv6-Prefix}', \
+ acctsessiontime = %{&Acct-Session-Time || 'NULL'}, \
+ class = '%{Class}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
+
+ #
+ # The update condition matched no existing sessions. Use
+ # the values provided in the update to create a new session.
+ #
+ query = "\
+ INSERT INTO ${...acct_table1} \
+ (${..column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{&NAS-Port-ID || &NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ (${...event_timestamp_epoch} - %{&Acct-Session-Time || 0}), \
+ ${...event_timestamp}, \
+ NULL, \
+ %{&Acct-Session-Time || 'NULL'}, \
+ '%{Acct-Authentic}', \
+ '%{Connect-Info}', \
+ '', \
+ %{&Acct-Input-Gigawords || 0} << 32 | %{&Acct-Input-Octets || 0}, \
+ %{&Acct-Output-Gigawords || 0} << 32 | %{&Acct-Output-Octets || 0}, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '%{Class}')"
+ }
+
+ stop {
+ #
+ # Session has terminated, update the stop time and statistics.
+ #
+ query = "\
+ UPDATE ${...acct_table2} SET \
+ acctstoptime = ${...event_timestamp}, \
+ acctsessiontime = %{&Acct-Session-Time || 'NULL'}, \
+ acctinputoctets = %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
+ acctoutputoctets = %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
+ acctterminatecause = '%{Acct-Terminate-Cause}', \
+ connectinfo_stop = '%{Connect-Info}', \
+ class = '%{Class}' \
+ WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'"
+
+ #
+ # The update condition matched no existing sessions. Use
+ # the values provided in the update to create a new session.
+ #
+ query = "\
+ INSERT INTO ${...acct_table2} \
+ (${..column_list}) \
+ VALUES \
+ ('%{Acct-Session-Id}', \
+ '%{Acct-Unique-Session-Id}', \
+ '%{SQL-User-Name}', \
+ '%{Realm}', \
+ '%{NAS-IP-Address}', \
+ '%{&NAS-Port-ID || &NAS-Port}', \
+ '%{NAS-Port-Type}', \
+ (${...event_timestamp_epoch} - %{&Acct-Session-Time || 0}), \
+ ${...event_timestamp}, \
+ ${...event_timestamp}, \
+ %{&Acct-Session-Time || 'NULL'}, \
+ '%{Acct-Authentic}', \
+ '', \
+ '%{Connect-Info}', \
+ %{(((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets}, \
+ %{(((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets}, \
+ '%{Called-Station-Id}', \
+ '%{Calling-Station-Id}', \
+ '%{Acct-Terminate-Cause}', \
+ '%{Service-Type}', \
+ '%{Framed-Protocol}', \
+ '%{Framed-IP-Address}', \
+ '%{Framed-IPv6-Address}', \
+ '%{Framed-IPv6-Prefix}', \
+ '%{Framed-Interface-Id}', \
+ '%{Delegated-IPv6-Prefix}', \
+ '%{Class}')"
}
}
+
#######################################################################
# Authentication Logging Queries
#######################################################################
-# postauth_query - Insert some info after authentication
+# send queries - Insert some info after authentication
#######################################################################
-post-auth {
+send {
# Write SQL queries to a logfile. This is potentially useful for bulk inserts
# when used with the rlm_sql_null driver.
# logfile = ${logdir}/post-auth.sql
+ access-accept {
+
+ query = "UPDATE ${...postauth_table} SET username = '%{User-Name}' WHERE 1 = 0"
+
+ query = "\
+ INSERT INTO ${...postauth_table} \
+ (username, pass, reply, authdate, class) \
+ VALUES ( \
+ '%{SQL-User-Name}', \
+ '%{&User-Password || &Chap-Password}', \
+ '%{reply.Packet-Type}', \
+ '%S.%M', \
+ '%{reply.Class}')"
+ }
- query = "\
- INSERT INTO ${..postauth_table} \
- (username, pass, reply, authdate, class) \
- VALUES ( \
- '%{SQL-User-Name}', \
- '%{&User-Password || &Chap-Password}', \
- '%{reply.Packet-Type}', \
- '%S.%M', \
- '%{reply.Class}')"
+ access-reject {
+ query = "${..access-accept.query}"
+ }
}