initial commit

This commit is contained in:
NeilClack
2026-08-07 14:51:41 -05:00
commit 9251b3a196
604 changed files with 464448 additions and 0 deletions
+234
View File
@@ -0,0 +1,234 @@
#include "nm_connection.h"
#include <algorithm>
#include <cstring>
#include <random>
#include <stdexcept>
#include <sstream>
namespace radiantwave::network {
// ─── UUID Generation (standard RFC 4122 v4) ─────────────────────────────
namespace {
std::string generateUuid() {
static std::random_device rd;
static std::mt19937_64 gen(rd());
static std::uniform_int_distribution<uint64_t> dis;
uint8_t bytes[16];
uint64_t v1 = dis(gen);
uint64_t v2 = dis(gen);
std::memcpy(bytes, &v1, 8);
std::memcpy(bytes + 8, &v2, 8);
bytes[6] = (bytes[6] & 0x0F) | 0x40; // Version 4
bytes[8] = (bytes[8] & 0x3F) | 0x80; // Variant RFC 4122
static const char hex[] = "0123456789abcdef";
char buf[37];
int p = 0;
for (int i = 0; i < 16; ++i) {
if (i == 4 || i == 6 || i == 8 || i == 10) {
buf[p++] = '-';
}
buf[p++] = hex[(bytes[i] >> 4) & 0x0F];
buf[p++] = hex[bytes[i] & 0x0F];
}
buf[36] = '\0';
return std::string(buf, 36);
}
} // anonymous namespace
// ─── Connection Builder ────────────────────────────────────────────────
ConnectionSettings buildConnectionSettings(
const std::string& ssid,
const std::string& password,
SecurityType security,
const std::string& interface_name
) {
// Validate SSID
if (!isValidSsid(ssid)) {
throw std::invalid_argument("Invalid SSID: must be 1-32 bytes with no null characters");
}
// Validate password if required
if (requiresPassword(security)) {
std::string error = validatePassword(password, security);
if (!error.empty()) {
throw std::invalid_argument(error);
}
}
ConnectionSettings settings;
// ── connection section ─────────────────────────────────────────────
settings["connection"] = {
{"id", ssid},
{"type", std::string("802-11-wireless")},
{"uuid", generateUuid()},
{"interface-name", interface_name},
{"autoconnect", true},
{"permissions", std::vector<std::string>()}
};
// ── 802-11-wireless section ────────────────────────────────────────
settings["802-11-wireless"] = {
{"ssid", ssidToBytes(ssid)},
{"mode", std::string("infrastructure")}
};
// ── 802-11-wireless-security section ───────────────────────────────
if (security != SecurityType::Open) {
SettingDict security_settings;
switch (security) {
case SecurityType::WEP:
security_settings["key-mgmt"] = std::string("none");
security_settings["wep-key0"] = password;
security_settings["wep-key-type"] = static_cast<uint32_t>(1); // WEP_KEY_TYPE_PASSPHRASE
break;
case SecurityType::WPA:
case SecurityType::WPA2:
security_settings["key-mgmt"] = std::string("wpa-psk");
security_settings["auth-alg"] = std::string("open");
security_settings["psk"] = password;
security_settings["psk-flags"] = static_cast<uint32_t>(0);
break;
case SecurityType::WPA3:
security_settings["key-mgmt"] = std::string("sae");
security_settings["psk"] = password;
break;
default:
break;
}
settings["802-11-wireless-security"] = security_settings;
}
// ── ipv4 section ───────────────────────────────────────────────────
settings["ipv4"] = {
{"method", std::string("auto")}
};
// ── ipv6 section ───────────────────────────────────────────────────
settings["ipv6"] = {
{"method", std::string("auto")}
};
return settings;
}
// ─── Security Detection ────────────────────────────────────────────────
SecurityType detectSecurityType(
uint32_t ap_flags,
uint32_t wpa_flags,
uint32_t rsn_flags
) {
// WPA3 uses SAE (flag 0x0400)
if (rsn_flags & nm_ap_wpa_flags::RsnSae) {
return SecurityType::WPA3;
}
// WPA2 uses RSN PSK (flag 0x0100)
if (rsn_flags & nm_ap_wpa_flags::RsnPsk) {
return SecurityType::WPA2;
}
// WPA uses WPA flags (not RSN)
if (wpa_flags != 0) {
return SecurityType::WPA;
}
// WEP uses privacy flag
if (ap_flags & nm_ap_flags::Privacy) {
return SecurityType::WEP;
}
return SecurityType::Open;
}
bool requiresPassword(SecurityType type) {
return type != SecurityType::Open;
}
// ─── SSID Utilities ────────────────────────────────────────────────────
std::vector<uint8_t> ssidToBytes(const std::string& ssid) {
return std::vector<uint8_t>(ssid.begin(), ssid.end());
}
std::string bytesToSsid(const std::vector<uint8_t>& bytes) {
return std::string(bytes.begin(), bytes.end());
}
bool isValidSsid(const std::string& ssid) {
// SSID must be 1-32 bytes
if (ssid.empty() || ssid.size() > 32) {
return false;
}
// SSID must not contain null bytes
for (char c : ssid) {
if (c == '\0') {
return false;
}
}
return true;
}
// ─── Password Validation ───────────────────────────────────────────────
std::string validatePassword(const std::string& password, SecurityType type) {
switch (type) {
case SecurityType::WEP:
// WEP keys can be 5 or 13 ASCII characters, or 10/26 hex digits
// For simplicity, we accept any non-empty string
if (password.empty()) {
return "WEP network requires a password";
}
break;
case SecurityType::WPA:
case SecurityType::WPA2:
// WPA/WPA2 PSK requires 8-63 characters
if (password.empty()) {
return "WPA/WPA2 network requires a password";
}
if (password.size() < 8) {
return "WPA/WPA2 password must be at least 8 characters";
}
if (password.size() > 63) {
return "WPA/WPA2 password must be at most 63 characters";
}
break;
case SecurityType::WPA3:
// WPA3 SAE requires 8-63 characters
if (password.empty()) {
return "WPA3 network requires a password";
}
if (password.size() < 8) {
return "WPA3 password must be at least 8 characters";
}
if (password.size() > 63) {
return "WPA3 password must be at most 63 characters";
}
break;
case SecurityType::Open:
// No password required
break;
}
return ""; // Valid
}
} // namespace radiantwave::network