]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Update main SQL queries to reflect new structure
authorNick Porter <nick@portercomputing.co.uk>
Wed, 17 Apr 2024 14:32:42 +0000 (15:32 +0100)
committerNick Porter <nick@portercomputing.co.uk>
Tue, 23 Apr 2024 09:47:07 +0000 (10:47 +0100)
Accounting queries go under

accounting {
  <accounting type> {
    query = "..."
  }
}

Post-Auth is now

send {
  <packet type> {
    query = "..."
  }
}

raddb/mods-config/sql/main/cassandra/queries.conf
raddb/mods-config/sql/main/mssql/queries.conf
raddb/mods-config/sql/main/mysql/queries.conf
raddb/mods-config/sql/main/oracle/queries.conf
raddb/mods-config/sql/main/postgresql/queries.conf
raddb/mods-config/sql/main/sqlite/queries.conf

index f1ecf277c9a3dae8ed33df9aee9a347674ed029b..810be8a0e85c292ae25f177593da8fdd68bc53f0 100644 (file)
@@ -108,9 +108,16 @@ authorize_group_reply_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 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
@@ -120,211 +127,207 @@ authorize_group_reply_query = "\
 # 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;"
        }
 }
 
@@ -332,21 +335,27 @@ accounting {
 #######################################################################
 # 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}"
+       }
 }
index 4e66e4a25fb6ffaf98bdd89833b2ffc97212ef54..c3d2badf265981408b89350192dcdb63a9b3ec16 100644 (file)
@@ -102,284 +102,290 @@ group_membership_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}"
+       }
 }
index 159eda9d5a068626f02648f860f38c5a3e8606a8..f366920ae4fb7256070e6bd2907901fe6ce69f17 100644 (file)
@@ -134,18 +134,19 @@ authorize_group_reply_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
@@ -161,231 +162,229 @@ accounting {
                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}')"
        }
 }
 
@@ -393,21 +392,27 @@ accounting {
 #######################################################################
 # 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}"
+       }
 }
index c894b29646a3cc14be8dbda4013a92f3bce18817..b9093847a03c2699ce2ca1b7eda756005a638c79 100644 (file)
@@ -109,284 +109,283 @@ group_membership_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}"
+       }
 }
index 9d616b2e84009e7d57b3bf20432afec172328e94..db0aec4f8f065ddff98e5d32620308abd448dce4 100644 (file)
@@ -157,19 +157,20 @@ group_membership_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
@@ -203,259 +204,250 @@ accounting {
                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}'"
        }
 }
 
@@ -463,21 +455,27 @@ accounting {
 #######################################################################
 # 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}"
+       }
 }
index 6f3b1ec21e0d886309fa6c943c59d5fce828cd5a..6d13cf0d9ab519e0b33aaf0a656c9cde35d6c198 100644 (file)
@@ -126,21 +126,22 @@ authorize_group_reply_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
@@ -174,247 +175,254 @@ accounting {
                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}"
+       }
 }