mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-10-29 01:22:25 +00:00
uspot: accounting: implement Accounting-On/Off
The RFC[1] says about Acct-Status-Type:
It MAY be used by the client to mark the start of accounting (for
example, upon booting) by specifying Accounting-On and to mark the
end of accounting (for example, just before a scheduled reboot) by
specifying Accounting-Off.
The RFC errata[2] further specifies that Accounting-On and
Accounting-Off messages apply to the whole NAS.
The RFC also mandates that[3]:
Either NAS-IP-Address or NAS-Identifier MUST be present in a
RADIUS Accounting-Request. It SHOULD contain a NAS-Port or NAS-
Port-Type attribute or both unless the service does not involve a
port or the NAS does not distinguish among its ports.
And[4]:
An Accounting-Request packet MUST have an Acct-Session-Id.
The Acct-Session-Id SHOULD contain UTF-8 encoded 10646 characters.
Finally the freeRADIUS recommendations here[5] suggest that:
1. Acct-Status-Type = Accounting-On should not be used to indicate
sub-system reboot.
2. IANA should allocate two new values for Acct-Status-Type:
Subsystem-On, and Subsystem-Off. These values have meaning similar
to Accounting-On and Accounting-Off, except that they apply to a
subystem of the NAS.
3. NASes should use these new values to indicate subsystem on/off.
4. The Called-Station-Id attribute should contain values unique to each
subsystem.
5. The NAS should signal that the entire system has rebooted by using
the existing Accounting-On and Accounting-Off values, with a value
for Called-Station-Id that is global to the NAS, or to omit it
entirely.
In order to reconcile all this, this commit implements Accounting-On and
Accounting-Off requests as follows:
- When accounting.uc is started, it loops through each uspot interface
and keeps track of the acct_server seen for each interface. Then for
each interface that do not use a previously seen server, it generates
a unique session ID, and sends an Accounting-On request to the
RADIUS server, using this session ID and the configured NAS-ID.
- When accounting.uc stops, it sends an Accounting-Off request for each
uspot interface for which an Accounting-On message was previously sent,
using the same global session ID.
If/when the Subsystem-On/Subsystem-Off values are implemented, this
commit can be revisited to simply lift the restriction on unique servers
and change the acct_type value accordingly.
Finally, it appears that while NAS-ID is provided in the request thus
making NAS-IP unnecessary, libradcli still includes this field in the
request. Likewise, it also insists on sending a NAS-Port attribute.
[1]: https://datatracker.ietf.org/doc/html/rfc2866#section-5.1
[2]: https://www.rfc-editor.org/errata_search.php?rfc=2866
[3]: https://datatracker.ietf.org/doc/html/rfc2866#section-4.1
[4]: https://datatracker.ietf.org/doc/html/rfc2866#section-5.5
[5]: https://freeradius.org/rfc/acct_status_type_subsystem.html
Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
This commit is contained in:
committed by
John Crispin
parent
a647368f15
commit
95a7b6d54d
@@ -231,6 +231,40 @@ function client_reset(interface, mac, reason) {
|
||||
client_kick(interface, mac, false);
|
||||
}
|
||||
|
||||
function radius_accton(interface)
|
||||
{
|
||||
// assign a global interface session ID for Accounting-On/Off messages
|
||||
let math = require('math');
|
||||
let sessionid = '';
|
||||
|
||||
for (let i = 0; i < 16; i++)
|
||||
sessionid += sprintf('%x', math.rand() % 16);
|
||||
|
||||
interfaces[interface].sessionid = sessionid;
|
||||
|
||||
const acct_type_accton = 7; // Accounting-On
|
||||
let payload = {
|
||||
acct_type: acct_type_accton,
|
||||
acct_session: sessionid,
|
||||
};
|
||||
payload = radius_init(interface, null, payload);
|
||||
payload.acct = true;
|
||||
radius_call(interface, null, payload);
|
||||
debug(interface, null, 'acct-on call');
|
||||
}
|
||||
|
||||
function radius_acctoff(interface)
|
||||
{
|
||||
const acct_type_acctoff = 8; // Accounting-Off
|
||||
let payload = {
|
||||
acct_type: acct_type_acctoff,
|
||||
acct_session: interfaces[interface].sessionid,
|
||||
};
|
||||
payload = radius_init(interface, null, payload);
|
||||
payload.acct = true;
|
||||
radius_call(interface, null, payload);
|
||||
debug(interface, null, 'acct-off call');
|
||||
}
|
||||
|
||||
function accounting(interface) {
|
||||
let list = ubus.call('spotfilter', 'client_list', { interface });
|
||||
@@ -277,8 +311,30 @@ function accounting(interface) {
|
||||
}
|
||||
}
|
||||
|
||||
function start()
|
||||
{
|
||||
let seen = {};
|
||||
|
||||
for (let interface, data in interfaces) {
|
||||
if (!data.settings.acct_server || (data.settings.acct_server in seen))
|
||||
continue; // avoid sending duplicate requests to the same server
|
||||
seen[data.settings.acct_server] = 1;
|
||||
radius_accton(interface);
|
||||
}
|
||||
}
|
||||
|
||||
function stop()
|
||||
{
|
||||
for (let interface, data in interfaces) {
|
||||
if (data.sessionid) // we have previously sent Accounting-On
|
||||
radius_acctoff(interface);
|
||||
}
|
||||
}
|
||||
|
||||
uloop.init();
|
||||
|
||||
start();
|
||||
|
||||
uloop.timer(10000, function() {
|
||||
for (let interface in interfaces)
|
||||
accounting(interface);
|
||||
@@ -286,3 +342,5 @@ uloop.timer(10000, function() {
|
||||
});
|
||||
|
||||
uloop.run();
|
||||
|
||||
stop();
|
||||
|
||||
Reference in New Issue
Block a user