feature: remove the limit of ip addresses = 254 (#1438)

This commit is contained in:
Cyril Anisimov 2025-03-06 15:43:47 +01:00 committed by GitHub
parent 4257c08b43
commit 69a00b0252
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 84 additions and 71 deletions

View file

@ -3,6 +3,7 @@
#include <QDebug> #include <QDebug>
#include <QJsonDocument> #include <QJsonDocument>
#include <QProcess> #include <QProcess>
#include <QRegularExpression>
#include <QString> #include <QString>
#include <QTemporaryDir> #include <QTemporaryDir>
#include <QTemporaryFile> #include <QTemporaryFile>
@ -19,13 +20,17 @@
#include "settings.h" #include "settings.h"
#include "utilities.h" #include "utilities.h"
WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings, const QSharedPointer<ServerController> &serverController, WireguardConfigurator::WireguardConfigurator(std::shared_ptr<Settings> settings,
bool isAwg, QObject *parent) const QSharedPointer<ServerController> &serverController, bool isAwg,
QObject *parent)
: ConfiguratorBase(settings, serverController, parent), m_isAwg(isAwg) : ConfiguratorBase(settings, serverController, parent), m_isAwg(isAwg)
{ {
m_serverConfigPath = m_isAwg ? amnezia::protocols::awg::serverConfigPath : amnezia::protocols::wireguard::serverConfigPath; m_serverConfigPath =
m_serverPublicKeyPath = m_isAwg ? amnezia::protocols::awg::serverPublicKeyPath : amnezia::protocols::wireguard::serverPublicKeyPath; m_isAwg ? amnezia::protocols::awg::serverConfigPath : amnezia::protocols::wireguard::serverConfigPath;
m_serverPskKeyPath = m_isAwg ? amnezia::protocols::awg::serverPskKeyPath : amnezia::protocols::wireguard::serverPskKeyPath; m_serverPublicKeyPath =
m_isAwg ? amnezia::protocols::awg::serverPublicKeyPath : amnezia::protocols::wireguard::serverPublicKeyPath;
m_serverPskKeyPath =
m_isAwg ? amnezia::protocols::awg::serverPskKeyPath : amnezia::protocols::wireguard::serverPskKeyPath;
m_configTemplate = m_isAwg ? ProtocolScriptType::awg_template : ProtocolScriptType::wireguard_template; m_configTemplate = m_isAwg ? ProtocolScriptType::awg_template : ProtocolScriptType::wireguard_template;
m_protocolName = m_isAwg ? config_key::awg : config_key::wireguard; m_protocolName = m_isAwg ? config_key::awg : config_key::wireguard;
@ -63,9 +68,31 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::genClientKeys()
return connData; return connData;
} }
QList<QHostAddress> WireguardConfigurator::getIpsFromConf(const QString &input)
{
QRegularExpression regex("AllowedIPs = (\\d+\\.\\d+\\.\\d+\\.\\d+)");
QRegularExpressionMatchIterator matchIterator = regex.globalMatch(input);
QList<QHostAddress> ips;
while (matchIterator.hasNext()) {
QRegularExpressionMatch match = matchIterator.next();
const QString address_string { match.captured(1) };
const QHostAddress address { address_string };
if (address.isNull()) {
qWarning() << "Couldn't recognize the ip address: " << address_string;
} else {
ips << address;
}
}
return ips;
}
WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardConfig(const ServerCredentials &credentials, WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardConfig(const ServerCredentials &credentials,
DockerContainer container, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode &errorCode) const QJsonObject &containerConfig,
ErrorCode &errorCode)
{ {
WireguardConfigurator::ConnectionData connData = WireguardConfigurator::genClientKeys(); WireguardConfigurator::ConnectionData connData = WireguardConfigurator::genClientKeys();
connData.host = credentials.hostName; connData.host = credentials.hostName;
@ -76,65 +103,45 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
return connData; return connData;
} }
// Get list of already created clients (only IP addresses) QString getIpsScript = QString("cat %1 | grep AllowedIPs").arg(m_serverConfigPath);
QString nextIpNumber; QString stdOut;
{ auto cbReadStdOut = [&](const QString &data, libssh::Client &) {
QString script = QString("cat %1 | grep AllowedIPs").arg(m_serverConfigPath); stdOut += data + "\n";
QString stdOut; return ErrorCode::NoError;
auto cbReadStdOut = [&](const QString &data, libssh::Client &) { };
stdOut += data + "\n";
return ErrorCode::NoError;
};
errorCode = m_serverController->runContainerScript(credentials, container, script, cbReadStdOut); errorCode = m_serverController->runContainerScript(credentials, container, getIpsScript, cbReadStdOut);
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
return connData; return connData;
} }
auto ips = getIpsFromConf(stdOut);
stdOut.replace("AllowedIPs = ", ""); QHostAddress nextIp = [&] {
stdOut.replace("/32", ""); QHostAddress result;
QStringList ips = stdOut.split("\n", Qt::SkipEmptyParts); QHostAddress lastIp;
if (ips.empty()) {
// remove extra IPs from each line for case when user manually edited the wg0.conf lastIp.setAddress(containerConfig.value(m_protocolName)
// and added there more IPs for route his itnernal networks, like: .toObject()
// ... .value(config_key::subnet_address)
// AllowedIPs = 10.8.1.6/32, 192.168.1.0/24, 192.168.2.0/24, ... .toString(protocols::wireguard::defaultSubnetAddress));
// ...
// without this code - next IP would be 1 if last item in 'ips' has format above
QStringList vpnIps;
for (const auto &ip : ips) {
vpnIps.append(ip.split(",", Qt::SkipEmptyParts).first().trimmed());
}
ips = vpnIps;
// Calc next IP address
if (ips.isEmpty()) {
nextIpNumber = "2";
} else { } else {
int next = ips.last().split(".").last().toInt() + 1; lastIp = ips.last();
if (next > 254) {
errorCode = ErrorCode::AddressPoolError;
return connData;
}
nextIpNumber = QString::number(next);
} }
} quint8 lastOctet = static_cast<quint8>(lastIp.toIPv4Address());
switch (lastOctet) {
QString subnetIp = containerConfig.value(m_protocolName).toObject().value(config_key::subnet_address).toString(protocols::wireguard::defaultSubnetAddress); case 254: result.setAddress(lastIp.toIPv4Address() + 3); break;
{ case 255: result.setAddress(lastIp.toIPv4Address() + 2); break;
QStringList l = subnetIp.split(".", Qt::SkipEmptyParts); default: result.setAddress(lastIp.toIPv4Address() + 1); break;
if (l.isEmpty()) {
errorCode = ErrorCode::AddressPoolError;
return connData;
} }
l.removeLast();
l.append(nextIpNumber);
connData.clientIP = l.join("."); return result;
} }();
connData.clientIP = nextIp.toString();
// Get keys // Get keys
connData.serverPubKey = m_serverController->getTextFileFromContainer(container, credentials, m_serverPublicKeyPath, errorCode); connData.serverPubKey =
m_serverController->getTextFileFromContainer(container, credentials, m_serverPublicKeyPath, errorCode);
connData.serverPubKey.replace("\n", ""); connData.serverPubKey.replace("\n", "");
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
return connData; return connData;
@ -161,10 +168,12 @@ WireguardConfigurator::ConnectionData WireguardConfigurator::prepareWireguardCon
return connData; return connData;
} }
QString script = QString("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'").arg(m_serverConfigPath); QString script = QString("sudo docker exec -i $CONTAINER_NAME bash -c 'wg syncconf wg0 <(wg-quick strip %1)'")
.arg(m_serverConfigPath);
errorCode = m_serverController->runScript( errorCode = m_serverController->runScript(
credentials, m_serverController->replaceVars(script, m_serverController->genVarsForScript(credentials, container))); credentials,
m_serverController->replaceVars(script, m_serverController->genVarsForScript(credentials, container)));
return connData; return connData;
} }
@ -173,8 +182,8 @@ QString WireguardConfigurator::createConfig(const ServerCredentials &credentials
const QJsonObject &containerConfig, ErrorCode &errorCode) const QJsonObject &containerConfig, ErrorCode &errorCode)
{ {
QString scriptData = amnezia::scriptData(m_configTemplate, container); QString scriptData = amnezia::scriptData(m_configTemplate, container);
QString config = QString config = m_serverController->replaceVars(
m_serverController->replaceVars(scriptData, m_serverController->genVarsForScript(credentials, container, containerConfig)); scriptData, m_serverController->genVarsForScript(credentials, container, containerConfig));
ConnectionData connData = prepareWireguardConfig(credentials, container, containerConfig, errorCode); ConnectionData connData = prepareWireguardConfig(credentials, container, containerConfig, errorCode);
if (errorCode != ErrorCode::NoError) { if (errorCode != ErrorCode::NoError) {
@ -208,16 +217,16 @@ QString WireguardConfigurator::createConfig(const ServerCredentials &credentials
return QJsonDocument(jConfig).toJson(); return QJsonDocument(jConfig).toJson();
} }
QString WireguardConfigurator::processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig, QString WireguardConfigurator::processConfigWithLocalSettings(const QPair<QString, QString> &dns,
QString &protocolConfigString) const bool isApiConfig, QString &protocolConfigString)
{ {
processConfigWithDnsSettings(dns, protocolConfigString); processConfigWithDnsSettings(dns, protocolConfigString);
return protocolConfigString; return protocolConfigString;
} }
QString WireguardConfigurator::processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig, QString WireguardConfigurator::processConfigWithExportSettings(const QPair<QString, QString> &dns,
QString &protocolConfigString) const bool isApiConfig, QString &protocolConfigString)
{ {
processConfigWithDnsSettings(dns, protocolConfigString); processConfigWithDnsSettings(dns, protocolConfigString);

View file

@ -1,6 +1,7 @@
#ifndef WIREGUARD_CONFIGURATOR_H #ifndef WIREGUARD_CONFIGURATOR_H
#define WIREGUARD_CONFIGURATOR_H #define WIREGUARD_CONFIGURATOR_H
#include <QHostAddress>
#include <QObject> #include <QObject>
#include <QProcessEnvironment> #include <QProcessEnvironment>
@ -12,8 +13,8 @@ class WireguardConfigurator : public ConfiguratorBase
{ {
Q_OBJECT Q_OBJECT
public: public:
WireguardConfigurator(std::shared_ptr<Settings> settings, const QSharedPointer<ServerController> &serverController, bool isAwg, WireguardConfigurator(std::shared_ptr<Settings> settings, const QSharedPointer<ServerController> &serverController,
QObject *parent = nullptr); bool isAwg, QObject *parent = nullptr);
struct ConnectionData struct ConnectionData
{ {
@ -26,15 +27,18 @@ public:
QString port; QString port;
}; };
QString createConfig(const ServerCredentials &credentials, DockerContainer container, const QJsonObject &containerConfig, QString createConfig(const ServerCredentials &credentials, DockerContainer container,
ErrorCode &errorCode); const QJsonObject &containerConfig, ErrorCode &errorCode);
QString processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig, QString &protocolConfigString); QString processConfigWithLocalSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig, QString &protocolConfigString); QString &protocolConfigString);
QString processConfigWithExportSettings(const QPair<QString, QString> &dns, const bool isApiConfig,
QString &protocolConfigString);
static ConnectionData genClientKeys(); static ConnectionData genClientKeys();
private: private:
QList<QHostAddress> getIpsFromConf(const QString &input);
ConnectionData prepareWireguardConfig(const ServerCredentials &credentials, DockerContainer container, ConnectionData prepareWireguardConfig(const ServerCredentials &credentials, DockerContainer container,
const QJsonObject &containerConfig, ErrorCode &errorCode); const QJsonObject &containerConfig, ErrorCode &errorCode);