feat: update AWG2 configuration handling in InstallProtocolManager and VpnClient
This commit is contained in:
@@ -431,6 +431,12 @@ class InstallProtocolManager
|
||||
$containerFilter = escapeshellarg('^' . $containerName . '$');
|
||||
$containerArg = escapeshellarg($containerName);
|
||||
|
||||
// Для AWG2 конфигурация внутри контейнера находится в /opt/amnezia/awg/awg0.conf
|
||||
// На хосте может быть /opt/amnezia/awg2/wg0.conf (монтируется как /opt/amnezia/awg внутри контейнера)
|
||||
$isAwg2 = (stripos($containerName, 'awg2') !== false || ($protocol['slug'] ?? '') === 'awg2');
|
||||
$configDir = $isAwg2 ? '/opt/amnezia/awg' : '/opt/amnezia/awg';
|
||||
$configFile = $isAwg2 ? 'awg0.conf' : 'wg0.conf';
|
||||
|
||||
$containerListRaw = trim($server->executeCommand("docker ps -a --filter name={$containerFilter} --format '{{.Names}}'", true));
|
||||
if ($containerListRaw === '') {
|
||||
return [
|
||||
@@ -460,11 +466,13 @@ class InstallProtocolManager
|
||||
|
||||
$containerState = trim($server->executeCommand("docker inspect --format '{{.State.Status}}' {$containerArg}", true));
|
||||
|
||||
$wgConfig = $server->executeCommand("docker exec -i {$containerArg} cat /opt/amnezia/awg/wg0.conf 2>/dev/null", true);
|
||||
// Для AWG2 проверяем оба возможных имени файла конфигурации
|
||||
$configFile = ($protocol['slug'] ?? '') === 'awg2' ? 'awg0.conf' : 'wg0.conf';
|
||||
$wgConfig = $server->executeCommand("docker exec -i {$containerArg} cat {$configDir}/{$configFile} 2>/dev/null", true);
|
||||
if (trim($wgConfig) === '') {
|
||||
return [
|
||||
'status' => 'partial',
|
||||
'message' => 'Контейнер найден, но конфигурация wg0.conf отсутствует',
|
||||
'message' => "Контейнер найден, но конфигурация {$configFile} отсутствует",
|
||||
'details' => [
|
||||
'container_name' => $containerName,
|
||||
'container_status' => $containerState,
|
||||
@@ -484,8 +492,8 @@ class InstallProtocolManager
|
||||
];
|
||||
}
|
||||
|
||||
$publicKey = trim($server->executeCommand("docker exec -i {$containerArg} cat /opt/amnezia/awg/wireguard_server_public_key.key 2>/dev/null", true));
|
||||
$presharedKey = trim($server->executeCommand("docker exec -i {$containerArg} cat /opt/amnezia/awg/wireguard_psk.key 2>/dev/null", true));
|
||||
$publicKey = trim($server->executeCommand("docker exec -i {$containerArg} cat {$configDir}/wireguard_server_public_key.key 2>/dev/null", true));
|
||||
$presharedKey = trim($server->executeCommand("docker exec -i {$containerArg} cat {$configDir}/wireguard_psk.key 2>/dev/null", true));
|
||||
|
||||
if ($publicKey === '' || $presharedKey === '') {
|
||||
return [
|
||||
@@ -498,7 +506,7 @@ class InstallProtocolManager
|
||||
];
|
||||
}
|
||||
|
||||
$clientsRaw = $server->executeCommand("docker exec -i {$containerArg} cat /opt/amnezia/awg/clientsTable 2>/dev/null", true);
|
||||
$clientsRaw = $server->executeCommand("docker exec -i {$containerArg} cat {$configDir}/clientsTable 2>/dev/null", true);
|
||||
$clients = json_decode(trim($clientsRaw), true);
|
||||
$clientsCount = is_array($clients) ? count($clients) : 0;
|
||||
|
||||
@@ -524,10 +532,16 @@ class InstallProtocolManager
|
||||
$containerName = $details['container_name'] ?? ($protocol['definition']['metadata']['container_name'] ?? 'amnezia-awg');
|
||||
$containerArg = escapeshellarg($containerName);
|
||||
|
||||
// Для AWG2 конфигурация внутри контейнера находится в /opt/amnezia/awg/awg0.conf
|
||||
// На хосте может быть /opt/amnezia/awg2/wg0.conf (монтируется как /opt/amnezia/awg внутри контейнера)
|
||||
$isAwg2 = (stripos($containerName, 'awg2') !== false || ($protocol['slug'] ?? '') === 'awg2');
|
||||
$configDir = '/opt/amnezia/awg'; // Внутри контейнера всегда /opt/amnezia/awg
|
||||
$configFile = $isAwg2 ? 'awg0.conf' : 'wg0.conf';
|
||||
|
||||
// Try to ensure container is running and wg is up
|
||||
$server->executeCommand("docker start {$containerArg} 2>/dev/null || true", true);
|
||||
$server->executeCommand("docker exec -i {$containerArg} wg-quick down /opt/amnezia/awg/wg0.conf 2>/dev/null || true", true);
|
||||
$server->executeCommand("docker exec -i {$containerArg} wg-quick up /opt/amnezia/awg/wg0.conf 2>/dev/null || true", true);
|
||||
$server->executeCommand("docker exec -i {$containerArg} wg-quick down {$configDir}/{$configFile} 2>/dev/null || true", true);
|
||||
$server->executeCommand("docker exec -i {$containerArg} wg-quick up {$configDir}/{$configFile} 2>/dev/null || true", true);
|
||||
|
||||
$pdo = DB::conn();
|
||||
$stmt = $pdo->prepare('
|
||||
@@ -553,9 +567,12 @@ class InstallProtocolManager
|
||||
$server->refresh();
|
||||
$serverData = $server->getData();
|
||||
|
||||
// Import existing peers from wg0.conf into database as disabled clients
|
||||
$wgConfig = $server->executeCommand("docker exec -i {$containerArg} cat /opt/amnezia/awg/wg0.conf 2>/dev/null", true);
|
||||
$tableRaw = $server->executeCommand("docker exec -i {$containerArg} cat /opt/amnezia/awg/clientsTable 2>/dev/null", true);
|
||||
// Import existing peers from config into database as disabled clients
|
||||
$serverId = $server->getId();
|
||||
Logger::appendInstall($serverId, "Restore: configDir={$configDir}, configFile={$configFile}, containerArg={$containerArg}");
|
||||
$wgConfig = $server->executeCommand("docker exec -i {$containerArg} cat {$configDir}/{$configFile} 2>/dev/null", true);
|
||||
$tableRaw = $server->executeCommand("docker exec -i {$containerArg} cat {$configDir}/clientsTable 2>/dev/null", true);
|
||||
Logger::appendInstall($serverId, "Restore: wgConfig length=" . strlen($wgConfig) . ", tableRaw length=" . strlen($tableRaw));
|
||||
$clientsTable = json_decode(trim($tableRaw), true);
|
||||
$nameByPub = [];
|
||||
if (is_array($clientsTable)) {
|
||||
@@ -569,6 +586,7 @@ class InstallProtocolManager
|
||||
}
|
||||
$restored = 0;
|
||||
$pid = self::resolveProtocolId($protocol);
|
||||
Logger::appendInstall($serverId, "Restore: protocol_id={$pid}, wgConfig empty=" . (trim($wgConfig) === '' ? 'yes' : 'no'));
|
||||
if (trim($wgConfig) !== '') {
|
||||
$pattern = '/\[Peer\][^\[]*?PublicKey\s*=\s*(.+?)\s*[\r\n]+[\s\S]*?AllowedIPs\s*=\s*(.+?)(?:\r?\n|$)/';
|
||||
if (preg_match_all($pattern, $wgConfig, $matches, PREG_SET_ORDER)) {
|
||||
@@ -611,6 +629,7 @@ class InstallProtocolManager
|
||||
}
|
||||
}
|
||||
|
||||
Logger::appendInstall($serverId, "Restore: finished, restored={$restored}");
|
||||
return [
|
||||
'success' => true,
|
||||
'mode' => 'restore',
|
||||
@@ -1836,10 +1855,13 @@ class InstallProtocolManager
|
||||
return;
|
||||
}
|
||||
|
||||
$containerName = $server->getData()['container_name'] ?? 'amnezia-awg';
|
||||
|
||||
// Read existing config
|
||||
$conf = $server->executeCommand("docker exec -i $containerName cat /opt/amnezia/awg/wg0.conf", true);
|
||||
$serverData = $server->getData();
|
||||
$containerName = $serverData['container_name'] ?? 'amnezia-awg';
|
||||
// Для AWG2 конфигурация внутри контейнера находится в /opt/amnezia/awg/awg0.conf
|
||||
$isAwg2 = (stripos($containerName, 'awg2') !== false || ($protocol['slug'] ?? '') === 'awg2');
|
||||
$configDir = '/opt/amnezia/awg'; // Внутри контейнера всегда /opt/amnezia/awg
|
||||
$configFile = $isAwg2 ? 'awg0.conf' : 'wg0.conf';
|
||||
$conf = $server->executeCommand("docker exec -i $containerName cat {$configDir}/{$configFile}", true);
|
||||
if (!$conf)
|
||||
return;
|
||||
|
||||
@@ -1869,7 +1891,7 @@ class InstallProtocolManager
|
||||
Logger::appendInstall($serverId, "Syncing $count existing clients to server config");
|
||||
$conf .= $newPeersBlock;
|
||||
$escaped = addslashes($conf);
|
||||
$server->executeCommand("docker exec -i $containerName sh -c 'echo \"$escaped\" > /opt/amnezia/awg/wg0.conf'", true);
|
||||
$server->executeCommand("docker exec -i $containerName sh -c 'echo \"$escaped\" > {$configDir}/{$configFile}'", true);
|
||||
|
||||
// Reload interface
|
||||
$server->executeCommand("docker exec -i $containerName wg-quick down wg0 || true", true);
|
||||
@@ -2185,9 +2207,12 @@ class InstallProtocolManager
|
||||
$serverData = $server->getData();
|
||||
$pid = self::resolveProtocolId($protocol);
|
||||
|
||||
// Read wg0.conf and clientsTable
|
||||
$wgConfig = $server->executeCommand("docker exec -i {$containerArg} cat /opt/amnezia/awg/wg0.conf 2>/dev/null", true);
|
||||
$tableRaw = $server->executeCommand("docker exec -i {$containerArg} cat /opt/amnezia/awg/clientsTable 2>/dev/null", true);
|
||||
// Для AWG2 конфигурация внутри контейнера находится в /opt/amnezia/awg/awg0.conf
|
||||
$isAwg2 = (stripos($containerName, 'awg2') !== false || ($protocol['slug'] ?? '') === 'awg2');
|
||||
$configDir = '/opt/amnezia/awg'; // Внутри контейнера всегда /opt/amnezia/awg
|
||||
$configFile = $isAwg2 ? 'awg0.conf' : 'wg0.conf';
|
||||
$wgConfig = $server->executeCommand("docker exec -i {$containerArg} cat {$configDir}/{$configFile} 2>/dev/null", true);
|
||||
$tableRaw = $server->executeCommand("docker exec -i {$containerArg} cat {$configDir}/clientsTable 2>/dev/null", true);
|
||||
$clientsTable = json_decode(trim($tableRaw), true);
|
||||
|
||||
// Build name lookup
|
||||
|
||||
+30
-10
@@ -1077,6 +1077,11 @@ class VpnClient
|
||||
public static function addClientToServer(array $serverData, string $publicKey, string $clientIP): void
|
||||
{
|
||||
$containerName = $serverData['container_name'];
|
||||
$protocolSlug = (string) ($serverData['install_protocol'] ?? '');
|
||||
// Для AWG2 конфигурация внутри контейнера находится в /opt/amnezia/awg/awg0.conf
|
||||
$isAwg2 = (stripos($containerName, 'awg2') !== false || $protocolSlug === 'awg2');
|
||||
$configDir = '/opt/amnezia/awg'; // Внутри контейнера всегда /opt/amnezia/awg
|
||||
$configFile = $isAwg2 ? 'awg0.conf' : 'wg0.conf';
|
||||
$presharedKey = $serverData['preshared_key'];
|
||||
$publicKey = trim($publicKey);
|
||||
|
||||
@@ -1111,7 +1116,8 @@ class VpnClient
|
||||
$peerBlock .= "AllowedIPs = {$clientIP}/32\n";
|
||||
|
||||
$escapedBlock = addslashes($peerBlock);
|
||||
$cmd4 = sprintf("docker exec -i %s sh -c 'echo \"%s\" >> /opt/amnezia/awg/wg0.conf'", $containerName, $escapedBlock);
|
||||
$configFile = (stripos($containerName, 'awg2') !== false || $protocolSlug === 'awg2') ? 'awg0.conf' : 'wg0.conf';
|
||||
$cmd4 = sprintf("docker exec -i %s sh -c 'echo \"%s\" >> %s/%s'", $containerName, $escapedBlock, $configDir, $configFile);
|
||||
self::executeServerCommand($serverData, $cmd4, true);
|
||||
|
||||
// 5. Update clientsTable
|
||||
@@ -1119,7 +1125,7 @@ class VpnClient
|
||||
|
||||
// 6. CRITICAL: Reload WG interface to apply AWG obfuscation params
|
||||
// Without this, the interface uses standard WireGuard without Jc/S1/S2/H1-H4
|
||||
$cmd5 = sprintf("docker exec -i %s sh -c 'ip link del wg0 2>/dev/null || true; wg-quick up /opt/amnezia/awg/wg0.conf 2>&1'", $containerName);
|
||||
$cmd5 = sprintf("docker exec -i %s sh -c 'ip link del wg0 2>/dev/null || true; wg-quick up %s/%s 2>&1'", $containerName, $configDir, $configFile);
|
||||
self::executeServerCommand($serverData, $cmd5, true);
|
||||
}
|
||||
|
||||
@@ -1129,9 +1135,12 @@ class VpnClient
|
||||
private static function updateClientsTable(array $serverData, string $publicKey, string $name): void
|
||||
{
|
||||
$containerName = $serverData['container_name'];
|
||||
$protocolSlug = (string) ($serverData['install_protocol'] ?? '');
|
||||
// Для AWG2 конфигурация внутри контейнера находится в /opt/amnezia/awg/
|
||||
$configDir = '/opt/amnezia/awg'; // Внутри контейнера всегда /opt/amnezia/awg
|
||||
|
||||
// Read current table
|
||||
$cmd = sprintf("docker exec -i %s cat /opt/amnezia/awg/clientsTable 2>/dev/null", $containerName);
|
||||
$cmd = sprintf("docker exec -i %s cat %s/clientsTable 2>/dev/null", $containerName, $configDir);
|
||||
$tableJson = self::executeServerCommand($serverData, $cmd, true);
|
||||
$table = json_decode(trim($tableJson), true);
|
||||
|
||||
@@ -1151,7 +1160,7 @@ class VpnClient
|
||||
// Save back
|
||||
$newTableJson = json_encode($table, JSON_PRETTY_PRINT);
|
||||
$escaped = addslashes($newTableJson);
|
||||
$updateCmd = sprintf("docker exec -i %s sh -c 'echo \"%s\" > /opt/amnezia/awg/clientsTable'", $containerName, $escaped);
|
||||
$updateCmd = sprintf("docker exec -i %s sh -c 'echo \"%s\" > %s/clientsTable'", $containerName, $escaped, $configDir);
|
||||
self::executeServerCommand($serverData, $updateCmd, true);
|
||||
}
|
||||
|
||||
@@ -1378,6 +1387,12 @@ class VpnClient
|
||||
private static function removeClientFromServer(array $serverData, string $publicKey): void
|
||||
{
|
||||
$containerName = $serverData['container_name'];
|
||||
$protocolSlug = (string) ($serverData['install_protocol'] ?? '');
|
||||
// Для AWG2 конфигурация внутри контейнера находится в /opt/amnezia/awg/
|
||||
$configDir = '/opt/amnezia/awg'; // Внутри контейнера всегда /opt/amnezia/awg
|
||||
|
||||
// Determine config filename
|
||||
$configFile = (stripos($containerName, 'awg2') !== false || $protocolSlug === 'awg2') ? 'awg0.conf' : 'wg0.conf';
|
||||
|
||||
// First, remove using wg command (live removal)
|
||||
$removeCmd = sprintf(
|
||||
@@ -1388,9 +1403,9 @@ class VpnClient
|
||||
|
||||
self::executeServerCommand($serverData, $removeCmd, true);
|
||||
|
||||
// Then remove from wg0.conf file to make it persistent
|
||||
// Then remove from config file to make it persistent
|
||||
// Use a more reliable method: read, filter, write
|
||||
$readCmd = sprintf("docker exec -i %s cat /opt/amnezia/awg/wg0.conf", $containerName);
|
||||
$readCmd = sprintf("docker exec -i %s cat %s/%s", $containerName, $configDir, $configFile);
|
||||
$config = self::executeServerCommand($serverData, $readCmd, true);
|
||||
|
||||
// Parse and remove the peer section
|
||||
@@ -1399,9 +1414,11 @@ class VpnClient
|
||||
// Write back to file
|
||||
$escapedConfig = str_replace("'", "'\\''", $newConfig);
|
||||
$writeCmd = sprintf(
|
||||
"docker exec -i %s sh -c 'echo '\''%s'\'' > /opt/amnezia/awg/wg0.conf'",
|
||||
"docker exec -i %s sh -c 'echo '\''%s'\'' > %s/%s'",
|
||||
$containerName,
|
||||
$escapedConfig
|
||||
$escapedConfig,
|
||||
$configDir,
|
||||
$configFile
|
||||
);
|
||||
|
||||
self::executeServerCommand($serverData, $writeCmd, true);
|
||||
@@ -1466,9 +1483,12 @@ class VpnClient
|
||||
private static function removeFromClientsTable(array $serverData, string $publicKey): void
|
||||
{
|
||||
$containerName = $serverData['container_name'];
|
||||
$protocolSlug = (string) ($serverData['install_protocol'] ?? '');
|
||||
// Для AWG2 конфигурация внутри контейнера находится в /opt/amnezia/awg/
|
||||
$configDir = '/opt/amnezia/awg'; // Внутри контейнера всегда /opt/amnezia/awg
|
||||
|
||||
// Read current table
|
||||
$cmd = sprintf("docker exec -i %s cat /opt/amnezia/awg/clientsTable 2>/dev/null", $containerName);
|
||||
$cmd = sprintf("docker exec -i %s cat %s/clientsTable 2>/dev/null", $containerName, $configDir);
|
||||
$tableJson = self::executeServerCommand($serverData, $cmd, true);
|
||||
$table = json_decode(trim($tableJson), true);
|
||||
|
||||
@@ -1487,7 +1507,7 @@ class VpnClient
|
||||
// Save back
|
||||
$newTableJson = json_encode($table, JSON_PRETTY_PRINT);
|
||||
$escaped = addslashes($newTableJson);
|
||||
$updateCmd = sprintf("docker exec -i %s sh -c 'echo \"%s\" > /opt/amnezia/awg/clientsTable'", $containerName, $escaped);
|
||||
$updateCmd = sprintf("docker exec -i %s sh -c 'echo \"%s\" > %s/clientsTable'", $containerName, $escaped, $configDir);
|
||||
self::executeServerCommand($serverData, $updateCmd, true);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user