diff --git a/example/s3/network-config.json b/example/s3/network-config.json index b41155c..547f7e9 100644 --- a/example/s3/network-config.json +++ b/example/s3/network-config.json @@ -57,8 +57,8 @@ "type": "GRE", "localIp": "10.10.0.1", "remoteIp": "10.10.0.2", - "port": "", - "serverId": "SWE-HIPHOST" + "serverId": "SWE-HIPHOST", + "serverId2": "DE-FRANKFURT" }, { "id": "if-wg-swe-nl", @@ -66,7 +66,8 @@ "type": "WireGuard", "localIp": "10.20.0.1", "remoteIp": "10.20.0.2", - "serverId": "SWE-HIPHOST" + "serverId": "SWE-HIPHOST", + "serverId2": "NL-AMSTERDAM" }, { "id": "if-gre-de-us", @@ -74,8 +75,8 @@ "type": "GRE", "localIp": "10.10.1.1", "remoteIp": "10.10.1.2", - "port": "", - "serverId": "DE-FRANKFURT" + "serverId": "DE-FRANKFURT", + "serverId2": "US-NEWYORK" }, { "id": "if-ipsec-nl-jp", @@ -83,7 +84,6 @@ "type": "IPSec", "localIp": "10.30.0.1", "remoteIp": "10.30.0.2", - "port": "", "serverId": "NL-AMSTERDAM" } ], diff --git a/frontend/src/NetworkConfigManager.jsx b/frontend/src/NetworkConfigManager.jsx index 34ba1f2..20cdf10 100644 --- a/frontend/src/NetworkConfigManager.jsx +++ b/frontend/src/NetworkConfigManager.jsx @@ -77,6 +77,7 @@ const getEmptyInterface = () => ({ localIp: '', remoteIp: '', serverId: '', + serverId2: '', // Второй сервер (опциональный) }); const getEmptyIpPool = () => ({ @@ -298,9 +299,17 @@ function NetworkConfigManager() { const interfacesByServer = useMemo(() => { const grouped = {}; filteredInterfaces.forEach(iface => { - const key = iface.serverId || '__unassigned__'; - if (!grouped[key]) grouped[key] = []; - grouped[key].push(iface); + // Группируем по первому серверу + const key1 = iface.serverId || '__unassigned__'; + if (!grouped[key1]) grouped[key1] = []; + grouped[key1].push(iface); + + // Если есть второй сервер, также добавляем в его группу + if (iface.serverId2) { + const key2 = iface.serverId2; + if (!grouped[key2]) grouped[key2] = []; + grouped[key2].push(iface); + } }); return grouped; }, [filteredInterfaces]); @@ -492,6 +501,70 @@ function NetworkConfigManager() { } }; + // === Генерация кода MikroTik для настройки IP адресов интерфейсов === + const generateMikrotikInterfaceAddresses = () => { + const interfacesWithBothServers = (config.tunnelInterfaces || []).filter(i => + i.serverId && i.serverId2 && i.localIp && i.remoteIp + ); + + if (interfacesWithBothServers.length === 0) { + return ''; + } + + let code = '\n# === Настройка IP адресов интерфейсов на обоих серверах ===\n'; + code += '# Эти команды нужно выполнить на соответствующих серверах\n\n'; + + // Группируем по серверам + const interfacesByServer = {}; + interfacesWithBothServers.forEach(iface => { + const server1 = getServerInfo(iface.serverId); + const server2 = getServerInfo(iface.serverId2); + + if (!server1 || !server2) return; + + const server1Name = server1.dns || server1.ip || iface.serverId; + const server2Name = server2.dns || server2.ip || iface.serverId2; + const interfaceName = iface.name || `${iface.type}-tunnel`; + + // Для первого сервера - используем localIp + if (!interfacesByServer[server1Name]) { + interfacesByServer[server1Name] = []; + } + interfacesByServer[server1Name].push({ + interfaceName, + ip: iface.localIp, + type: iface.type, + remoteIp: iface.remoteIp, + server2Name + }); + + // Для второго сервера - используем remoteIp + if (!interfacesByServer[server2Name]) { + interfacesByServer[server2Name] = []; + } + interfacesByServer[server2Name].push({ + interfaceName, + ip: iface.remoteIp, + type: iface.type, + remoteIp: iface.localIp, // Для второго сервера remoteIp - это localIp первого + server2Name: server1Name + }); + }); + + 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`; + }); + }); + + code += '\n# Проверка настроенных адресов:\n'; + code += '# /ip address print\n'; + + return code; + }; + // === Генерация кода MikroTik для рекурсивных маршрутов === const generateMikrotikRecursiveRoutes = () => { const recursiveGateways = (config.gateways || []).filter(gw => gw.type === 'recursive'); @@ -575,6 +648,12 @@ function NetworkConfigManager() { code += '# /ip route print where comment~"Recursive"\n'; code += `\n# Всего создано маршрутов: ${validRoutesCount}\n`; + // Добавляем код для настройки IP адресов интерфейсов + const interfaceAddressesCode = generateMikrotikInterfaceAddresses(); + if (interfaceAddressesCode) { + code += interfaceAddressesCode; + } + return code; }; @@ -813,73 +892,96 @@ function NetworkConfigManager() { }; // === Рендер карточки Interface === - const renderInterfaceCard = (iface) => ( -
-
-
-
- - - -
-
{iface.name || '—'}
+ const renderInterfaceCard = (iface) => { + const server = getServerInfo(iface.serverId); + const server2 = getServerInfo(iface.serverId2); + + return ( +
+
+
+
+ + + +
+
{iface.name || '—'}
{iface.type}
-
-
- -
- -
+
+ +
+ + +
-
- -
-
-
Local IP
-
- {iface.localIp || '—'} - {iface.localIp && ( - - )} + +
+
+
Local IP
+
+ {iface.localIp || '—'} + {iface.localIp && ( + + )} +
+
+
+
Remote IP
+
+ {iface.remoteIp || '—'} + {iface.remoteIp && ( + + )} +
-
-
Remote IP
-
- {iface.remoteIp || '—'} - {iface.remoteIp && ( - - )} -
+ + {/* Серверы */} +
+ {server && ( +
+ + Сервер 1: + {server.dns || server.ip} +
+ )} + {server2 && ( +
+ + Сервер 2: + {server2.dns || server2.ip} +
+ )}
-
- ); + ); + }; return (
@@ -1307,13 +1409,14 @@ function NetworkConfigManager() { Тип Local IP Remote IP - Сервер + Серверы Действия {filteredInterfaces.map(iface => { const server = getServerInfo(iface.serverId); + const server2 = getServerInfo(iface.serverId2); return ( {iface.name || '—'} @@ -1336,18 +1439,39 @@ function NetworkConfigManager() { )} - {iface.remoteIp || '—'} - {server ? ( -
- - {server.dns || server.ip} -
- ) : iface.serverId ? ( - {iface.serverId} - ) : ( - - )} + + {iface.remoteIp || '—'} + {iface.remoteIp && ( + + )} + + + +
+ {server ? ( +
+ + {server.dns || server.ip} +
+ ) : iface.serverId ? ( + {iface.serverId} + ) : ( + + )} + {server2 && ( +
+ + {server2.dns || server2.ip} +
+ )} +
@@ -1617,7 +1741,7 @@ function NetworkConfigManager() { placeholder="10.10.0.1" />
-
+
+
+ + setEditingInterface({ ...editingInterface, serverId2: val })} + servers={servers.filter(s => s.id !== editingInterface.serverId && s.ip !== editingInterface.serverId)} + placeholder="Выберите второй сервер (для понимания связи между серверами)..." + /> +
+ Укажите второй сервер, если интерфейс связывает два сервера +
+
+ {editingInterface.serverId && (() => { + const server = getServerInfo(editingInterface.serverId); + return server ? ( +
+
+
+ +
+ Сервер 1: {server.dns || server.ip} + {server.provider && • {server.provider}} + {server.country && • {countryToFlag(server.country)} {server.country}} +
+
+
+
+ ) : null; + })()} + {editingInterface.serverId2 && (() => { + const server2 = getServerInfo(editingInterface.serverId2); + return server2 ? ( +
+
+
+ +
+ Сервер 2: {server2.dns || server2.ip} + {server2.provider && • {server2.provider}} + {server2.country && • {countryToFlag(server2.country)} {server2.country}} +
+
+
+
+ ) : null; + })()}
)}