Files
amneziavpnphp/scripts/sync_awg_all.php
T

137 lines
4.9 KiB
PHP

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
if (php_sapi_name() !== 'cli') {
die("CLI only");
}
require_once __DIR__ . '/../inc/Config.php';
require_once __DIR__ . '/../inc/DB.php';
require_once __DIR__ . '/../inc/VpnServer.php';
echo "Starting AmneziaWG Sync (DB -> Server)...\n";
try {
// Assuming Server ID 1 for now (or pass as arg)
$serverId = 1;
$server = new VpnServer($serverId);
$data = $server->getData();
if (!$data) {
die("Server not found\n");
}
$containerName = $data['container_name'] ?? 'amnezia-awg';
// 1. Get Server Params
$awgParams = json_decode($data['awg_params'] ?? '[]', true);
if (empty($awgParams)) {
// Safe Fallback if DB empty? Or error?
// Better error out to avoid breakage, but user wants FIX.
// If empty, generate new randoms?
// Let's assume params exist or fetch from current wg0 check.
// For now, fail if missing.
echo "Warning: AWG Params missing in DB. Fetching defaults/randoms...\n";
$awgParams = [
'Jc' => 5,
'Jmin' => 50,
'Jmax' => 1000,
'S1' => 100,
'S2' => 200,
'H1' => 18274619,
'H2' => 2938471,
'H3' => 918273,
'H4' => 1928374
];
}
// 2. Get Keys (Interface)
// Server Private Key should be in DB?
// vpn_servers table has server_public_key... but usually NOT private key?
// Start script puts keys in /opt/amnezia/awg/....key
// We should READ them from file to be safe.
// Read directly from HOST file to avoid container dependency (deadlock if stuck in restart loop)
$privKey = trim($server->executeCommand("cat /opt/amnezia/awg/wireguard_server_private_key.key 2>/dev/null", true));
if (empty($privKey)) {
// Fallback: try container exec (only if host file missing)
$privKey = trim($server->executeCommand("docker exec -i $containerName cat /opt/amnezia/awg/server_private.key", true));
}
if (!$privKey || strpos($privKey, 'Error response') !== false) {
// If still missing or error message
die("Fatal: Could not retrieve Server Private Key. Check /opt/amnezia/awg/ directory.\n");
}
$vpnPort = $data['vpn_port'] ?? 51820;
// 3. Build Interface Block
$conf = "[Interface]\n";
$conf .= "PrivateKey = $privKey\n";
$conf .= "Address = 10.8.1.1/24\n"; // Hardcoded or from DB? vpn_subnet usually.
$conf .= "ListenPort = $vpnPort\n";
// Normalize params
$cleanParams = [];
foreach ($awgParams as $k => $v)
$cleanParams[strtoupper($k)] = $v;
$conf .= "Jc = " . ($cleanParams['JC'] ?? 5) . "\n";
$conf .= "Jmin = " . ($cleanParams['JMIN'] ?? 50) . "\n";
$conf .= "Jmax = " . ($cleanParams['JMAX'] ?? 1000) . "\n";
$conf .= "S1 = " . ($cleanParams['S1'] ?? 50) . "\n";
$conf .= "S2 = " . ($cleanParams['S2'] ?? 100) . "\n";
$conf .= "H1 = " . ($cleanParams['H1'] ?? 1) . "\n";
$conf .= "H2 = " . ($cleanParams['H2'] ?? 2) . "\n";
$conf .= "H3 = " . ($cleanParams['H3'] ?? 3) . "\n";
$conf .= "H4 = " . ($cleanParams['H4'] ?? 4) . "\n";
$conf .= "PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE\n";
$conf .= "PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE\n\n";
// 4. Load Clients
$pdo = DB::conn();
$stmt = $pdo->prepare("SELECT * FROM vpn_clients WHERE server_id = ? AND status = 'active'");
$stmt->execute([$serverId]);
$clients = $stmt->fetchAll();
echo "Found " . count($clients) . " clients in DB.\n";
foreach ($clients as $client) {
$pub = $client['public_key'];
if (empty($pub)) {
echo "Skipping client {$client['id']} (Empty Public Key)\n";
continue;
}
$psk = $client['preshared_key'];
$ip = $client['client_ip'];
$allowed = $client['allowed_ips'] ?? "$ip/32"; // Fallback to IP/32
$conf .= "[Peer]\n";
$conf .= "PublicKey = $pub\n";
if ($psk)
$conf .= "PresharedKey = $psk\n";
$conf .= "AllowedIPs = $allowed\n\n";
}
// 5. Write Config
// Use host path that matches container volume (-v /opt/amnezia/awg:/opt/amnezia/awg)
$hostConfPath = '/opt/amnezia/awg/wg0.conf';
$escaped = addslashes($conf);
$server->executeCommand("echo \"$escaped\" > $hostConfPath", true);
// Also copy to container path if mounted (usually same file via bind mount)
// 6. Restart Interface
echo "Restarting WireGuard interface...\n";
$server->executeCommand("docker exec -i $containerName wg-quick down wg0 || true", true);
$server->executeCommand("docker exec -i $containerName wg-quick up wg0", true);
echo "Sync Complete.\n";
} catch (Throwable $e) {
echo "Error: " . $e->getMessage() . "\n";
exit(1);
}