mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-15 20:37:20 +00:00
captive: add missing UAM/ACCT/rate features
Fixes: WIFI-10665 Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
13
feeds/ucentral/uspot/files/etc/init.d/uspot
Executable file
13
feeds/ucentral/uspot/files/etc/init.d/uspot
Executable file
@@ -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
|
||||
}
|
||||
53
feeds/ucentral/uspot/files/usr/bin/captive
Executable file
53
feeds/ucentral/uspot/files/usr/bin/captive
Executable file
@@ -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;
|
||||
}
|
||||
211
feeds/ucentral/uspot/files/usr/share/uspot/accounting.uc
Executable file
211
feeds/ucentral/uspot/files/usr/share/uspot/accounting.uc
Executable file
@@ -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();
|
||||
@@ -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)
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
Status: 200 OK
|
||||
Status: 302 Found
|
||||
Location: http://{{env.SERVER_ADDR}}/hotspot/?redir={{env.headers.host}}
|
||||
Content-Type: text/html
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
<meta http-equiv="refresh" content="0; URL=http://{{env.SERVER_ADDR}}/hotspot/?redir={{env.headers.host}}" />
|
||||
</head>
|
||||
<body style="background-color: white">
|
||||
<a style="color: black; font-family: arial, helvetica, sans-serif;" href="http://{{env.SERVER_ADDR}}/hotspot">HotSpot Login</a>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -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 });
|
||||
};
|
||||
%}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
%}
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
|
||||
4
feeds/ucentral/uspot/files/usr/share/uspot/logoff.uc
Normal file
4
feeds/ucentral/uspot/files/usr/share/uspot/logoff.uc
Normal file
@@ -0,0 +1,4 @@
|
||||
Status: 200 OK
|
||||
Content-Type: text/html
|
||||
|
||||
<h1> You are now logged-off </h1>
|
||||
@@ -9,8 +9,10 @@
|
||||
#include <libubox/blobmsg_json.h>
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user