summaryrefslogtreecommitdiffstats
path: root/raddb/policy.d/accounting
blob: 7c52637d11dd04f6b229fd26bcbc923436fd2f74 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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
}