From b5e33cec05ff54178f7eb7b522f3113588ab50bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= Date: Wed, 24 May 2023 18:26:02 +0200 Subject: [PATCH] uspot: accouting: save interface-wide settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before this commit, interface-wide settings (mainly radius) were stored per client, resulting in duplicate data. This commit runs a first pass that renames the "clients" global variable to "interfaces" which is expected to have the following content: interfaces { settings {}, clients {}, } Thus the settings are stored per interface now, and the list of clients belonging to that interface is stored within the object. This change enables us to also remove direct calls to uci configuration in the code and thus we no longer need to store it locally. Signed-off-by: Thibaut VARĂˆNE --- .../uspot/files/usr/share/uspot/accounting.uc | 98 +++++++++++-------- 1 file changed, 58 insertions(+), 40 deletions(-) diff --git a/feeds/ucentral/uspot/files/usr/share/uspot/accounting.uc b/feeds/ucentral/uspot/files/usr/share/uspot/accounting.uc index 028ef5744..d8bfa724c 100755 --- a/feeds/ucentral/uspot/files/usr/share/uspot/accounting.uc +++ b/feeds/ucentral/uspot/files/usr/share/uspot/accounting.uc @@ -6,21 +6,35 @@ let fs = require('fs'); let uloop = require('uloop'); let ubus = require('ubus').connect(); let uci = require('uci').cursor(); -let config = uci.get_all('uspot'); -let clients = {}; +let interfaces = {}; -if (!config) { +let uciload = uci.foreach('uspot', 'uspot', (d) => { + if (!d[".anonymous"]) { + let accounting = !!(d.acct_server && d.acct_secret); + interfaces[d[".name"]] = { + settings: { + accounting, + acct_server: d.acct_server, + acct_secret: d.acct_secret, + acct_port: d.acct_port || 1813, + acct_proxy: d.acct_proxy, + acct_interval: d.acct_interval, + idle_timeout: d.idle_timeout || 600, + session_timeout: d.session_timeout || 0, + debug: d.debug, + }, + clients: {}, + }; + } +}); + +if (!uciload) { let log = 'uspot: failed to load config'; system('logger ' + log); warn(log + '\n'); exit(1); } -uci.foreach('uspot', 'uspot', (d) => { - if (!d[".anonymous"]) - clients[d[".name"]] = {}; -}); - function syslog(interface, mac, msg) { let log = sprintf('uspot: %s %s %s', interface, mac, msg); @@ -29,17 +43,18 @@ function syslog(interface, mac, msg) { } function debug(interface, mac, msg) { - if (+config[interface].debug) + if (+interfaces[interface].settings.debug) syslog(interface, mac, msg); } function radius_init(interface, mac, payload) { + let client = interfaces[interface].clients[mac]; for (let key in [ 'server', 'acct_server', 'acct_session', 'client_ip', 'called_station', 'calling_station', 'nas_ip', 'nas_id', 'username', 'location_name' ]) - if (clients[interface][mac].radius[key]) - payload[key] = clients[interface][mac].radius[key]; + if (client.radius[key]) + payload[key] = client.radius[key]; - if (config[interface].acct_proxy) - payload.acct_proxy = config[interface].acct_proxy; + if (interfaces[interface].settings.acct_proxy) + payload.acct_proxy = interfaces[interface].settings.acct_proxy; return payload; } @@ -52,7 +67,7 @@ function radius_call(interface, mac, payload) { system('/usr/bin/radius-client ' + path); - if (!+config[interface].debug) + if (!+interfaces[interface].settings.debug) fs.unlink(path); } @@ -60,7 +75,7 @@ function radius_acct(interface, mac, payload) { let state = ubus.call('spotfilter', 'client_get', { interface, address: mac - }) || clients[interface][mac]; // fallback to last known state + }) || interfaces[interface].clients[mac]; // fallback to last known state if (!state) return; @@ -87,7 +102,7 @@ const radtc_sessionto = 5; // Session Timeout const radtc_adminreset = 6; // Admin Reset function radius_terminate(interface, mac, cause) { - if (!clients[interface][mac].radius) + if (!interfaces[interface].clients[mac].radius) return; const acct_type_stop = 2; @@ -109,11 +124,11 @@ function radius_interim(interface, mac) { } function client_interim(interface, mac, time) { - let client = clients[interface][mac]; - - if (!client.accounting) + if (!interfaces[interface].settings.accounting) return; + let client = interfaces[interface].clients[mac]; + // preserve a copy of last spotfilter stats for use in disconnect case let state = ubus.call('spotfilter', 'client_get', { interface, @@ -139,22 +154,23 @@ function client_add(interface, mac, state) { let defval = 0; - let accounting = !!(config[interface].acct_server && config[interface].acct_secret); + let settings = interfaces[interface].settings; + let accounting = settings.accounting; // RFC: NAS local interval value *must* override RADIUS attribute - defval = config[interface].acct_interval; + defval = settings.acct_interval; let interval = +(defval || state.data?.radius?.reply['Acct-Interim-Interval'] || 0); - defval = config[interface].session_timeout || 0; + defval = settings.session_timeout; let session = +(state.data?.radius?.reply['Session-Timeout'] || defval); - defval = config[interface].idle_timeout || 600; + defval = settings.idle_timeout; let idle = +(state.data?.radius?.reply['Idle-Timeout'] || defval); let max_total = +(state.data?.radius?.reply['ChilliSpot-Max-Total-Octets'] || 0); - clients[interface][mac] = { - accounting, + let clients = interfaces[interface].clients; + clients[mac] = { interval, session, idle, @@ -164,13 +180,13 @@ function client_add(interface, mac, state) { } }; if (state.ip4addr) - clients[interface][mac].ip4addr = state.ip4addr; + clients[mac].ip4addr = state.ip4addr; if (state.ip6addr) - clients[interface][mac].ip6addr = state.ip6addr; + clients[mac].ip6addr = state.ip6addr; if (state.data?.radius?.request) { - clients[interface][mac].radius = state.data.radius.request; + clients[mac].radius = state.data.radius.request; if (accounting && interval) - clients[interface][mac].next_interim = state.data.connect + interval; + clients[mac].next_interim = state.data.connect + interval; } syslog(interface, mac, 'adding client'); } @@ -190,12 +206,14 @@ function client_kick(interface, mac, remove) { ubus.call('spotfilter', remove ? 'client_remove' : 'client_set', payload); - if (clients[interface][mac].ip4addr) - system('conntrack -D -s ' + clients[interface][mac].ip4addr + ' -m 2'); - if (clients[interface][mac].ip6addr) - system('conntrack -D -s ' + clients[interface][mac].ip6addr + ' -m 2'); + let client = interfaces[interface].clients[mac]; - delete clients[interface][mac]; + if (client.ip4addr) + system('conntrack -D -s ' + client.ip4addr + ' -m 2'); + if (client.ip6addr) + system('conntrack -D -s ' + client.ip6addr + ' -m 2'); + + delete interfaces[interface].clients[mac]; } function client_remove(interface, mac, reason) { @@ -214,10 +232,10 @@ function accounting(interface) { let t = time(); for (let mac, payload in list) - if (!clients[interface][mac]) + if (!interfaces[interface].clients[mac]) client_add(interface, mac, payload); - for (let mac in clients[interface]) { + for (let mac, client in interfaces[interface].clients) { if (!list[mac] || !list[mac].state) { radius_terminate(interface, mac, radtc_lostcarrier); client_remove(interface, mac, 'disconnect event'); @@ -230,18 +248,18 @@ function accounting(interface) { continue; } - if (+list[mac].idle > +clients[interface][mac].idle) { + if (+list[mac].idle > +client.idle) { radius_terminate(interface, mac, radtc_idleto); client_reset(interface, mac, 'idle event'); continue; } - let timeout = +clients[interface][mac].session; + let timeout = +client.session; if (timeout && ((t - list[mac].data.connect) > timeout)) { radius_terminate(interface, mac, radtc_sessionto); client_reset(interface, mac, 'session timeout'); continue; } - let maxtotal = +clients[interface][mac].max_total; + let maxtotal = +client.max_total; if (maxtotal && ((list[mac].acct_data.bytes_ul + list[mac].acct_data.bytes_dl) >= maxtotal)) { radius_terminate(interface, mac, radtc_sessionto); client_reset(interface, mac, 'max octets reached'); @@ -255,7 +273,7 @@ function accounting(interface) { uloop.init(); uloop.timer(10000, function() { - for (let interface in clients) + for (let interface in interfaces) accounting(interface); this.set(10000); });