diff options
Diffstat (limited to 'raddb/policy.d/accounting')
-rw-r--r-- | raddb/policy.d/accounting | 134 |
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 +} |