From cd2fbd11f29b30e187843c3c5134ccc03926eb09 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 20 Sep 2022 08:41:00 +0200 Subject: [PATCH] captive: add missing UAM/ACCT/rate features Fixes: WIFI-10665 Signed-off-by: John Crispin --- feeds/ucentral/spotfilter/src/client.c | 12 +- feeds/ucentral/spotfilter/src/client.h | 4 +- feeds/ucentral/spotfilter/src/interface.c | 6 - feeds/ucentral/spotfilter/src/interface.h | 5 + feeds/ucentral/spotfilter/src/nl80211.c | 8 +- .../ucentral/spotfilter/src/spotfilter-bpf.c | 10 +- .../ucentral/spotfilter/src/spotfilter-bpf.h | 2 + feeds/ucentral/spotfilter/src/ubus.c | 16 +- feeds/ucentral/uspot/Makefile | 2 +- feeds/ucentral/uspot/files/etc/config/uspot | 19 - feeds/ucentral/uspot/files/etc/init.d/uspot | 13 + feeds/ucentral/uspot/files/usr/bin/captive | 53 +++ .../uspot/files/usr/share/uspot/accounting.uc | 211 +++++++++ .../uspot/files/usr/share/uspot/common.uc | 118 ++++- .../uspot/files/usr/share/uspot/cpd.uc | 14 +- .../files/usr/share/uspot/handler-cpd.uc | 5 + .../files/usr/share/uspot/handler-uam.uc | 48 +- .../uspot/files/usr/share/uspot/handler.uc | 26 +- .../uspot/files/usr/share/uspot/logoff.uc | 4 + feeds/ucentral/uspot/src/radius.c | 435 +++++++----------- 20 files changed, 645 insertions(+), 366 deletions(-) create mode 100755 feeds/ucentral/uspot/files/etc/init.d/uspot create mode 100755 feeds/ucentral/uspot/files/usr/bin/captive create mode 100755 feeds/ucentral/uspot/files/usr/share/uspot/accounting.uc create mode 100644 feeds/ucentral/uspot/files/usr/share/uspot/logoff.uc diff --git a/feeds/ucentral/spotfilter/src/client.c b/feeds/ucentral/spotfilter/src/client.c index 005488e88..7c2b084d3 100644 --- a/feeds/ucentral/spotfilter/src/client.c +++ b/feeds/ucentral/spotfilter/src/client.c @@ -97,7 +97,8 @@ static void client_set_id(struct interface *iface, struct client *cl, const char } int client_set(struct interface *iface, const void *addr, const char *id, - int state, int dns_state, int accounting, struct blob_attr *data) + int state, int dns_state, int accounting, struct blob_attr *data, + const char *device, bool flush) { struct cache_entry *c; struct blob_attr *cur; @@ -142,12 +143,21 @@ int client_set(struct interface *iface, const void *addr, const char *id, kvlist_set(&cl->kvdata, blobmsg_name(cur), cur); } + if (device) + cl->device = device; if (state >= 0) cl->data.cur_class = state; if (dns_state >= 0) cl->data.dns_class = dns_state; if (accounting >= 0) cl->data.flags = accounting; + if (flush) { + kvlist_free(&cl->kvdata); + cl->data.packets_ul = 0; + cl->data.packets_dl = 0; + cl->data.bytes_ul = 0; + cl->data.bytes_dl = 0; + } spotfilter_bpf_set_client(iface, &cl->key, &cl->data); if (new_client) diff --git a/feeds/ucentral/spotfilter/src/client.h b/feeds/ucentral/spotfilter/src/client.h index 722ead082..0e45cf2d4 100644 --- a/feeds/ucentral/spotfilter/src/client.h +++ b/feeds/ucentral/spotfilter/src/client.h @@ -17,10 +17,12 @@ struct client { struct spotfilter_client_key key; struct spotfilter_client_data data; + const char *device; }; int client_set(struct interface *iface, const void *addr, const char *id, - int state, int dns_state, int accounting, struct blob_attr *data); + int state, int dns_state, int accounting, struct blob_attr *data, + const char *device, bool flush); void client_free(struct interface *iface, struct client *cl); void client_set_ipaddr(const void *mac, const void *addr, bool ipv6); void client_init_interface(struct interface *iface); diff --git a/feeds/ucentral/spotfilter/src/interface.c b/feeds/ucentral/spotfilter/src/interface.c index fed457131..f467f2a41 100644 --- a/feeds/ucentral/spotfilter/src/interface.c +++ b/feeds/ucentral/spotfilter/src/interface.c @@ -32,12 +32,6 @@ void interface_free(struct interface *iface) free(iface); } -static inline const char * -device_name(struct device *dev) -{ - return dev->node.avl.key; -} - static void interface_check_device(struct interface *iface, struct device *dev) { diff --git a/feeds/ucentral/spotfilter/src/interface.h b/feeds/ucentral/spotfilter/src/interface.h index 5f3b6cfa5..73e0e5ab8 100644 --- a/feeds/ucentral/spotfilter/src/interface.h +++ b/feeds/ucentral/spotfilter/src/interface.h @@ -64,6 +64,11 @@ static inline const char *interface_name(struct interface *iface) return iface->node.key; } +static inline const char *device_name(struct device *dev) +{ + return dev->node.avl.key; +} + void interface_add(const char *name, struct blob_attr *config, struct blob_attr *devices); void interface_free(struct interface *iface); diff --git a/feeds/ucentral/spotfilter/src/nl80211.c b/feeds/ucentral/spotfilter/src/nl80211.c index 2206b3be6..0ce416410 100644 --- a/feeds/ucentral/spotfilter/src/nl80211.c +++ b/feeds/ucentral/spotfilter/src/nl80211.c @@ -155,14 +155,12 @@ nl80211_interface_update(struct interface *iface) struct client *cl, *tmp; struct device *dev; - if (!iface->client_autoremove) - return; - avl_for_each_element_safe(&iface->clients, cl, node, tmp) { if (cl->idle++ < iface->client_timeout) continue; - client_free(iface, cl); + if (iface->client_autoremove) + client_free(iface, cl); } vlist_for_each_element(&iface->devices, dev, node) @@ -218,7 +216,7 @@ found: if (cl) cl->idle = 0; else if (iface->client_autocreate) - client_set(iface, addr, NULL, -1, -1, -1, NULL); + client_set(iface, addr, NULL, -1, -1, -1, NULL, device_name(dev), false); return NL_SKIP; } diff --git a/feeds/ucentral/spotfilter/src/spotfilter-bpf.c b/feeds/ucentral/spotfilter/src/spotfilter-bpf.c index 6b969551c..26b04919b 100644 --- a/feeds/ucentral/spotfilter/src/spotfilter-bpf.c +++ b/feeds/ucentral/spotfilter/src/spotfilter-bpf.c @@ -158,9 +158,9 @@ int spotfilter_out(struct __sk_buff *skb) return TC_ACT_UNSPEC; cl = bpf_map_lookup_elem(&client, eth->h_dest); - if (cl) { - if (cl->flags & SPOTFILTER_CLIENT_F_ACCT_DL) - cl->bytes_dl += skb->len; + if (cl && (cl->flags & SPOTFILTER_CLIENT_F_ACCT_DL)) { + cl->packets_dl++; + cl->bytes_dl += skb->len; } skb_parse_vlan(&info); @@ -204,8 +204,10 @@ int spotfilter_in(struct __sk_buff *skb) cl = bpf_map_lookup_elem(&client, eth->h_source); if (cl) { cldata = *cl; - if (cl->flags & SPOTFILTER_CLIENT_F_ACCT_UL) + if (cl->flags & SPOTFILTER_CLIENT_F_ACCT_UL) { + cl->packets_ul++; cl->bytes_ul += skb->len; + } } has_vlan = !!skb_parse_vlan(&info); diff --git a/feeds/ucentral/spotfilter/src/spotfilter-bpf.h b/feeds/ucentral/spotfilter/src/spotfilter-bpf.h index d9f4f08f3..94a4d162b 100644 --- a/feeds/ucentral/spotfilter/src/spotfilter-bpf.h +++ b/feeds/ucentral/spotfilter/src/spotfilter-bpf.h @@ -19,6 +19,8 @@ struct spotfilter_client_data { uint8_t dns_class; uint8_t flags; + uint64_t packets_ul; + uint64_t packets_dl; uint64_t bytes_ul; uint64_t bytes_dl; }; diff --git a/feeds/ucentral/spotfilter/src/ubus.c b/feeds/ucentral/spotfilter/src/ubus.c index 8083c589f..2c558ef32 100644 --- a/feeds/ucentral/spotfilter/src/ubus.c +++ b/feeds/ucentral/spotfilter/src/ubus.c @@ -88,6 +88,7 @@ enum { CLIENT_ATTR_DNS_STATE, CLIENT_ATTR_ACCOUNTING, CLIENT_ATTR_DATA, + CLIENT_ATTR_FLUSH, __CLIENT_ATTR_MAX }; @@ -99,6 +100,7 @@ static const struct blobmsg_policy client_policy[__CLIENT_ATTR_MAX] = { [CLIENT_ATTR_DNS_STATE] = { "dns_state", BLOBMSG_TYPE_INT32 }, [CLIENT_ATTR_ACCOUNTING] = { "accounting", BLOBMSG_TYPE_ARRAY }, [CLIENT_ATTR_DATA] = { "data", BLOBMSG_TYPE_TABLE }, + [CLIENT_ATTR_FLUSH] = { "flush", BLOBMSG_TYPE_BOOL }, }; static int @@ -176,6 +178,7 @@ client_ubus_update(struct ubus_context *ctx, struct ubus_object *obj, const char *id = NULL; int state = -1, dns_state = -1; int accounting = -1; + bool flush = false; int ret; ret = client_ubus_init(msg, tb, &iface, &addr, &id, &cl); @@ -203,8 +206,11 @@ client_ubus_update(struct ubus_context *ctx, struct ubus_object *obj, if (!addr) return UBUS_STATUS_INVALID_ARGUMENT; + if (tb[CLIENT_ATTR_FLUSH]) + flush = blobmsg_get_bool(tb[CLIENT_ATTR_FLUSH]); + client_set(iface, addr, id, state, dns_state, accounting, - tb[CLIENT_ATTR_DATA]); + tb[CLIENT_ATTR_DATA], NULL, flush); return 0; } @@ -241,8 +247,10 @@ static void client_dump(struct interface *iface, struct client *cl) spotfilter_bpf_get_client(iface, &cl->key, &cl->data); - if (iface->client_autoremove) - blobmsg_add_u32(&b, "idle", cl->idle); + if (cl->device) + blobmsg_add_string(&b, "device", cl->device); + + blobmsg_add_u32(&b, "idle", cl->idle); blobmsg_add_u32(&b, "state", cl->data.cur_class); blobmsg_add_u32(&b, "dns_state", cl->data.dns_class); @@ -281,6 +289,8 @@ static void client_dump(struct interface *iface, struct client *cl) interface_dump_action(&b, iface, cl->data.dns_class); blobmsg_close_table(&b, c); + blobmsg_add_u64(&b, "packets_ul", cl->data.packets_ul); + blobmsg_add_u64(&b, "packets_dl", cl->data.packets_dl); blobmsg_add_u64(&b, "bytes_ul", cl->data.bytes_ul); blobmsg_add_u64(&b, "bytes_dl", cl->data.bytes_dl); } diff --git a/feeds/ucentral/uspot/Makefile b/feeds/ucentral/uspot/Makefile index 9e0bac763..8e2761e2a 100644 --- a/feeds/ucentral/uspot/Makefile +++ b/feeds/ucentral/uspot/Makefile @@ -18,7 +18,7 @@ endef define Package/uspot/install $(INSTALL_DIR) $(1)/usr/bin/ $(1)/usr/lib/ucode - $(INSTALL_BIN) $(PKG_BUILD_DIR)/radius-client $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/radius-client $(1)/usr/bin/radius-client $(INSTALL_DATA) $(PKG_BUILD_DIR)/libuam.so $(1)/usr/lib/ucode/uam.so $(CP) ./files/* $(1) endef diff --git a/feeds/ucentral/uspot/files/etc/config/uspot b/feeds/ucentral/uspot/files/etc/config/uspot index 8cabbaef1..03734bab5 100644 --- a/feeds/ucentral/uspot/files/etc/config/uspot +++ b/feeds/ucentral/uspot/files/etc/config/uspot @@ -1,25 +1,6 @@ config uspot config - #option auth_mode 'uam' - #option auth_mode 'radius' - #option auth_mode 'credentials' - option auth_mode 'click-to-continue' config radius radius -# option auth_server 212.24.98.232 -# option auth_port 1812 -# option auth_secret secret config uam uam -# option port 3990 -# option nasid AlmondLabs -# option nasmac 903cb3bb25e3 -# option server https://customer.hotspotsystem.com/customer/hotspotlogin.php -# option secret hotsys123 -#config credential -# option username abc -# option password def - -#config credential -# option username 123 -# option password 456 diff --git a/feeds/ucentral/uspot/files/etc/init.d/uspot b/feeds/ucentral/uspot/files/etc/init.d/uspot new file mode 100755 index 000000000..fc321c0f7 --- /dev/null +++ b/feeds/ucentral/uspot/files/etc/init.d/uspot @@ -0,0 +1,13 @@ +#!/bin/sh /etc/rc.common + +START=80 + +USE_PROCD=1 +PROG=/usr/share/uspot/accounting.uc + +start_service() { + procd_open_instance + procd_set_param command "$PROG" + procd_set_param respawn + procd_close_instance +} diff --git a/feeds/ucentral/uspot/files/usr/bin/captive b/feeds/ucentral/uspot/files/usr/bin/captive new file mode 100755 index 000000000..bfedb5167 --- /dev/null +++ b/feeds/ucentral/uspot/files/usr/bin/captive @@ -0,0 +1,53 @@ +#!/usr/bin/ucode + +let ubus = require('ubus').connect(); +let uci = require('uci').cursor(); + +function restart() { + system('/etc/init.d/spotfilter restart'); + system('/etc/init.d/uhttpd restart'); +} + +switch(ARGV[0]) { +case 'dump': + let clients = ubus.call('spotfilter', 'client_list', { interface: 'hotspot'}); + printf('%.J\n', clients); + break; +case 'clients': + let clients = ubus.call('spotfilter', 'client_list', { interface: 'hotspot'}); + let res = {}; + let t = time(); + + for (let c, val in clients) { + res[c] = { + status: val.state ? 'Authenticated' : 'Garden', + idle: val.idle || 0, + time: val.data.connect ? t - val.data.connect : 0, + ip4addr: val.ip4addr || '', + ip6addr: val.ip6addr || '', + packets_ul: val.packets_ul || 0, + bytes_ul: val.bytes_ul || 0, + packets_dl: val.packets_dl || 0, + bytes_dl: val.bytes_dl || 0, + }; + } + printf('%.J\n', res); + break; +case 'remove': + ubus.call('spotfilter', 'client_remove', { interface: 'hotspot', address: ARGV[1] || ''}); + break; +case 'restart': + restart(); + break; +case 'log': + system('logread -f | grep uspot:'); + break; +case 'debugon': +case 'debugoff': + uci.set('uspot', 'config', 'debug', 1); + uci.commit(); + restart(); + break; +default: + break; +} diff --git a/feeds/ucentral/uspot/files/usr/share/uspot/accounting.uc b/feeds/ucentral/uspot/files/usr/share/uspot/accounting.uc new file mode 100755 index 000000000..cf1007c19 --- /dev/null +++ b/feeds/ucentral/uspot/files/usr/share/uspot/accounting.uc @@ -0,0 +1,211 @@ +#!/usr/bin/ucode + +'use strict'; + +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 acct_interval = config.radius?.acct_interval || 600; +let idle_timeout = config.config.idle_timeout || 600; +let session_timeout = config.config.session_timeout || 0; + +function syslog(mac, msg) { + let log = sprintf('uspot: %s %s', mac, msg); + + system('logger ' + log); + warn(log + '\n'); +} + +function debug(mac, msg) { + if (config.config.debug) + syslog(mac, msg); +} + +function get_idle_timeout(mac) { + if (clients[mac]) + return clients[mac].idle; + return idle_timeout; +} + +function get_session_timeout(mac) { + if (clients[mac]?.session_timeout) + return clients[mac].session_timeout; + return session_timeout; +} + +function radius_init(mac, payload) { + for (let key in [ 'server', 'acct_server', 'acct_session', 'client_ip', 'called_station', 'calling_station', 'nas_ip', 'nas_id', 'username' ]) + if (clients[mac].radius[key]) + payload[key] = clients[mac].radius[key]; + return payload; +} + +function radius_call(mac, payload) { + let cfg = fs.open('/tmp/acct' + mac + '.json', 'w'); + cfg.write(payload); + cfg.close(); + + system('/usr/bin/radius-client /tmp/acct' + mac + '.json'); +} + +function radius_stop(mac) { + debug(mac, 'stopping accounting'); + + let payload = { + acct: true, + acct_type: 8, + terminate_cause: 0, + }; + radius_init(mac, payload); + radius_call(mac, payload); +} + +function radius_acct(mac, payload) { + let state = ubus.call('spotfilter', 'client_get', { + interface: 'hotspot', + address: mac + }); + if (!state) { + return false; + } + + payload = radius_init(mac, payload); + payload.acct = true; + payload.session_time = time() - state.data.connect; + payload.output_octets = state.bytes_dl & 0xffffffff; + payload.input_octets = state.bytes_ul & 0xffffffff; + payload.output_gigawords = state.bytes_dl >> 32; + payload.input_gigawords = state.bytes_ul >> 32; + payload.output_packets = state.packets_dl; + payload.input_packets = state.packets_ul; + + radius_call(mac, payload); + return true; +} + +function radius_idle_time(mac) { + let payload = { + acct_type: 2, + terminate_cause: 4, + }; + radius_acct(mac, payload); +} + +function radius_session_time(mac) { + let payload = { + acct_type: 2, + terminate_cause: 5, + }; + radius_acct(mac, payload); +} + +function radius_disconnect(mac) { + let payload = { + acct_type: 2, + terminate_cause: 1, + }; + radius_acct(mac, payload); +} + +function radius_interim(mac) { + let payload = { + acct_type: 3, + }; + if (radius_acct(mac, payload)) + debug(mac, 'iterim acct call'); + else + syslog(mac, 'failed to sent interim accounting frame\n'); + clients[mac].timeout.set(clients[mac].interval); +} + +function client_add(mac, state) { + if (state.state != 1) + return; + + let interval = (state.data?.radius?.reply['Acct-Interim-Interval'] || acct_interval) * 1000; + let idle = (state.data?.radius?.reply['Idle-Timeout'] || idle_timeout); + let session = (state.data?.radius?.reply['Session-Timeout'] || session_timeout); + let accounting = (config.radius?.acct_server && config.radius?.acct_secret); + + clients[mac] = { + accounting, + radius: state.data.radius.request, + interval, + idle, + }; + syslog(mac, 'adding client'); + if (accounting) + clients[mac].timeout = uloop.timer(interval, () => radius_interim(mac)); +} + +function client_remove(mac, reason) { + syslog(mac, reason); + if (clients[mac]) { + radius_stop(mac); + if (clients[mac].accounting) + clients[mac].timeout.cancel(); + delete clients[mac]; + } + ubus.call('spotfilter', 'client_remove', { + interface: "hotspot", + address: mac + }); +} + +function client_timeout(mac) { + syslog(mac, 'session timeout'); + if (clients[mac]) { + radius_stop(mac); + if (clients[mac].accounting) + clients[mac].timeout.cancel(); + delete clients[mac]; + } + ubus.call('spotfilter', 'client_set', { + interface: "hotspot", + state: 0, + address: mac, + accounting: [], + flush: true, + }); +} + +uloop.init(); + +uloop.timer(1000, function() { + let list = ubus.call('spotfilter', 'client_list', { interface: 'hotspot'}); + let t = time(); + + for (let k, v in list) + if (!clients[k]) + client_add(k, v); + + for (let k, v in clients) + if (!list[k] || !list[k].state) { + radius_disconnect(k); + client_remove(k, 'disconnect event'); + } + + for (let k, v in list) { + if (v.idle > get_idle_timeout(k)) { + if (clients[k]) + radius_idle_time(k); + client_remove(k, 'idle event'); + + } + let timeout = get_session_timeout(k); + if (timeout && ((t - v.data.connect) > timeout)) { + if (clients[k]) + radius_session_time(k); + client_timeout(k); + + } + } + + this.set(5000); +}); + +uloop.run(); diff --git a/feeds/ucentral/uspot/files/usr/share/uspot/common.uc b/feeds/ucentral/uspot/files/usr/share/uspot/common.uc index f0893e97c..9b4c64dbd 100644 --- a/feeds/ucentral/uspot/files/usr/share/uspot/common.uc +++ b/feeds/ucentral/uspot/files/usr/share/uspot/common.uc @@ -26,6 +26,46 @@ return { header, footer, + // syslog helper + syslog: function(ctx, msg) { + warn('uspot: ' + ctx.env.REMOTE_ADDR + ' - ' + msg + '\n'); + }, + + debug: function(ctx, msg) { + if (config.config.debug) + this.syslog(ctx, msg); + }, + + // mac re-formater + format_mac: function(mac) { + switch(config.uam.mac_format) { + case 'aabbccddeeff': + case 'AABBCCDDEEFF': + mac = replace(mac, ':', ''); + break; + case 'aa-bb-cc-dd-ee-ff': + case 'AA-BB-CC-DD-EE-FF': + mac = replace(mac, ':', '-'); + warn('uspot: ' + ctx.env.REMOTE_ADDR + ' - ' + msg + '\n'); + break; + } + + switch(config.uam.mac_format) { + case 'aabbccddeeff': + case 'aa-bb-cc-dd-ee-ff': + case 'aa:bb:cc:dd:ee:ff': + mac = lc(mac); + break; + case 'AABBCCDDEEFF': + case 'AA:BB:CC:DD:EE:FF': + case 'AA-BB-CC-DD-EE-FF': + mac = uc(mac); + break; + } + + return mac; + }, + // wrapper for scraping external tools stdout fs_popen: function(cmd) { let stdout = fs.popen(cmd); @@ -43,45 +83,79 @@ return { }, // give a client access to the internet - allow_client: function(ctx) { + allow_client: function(ctx, data) { + this.syslog(ctx, 'allow client to pass traffic'); ctx.ubus.call('spotfilter', 'client_set', { "interface": "hotspot", - "address": replace(ctx.mac, '-', ':'), + "address": ctx.mac, "state": 1, "dns_state": 1, "accounting": [ "dl", "ul"], "data": { - "connect": time() + ... data || {}, + "connect": time(), } }); if (ctx.query_string.userurl) include('redir.uc', { redir_location: ctx.query_string.userurl }); else include('allow.uc', ctx); + //data.radius.reply['WISPr-Bandwidth-Max-Up'] = "20000000"; + //data.radius.reply['WISPr-Bandwidth-Max-Down'] = "10000000"; + if (data?.radius?.reply && (+data.radius.reply['WISPr-Bandwidth-Max-Up'] && +data.radius.reply['WISPr-Bandwidth-Max-Down'])) + ctx.ubus.call('ratelimit', 'client_set', { + device: ctx.device, + address: ctx.mac, + rate_egress: sprintf('%s', data.radius.reply['WISPr-Bandwidth-Max-Down']), + rate_ingress: sprintf('%s', data.radius.reply['WISPr-Bandwidth-Max-Up']), + }); + }, + + // put a client back into pre-auth state + logoff: function(ctx, data) { + this.syslog(ctx, 'logging client off'); + ctx.ubus.call('spotfilter', 'client_set', { + interface: 'hotspot', + address: ctx.mac, + state: 0, + dns_state: 1, + accounting: [], + flush: true, + }); + include('logoff.uc', ctx); }, // generate the default radius auth payload - radius_init: function(ctx) { + radius_init: function(ctx, acct_session) { + let math = require('math'); + if (!acct_session) { + acct_session = ''; + + for (let i = 0; i < 16; i++) + acct_session += sprintf('%d', math.rand() % 10); + } + return { server: sprintf('%s:%s:%s', this.config.radius.auth_server, this.config.radius.auth_port, this.config.radius.auth_secret), - acct_session: "0123456789", + acct_server: sprintf('%s:%s:%s', this.config.radius.acct_server, this.config.radius.acct_port, this.config.radius.acct_secret), + acct_session, client_ip: ctx.env.REMOTE_ADDR, - called_station: ctx.mac, - calling_station: this.config.uam.nasmac, + called_station: this.config.uam.nasmac, + calling_station: this.format_mac(ctx.mac), nas_ip: ctx.env.SERVER_ADDR, nas_id: this.config.uam.nasid }; }, radius_call: function(ctx, payload) { - let cfg = fs.open('/tmp/' + ctx.mac + '.json', 'w'); + let cfg = fs.open('/tmp/auth' + ctx.mac + '.json', 'w'); cfg.write(payload); cfg.close(); - return this.fs_popen('/usr/bin/radius-client /tmp/' + ctx.mac + '.json'); + return this.fs_popen('/usr/bin/radius-client /tmp/auth' + ctx.mac + '.json'); }, - handle_request: function(env) { + handle_request: function(env, uam) { let mac; let form_data = {}; let query_string = {}; @@ -91,25 +165,39 @@ return { // lookup the peers MAC let macs = this.rtnl.request(this.rtnl.const.RTM_GETNEIGH, this.rtnl.const.NLM_F_DUMP, { }); for (let m in macs) - if (m.dst == env.REMOTE_HOST) - ctx.mac = replace(m.lladdr, ':', '-'); + if (m.dst == env.REMOTE_HOST && m.lladdr) + ctx.mac = m.lladdr; // if the MAC lookup failed, go to the error page if (!ctx.mac) { + this.syslog(ctx, 'failed to look up mac'); include('error.uc', ctx); return NULL; } + ctx.format_mac = this.format_mac(ctx.mac); // check if a client is already connected ctx.ubus = ubus.connect(); let connected = ctx.ubus.call('spotfilter', 'client_get', { - 'interface': 'hotspot', - 'address': ctx.mac + interface: 'hotspot', + address: ctx.mac, }); - if (connected?.state) { + if (!uam && connected?.state) { include('connected.uc', ctx); return NULL; } + if (!connected.data.ssid) { + let hapd = ctx.ubus.call('hostapd.' + connected.device, 'get_status'); + ctx.ubus.call('spotfilter', 'client_set', { + interface: 'hotspot', + address: ctx.mac, + data: { + ssid: hapd.ssid || 'unknown' + } + }); + } + ctx.device = connected.device; + ctx.ssid = connected.data.ssid; // split QUERY_STRING if (env.QUERY_STRING) diff --git a/feeds/ucentral/uspot/files/usr/share/uspot/cpd.uc b/feeds/ucentral/uspot/files/usr/share/uspot/cpd.uc index 3326e91b1..160ef5d73 100644 --- a/feeds/ucentral/uspot/files/usr/share/uspot/cpd.uc +++ b/feeds/ucentral/uspot/files/usr/share/uspot/cpd.uc @@ -1,14 +1,4 @@ -Status: 200 OK +Status: 302 Found +Location: http://{{env.SERVER_ADDR}}/hotspot/?redir={{env.headers.host}} Content-Type: text/html - - - - - - - - -HotSpot Login - - diff --git a/feeds/ucentral/uspot/files/usr/share/uspot/handler-cpd.uc b/feeds/ucentral/uspot/files/usr/share/uspot/handler-cpd.uc index 81ba42c71..aa5e44cc7 100644 --- a/feeds/ucentral/uspot/files/usr/share/uspot/handler-cpd.uc +++ b/feeds/ucentral/uspot/files/usr/share/uspot/handler-cpd.uc @@ -2,7 +2,12 @@ 'use strict'; +let uci = require('uci').cursor(); +let config = uci.get_all('uspot'); + global.handle_request = function(env) { + if (env.REMOTE_ADDR && config.config.debug) + warn('uspot: ' + env.REMOTE_ADDR + ' - CPD redirect\n'); include('cpd.uc', { env }); }; %} diff --git a/feeds/ucentral/uspot/files/usr/share/uspot/handler-uam.uc b/feeds/ucentral/uspot/files/usr/share/uspot/handler-uam.uc index 1b4ad5ae8..9e533975c 100644 --- a/feeds/ucentral/uspot/files/usr/share/uspot/handler-uam.uc +++ b/feeds/ucentral/uspot/files/usr/share/uspot/handler-uam.uc @@ -12,10 +12,10 @@ function auth_client(ctx) { let password; let payload = portal.radius_init(ctx); + payload.logoff_url = sprintf('http://%s:3990/logoff', ctx.env.SERVER_ADDR); if (ctx.query_string.username && ctx.query_string.response) { - let challenge = uam.md5(portal.config.uam.challenge, ctx.mac); + let challenge = uam.md5(portal.config.uam.challenge, ctx.format_mac); - payload.type = 'uam-chap-auth'; payload.username = ctx.query_string.username; payload.chap_password = ctx.query_string.response; if (portal.config.uam.secret) @@ -23,24 +23,44 @@ function auth_client(ctx) { else payload.chap_challenge = challenge; } else if (ctx.query_string.username && ctx.query_string.password) { - payload.type = 'uam-auth'; - payload.username = ctx.mac; - payload.password = uam.password(uam.md5(portal.config.uam.challenge, ctx.mac), ctx.query_string.password, portal.config.uam.uam_secret); - } + payload.username = ctx.query_string.username; + payload.password = uam.password(uam.md5(portal.config.uam.challenge, ctx.format_mac), ctx.query_string.password, portal.config.uam.uam_secret); + } else + include('error.uc', ctx); - let reply = portal.radius_call(ctx, payload); - if (reply['access-accept']) { - portal.allow_client(ctx); - return; - } + let radius = portal.radius_call(ctx, payload); + if (radius['access-accept']) { + portal.allow_client(ctx, { radius: { reply: radius.reply, request: payload } } ); + + payload = portal.radius_init(ctx, payload.acct_session); + payload.acct = true; + payload.username = ctx.query_string.username; + payload.acct_type = 1; + portal.radius_call(ctx, payload); + return; + } include('error.uc', ctx); } -global.handle_request = function(env) { - let ctx = portal.handle_request(env); +// disconnect client +function deauth_client(ctx) { + portal.logoff(ctx); +} - if (ctx) +global.handle_request = function(env) { + let ctx = portal.handle_request(env, true); + + switch (split(ctx.env.REQUEST_URI, '?')[0] || '') { + case '/logon': auth_client(ctx); + break; + case '/logoff': + deauth_client(ctx); + break; + default: + include('error.uc', ctx); + break; + } }; %} diff --git a/feeds/ucentral/uspot/files/usr/share/uspot/handler.uc b/feeds/ucentral/uspot/files/usr/share/uspot/handler.uc index 5a7d444e5..a629b9aa4 100644 --- a/feeds/ucentral/uspot/files/usr/share/uspot/handler.uc +++ b/feeds/ucentral/uspot/files/usr/share/uspot/handler.uc @@ -7,6 +7,7 @@ let portal = require('common'); // delegate an initial connection to the correct handler function request_start(ctx) { + portal.debug(ctx, 'start ' + (portal.config?.config?.auth_mode || '') + ' flow'); switch (portal.config?.config?.auth_mode) { case 'click-to-continue': include('click.uc', ctx); @@ -22,12 +23,14 @@ function request_start(ctx) { '?res=notyet' + '&uamip=' + ctx.env.SERVER_ADDR + '&uamport=' + portal.config.uam.uam_port + - '&challenge=' + portal.uam.md5(portal.config.uam.challenge, ctx.mac) + - '&mac=' + replace(ctx.mac, ':', '-') + + '&challenge=' + portal.uam.md5(portal.config.uam.challenge, ctx.format_mac) + + '&mac=' + ctx.format_mac + '&ip=' + ctx.env.REMOTE_ADDR + '&called=' + portal.config.uam.nasmac + - '&nasid=' + portal.config.uam.nasid; - ctx.redir_location += '&md=' + portal.uam.md5(ctx.uam_location, portal.config.uam.uam_secret); + '&nasid=' + portal.config.uam.nasid + + '&ssid=' + ctx.ssid; + if (portal.config.uam.uam_secret) + ctx.redir_location += '&md=' + portal.uam.md5(ctx.redir_location, portal.config.uam.uam_secret); include('redir.uc', ctx); return; default: @@ -46,6 +49,7 @@ function request_click(ctx) { // check if a username and password was provided if (ctx.form_data.accept_terms != 'clicked') { + portal.debug(ctx, 'user did not accept conditions'); request_start({ ...ctx, error: 1 }); return; } @@ -62,6 +66,7 @@ function request_credentials(ctx) { // check if a username and password was provided if (!ctx.form_data.username || !ctx.form_data.password) { + portal.debug(ctx, 'missing credentials\n'); request_start({ ...ctx, error: 1 }); return; } @@ -76,11 +81,12 @@ function request_credentials(ctx) { ctx.form_data.password != cred.password) continue; - portal.allow_client(ctx); + portal.allow_client(ctx, { username: ctx.form_data.username }); return; } // auth failed + portal.debug(ctx, 'invalid credentials\n'); request_start({ ...ctx, error: 1 }); } @@ -94,23 +100,25 @@ function request_radius(ctx) { // check if a username and password was provided if (!ctx.form_data.username || !ctx.form_data.password) { + portal.debug(ctx, 'missing credentials\n'); request_start({ ...ctx, error: 1 }); return; } // trigger the radius auth - let payload = radius_init(ctx); + let payload = portal.radius_init(ctx); payload.type = 'auth'; payload.username = ctx.form_data.username; payload.password = ctx.form_data.password; - let reply = portal.radius_call(ctx, payload); - if (reply['access-accept']) { - portal.allow_client(ctx); + let radius = portal.radius_call(ctx, payload); + if (radius['access-accept']) { + portal.allow_client(ctx, { username: ctx.form_data.username, radius: { reply: radius.reply, request: payload } } ); return; } // auth failed + portal.debug(ctx, 'invalid credentials\n'); request_start({ ...ctx, error: 1 }); } diff --git a/feeds/ucentral/uspot/files/usr/share/uspot/logoff.uc b/feeds/ucentral/uspot/files/usr/share/uspot/logoff.uc new file mode 100644 index 000000000..302c936b6 --- /dev/null +++ b/feeds/ucentral/uspot/files/usr/share/uspot/logoff.uc @@ -0,0 +1,4 @@ +Status: 200 OK +Content-Type: text/html + +

You are now logged-off

diff --git a/feeds/ucentral/uspot/src/radius.c b/feeds/ucentral/uspot/src/radius.c index f11b98eee..d55fc31d6 100644 --- a/feeds/ucentral/uspot/src/radius.c +++ b/feeds/ucentral/uspot/src/radius.c @@ -9,8 +9,10 @@ #include enum { - RADIUS_TYPE, + RADIUS_ACCT, RADIUS_SERVER, + RADIUS_ACCT_SERVER, + RADIUS_ACCT_TYPE, RADIUS_USERNAME, RADIUS_PASSWORD, RADIUS_CHAP_PASSWORD, @@ -21,12 +23,23 @@ enum { RADIUS_CALLING_STATION, RADIUS_NAS_IP, RADIUS_NAS_ID, + RADIUS_TERMINATE_CAUSE, + RADIUS_SESSION_TIME, + RADIUS_INPUT_OCTETS, + RADIUS_OUTPUT_OCTETS, + RADIUS_INPUT_GIGAWORDS, + RADIUS_OUTPUT_GIGAWORDS, + RADIUS_INPUT_PACKETS, + RADIUS_OUTPUT_PACKETS, + RADIUS_LOGOFF_URL, __RADIUS_MAX, }; static const struct blobmsg_policy radius_policy[__RADIUS_MAX] = { - [RADIUS_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING }, + [RADIUS_ACCT] = { .name = "acct", .type = BLOBMSG_TYPE_BOOL }, [RADIUS_SERVER] = { .name = "server", .type = BLOBMSG_TYPE_STRING }, + [RADIUS_ACCT_SERVER] = { .name = "acct_server", .type = BLOBMSG_TYPE_STRING }, + [RADIUS_ACCT_TYPE] = { .name = "acct_type", .type = BLOBMSG_TYPE_INT32 }, [RADIUS_USERNAME] = { .name = "username", .type = BLOBMSG_TYPE_STRING }, [RADIUS_PASSWORD] = { .name = "password", .type = BLOBMSG_TYPE_STRING }, [RADIUS_CHAP_PASSWORD] = { .name = "chap_password", .type = BLOBMSG_TYPE_STRING }, @@ -37,23 +50,17 @@ static const struct blobmsg_policy radius_policy[__RADIUS_MAX] = { [RADIUS_CALLING_STATION] = { .name = "calling_station", .type = BLOBMSG_TYPE_STRING }, [RADIUS_NAS_IP] = { .name = "nas_ip", .type = BLOBMSG_TYPE_STRING }, [RADIUS_NAS_ID] = { .name = "nas_id", .type = BLOBMSG_TYPE_STRING }, + [RADIUS_TERMINATE_CAUSE] = { .name = "terminate_cause", .type = BLOBMSG_TYPE_INT32 }, + [RADIUS_SESSION_TIME] = { .name = "session_time", .type = BLOBMSG_TYPE_INT32 }, + [RADIUS_INPUT_OCTETS] = { .name = "input_octets", .type = BLOBMSG_TYPE_INT32 }, + [RADIUS_OUTPUT_OCTETS] = { .name = "output_octets", .type = BLOBMSG_TYPE_INT32 }, + [RADIUS_INPUT_GIGAWORDS] = { .name = "input_gigawords", .type = BLOBMSG_TYPE_INT32 }, + [RADIUS_OUTPUT_GIGAWORDS] = { .name = "output_gigawords", .type = BLOBMSG_TYPE_INT32 }, + [RADIUS_INPUT_PACKETS] = { .name = "input_packets", .type = BLOBMSG_TYPE_INT32 }, + [RADIUS_OUTPUT_PACKETS] = { .name = "output_packets", .type = BLOBMSG_TYPE_INT32 }, + [RADIUS_LOGOFF_URL] = { .name = "logoff_url", .type = BLOBMSG_TYPE_STRING }, }; -static struct config { - char *type; - char *server; - char *username; - char *password; - char chap_password[17]; - char chap_challenge[16]; - char *acct_session; - struct sockaddr_in client_ip; - char *called_station; - char *calling_station; - struct sockaddr_in nas_ip; - char *nas_id; -} config; - static struct blob_buf b = {}; static struct blob_attr *tb[__RADIUS_MAX] = {}; @@ -104,266 +111,158 @@ result(rc_handle const *rh, int accept, VALUE_PAIR *pair) return accept; } -static void -config_load(void) -{ - if (tb[RADIUS_TYPE]) - config.type = blobmsg_get_string(tb[RADIUS_TYPE]); - - if (tb[RADIUS_SERVER]) - config.server = blobmsg_get_string(tb[RADIUS_SERVER]); - - if (tb[RADIUS_USERNAME]) - config.username = blobmsg_get_string(tb[RADIUS_USERNAME]); - - if (tb[RADIUS_PASSWORD]) - config.password = blobmsg_get_string(tb[RADIUS_PASSWORD]); - - if (tb[RADIUS_CHAP_PASSWORD]) { - *config.chap_password = '\0'; - str_to_hex(blobmsg_get_string(tb[RADIUS_CHAP_PASSWORD]), &config.chap_password[1], 16); - } - - if (tb[RADIUS_CHAP_CHALLENGE]) - str_to_hex(blobmsg_get_string(tb[RADIUS_CHAP_CHALLENGE]), config.chap_challenge, 16); - - if (tb[RADIUS_ACCT_SESSION]) - config.acct_session = blobmsg_get_string(tb[RADIUS_ACCT_SESSION]); - - if (tb[RADIUS_CLIENT_IP]) { - inet_pton(AF_INET, blobmsg_get_string(tb[RADIUS_CLIENT_IP]), &(config.client_ip.sin_addr)); - config.client_ip.sin_addr.s_addr = ntohl(config.client_ip.sin_addr.s_addr); - } - - if (tb[RADIUS_CALLED_STATION]) - config.called_station = blobmsg_get_string(tb[RADIUS_CALLED_STATION]); - - if (tb[RADIUS_CALLING_STATION]) - config.calling_station = blobmsg_get_string(tb[RADIUS_CALLING_STATION]); - - if (tb[RADIUS_NAS_IP]) { - inet_pton(AF_INET, blobmsg_get_string(tb[RADIUS_NAS_IP]), &(config.nas_ip.sin_addr)); - config.nas_ip.sin_addr.s_addr = ntohl(config.nas_ip.sin_addr.s_addr); - } - - if (tb[RADIUS_NAS_ID]) - config.nas_id = blobmsg_get_string(tb[RADIUS_NAS_ID]); -} - -static rc_handle * -radius_init(void) +static int +radius(void) { + VALUE_PAIR *send = NULL, *received; + struct sockaddr_in client_ip = {}; + struct sockaddr_in nas_ip = {}; + char chap_challenge[16] = {}; + char chap_password[17] = {}; rc_handle *rh = rc_new(); + uint32_t val; + if (rh == NULL) - return NULL; + return result(rh, 0, NULL);; rh = rc_config_init(rh); if (rh == NULL) - return NULL; + return result(rh, 0, NULL);; - rc_add_config(rh, "authserver", config.server, "code", __LINE__); + if (tb[RADIUS_SERVER]) + rc_add_config(rh, "authserver", blobmsg_get_string(tb[RADIUS_SERVER]), "code", __LINE__); + + if (tb[RADIUS_ACCT_SERVER]) + rc_add_config(rh, "acctserver", blobmsg_get_string(tb[RADIUS_ACCT_SERVER]), "code", __LINE__); rc_add_config(rh, "servers", "/tmp/radius.servers", "code", __LINE__); rc_add_config(rh, "dictionary", "/etc/radcli/dictionary", "code", __LINE__); - rc_add_config(rh, "radius_timeout", "5", "code", __LINE__); + rc_add_config(rh, "radius_timeout", "2", "code", __LINE__); rc_add_config(rh, "radius_retries", "1", "code", __LINE__); rc_add_config(rh, "bindaddr", "*", "code", __LINE__); if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) - return NULL; - - return rh; -} - -static int -auth(void) -{ - VALUE_PAIR *send = NULL, *received; - rc_handle *rh = NULL; - - if (!config.server || !config.username || !config.password) - return result(NULL, 0, NULL); - - rh = radius_init(); - if (!rh) - return result(NULL, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_USER_NAME, config.username, -1, 0) == NULL) return result(rh, 0, NULL); - if (rc_avpair_add(rh, &send, PW_USER_PASSWORD, config.password, -1, 0) == NULL) + if (tb[RADIUS_ACCT_TYPE]) { + val = blobmsg_get_u32(tb[RADIUS_ACCT_TYPE]); + if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &val, 4, 0) == NULL) + return result(rh, 0, NULL); + } + + if (tb[RADIUS_USERNAME]) + if (rc_avpair_add(rh, &send, PW_USER_NAME, blobmsg_get_string(tb[RADIUS_USERNAME]), -1, 0) == NULL) + return result(rh, 0, NULL); + + if (tb[RADIUS_PASSWORD]) + if (rc_avpair_add(rh, &send, PW_USER_PASSWORD, blobmsg_get_string(tb[RADIUS_PASSWORD]), -1, 0) == NULL) + return result(rh, 0, NULL); + + if (tb[RADIUS_CHAP_PASSWORD]) { + str_to_hex(blobmsg_get_string(tb[RADIUS_CHAP_PASSWORD]), &chap_password[1], 16); + if (rc_avpair_add(rh, &send, PW_CHAP_PASSWORD, chap_password, 17, 0) == NULL) + return result(rh, 0, NULL); + } + + if (tb[RADIUS_CHAP_CHALLENGE]) { + str_to_hex(blobmsg_get_string(tb[RADIUS_CHAP_CHALLENGE]), chap_challenge, 16); + if (rc_avpair_add(rh, &send, PW_CHAP_CHALLENGE, chap_challenge, 16, 0) == NULL) + return result(rh, 0, NULL); + } + + if (tb[RADIUS_ACCT_SESSION]) + if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, blobmsg_get_string(tb[RADIUS_ACCT_SESSION]), -1, 0) == NULL) + return result(rh, 0, NULL); + + if (tb[RADIUS_CLIENT_IP]) { + inet_pton(AF_INET, blobmsg_get_string(tb[RADIUS_CLIENT_IP]), &(client_ip.sin_addr)); + client_ip.sin_addr.s_addr = ntohl(client_ip.sin_addr.s_addr); + if (rc_avpair_add(rh, &send, PW_FRAMED_IP_ADDRESS, &client_ip.sin_addr, 4, 0) == NULL) + return result(rh, 0, NULL); + } + + if (tb[RADIUS_CALLED_STATION]) + if (rc_avpair_add(rh, &send, PW_CALLED_STATION_ID, blobmsg_get_string(tb[RADIUS_CALLED_STATION]), -1, 0) == NULL) + return result(rh, 0, NULL); + + if (tb[RADIUS_LOGOFF_URL]) + if (rc_avpair_add(rh, &send, 3, blobmsg_get_string(tb[RADIUS_LOGOFF_URL]), -1, 14122) == NULL) + return result(rh, 0, NULL); + + if (tb[RADIUS_CALLING_STATION]) + if (rc_avpair_add(rh, &send, PW_CALLING_STATION_ID, blobmsg_get_string(tb[RADIUS_CALLING_STATION]), -1, 0) == NULL) + return result(rh, 0, NULL); + + if (tb[RADIUS_NAS_IP]) { + inet_pton(AF_INET, blobmsg_get_string(tb[RADIUS_NAS_IP]), &(nas_ip.sin_addr)); + nas_ip.sin_addr.s_addr = ntohl(nas_ip.sin_addr.s_addr); + if (rc_avpair_add(rh, &send, PW_NAS_IP_ADDRESS, &nas_ip.sin_addr, 4, 0) == NULL) + return result(rh, 0, NULL); + } + + if (tb[RADIUS_NAS_ID]) + if (rc_avpair_add(rh, &send, PW_NAS_IDENTIFIER, blobmsg_get_string(tb[RADIUS_NAS_ID]), -1, 0) == NULL) + return result(rh, 0, NULL); + + if (tb[RADIUS_TERMINATE_CAUSE]) { + val = blobmsg_get_u32(tb[RADIUS_TERMINATE_CAUSE]); + if (rc_avpair_add(rh, &send, PW_ACCT_TERMINATE_CAUSE, &val, 4, 0) == NULL) + return result(rh, 0, NULL); + } + + if (tb[RADIUS_SESSION_TIME]) { + val = blobmsg_get_u32(tb[RADIUS_SESSION_TIME]); + if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_TIME, &val, 4, 0) == NULL) + return result(rh, 0, NULL); + } + + if (tb[RADIUS_INPUT_OCTETS]) { + val = blobmsg_get_u32(tb[RADIUS_INPUT_OCTETS]); + if (rc_avpair_add(rh, &send, PW_ACCT_INPUT_OCTETS, &val, 4, 0) == NULL) + return result(rh, 0, NULL); + } + + if (tb[RADIUS_OUTPUT_OCTETS]) { + val = blobmsg_get_u32(tb[RADIUS_OUTPUT_OCTETS]); + if (rc_avpair_add(rh, &send, PW_ACCT_OUTPUT_OCTETS, &val, 4, 0) == NULL) + return result(rh, 0, NULL); + } + + if (tb[RADIUS_INPUT_GIGAWORDS]) { + val = blobmsg_get_u32(tb[RADIUS_INPUT_GIGAWORDS]); + if (rc_avpair_add(rh, &send, PW_ACCT_INPUT_GIGAWORDS, &val, 4, 0) == NULL) + return result(rh, 0, NULL); + } + + if (tb[RADIUS_OUTPUT_GIGAWORDS]) { + val = blobmsg_get_u32(tb[RADIUS_OUTPUT_GIGAWORDS]); + if (rc_avpair_add(rh, &send, PW_ACCT_OUTPUT_GIGAWORDS, &val, 4, 0) == NULL) + return result(rh, 0, NULL); + } + + if (tb[RADIUS_INPUT_PACKETS]) { + val = blobmsg_get_u32(tb[RADIUS_INPUT_PACKETS]); + if (rc_avpair_add(rh, &send, PW_ACCT_INPUT_PACKETS, &val, 4, 0) == NULL) + return result(rh, 0, NULL); + } + + if (tb[RADIUS_OUTPUT_PACKETS]) { + val = blobmsg_get_u32(tb[RADIUS_OUTPUT_PACKETS]); + if (rc_avpair_add(rh, &send, PW_ACCT_OUTPUT_PACKETS, &val, 4, 0) == NULL) + return result(rh, 0, NULL); + } + + val = 19; + if (rc_avpair_add(rh, &send, PW_NAS_PORT_TYPE, &val, 4, 0) == NULL) return result(rh, 0, NULL); rc_apply_config(rh); - if (rc_auth(rh, 0, send, &received, NULL) == OK_RC) - return result(rh, 1, received); - - return result(rh, 0, NULL); -} - -static int -uam_auth(void) -{ - VALUE_PAIR *send = NULL, *received; - rc_handle *rh = NULL; - - if (!config.server || !config.username || !config.password || - !config.acct_session || !config.called_station || - !config.calling_station || !config.nas_id) - return result(NULL, 0, NULL); - - rh = radius_init(); - if (!rh) - return result(NULL, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_USER_NAME, config.username, -1, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_USER_PASSWORD, config.password, -1, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, config.acct_session, -1, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_FRAMED_IP_ADDRESS, &config.client_ip.sin_addr, 4, 0) == NULL) - return result(rh, 0, NULL); - - //if (rc_avpair_add(rh, &send, PW_NAS_PORT_TYPE, , -1, 0) == NULL) - // return result(rh, 0, NULL); - - //if (rc_avpair_add(rh, &send, PW_NAS_PORT, , -1, 0) == NULL) - // return result(rh, 0, NULL); - -// if (rc_avpair_add(rh, &send, PW_NAS_PORT_ID_STRING, , -1, 0) == NULL) -// return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_CALLED_STATION_ID, config.called_station, -1, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_CALLING_STATION_ID, config.calling_station, -1, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_NAS_IP_ADDRESS, &config.nas_ip.sin_addr, 4, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_NAS_IDENTIFIER, config.nas_id, -1, 0) == NULL) - return result(rh, 0, NULL); - - rc_apply_config(rh); - if (rc_auth(rh, 0, send, &received, NULL) == OK_RC) - return result(rh, 1, received); - - return result(rh, 0, NULL); -} - -static int -uam_chap_auth(void) -{ - VALUE_PAIR *send = NULL, *received; - rc_handle *rh = NULL; - - if (!config.server || !config.username || - !config.acct_session || !config.called_station || - !config.calling_station || !config.nas_id) - return result(NULL, 0, NULL); - - rh = radius_init(); - if (!rh) - return result(NULL, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_USER_NAME, config.username, -1, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_CHAP_PASSWORD, config.chap_password, 17, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_CHAP_CHALLENGE, config.chap_challenge, 16, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, config.acct_session, -1, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_FRAMED_IP_ADDRESS, &config.client_ip.sin_addr, 4, 0) == NULL) - return result(rh, 0, NULL); - - //if (rc_avpair_add(rh, &send, PW_NAS_PORT_TYPE, , -1, 0) == NULL) - // return result(rh, 0, NULL); - - //if (rc_avpair_add(rh, &send, PW_NAS_PORT, , -1, 0) == NULL) - // return result(rh, 0, NULL); - -// if (rc_avpair_add(rh, &send, PW_NAS_PORT_ID_STRING, , -1, 0) == NULL) -// return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_CALLED_STATION_ID, config.called_station, -1, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_CALLING_STATION_ID, config.calling_station, -1, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_NAS_IP_ADDRESS, &config.nas_ip.sin_addr, 4, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_NAS_IDENTIFIER, config.nas_id, -1, 0) == NULL) - return result(rh, 0, NULL); - - rc_apply_config(rh); - if (rc_auth(rh, 0, send, &received, NULL) == OK_RC) - return result(rh, 1, received); - - return result(rh, 0, NULL); -} - -static int -uam_acct(void) -{ - VALUE_PAIR *send = NULL, *received; - rc_handle *rh = NULL; - - if (!config.server || !config.username || !config.password || - !config.acct_session || !config.called_station || - !config.calling_station || !config.nas_id) - return result(NULL, 0, NULL); - - rh = radius_init(); - if (!rh) - return result(NULL, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_USER_NAME, config.username, -1, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_USER_PASSWORD, config.password, -1, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, config.acct_session, -1, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_FRAMED_IP_ADDRESS, &config.client_ip.sin_addr, 4, 0) == NULL) - return result(rh, 0, NULL); - - //if (rc_avpair_add(rh, &send, PW_NAS_PORT_TYPE, , -1, 0) == NULL) - // return result(rh, 0, NULL); - - //if (rc_avpair_add(rh, &send, PW_NAS_PORT, , -1, 0) == NULL) - // return result(rh, 0, NULL); - -// if (rc_avpair_add(rh, &send, PW_NAS_PORT_ID_STRING, , -1, 0) == NULL) -// return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_CALLED_STATION_ID, config.called_station, -1, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_CALLING_STATION_ID, config.calling_station, -1, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_NAS_IP_ADDRESS, &config.nas_ip.sin_addr, 4, 0) == NULL) - return result(rh, 0, NULL); - - if (rc_avpair_add(rh, &send, PW_NAS_IDENTIFIER, config.nas_id, -1, 0) == NULL) - return result(rh, 0, NULL); - - rc_apply_config(rh); - if (rc_auth(rh, 0, send, &received, NULL) == OK_RC) - return result(rh, 1, received); + if (tb[RADIUS_ACCT] && blobmsg_get_bool(tb[RADIUS_ACCT])) { + if (rc_acct(rh, 0, send) == OK_RC) + return result(rh, 1, NULL); + } else { + if (rc_auth(rh, 0, send, &received, NULL) == OK_RC) + return result(rh, 1, received); + } return result(rh, 0, NULL); } @@ -380,21 +279,5 @@ main(int argc, char **argv) blobmsg_parse(radius_policy, __RADIUS_MAX, tb, blob_data(b.head), blob_len(b.head)); - config_load(); - if (!config.type) - return result(NULL, 0, NULL); - - if (!strcmp(config.type, "auth")) - return auth(); - - if (!strcmp(config.type, "uam-auth")) - return uam_auth(); - - if (!strcmp(config.type, "uam-chap-auth")) - return uam_chap_auth(); - - if (!strcmp(config.type, "uam-acct")) - return uam_acct(); - - return result(NULL, 0, NULL); + return radius(); }