Files
wlan-cloud-userportal/src/ConfigMaker.cpp
2023-02-21 13:41:37 -08:00

384 lines
13 KiB
C++

//
// Created by stephane bourque on 2021-12-13.
//
#include "ConfigMaker.h"
#include "RESTObjects/RESTAPI_SubObjects.h"
#include "StorageService.h"
#include "framework/utils.h"
#include "nlohmann/json.hpp"
#include "sdks/SDK_gw.h"
#include "sdks/SDK_prov.h"
namespace OpenWifi {
static std::string ConvertBand(const std::string &B) {
if (B == "2G")
return "2G";
if (B == "6G")
return "6G";
if (B == "5GU")
return "5G-upper";
if (B == "5GL")
return "5G-lower";
return B;
}
static std::vector<std::string> ConvertBands(const std::vector<std::string> &Bs) {
std::vector<std::string> R;
for (const auto &i : Bs)
R.emplace_back(ConvertBand(i));
return R;
}
void CreateDHCPInfo(std::string &Subnet, const std::string &First, const std::string &Last,
uint64_t &DHCPFirst, uint64_t &HowMany) {
Poco::Net::IPAddress SubnetAddr, FirstAddress, LastAddress;
auto Tokens = Poco::StringTokenizer(Subnet, "/");
if (!Poco::Net::IPAddress::tryParse(Tokens[0], SubnetAddr) ||
!Poco::Net::IPAddress::tryParse(First, FirstAddress) ||
!Poco::Net::IPAddress::tryParse(Last, LastAddress)) {
Subnet = "192.168.1.1/24";
DHCPFirst = 10;
HowMany = 100;
return;
}
if (LastAddress < FirstAddress)
std::swap(LastAddress, FirstAddress);
struct in_addr FA {
*static_cast<const in_addr *>(FirstAddress.addr())
}, LA{*static_cast<const in_addr *>(LastAddress.addr())};
HowMany = htonl(LA.s_addr) - htonl(FA.s_addr);
auto SubNetBits = std::stoull(Tokens[1], nullptr, 10);
uint64_t SubNetBitMask;
if (SubNetBits == 8)
SubNetBitMask = 0x000000ff;
else if (SubNetBits == 16)
SubNetBitMask = 0x0000ffff;
else
SubNetBitMask = 0x000000ff;
DHCPFirst = htonl(FA.s_addr) & SubNetBitMask;
}
// #define __DBG__ std::cout << __LINE__ << std::endl ;
// #define __DBG__
bool ConfigMaker::Prepare() {
SubObjects::SubscriberInfo SI;
if (!StorageService()->SubInfoDB().GetRecord("id", id_, SI)) {
bad_ = true;
return false;
}
// We need to create the basic sections
auto metrics = R"(
{
"metrics": {
"dhcp-snooping": {
"filters": [
"ack",
"discover",
"offer",
"request",
"solicit",
"reply",
"renew"
]
},
"health": {
"interval": 60
},
"statistics": {
"interval": 60,
"types": [
"ssids",
"lldp",
"clients"
]
},
"wifi-frames": {
"filters": [
"probe",
"auth",
"assoc",
"disassoc",
"deauth",
"local-deauth",
"inactive-deauth",
"key-mismatch",
"beacon-report",
"radar-detected"
]
}
}
}
)"_json;
auto services = R"(
{
"services": {
"lldp": {
"describe": "uCentral",
"location": "universe"
},
"ssh": {
"authorized-keys": [],
"password-authentication": false,
"port": 22
}
}
} )"_json;
for (auto &i : SI.accessPoints.list) {
nlohmann::json Interfaces;
nlohmann::json UpstreamInterface;
nlohmann::json DownstreamInterface;
nlohmann::json radios;
if (i.macAddress.empty())
continue;
Logger_.information(fmt::format("{}: Generating configuration.", i.macAddress));
UpstreamInterface["name"] = "WAN";
UpstreamInterface["role"] = "upstream";
UpstreamInterface["services"].push_back("lldp");
std::vector<std::string> AllBands;
for (const auto &rr : i.radios)
AllBands.emplace_back(ConvertBand(rr.band));
nlohmann::json UpstreamPort, DownstreamPort;
if (i.internetConnection.type == "manual") {
UpstreamInterface["addressing"] = "static";
UpstreamInterface["subnet"] = i.internetConnection.subnetMask;
UpstreamInterface["gateway"] = i.internetConnection.defaultGateway;
UpstreamInterface["send-hostname"] = i.internetConnection.sendHostname;
UpstreamInterface["use-dns"].push_back(i.internetConnection.primaryDns);
if (!i.internetConnection.secondaryDns.empty())
UpstreamInterface["use-dns"].push_back(i.internetConnection.secondaryDns);
} else if (i.internetConnection.type == "pppoe") {
nlohmann::json Port;
Port["select-ports"].push_back("WAN*");
UpstreamInterface["ethernet"].push_back(Port);
UpstreamInterface["broad-band"]["protocol"] = "pppoe";
UpstreamInterface["broad-band"]["user-name"] = i.internetConnection.username;
UpstreamInterface["broad-band"]["password"] = i.internetConnection.password;
UpstreamInterface["ipv4"]["addressing"] = "dynamic";
if (i.internetConnection.ipV6Support)
UpstreamInterface["ipv6"]["addressing"] = "dynamic";
} else if (i.internetConnection.type == "automatic") {
nlohmann::json Port;
Port["select-ports"].push_back("WAN*");
if (i.deviceMode.type == "bridge")
Port["select-ports"].push_back("LAN*");
UpstreamInterface["ethernet"].push_back(Port);
UpstreamInterface["ipv4"]["addressing"] = "dynamic";
if (i.internetConnection.ipV6Support)
UpstreamInterface["ipv6"]["addressing"] = "dynamic";
}
if (i.deviceMode.type == "bridge") {
UpstreamPort["select-ports"].push_back("LAN*");
UpstreamPort["select-ports"].push_back("WAN*");
} else if (i.deviceMode.type == "manual") {
UpstreamPort.push_back("WAN*");
DownstreamPort.push_back("LAN*");
DownstreamInterface["name"] = "LAN";
DownstreamInterface["role"] = "downstream";
DownstreamInterface["services"].push_back("lldp");
DownstreamInterface["services"].push_back("ssh");
DownstreamInterface["ipv4"]["addressing"] = "static";
uint64_t HowMany = 0;
uint64_t FirstIPInRange;
CreateDHCPInfo(i.deviceMode.subnet, i.deviceMode.startIP, i.deviceMode.endIP,
FirstIPInRange, HowMany);
DownstreamInterface["ipv4"]["subnet"] = i.deviceMode.subnet;
DownstreamInterface["ipv4"]["dhcp"]["lease-first"] = FirstIPInRange;
DownstreamInterface["ipv4"]["dhcp"]["lease-count"] = HowMany;
DownstreamInterface["ipv4"]["dhcp"]["lease-time"] =
i.deviceMode.leaseTime.empty() ? "24h" : i.deviceMode.leaseTime;
} else if (i.deviceMode.type == "nat") {
UpstreamPort["select-ports"].push_back("WAN*");
DownstreamPort["select-ports"].push_back("LAN*");
DownstreamInterface["name"] = "LAN";
DownstreamInterface["role"] = "downstream";
DownstreamInterface["services"].push_back("lldp");
DownstreamInterface["services"].push_back("ssh");
DownstreamInterface["ipv4"]["addressing"] = "static";
uint64_t HowMany = 0;
uint64_t FirstIPInRange;
CreateDHCPInfo(i.deviceMode.subnet, i.deviceMode.startIP, i.deviceMode.endIP,
FirstIPInRange, HowMany);
DownstreamInterface["ipv4"]["subnet"] = i.deviceMode.subnet;
DownstreamInterface["ipv4"]["dhcp"]["lease-first"] = FirstIPInRange;
DownstreamInterface["ipv4"]["dhcp"]["lease-count"] = HowMany;
DownstreamInterface["ipv4"]["dhcp"]["lease-time"] =
i.deviceMode.leaseTime.empty() ? "24h" : i.deviceMode.leaseTime;
}
bool hasGuest = false;
nlohmann::json main_ssids, guest_ssids;
for (const auto &j : i.wifiNetworks.wifiNetworks) {
nlohmann::json ssid;
ssid["name"] = j.name;
if (j.bands[0] == "all") {
ssid["wifi-bands"] = AllBands;
} else {
ssid["wifi-bands"] = ConvertBands(j.bands);
}
ssid["bss-mode"] = "ap";
if (j.encryption == "wpa1-personal") {
ssid["encryption"]["proto"] = "psk";
ssid["encryption"]["ieee80211w"] = "disabled";
} else if (j.encryption == "wpa2-personal") {
ssid["encryption"]["proto"] = "psk2";
ssid["encryption"]["ieee80211w"] = "disabled";
} else if (j.encryption == "wpa3-personal") {
ssid["encryption"]["proto"] = "sae";
ssid["encryption"]["ieee80211w"] = "required";
} else if (j.encryption == "wpa1/2-personal") {
ssid["encryption"]["proto"] = "psk-mixed";
ssid["encryption"]["ieee80211w"] = "disabled";
} else if (j.encryption == "wpa2/3-personal") {
ssid["encryption"]["proto"] = "sae-mixed";
ssid["encryption"]["ieee80211w"] = "disabled";
}
ssid["encryption"]["key"] = j.password;
if (j.type == "main") {
main_ssids.push_back(ssid);
} else {
hasGuest = true;
ssid["isolate-clients"] = true;
guest_ssids.push_back(ssid);
}
}
if (i.deviceMode.type == "bridge")
UpstreamInterface["ssids"] = main_ssids;
else
DownstreamInterface["ssids"] = main_ssids;
nlohmann::json UpStreamEthernet, DownStreamEthernet;
if (!UpstreamPort.empty()) {
UpStreamEthernet.push_back(UpstreamPort);
}
if (!DownstreamPort.empty()) {
DownStreamEthernet.push_back(DownstreamPort);
}
if (i.deviceMode.type == "bridge") {
UpstreamInterface["ethernet"] = UpStreamEthernet;
Interfaces.push_back(UpstreamInterface);
} else {
UpstreamInterface["ethernet"] = UpStreamEthernet;
DownstreamInterface["ethernet"] = DownStreamEthernet;
Interfaces.push_back(UpstreamInterface);
Interfaces.push_back(DownstreamInterface);
}
if (hasGuest) {
nlohmann::json GuestInterface;
GuestInterface["name"] = "Guest";
GuestInterface["role"] = "downstream";
GuestInterface["isolate-hosts"] = true;
GuestInterface["ipv4"]["addressing"] = "static";
GuestInterface["ipv4"]["subnet"] = "192.168.10.1/24";
GuestInterface["ipv4"]["dhcp"]["lease-first"] = (uint64_t)10;
GuestInterface["ipv4"]["dhcp"]["lease-count"] = (uint64_t)100;
GuestInterface["ipv4"]["dhcp"]["lease-time"] = "6h";
GuestInterface["ssids"] = guest_ssids;
Interfaces.push_back(GuestInterface);
}
for (const auto &k : i.radios) {
nlohmann::json radio;
radio["band"] = ConvertBand(k.band);
radio["bandwidth"] = k.bandwidth;
if (k.channel == 0)
radio["channel"] = "auto";
else
radio["channel"] = k.channel;
if (k.country.size() == 2)
radio["country"] = k.country;
radio["channel-mode"] = k.channelMode;
radio["channel-width"] = k.channelWidth;
if (!k.requireMode.empty())
radio["require-mode"] = k.requireMode;
if (k.txpower > 0)
radio["tx-power"] = k.txpower;
if (k.allowDFS)
radio["allow-dfs"] = true;
if (!k.mimo.empty())
radio["mimo"] = k.mimo;
radio["legacy-rates"] = k.legacyRates;
radio["beacon-interval"] = k.beaconInterval;
radio["dtim-period"] = k.dtimPeriod;
radio["maximum-clients"] = k.maximumClients;
radio["rates"]["beacon"] = k.rates.beacon;
radio["rates"]["multicast"] = k.rates.multicast;
radio["he-settings"]["multiple-bssid"] = k.he.multipleBSSID;
radio["he-settings"]["ema"] = k.he.ema;
radio["he-settings"]["bss-color"] = k.he.bssColor;
radios.push_back(radio);
}
ProvObjects::DeviceConfigurationElement Metrics{.name = "metrics",
.description = "default metrics",
.weight = 0,
.configuration = to_string(metrics)};
ProvObjects::DeviceConfigurationElement Services{.name = "services",
.description = "default services",
.weight = 0,
.configuration = to_string(services)};
nlohmann::json InterfaceSection;
InterfaceSection["interfaces"] = Interfaces;
ProvObjects::DeviceConfigurationElement InterfacesList{
.name = "interfaces",
.description = "default interfaces",
.weight = 0,
.configuration = to_string(InterfaceSection)};
nlohmann::json RadiosSection;
RadiosSection["radios"] = radios;
ProvObjects::DeviceConfigurationElement RadiosList{.name = "radios",
.description = "default radios",
.weight = 0,
.configuration =
to_string(RadiosSection)};
ProvObjects::SubscriberDevice SubDevice;
if (SDK::Prov::Subscriber::GetDevice(nullptr, i.serialNumber, SubDevice)) {
SubDevice.configuration.clear();
SubDevice.configuration.push_back(Metrics);
SubDevice.configuration.push_back(Services);
SubDevice.configuration.push_back(InterfacesList);
SubDevice.configuration.push_back(RadiosList);
SubDevice.deviceRules.firmwareUpgrade = i.automaticUpgrade ? "yes" : "no";
if (SDK::Prov::Subscriber::SetDevice(nullptr, SubDevice)) {
Logger_.information(
fmt::format("Updating configuration for {}", i.serialNumber));
} else {
Logger_.information(
fmt::format("Cannot update configuration for {}", i.serialNumber));
}
} else {
Logger_.information(fmt::format(
"Could not find Subscriber device in provisioning for {}", i.serialNumber));
}
SDK::GW::Device::SetSubscriber(nullptr, i.serialNumber, SI.id);
}
SI.modified = Utils::Now();
return StorageService()->SubInfoDB().UpdateRecord("id", id_, SI);
}
} // namespace OpenWifi