summaryrefslogtreecommitdiffstats
path: root/raddb/policy.d/accounting
diff options
context:
space:
mode:
Diffstat (limited to 'raddb/policy.d/accounting')
-rw-r--r--raddb/policy.d/accounting134
1 files changed, 134 insertions, 0 deletions
diff --git a/raddb/policy.d/accounting b/raddb/policy.d/accounting
new file mode 100644
index 0000000..7c52637
--- /dev/null
+++ b/raddb/policy.d/accounting
@@ -0,0 +1,134 @@
+# We check for this prefix to determine whether the class value was
+# generated by this server. It should be changed so that it is
+# globally unique.
+class_value_prefix = 'ai:'
+
+#
+# Replacement for the old rlm_acct_unique module
+#
+acct_unique {
+ #
+ # If we have a class attribute in the format
+ # 'auth_id:[0-9a-f]{32}' it'll have a local value
+ # (defined by insert_acct_class), this ensures
+ # uniqueness and suitability.
+ #
+ # We could just use the Class attribute as
+ # Acct-Unique-Session-Id, but this may cause problems
+ # with NAS that carry Class values across between
+ # multiple linked sessions. So we rehash class with
+ # Acct-Session-ID to provide a truely unique session
+ # identifier.
+ #
+ # Using a Class/Session-ID combination is more robust
+ # than using elements in the Accounting-Request,
+ # which may be subject to change, such as
+ # NAS-IP-Address, Client-IP-Address and
+ # NAS-Port-ID/NAS-Port.
+ #
+ # This policy should ensure that session data is not
+ # affected if NAS IP addresses change, or the client
+ # roams to a different 'port' whilst maintaining its
+ # initial authentication session (Common in a
+ # wireless environment).
+ #
+ update request {
+ &Tmp-String-9 := "${policy.class_value_prefix}"
+ }
+
+ if (("%{hex:&Class}" =~ /^%{hex:&Tmp-String-9}/) && \
+ ("%{string:&Class}" =~ /^${policy.class_value_prefix}([0-9a-f]{32})/i)) {
+ update request {
+ &Acct-Unique-Session-Id := "%{md5:%{1},%{Acct-Session-ID}}"
+ }
+ }
+
+ #
+ # Not All devices respect RFC 2865 when dealing with
+ # the class attribute, so be prepared to use the
+ # older style of hashing scheme if a class attribute
+ # is not included
+ #
+ else {
+ update request {
+ &Acct-Unique-Session-Id := "%{md5:%{User-Name},%{Acct-Session-ID},%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}},%{NAS-Identifier},%{NAS-Port-ID},%{NAS-Port}}"
+ }
+ }
+
+ update request {
+ &Tmp-String-9 !* ANY
+ }
+}
+
+#
+# Insert a (hopefully unique) value into class
+#
+insert_acct_class {
+ update reply {
+ &Class = "${policy.class_value_prefix}%{md5:%t,%{Packet-Src-Port},%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}},%{NAS-IP-Address},%{Calling-Station-ID},%{User-Name},%{session-state:User-Name} }"
+ }
+}
+
+#
+# Merges Acct-[Input|Output]-Octets and Acct-[Input|Output]-Gigawords into Acct-[Input|Output]-Octets64
+#
+# If the &Attr-Foo doesn't exist, it's value is taken as zero.
+#
+acct_counters64.preacct {
+ update request {
+ &Acct-Input-Octets64 = "%{expr:(&Acct-Input-Gigawords << 32) | &Acct-Input-Octets}"
+ &Acct-Output-Octets64 = "%{expr:(&Acct-Output-Gigawords << 32) | &Acct-Output-Octets}"
+ }
+}
+
+#
+# There is a delay between sending the Access-Accept and receiving
+# the corresponding Accounting-Request "start" packet. This delay
+# can be leveraged by a user to bypass Simultaneous-Use checks.
+#
+# The user can start up multiple sessions at the same time. When
+# that happens, both Simultaneous-Use checks are performed before any
+# Accounting-Request packet is received. Both Simultaneous-Use
+# checks will result in "no user session" in the radacct table, and
+# both sessions will be allowed. At some point later in time, the
+# Accounting-Request packets are received. But by then it's too
+# late.
+#
+# The solution is to insert a temporary session into the "radacct"
+# table, during the "post-auth" section. This is done by
+# uncommenting the "sql_session_start" entry in
+# sites-enabled/default. Then, reading
+# raddb/mods-config/sql/main/*/queries.conf, and looking for the
+# "sql_session_start" comments. Follow the instructions there to
+# finalize the configuration.
+#
+# The server will then create a temporary entry in "radacct" before
+# it returns the Access-Request. Any other Access-Request which is
+# received at the same time will then have it's Simultaneous-Use
+# check see that entry, and will be rejected.
+#
+# Subsequent Accounting-Request packets for the first session will
+# then UPDATE (not INSERT) the data for the session.
+#
+# There is still a small race condition as the Simultaneous-Use
+# checks are not done at the same time as updating radacct. But the
+# window of opportunity is much smaller. i.e. milliseconds, instead
+# of seconds.
+#
+# This policy can also be used to "bootstrap" accounting sessions.
+# If there is data which is only available in the Access-Request,
+# it can be placed in the accounting table. Then, when accounting
+# packets are received, they will update the row which contains
+# the session information.
+#
+sql_session_start.post-auth {
+ acct_unique
+
+ #
+ # The SQL accounting queries need an Acct-Status-Type attribute
+ #
+ update request {
+ Acct-Status-Type := Start
+ }
+ sql.accounting
+}