#  -*- text -*- $Id: 567a7bd8ccb271ff287a62383fdde51fbbd03e9f $

#######################################################################

#  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
#
#	NOTE: For compatibility with v3, the calculation of
#	Acct-Unique-Session-Id converts the input of the MD5
#	calculating to strings, and then converts the output
#	of the MD5 calculation to hex.  The result is that
#	the calculations done here will be the same as for
#	v3.
#
#	This change was necessary because in v4, the expansions
#	are binary safe.  i.e. expanding an IP address will not
#	result in the string `192.0.2.1`, but will instead be
#	represented internally as 32-bits of binary data `c0000201`.
#	The MD5 hash of those inputs will then be different.
#
#	We fix this issue by converting the MD5 inputs into printable
#	string form.
#
#	Similarly, the output of `%hash.md5(..)` is binary safe, and is
#	therefore a binary blob.  We therefore convert the output
#	of it to a printable string via `%hex(...)`
#
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 truly 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, Net.Src.IP 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).
	#
	if (Class =~ /${policy.class_value_prefix}([0-9a-f]{32})/i) {
		request.Acct-Unique-Session-Id := %hex(%hash.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 {
		request.Acct-Unique-Session-Id := %hex(%hash.md5("%{User-Name},%{Acct-Multi-Session-ID},%{Acct-Session-ID},%{NAS-IPv6-Address || NAS-IP-Address},%{NAS-Identifier},%{NAS-Port-ID},%{NAS-Port}"))
	}
}

#
#	Insert a (hopefully unique) value into class
#
insert_acct_class {
	reply.Class = '${policy.class_value_prefix}' + %hex(%hash.md5("%t%I%{Net.Src.Port}%{Net.Src.IP}%{NAS-IP-Address}%{Calling-Station-ID}%{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 {
	if (!Acct-Input-Gigawords) {
		request.Acct-Input-Octets64 := %{Acct-Input-Octets || 0}
	}
	else {
		request.Acct-Input-Octets64 =  (((uint64) Acct-Input-Gigawords) << 32) | (uint64) Acct-Input-Octets
	}
	if (!Acct-Output-Gigawords) {
		request.Acct-Output-Octets64 := %{Acct-Output-Octets || 0}
	}
	else {
		request.Acct-Output-Octets64 = (((uint64) Acct-Output-Gigawords) << 32) | (uint64) Acct-Output-Octets
	}
}

