networking: add networking library

This commit is contained in:
Carson Powers 2025-07-03 13:06:21 -05:00 committed by outfoxxed
parent bcc3d4265e
commit db37dc580a
No known key found for this signature in database
GPG key ID: 4C88A185FB89301E
34 changed files with 3177 additions and 1 deletions

248
src/network/nm/utils.cpp Normal file
View file

@ -0,0 +1,248 @@
#include "utils.hpp"
// We depend on non-std Linux extensions that ctime doesn't put in the global namespace
// NOLINTNEXTLINE(modernize-deprecated-headers)
#include <time.h>
#include <qcontainerfwd.h>
#include <qdatetime.h>
#include <qdbusservicewatcher.h>
#include <qobject.h>
#include <qqmlintegration.h>
#include <qtypes.h>
#include "../wifi.hpp"
#include "dbus_types.hpp"
#include "enums.hpp"
namespace qs::network {
WifiSecurityType::Enum securityFromConnectionSettings(const ConnectionSettingsMap& settings) {
const QVariantMap& security = settings.value("802-11-wireless-security");
if (security.isEmpty()) {
return WifiSecurityType::Open;
};
const QString keyMgmt = security["key-mgmt"].toString();
const QString authAlg = security["auth-alg"].toString();
const QList<QVariant> proto = security["proto"].toList();
if (keyMgmt == "none") {
return WifiSecurityType::StaticWep;
} else if (keyMgmt == "ieee8021x") {
if (authAlg == "leap") {
return WifiSecurityType::Leap;
} else {
return WifiSecurityType::DynamicWep;
}
} else if (keyMgmt == "wpa-psk") {
if (proto.contains("wpa") && proto.contains("rsn")) return WifiSecurityType::WpaPsk;
return WifiSecurityType::Wpa2Psk;
} else if (keyMgmt == "wpa-eap") {
if (proto.contains("wpa") && proto.contains("rsn")) return WifiSecurityType::WpaEap;
return WifiSecurityType::Wpa2Eap;
} else if (keyMgmt == "sae") {
return WifiSecurityType::Sae;
} else if (keyMgmt == "wpa-eap-suite-b-192") {
return WifiSecurityType::Wpa3SuiteB192;
}
return WifiSecurityType::Open;
}
bool deviceSupportsApCiphers(
NMWirelessCapabilities::Enum caps,
NM80211ApSecurityFlags::Enum apFlags,
WifiSecurityType::Enum type
) {
bool havePair = false;
bool haveGroup = false;
// Device needs to support at least one pairwise and one group cipher
if (type == WifiSecurityType::StaticWep) {
// Static WEP only uses group ciphers
havePair = true;
} else {
if (caps & NMWirelessCapabilities::CipherWep40 && apFlags & NM80211ApSecurityFlags::PairWep40) {
havePair = true;
}
if (caps & NMWirelessCapabilities::CipherWep104 && apFlags & NM80211ApSecurityFlags::PairWep104)
{
havePair = true;
}
if (caps & NMWirelessCapabilities::CipherTkip && apFlags & NM80211ApSecurityFlags::PairTkip) {
havePair = true;
}
if (caps & NMWirelessCapabilities::CipherCcmp && apFlags & NM80211ApSecurityFlags::PairCcmp) {
havePair = true;
}
}
if (caps & NMWirelessCapabilities::CipherWep40 && apFlags & NM80211ApSecurityFlags::GroupWep40) {
haveGroup = true;
}
if (caps & NMWirelessCapabilities::CipherWep104 && apFlags & NM80211ApSecurityFlags::GroupWep104)
{
haveGroup = true;
}
if (type != WifiSecurityType::StaticWep) {
if (caps & NMWirelessCapabilities::CipherTkip && apFlags & NM80211ApSecurityFlags::GroupTkip) {
haveGroup = true;
}
if (caps & NMWirelessCapabilities::CipherCcmp && apFlags & NM80211ApSecurityFlags::GroupCcmp) {
haveGroup = true;
}
}
return (havePair && haveGroup);
}
bool securityIsValid(
WifiSecurityType::Enum type,
NMWirelessCapabilities::Enum caps,
bool adhoc,
NM80211ApFlags::Enum apFlags,
NM80211ApSecurityFlags::Enum apWpa,
NM80211ApSecurityFlags::Enum apRsn
) {
switch (type) {
case WifiSecurityType::Open:
if (apFlags & NM80211ApFlags::Privacy) return false;
if (apWpa || apRsn) return false;
break;
case WifiSecurityType::Leap:
if (adhoc) return false;
case WifiSecurityType::StaticWep:
if (!(apFlags & NM80211ApFlags::Privacy)) return false;
if (apWpa || apRsn) {
if (!deviceSupportsApCiphers(caps, apWpa, WifiSecurityType::StaticWep)) {
if (!deviceSupportsApCiphers(caps, apRsn, WifiSecurityType::StaticWep)) return false;
}
}
break;
case WifiSecurityType::DynamicWep:
if (adhoc) return false;
if (apRsn || !(apFlags & NM80211ApFlags::Privacy)) return false;
if (apWpa) {
if (!(apWpa & NM80211ApSecurityFlags::KeyMgmt8021x)) return false;
if (!deviceSupportsApCiphers(caps, apWpa, WifiSecurityType::DynamicWep)) return false;
}
break;
case WifiSecurityType::WpaPsk:
if (adhoc) return false;
if (!(caps & NMWirelessCapabilities::Wpa)) return false;
if (apWpa & NM80211ApSecurityFlags::KeyMgmtPsk) {
if (apWpa & NM80211ApSecurityFlags::PairTkip && caps & NMWirelessCapabilities::CipherTkip) {
return true;
}
if (apWpa & NM80211ApSecurityFlags::PairCcmp && caps & NMWirelessCapabilities::CipherCcmp) {
return true;
}
}
return false;
case WifiSecurityType::Wpa2Psk:
if (!(caps & NMWirelessCapabilities::Rsn)) return false;
if (adhoc) {
if (!(caps & NMWirelessCapabilities::IbssRsn)) return false;
if (apRsn & NM80211ApSecurityFlags::PairCcmp && caps & NMWirelessCapabilities::CipherCcmp) {
return true;
}
} else {
if (apRsn & NM80211ApSecurityFlags::KeyMgmtPsk) {
if (apRsn & NM80211ApSecurityFlags::PairTkip && caps & NMWirelessCapabilities::CipherTkip) {
return true;
}
if (apRsn & NM80211ApSecurityFlags::PairCcmp && caps & NMWirelessCapabilities::CipherCcmp) {
return true;
}
}
}
return false;
case WifiSecurityType::WpaEap:
if (adhoc) return false;
if (!(caps & NMWirelessCapabilities::Wpa)) return false;
if (!(apWpa & NM80211ApSecurityFlags::KeyMgmt8021x)) return false;
if (!deviceSupportsApCiphers(caps, apWpa, WifiSecurityType::WpaEap)) return false;
break;
case WifiSecurityType::Wpa2Eap:
if (adhoc) return false;
if (!(caps & NMWirelessCapabilities::Rsn)) return false;
if (!(apRsn & NM80211ApSecurityFlags::KeyMgmt8021x)) return false;
if (!deviceSupportsApCiphers(caps, apRsn, WifiSecurityType::Wpa2Eap)) return false;
break;
case WifiSecurityType::Sae:
if (!(caps & NMWirelessCapabilities::Rsn)) return false;
if (adhoc) {
if (!(caps & NMWirelessCapabilities::IbssRsn)) return false;
if (apRsn & NM80211ApSecurityFlags::PairCcmp && caps & NMWirelessCapabilities::CipherCcmp) {
return true;
}
} else {
if (apRsn & NM80211ApSecurityFlags::KeyMgmtSae) {
if (apRsn & NM80211ApSecurityFlags::PairTkip && caps & NMWirelessCapabilities::CipherTkip) {
return true;
}
if (apRsn & NM80211ApSecurityFlags::PairCcmp && caps & NMWirelessCapabilities::CipherCcmp) {
return true;
}
}
}
return false;
case WifiSecurityType::Owe:
if (adhoc) return false;
if (!(caps & NMWirelessCapabilities::Rsn)) return false;
if (!(apRsn & NM80211ApSecurityFlags::KeyMgmtOwe)
&& !(apRsn & NM80211ApSecurityFlags::KeyMgmtOweTm))
{
return false;
}
break;
case WifiSecurityType::Wpa3SuiteB192:
if (adhoc) return false;
if (!(caps & NMWirelessCapabilities::Rsn)) return false;
if (!(apRsn & NM80211ApSecurityFlags::KeyMgmtEapSuiteB192)) return false;
break;
default: return false;
}
return true;
}
WifiSecurityType::Enum findBestWirelessSecurity(
NMWirelessCapabilities::Enum caps,
bool adHoc,
NM80211ApFlags::Enum apFlags,
NM80211ApSecurityFlags::Enum apWpa,
NM80211ApSecurityFlags::Enum apRsn
) {
// Loop through security types from most to least secure since the enum
// values are sequential and in priority order (0-10, excluding Unknown=11)
for (int i = WifiSecurityType::Wpa3SuiteB192; i <= WifiSecurityType::Open; ++i) {
auto type = static_cast<WifiSecurityType::Enum>(i);
if (securityIsValid(type, caps, adHoc, apFlags, apWpa, apRsn)) {
return type;
}
}
return WifiSecurityType::Unknown;
}
// NOLINTBEGIN
QDateTime clockBootTimeToDateTime(qint64 clockBootTime) {
clockid_t clkId = CLOCK_BOOTTIME;
struct timespec tp {};
const QDateTime now = QDateTime::currentDateTime();
int r = clock_gettime(clkId, &tp);
if (r == -1 && errno == EINVAL) {
clkId = CLOCK_MONOTONIC;
r = clock_gettime(clkId, &tp);
}
// Convert to milliseconds
const qint64 nowInMs = tp.tv_sec * 1000 + tp.tv_nsec / 1000000;
// Return a QDateTime of the millisecond diff
const qint64 offset = clockBootTime - nowInMs;
return QDateTime::fromMSecsSinceEpoch(now.toMSecsSinceEpoch() + offset);
}
// NOLINTEND
} // namespace qs::network