mirror of
https://github.com/Telecominfraproject/wlan-cloud-userportal.git
synced 2026-01-28 02:23:10 +00:00
384 lines
13 KiB
C++
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
|