schema: add captive portal support

Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
John Crispin
2021-05-21 16:06:48 +02:00
parent 5406f01b11
commit f6027eb7e7
9 changed files with 153 additions and 158 deletions

View File

@@ -181,6 +181,9 @@ let ethernet = {
calculate_name: function(interface) {
let vid = interface.vlan ? interface.vlan.id : '';
if (interface.captive)
return 'captive';
return (interface.role == 'upstream' ? 'wan' : 'lan') + vid;
},

View File

@@ -59,6 +59,12 @@
}
}
// Captive Portal is only supported on downstream interfaces
if (interface.captive && interface.role != 'downstream') {
warn("Trying to create a Cpative Portal on a none downstream interface.");
return;
}
// Gather related BSS modes and ethernet ports.
let bss_modes = map(interface.ssids, ssid => ssid.bss_mode);
let eth_ports = ethernet.lookup_by_interface_spec(interface);
@@ -113,8 +119,11 @@
if (tunnel_proto == "mesh")
include("interface/mesh.uc", { name });
// All none L2/3 tunnel require a vlan inside their bridge
include("interface/bridge-vlan.uc", { interface, name, eth_ports, this_vid, bridgedev });
// All none L2/3 tunnel require a vlan inside their bridge (unless we run a captive portal)
if (interface.captive)
netdev = '';
else
include("interface/bridge-vlan.uc", { interface, name, eth_ports, this_vid, bridgedev });
include("interface/common.uc", {
name, this_vid, netdev,
@@ -147,4 +156,7 @@
count++;
}
}
if (interface.captive)
include('interface/captive.uc', { netdev });
%}

View File

@@ -0,0 +1,22 @@
# Captive Portal Configuration
add opennds opennds
set opennds.@opennds[-1].enabled='1'
set opennds.@opennds[-1].fwhook_enabled='1'
set opennds.@opennds[-1].debuglevel='1'
add_list opennds.@opennds[-1].users_to_router='allow tcp port 53'
add_list opennds.@opennds[-1].users_to_router='allow udp port 53'
add_list opennds.@opennds[-1].users_to_router='allow udp port 67'
add_list opennds.@opennds[-1].users_to_router='allow tcp port 22'
add_list opennds.@opennds[-1].users_to_router='allow tcp port 80'
add_list opennds.@opennds[-1].users_to_router='allow tcp port 443'
add_list opennds.@opennds[-1].authenticated_users='allow all'
set opennds.@opennds[-1].login_option_enabled='1'
set opennds.@opennds[-1].gatewayinterface='br-captive'
set opennds.@opennds[-1].gatewayname={{ s(interface.captive.gateway_name) }}
set opennds.@opennds[-1].maxclients='{{ interface.captive.max_clients }}'
set opennds.@opennds[-1].gatewayfqdn={{ s(interface.captive.gateway_fqdn) }}
set opennds.@opennds[-1].uploadrate='{{ interface.captive.upload_rate }}'
set opennds.@opennds[-1].downloadrate='{{ interface.captive.download_rate }}'
set opennds.@opennds[-1].uploadquota='{{ interface.captive.upload_quota }}'
set opennds.@opennds[-1].downloadquota='{{ interface.captive.download_quota }}'

View File

@@ -13,7 +13,7 @@ properties:
type: string
format: fqdn
default: ucentral.splash
maxclients:
max-clients:
description:
The maximum number of clients that shall be accept.
type: integer
@@ -22,19 +22,19 @@ properties:
description:
The maximum upload rate for a specific client.
type: integer
default: 10000
default: 0
download-rate:
description:
The maximum download rate for a specific client.
type: integer
default: 10000
default: 0
upload-quota:
description:
The maximum upload quota for a specific client.
type: integer
default : 10000
default : 0
download-quota:
description:
The maximum download quota for a specific client.
type: integer
default: 10000
default: 0

View File

@@ -1,40 +0,0 @@
description:
This section can be used to setup a captive portal on the AP.
type: object
properties:
gateway-name:
description:
This name will be presented to connecting users in on the splash page.
type: string
default: uCentral - Captive Portal
gateway-fqdn:
description:
The fqdn used for the captive portal IP.
type: string
format: fqdn
default: ucentral.splash
maxclients:
description:
The maximum number of clients that shall be accept.
type: integer
default: 32
upload-rate:
description:
The maximum upload rate for a specific client.
type: integer
default: 10000
download-rate:
description:
The maximum download rate for a specific client.
type: integer
default: 10000
upload-quota:
description:
The maximum upload quota for a specific client.
type: integer
default : 10000
download-quota:
description:
The maximum download quota for a specific client.
type: integer
default: 10000

View File

@@ -80,8 +80,6 @@ properties:
type: array
items:
$ref: "https://ucentral.io/schema/v1/interface/ssid/multi-psk/"
captive:
$ref: "https://ucentral.io/schema/v1/interface/ssid/captive/"
rrm:
$ref: "https://ucentral.io/schema/v1/interface/ssid/rrm/"
rates:

View File

@@ -53,6 +53,8 @@ properties:
$ref: "https://ucentral.io/schema/v1/interface/ipv4/"
ipv6:
$ref: "https://ucentral.io/schema/v1/interface/ipv6/"
captive:
$ref: "https://ucentral.io/schema/v1/interface/captive/"
ssids:
type: array
items:

View File

@@ -607,6 +607,71 @@ function instantiateInterfaceIpv6(value) {
return obj;
}
function instantiateInterfaceCaptive(value) {
assert(type(value) == "object", "Property interface.captive must be of type object");
let obj = {};
if (exists(value, "gateway-name")) {
assert(type(value["gateway-name"]) == "string", "Property interface.captive.gateway-name must be of type string");
obj.gateway_name = value["gateway-name"];
}
else {
obj.gateway_name = "uCentral - Captive Portal";
}
if (exists(value, "gateway-fqdn")) {
assert(type(value["gateway-fqdn"]) == "string", "Property interface.captive.gateway-fqdn must be of type string");
assert(matchFqdn(value["gateway-fqdn"]), "Property interface.captive.gateway-fqdn must match fqdn format");
obj.gateway_fqdn = value["gateway-fqdn"];
}
else {
obj.gateway_fqdn = "ucentral.splash";
}
if (exists(value, "max-clients")) {
assert(type(value["max-clients"]) == "int", "Property interface.captive.max-clients must be of type integer");
obj.max_clients = value["max-clients"];
}
else {
obj.max_clients = 32;
}
if (exists(value, "upload-rate")) {
assert(type(value["upload-rate"]) == "int", "Property interface.captive.upload-rate must be of type integer");
obj.upload_rate = value["upload-rate"];
}
else {
obj.upload_rate = 0;
}
if (exists(value, "download-rate")) {
assert(type(value["download-rate"]) == "int", "Property interface.captive.download-rate must be of type integer");
obj.download_rate = value["download-rate"];
}
else {
obj.download_rate = 0;
}
if (exists(value, "upload-quota")) {
assert(type(value["upload-quota"]) == "int", "Property interface.captive.upload-quota must be of type integer");
obj.upload_quota = value["upload-quota"];
}
else {
obj.upload_quota = 0;
}
if (exists(value, "download-quota")) {
assert(type(value["download-quota"]) == "int", "Property interface.captive.download-quota must be of type integer");
obj.download_quota = value["download-quota"];
}
else {
obj.download_quota = 0;
}
return obj;
}
function instantiateInterfaceSsidEncryption(value) {
assert(type(value) == "object", "Property interface.ssid.encryption must be of type object");
@@ -668,71 +733,6 @@ function instantiateInterfaceSsidMultiPsk(value) {
return obj;
}
function instantiateInterfaceSsidCaptive(value) {
assert(type(value) == "object", "Property interface.ssid.captive must be of type object");
let obj = {};
if (exists(value, "gateway-name")) {
assert(type(value["gateway-name"]) == "string", "Property interface.ssid.captive.gateway-name must be of type string");
obj.gateway_name = value["gateway-name"];
}
else {
obj.gateway_name = "uCentral - Captive Portal";
}
if (exists(value, "gateway-fqdn")) {
assert(type(value["gateway-fqdn"]) == "string", "Property interface.ssid.captive.gateway-fqdn must be of type string");
assert(matchFqdn(value["gateway-fqdn"]), "Property interface.ssid.captive.gateway-fqdn must match fqdn format");
obj.gateway_fqdn = value["gateway-fqdn"];
}
else {
obj.gateway_fqdn = "ucentral.splash";
}
if (exists(value, "maxclients")) {
assert(type(value["maxclients"]) == "int", "Property interface.ssid.captive.maxclients must be of type integer");
obj.maxclients = value["maxclients"];
}
else {
obj.maxclients = 32;
}
if (exists(value, "upload-rate")) {
assert(type(value["upload-rate"]) == "int", "Property interface.ssid.captive.upload-rate must be of type integer");
obj.upload_rate = value["upload-rate"];
}
else {
obj.upload_rate = 10000;
}
if (exists(value, "download-rate")) {
assert(type(value["download-rate"]) == "int", "Property interface.ssid.captive.download-rate must be of type integer");
obj.download_rate = value["download-rate"];
}
else {
obj.download_rate = 10000;
}
if (exists(value, "upload-quota")) {
assert(type(value["upload-quota"]) == "int", "Property interface.ssid.captive.upload-quota must be of type integer");
obj.upload_quota = value["upload-quota"];
}
else {
obj.upload_quota = 10000;
}
if (exists(value, "download-quota")) {
assert(type(value["download-quota"]) == "int", "Property interface.ssid.captive.download-quota must be of type integer");
obj.download_quota = value["download-quota"];
}
else {
obj.download_quota = 10000;
}
return obj;
}
function instantiateInterfaceSsidRrm(value) {
assert(type(value) == "object", "Property interface.ssid.rrm must be of type object");
@@ -1245,10 +1245,6 @@ function instantiateInterfaceSsid(value) {
obj.multi_psk = parseMultiPsk(value["multi-psk"]);
}
if (exists(value, "captive")) {
obj.captive = instantiateInterfaceSsidCaptive(value["captive"]);
}
if (exists(value, "rrm")) {
obj.rrm = instantiateInterfaceSsidRrm(value["rrm"]);
}
@@ -1461,6 +1457,10 @@ function instantiateInterface(value) {
obj.ipv6 = instantiateInterfaceIpv6(value["ipv6"]);
}
if (exists(value, "captive")) {
obj.captive = instantiateInterfaceCaptive(value["captive"]);
}
function parseSsids(value) {
assert(type(value) == "array", "Property interface.ssids must be of type array");
@@ -1821,7 +1821,6 @@ function instantiateMetricsStatistics(value) {
if (exists(value, "interval")) {
assert(type(value["interval"]) == "int", "Property metrics.statistics.interval must be of type integer");
assert(value["interval"] >= 60, "Property metrics.statistics.interval must be >= 60");
obj.interval = value["interval"];
}

View File

@@ -477,6 +477,40 @@
}
}
},
"interface.captive": {
"type": "object",
"properties": {
"gateway-name": {
"type": "string",
"default": "uCentral - Captive Portal"
},
"gateway-fqdn": {
"type": "string",
"format": "fqdn",
"default": "ucentral.splash"
},
"max-clients": {
"type": "integer",
"default": 32
},
"upload-rate": {
"type": "integer",
"default": 0
},
"download-rate": {
"type": "integer",
"default": 0
},
"upload-quota": {
"type": "integer",
"default": 0
},
"download-quota": {
"type": "integer",
"default": 0
}
}
},
"interface.ssid.encryption": {
"type": "object",
"properties": {
@@ -539,40 +573,6 @@
}
}
},
"interface.ssid.captive": {
"type": "object",
"properties": {
"gateway-name": {
"type": "string",
"default": "uCentral - Captive Portal"
},
"gateway-fqdn": {
"type": "string",
"format": "fqdn",
"default": "ucentral.splash"
},
"maxclients": {
"type": "integer",
"default": 32
},
"upload-rate": {
"type": "integer",
"default": 10000
},
"download-rate": {
"type": "integer",
"default": 10000
},
"upload-quota": {
"type": "integer",
"default": 10000
},
"download-quota": {
"type": "integer",
"default": 10000
}
}
},
"interface.ssid.rrm": {
"type": "object",
"properties": {
@@ -1008,9 +1008,6 @@
"$ref": "#/$defs/interface.ssid.multi-psk"
}
},
"captive": {
"$ref": "#/$defs/interface.ssid.captive"
},
"rrm": {
"$ref": "#/$defs/interface.ssid.rrm"
},
@@ -1167,6 +1164,9 @@
"ipv6": {
"$ref": "#/$defs/interface.ipv6"
},
"captive": {
"$ref": "#/$defs/interface.captive"
},
"ssids": {
"type": "array",
"items": {
@@ -1411,8 +1411,7 @@
"type": "object",
"properties": {
"interval": {
"type": "integer",
"minimum": 60
"type": "integer"
},
"types": {
"type": "array",