From fdc8b1f4587b78091233bc9135d572428f829f28 Mon Sep 17 00:00:00 2001 From: shats Date: Thu, 22 Jan 2026 13:18:46 +0700 Subject: [PATCH] feat(NetworkConfigManager): add optional second interface name for dual server configurations; enhance UI to support interface naming for both servers --- example/s3/network-config.json | 2 + frontend/src/NetworkConfigManager.jsx | 110 ++++++++++++++++++++------ 2 files changed, 87 insertions(+), 25 deletions(-) diff --git a/example/s3/network-config.json b/example/s3/network-config.json index 547f7e9..1d890d6 100644 --- a/example/s3/network-config.json +++ b/example/s3/network-config.json @@ -54,6 +54,7 @@ { "id": "if-gre-swe-de", "name": "gre-swe-de", + "name2": "gre-de-swe", "type": "GRE", "localIp": "10.10.0.1", "remoteIp": "10.10.0.2", @@ -63,6 +64,7 @@ { "id": "if-wg-swe-nl", "name": "wg0", + "name2": "wg1", "type": "WireGuard", "localIp": "10.20.0.1", "remoteIp": "10.20.0.2", diff --git a/frontend/src/NetworkConfigManager.jsx b/frontend/src/NetworkConfigManager.jsx index 20cdf10..7e75e0c 100644 --- a/frontend/src/NetworkConfigManager.jsx +++ b/frontend/src/NetworkConfigManager.jsx @@ -73,6 +73,7 @@ const getEmptyGateway = () => ({ const getEmptyInterface = () => ({ id: `if-${Date.now()}-${Math.random().toString(16).slice(2, 6)}`, name: '', + name2: '', // Имя интерфейса на втором сервере (опционально) type: 'GRE', localIp: '', remoteIp: '', @@ -511,8 +512,10 @@ function NetworkConfigManager() { return ''; } - let code = '\n# === Настройка IP адресов интерфейсов на обоих серверах ===\n'; - code += '# Эти команды нужно выполнить на соответствующих серверах\n\n'; + let code = '\n# ====================================================================\n'; + code += '# === НАСТРОЙКА IP АДРЕСОВ ИНТЕРФЕЙСОВ НА ОБОИХ СЕРВЕРАХ ===\n'; + code += '# Эти команды нужно выполнить на соответствующих серверах\n'; + code += '# ====================================================================\n\n'; // Группируем по серверам const interfacesByServer = {}; @@ -524,43 +527,84 @@ function NetworkConfigManager() { const server1Name = server1.dns || server1.ip || iface.serverId; const server2Name = server2.dns || server2.ip || iface.serverId2; - const interfaceName = iface.name || `${iface.type}-tunnel`; - // Для первого сервера - используем localIp + // Имя интерфейса для первого сервера + const interfaceName1 = iface.name || `${iface.type}-tunnel`; + // Имя интерфейса для второго сервера (может отличаться) + const interfaceName2 = iface.name2 || iface.name || `${iface.type}-tunnel`; + + // Для первого сервера - используем localIp как local, remoteIp как remote if (!interfacesByServer[server1Name]) { - interfacesByServer[server1Name] = []; + interfacesByServer[server1Name] = { + serverInfo: server1, + interfaces: [] + }; } - interfacesByServer[server1Name].push({ - interfaceName, - ip: iface.localIp, - type: iface.type, + interfacesByServer[server1Name].interfaces.push({ + interfaceName: interfaceName1, + localIp: iface.localIp, remoteIp: iface.remoteIp, - server2Name + type: iface.type, + server2Name, + server2Info: server2 }); - // Для второго сервера - используем remoteIp + // Для второго сервера - МЕНЯЕМ МЕСТАМИ: remoteIp становится localIp, localIp становится remoteIp if (!interfacesByServer[server2Name]) { - interfacesByServer[server2Name] = []; + interfacesByServer[server2Name] = { + serverInfo: server2, + interfaces: [] + }; } - interfacesByServer[server2Name].push({ - interfaceName, - ip: iface.remoteIp, + interfacesByServer[server2Name].interfaces.push({ + interfaceName: interfaceName2, + localIp: iface.remoteIp, // На втором сервере remoteIp первого становится localIp + remoteIp: iface.localIp, // На втором сервере localIp первого становится remoteIp type: iface.type, - remoteIp: iface.localIp, // Для второго сервера remoteIp - это localIp первого - server2Name: server1Name + server2Name: server1Name, + server2Info: server1 }); }); - Object.entries(interfacesByServer).forEach(([serverName, interfaces]) => { - code += `\n# --- Команды для сервера: ${serverName} ---\n`; - interfaces.forEach(iface => { - code += `# Интерфейс: ${iface.interfaceName} (${iface.type}) - связь с ${iface.server2Name}\n`; - code += `/ip address add address=${iface.ip}/32 interface="${iface.interfaceName}" comment="Interface: ${iface.interfaceName} (${iface.type}) to ${iface.server2Name}"\n`; + // Сортируем серверы по имени для консистентности + const sortedServers = Object.entries(interfacesByServer).sort(([a], [b]) => a.localeCompare(b)); + + sortedServers.forEach(([serverName, serverData], index) => { + const server = serverData.serverInfo; + + // Отдельный блок для каждого сервера + code += '\n'; + code += '# ' + '='.repeat(70) + '\n'; + code += `# СЕРВЕР ${index + 1}: ${serverName}\n`; + if (server.provider) { + code += `# Провайдер: ${server.provider}\n`; + } + if (server.country) { + code += `# Страна: ${server.country}\n`; + } + if (server.ip && server.ip !== serverName) { + code += `# IP: ${server.ip}\n`; + } + code += '# ' + '='.repeat(70) + '\n'; + code += '\n'; + + serverData.interfaces.forEach((iface, ifaceIndex) => { + code += `# Интерфейс ${ifaceIndex + 1}: ${iface.interfaceName} (${iface.type})\n`; + code += `# Связь с сервером: ${iface.server2Name}\n`; + code += `# Local IP: ${iface.localIp}\n`; + code += `# Remote IP: ${iface.remoteIp}\n`; + code += `/ip address add address=${iface.localIp}/32 interface="${iface.interfaceName}" comment="Interface: ${iface.interfaceName} (${iface.type}) to ${iface.server2Name}"\n`; + code += '\n'; }); + + code += '# Проверка настроенных адресов на этом сервере:\n'; + code += '# /ip address print\n'; + code += '\n'; }); - code += '\n# Проверка настроенных адресов:\n'; - code += '# /ip address print\n'; + code += '# ' + '='.repeat(70) + '\n'; + code += '# КОНЕЦ КОНФИГУРАЦИИ IP АДРЕСОВ ИНТЕРФЕЙСОВ\n'; + code += '# ' + '='.repeat(70) + '\n'; return code; }; @@ -967,6 +1011,7 @@ function NetworkConfigManager() { Сервер 1: {server.dns || server.ip} + {iface.name && ({iface.name})} )} {server2 && ( @@ -974,6 +1019,9 @@ function NetworkConfigManager() { Сервер 2: {server2.dns || server2.ip} + {(iface.name2 || iface.name) && ( + ({iface.name2 || iface.name}) + )} )} @@ -1714,7 +1762,7 @@ function NetworkConfigManager() {
setEditingInterface({ ...editingInterface, name: val })} @@ -1722,6 +1770,18 @@ function NetworkConfigManager() { required />
+ {editingInterface.serverId2 && ( +
+ setEditingInterface({ ...editingInterface, name2: val })} + placeholder="gre-tunnel2" + /> +
Если не указано, будет использовано имя с сервера 1
+
+ )}