root 11 mēneši atpakaļ
vecāks
revīzija
0b65028cec
1 mainītis faili ar 339 papildinājumiem un 0 dzēšanām
  1. 339 0
      index.php

+ 339 - 0
index.php

@@ -0,0 +1,339 @@
+<?php
+// Настройки
+$page_title = 'OpenVPN Status';
+
+// Ограничение частоты запросов (в секундах)
+define('REQUEST_INTERVAL', 60);
+
+$servers = [
+    'server1' => [
+        'name' => 'server1',
+        'title' => 'Server1',
+        'config' => '/etc/openvpn/server/server.conf',
+        'ccd' => '/etc/openvpn/server/server/ccd',
+        'port' => '3003',
+        'host' => '127.0.0.1',
+        'password' => 'password'
+    ],
+];
+
+session_start();
+
+// Проверяем и инициализируем массив, если его нет
+if (!isset($_SESSION['last_request_time']) || !is_array($_SESSION['last_request_time'])) {
+    $_SESSION['last_request_time'] = []; // Создаем пустой массив
+}
+
+function canRequestStatus($server) {
+    if (!isset($_SESSION['last_request_time'][$server['name']])) { return true; }
+    if (time() - $_SESSION['last_request_time'][$server['name']] >= REQUEST_INTERVAL) { return true; }
+    return false;
+}
+
+function updateLastRequestTime($server) {
+    $_SESSION['last_request_time'][$server['name']] = time();
+}
+
+function openvpnManagementCommand($server, $command) {
+    $mgmt_host = $server['host'];
+    $mgmt_port = $server['port'];
+    $mgmt_pass = $server['password'];
+
+    $timeout = 5;
+    $socket = @fsockopen($mgmt_host, $mgmt_port, $errno, $errstr, $timeout);
+    
+    if (!$socket) {
+        error_log("OpenVPN management connection failed to {$server['name']}: $errstr ($errno)");
+        return false;
+    }
+
+    stream_set_timeout($socket, $timeout);
+    
+    try {
+        // Читаем приветственное сообщение
+        $welcome = '';
+        while (!feof($socket)) {
+            $line = fgets($socket);
+            if ($line === false) break;
+            $welcome .= $line;
+            if (strpos($welcome, 'ENTER PASSWORD:') !== false) break;
+        }
+
+        // Отправляем пароль
+        if (@fwrite($socket, "$mgmt_pass\n") === false) {
+            throw new Exception("Failed to send password");
+        }
+
+        // Ждем подтверждения аутентификации
+        $authResponse = '';
+        while (!feof($socket)) {
+            $line = fgets($socket);
+            if ($line === false) break;
+            $authResponse .= $line;
+            if (strpos($authResponse, 'SUCCESS:') !== false || strpos($authResponse, '>INFO:') !== false) break;
+        }
+
+        // Отправляем команду
+        if (@fwrite($socket, "$command\n") === false) {
+            throw new Exception("Failed to send command");
+        }
+
+        // Читаем ответ
+        $response = '';
+        $expectedEnd = strpos($command, 'status') !== false ? "END\r\n" : ">";
+        while (!feof($socket)) {
+            $line = fgets($socket);
+            if ($line === false) break;
+            $response .= $line;
+            if (strpos($response, $expectedEnd) !== false) break;
+        }
+
+        return $response;
+
+    } catch (Exception $e) {
+        error_log("OpenVPN management error ({$server['name']}): " . $e->getMessage());
+        return false;
+    } finally {
+        @fwrite($socket, "quit\n");
+        @fclose($socket);
+    }
+}
+
+function getOpenVPNStatus($server) {
+    // Проверяем, можно ли делать запрос
+    if (!canRequestStatus($server)) {
+        // Возвращаем кэшированные данные или пустой массив
+        return $_SESSION['cached_status'][$server['name']] ?? [];
+    }
+
+    // Обновляем время последнего запроса
+    updateLastRequestTime($server);
+
+    $response = openvpnManagementCommand($server, "status 2");
+    if (!$response) return $_SESSION['cached_status'][$server['name']] ?? [];
+
+    $clients = [];
+    $lines = explode("\n", $response);
+    $in_client_list = false;
+
+    foreach ($lines as $line) {
+        $line = trim($line);
+
+        if (strpos($line, 'HEADER,CLIENT_LIST') === 0) {
+            $in_client_list = true;
+            continue;
+        }
+
+        if (strpos($line, 'HEADER,ROUTING_TABLE') === 0) {
+            $in_client_list = false;
+            continue;
+        }
+
+        if ($in_client_list && strpos($line, 'CLIENT_LIST') === 0) {
+            $parts = explode(',', $line);
+            if (count($parts) >= 9) {
+                $clients[] = [
+                    'name' => $parts[1],
+                    'real_ip' => $parts[2],
+                    'virtual_ip' => $parts[3],
+                    'bytes_received' => formatBytes($parts[5]),
+                    'bytes_sent' => formatBytes($parts[6]),
+                    'connected_since' => $parts[7],
+                    'username' => $parts[8] ?? $parts[1],
+                    'banned' => isClientBanned($server, $parts[1])
+                ];
+            }
+        }
+    }
+
+  // Кэшируем результат
+    $_SESSION['cached_status'][$server['name']] = $clients;
+
+    return $clients;
+}
+
+function isClientBanned($server, $client_name) {
+    $ccd_file = "{$server['ccd']}/$client_name";
+    return file_exists($ccd_file) && 
+           preg_match('/^disable$/m', file_get_contents($ccd_file));
+}
+
+function kickClient($server, $client_name) {
+    return openvpnManagementCommand($server, "kill $client_name");
+}
+
+function banClient($server, $client_name) {
+    $ccd_file = "{$server['ccd']}/$client_name";
+    
+    // Добавляем директиву disable
+    $content = file_exists($ccd_file) ? file_get_contents($ccd_file) : '';
+    if (!preg_match('/^disable$/m', $content)) {
+        file_put_contents($ccd_file, $content . "\ndisable\n");
+    }
+
+    // Кикаем клиента
+    kickClient($server, $client_name);
+    return true;
+}
+
+function unbanClient($server, $client_name) {
+    $ccd_file = "{$server['ccd']}/$client_name";
+    if (file_exists($ccd_file)) {
+        $content = file_get_contents($ccd_file);
+        $new_content = preg_replace('/^disable$\n?/m', '', $content);
+        file_put_contents($ccd_file, $new_content);
+        return true;
+    }
+    return false;
+}
+
+function formatBytes($bytes) {
+    $bytes = (int)$bytes;
+    if ($bytes <= 0) return '0 B';
+    $units = ['B', 'KB', 'MB', 'GB', 'TB'];
+    $pow = floor(log($bytes)/log(1024));
+    return round($bytes/pow(1024,$pow),2).' '.$units[$pow];
+}
+
+function getBannedClients($server, $active_clients) {
+    $banned = [];
+    $active_names = array_column($active_clients, 'name');
+    
+    if (is_dir($server['ccd'])) {
+        foreach (scandir($server['ccd']) as $file) {
+            if ($file !== '.' && $file !== '..' && is_file("{$server['ccd']}/$file")) {
+                if (isClientBanned($server, $file) && !in_array($file, $active_names)) {
+                    $banned[] = $file;
+                }
+            }
+        }
+    }
+    
+    return $banned;
+}
+
+// Обработка POST-запросов
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+    foreach ($servers as $server_name => $server) {
+        if (isset($_POST["ban-$server_name"])) {
+            banClient($server, $_POST["ban-$server_name"]);
+        } elseif (isset($_POST["unban-$server_name"])) {
+            unbanClient($server, $_POST["unban-$server_name"]);
+        }
+    }
+    header("Location: ".$_SERVER['PHP_SELF']);
+    exit();
+}
+?>
+
+<!DOCTYPE html>
+<html>
+<head>
+    <title><?= htmlspecialchars($page_title) ?></title>
+    <meta http-equiv="refresh" content="<?= REQUEST_INTERVAL ?>">
+    <style>
+        body { font-family: Arial, sans-serif; margin: 20px; }
+        table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
+        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
+        th { background-color: #f2f2f2; }
+        .banned { background-color: #ffeeee; }
+        .actions { white-space: nowrap; }
+        .btn { padding: 3px 8px; margin: 2px; cursor: pointer; border: 1px solid #ccc; border-radius: 3px; }
+        .kick-btn { background-color: #ffcccc; }
+        .ban-btn { background-color: #ff9999; }
+        .unban-btn { background-color: #ccffcc; }
+        .section { margin-bottom: 30px; }
+        .status-badge { padding: 2px 5px; border-radius: 3px; font-size: 0.8em; }
+        .status-active { background-color: #ccffcc; }
+        .status-banned { background-color: #ff9999; }
+        .server-section { border: 1px solid #ddd; padding: 15px; margin-bottom: 20px; border-radius: 5px; }
+    </style>
+</head>
+<body>
+    <h1><?= htmlspecialchars($page_title) ?></h1>
+    
+    <form method="post">
+    <?php foreach ($servers as $server_name => $server): 
+        $clients = getOpenVPNStatus($server);
+        $banned_clients = getBannedClients($server, $clients);
+    ?>
+    <div class="server-section">
+        <h2><?= htmlspecialchars($server['title']) ?></h2>
+        
+        <div class="section">
+            <h3>Active Connections</h3>
+            <table>
+                <thead>
+                    <tr>
+                        <th>Client</th>
+                        <th>Real IP</th>
+                        <th>Virtual IP</th>
+                        <th>Traffic</th>
+                        <th>Connected</th>
+                        <th>Status</th>
+                        <th>Actions</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    <?php foreach ($clients as $client): ?>
+                    <tr class="<?= $client['banned'] ? 'banned' : '' ?>">
+                        <td><?= htmlspecialchars($client['name']) ?></td>
+                        <td><?= htmlspecialchars($client['real_ip']) ?></td>
+                        <td><?= htmlspecialchars($client['virtual_ip']) ?></td>
+                        <td>↓<?= $client['bytes_received'] ?> ↑<?= $client['bytes_sent'] ?></td>
+                        <td><?= htmlspecialchars($client['connected_since']) ?></td>
+                        <td>
+                            <span class="status-badge <?= $client['banned'] ? 'status-banned' : 'status-active' ?>">
+                                <?= $client['banned'] ? 'BANNED' : 'Active' ?>
+                            </span>
+                        </td>
+                        <td class="actions">
+                            <?php if ($client['banned']): ?>
+                                <button type="submit" name="unban-<?= $server_name ?>" value="<?= htmlspecialchars($client['name']) ?>" 
+                                        class="btn unban-btn">Unban</button>
+                            <?php else: ?>
+                                <button type="submit" name="ban-<?= $server_name ?>" value="<?= htmlspecialchars($client['name']) ?>" 
+                                        class="btn ban-btn">Ban</button>
+                            <?php endif; ?>
+                        </td>
+                    </tr>
+                    <?php endforeach; ?>
+                </tbody>
+            </table>
+        </div>
+
+        <?php if (!empty($banned_clients)): ?>
+        <div class="section">
+            <h3>Banned Clients (Not Connected)</h3>
+            <table>
+                <thead>
+                    <tr>
+                        <th>Client Name</th>
+                        <th>Action</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    <?php foreach ($banned_clients as $client): ?>
+                    <tr>
+                        <td><?= htmlspecialchars($client) ?></td>
+                        <td class="actions">
+                            <button type="submit" name="unban-<?= $server_name ?>" value="<?= htmlspecialchars($client) ?>" 
+                                    class="btn unban-btn">Unban</button>
+                        </td>
+                    </tr>
+                    <?php endforeach; ?>
+                </tbody>
+            </table>
+        </div>
+        <?php endif; ?>
+    </div>
+
+    <p>Next update in: <?= REQUEST_INTERVAL - (time() - $_SESSION['last_request_time'][$server['name']]) ?> seconds</p>
+
+    <?php endforeach; ?>
+    </form>
+
+<p>Last update: <?= date('Y-m-d H:i:s') ?></p>
+
+</body>
+</html>