diff --git a/frontend/src/NetworkConfigManager.jsx b/frontend/src/NetworkConfigManager.jsx index f1f007f..6f41855 100644 --- a/frontend/src/NetworkConfigManager.jsx +++ b/frontend/src/NetworkConfigManager.jsx @@ -551,7 +551,7 @@ function NetworkConfigManager() { remoteIp: remoteIp, serverId: templateServer1, serverId2: templateServer2, - ipsecPasswordId: templateType === 'IPSec' && templateIpsecPasswordId ? templateIpsecPasswordId : '' + ipsecPasswordId: (templateType === 'IPSec' || templateType === 'GRE') && templateIpsecPasswordId ? templateIpsecPasswordId : '' }; const conflicts = checkInterfaceIpConflict(newInterface); @@ -917,12 +917,12 @@ function NetworkConfigManager() { } // Если создан новый пароль и открыт шаблон интерфейса, автоматически выбираем его - if (savedPasswordId && interfaceTemplateModalOpen && templateType === 'IPSec') { + if (savedPasswordId && interfaceTemplateModalOpen && (templateType === 'IPSec' || templateType === 'GRE')) { setTemplateIpsecPasswordId(savedPasswordId); } - // Если создан новый пароль и открыт модал интерфейса с типом IPSec, автоматически выбираем его - if (savedPasswordId && interfaceModalOpen && editingInterface?.type === 'IPSec') { + // Если создан новый пароль и открыт модал интерфейса с типом IPSec или GRE, автоматически выбираем его + if (savedPasswordId && interfaceModalOpen && (editingInterface?.type === 'IPSec' || editingInterface?.type === 'GRE')) { setEditingInterface({ ...editingInterface, ipsecPasswordId: savedPasswordId }); } } catch (error) { @@ -1019,7 +1019,7 @@ function NetworkConfigManager() { }; // === Генерация кода MikroTik для настройки IP адресов интерфейсов === - const generateMikrotikInterfaceAddresses = () => { + const generateMikrotikInterfaceAddresses = async () => { const interfacesWithBothServers = (config.tunnelInterfaces || []).filter(i => i.serverId && i.serverId2 && i.localIp && i.remoteIp ); @@ -1028,6 +1028,23 @@ function NetworkConfigManager() { return []; } + // Загружаем пароли для интерфейсов с IPSec + const passwordIds = [...new Set(interfacesWithBothServers + .filter(i => i.ipsecPasswordId) + .map(i => i.ipsecPasswordId) + )]; + + const passwordMap = {}; + for (const passwordId of passwordIds) { + try { + const response = await api.get(`/ipsec-passwords/${passwordId}`); + passwordMap[passwordId] = response.data?.password || ''; + } catch (error) { + console.error(`Error loading IPSec password ${passwordId}:`, error); + passwordMap[passwordId] = ''; + } + } + // Группируем по серверам const interfacesByServer = {}; interfacesWithBothServers.forEach(iface => { @@ -1057,7 +1074,9 @@ function NetworkConfigManager() { remoteIp: iface.remoteIp, type: iface.type, server2Name, - server2Info: server2 + server2Info: server2, + ipsecPasswordId: iface.ipsecPasswordId || null, + ipsecPassword: iface.ipsecPasswordId ? passwordMap[iface.ipsecPasswordId] : null }); // Для второго сервера - МЕНЯЕМ МЕСТАМИ: remoteIp становится localIp, localIp становится remoteIp @@ -1074,7 +1093,9 @@ function NetworkConfigManager() { remoteIp: iface.localIp, // На втором сервере localIp первого становится remoteIp type: iface.type, server2Name: server1Name, - server2Info: server1 + server2Info: server1, + ipsecPasswordId: iface.ipsecPasswordId || null, + ipsecPassword: iface.ipsecPasswordId ? passwordMap[iface.ipsecPasswordId] : null }); }); @@ -1102,6 +1123,41 @@ function NetworkConfigManager() { code += `# Связь с сервером: ${iface.server2Name}\n`; code += `# Local IP: ${iface.localIp}\n`; code += `# Remote IP: ${iface.remoteIp}\n`; + + // Для GRE туннелей - создаем туннель, опционально с IPSec + if (iface.type === 'GRE') { + const remoteServerIp = iface.server2Info?.ip || iface.server2Name; + const localServerIp = server.ip || serverName; + + if (iface.ipsecPasswordId && iface.ipsecPassword) { + // GRE туннель с IPSec + code += `# Создание GRE туннеля с IPSec\n`; + code += `/interface gre add name="${iface.interfaceName}" remote-address=${remoteServerIp} local-address=${localServerIp} keepalive=10s\n`; + code += '\n'; + + // Создаем IPSec peer + code += `# Настройка IPSec peer для ${iface.interfaceName}\n`; + code += `/ip ipsec peer add name="${iface.interfaceName}-peer" address=${remoteServerIp}/32 local-address=${localServerIp} exchange-mode=ike2 passive=no\n`; + code += '\n'; + + // Создаем IPSec identity + code += `# Настройка IPSec identity для ${iface.interfaceName}\n`; + code += `/ip ipsec identity add peer="${iface.interfaceName}-peer" auth-method=pre-shared-key secret="${iface.ipsecPassword}"\n`; + code += '\n'; + + // Создаем IPSec policy + code += `# Настройка IPSec policy для ${iface.interfaceName}\n`; + code += `/ip ipsec policy add src-address=${iface.localIp}/30 dst-address=${iface.remoteIp}/30 sa-src-address=${localServerIp} sa-dst-address=${remoteServerIp} peer="${iface.interfaceName}-peer" tunnel=yes\n`; + code += '\n'; + } else { + // GRE туннель без IPSec (голый GRE) + code += `# Создание GRE туннеля (без IPSec)\n`; + code += `/interface gre add name="${iface.interfaceName}" remote-address=${remoteServerIp} local-address=${localServerIp} keepalive=10s\n`; + code += '\n'; + } + } + + // Добавляем IP адрес на интерфейс code += `/ip address add address=${iface.localIp}/30 interface="${iface.interfaceName}" comment="Interface: ${iface.interfaceName} (${iface.type}) to ${iface.server2Name}"\n`; code += '\n'; }); @@ -1121,7 +1177,7 @@ function NetworkConfigManager() { }; // === Генерация кода MikroTik для рекурсивных маршрутов === - const generateMikrotikRecursiveRoutes = () => { + const generateMikrotikRecursiveRoutes = async () => { const recursiveGateways = (config.gateways || []).filter(gw => gw.type === 'recursive'); const blocks = []; @@ -1241,7 +1297,7 @@ function NetworkConfigManager() { } // Генерируем блоки для IP адресов интерфейсов - const interfaceBlocks = generateMikrotikInterfaceAddresses(); + const interfaceBlocks = await generateMikrotikInterfaceAddresses(); if (interfaceBlocks && interfaceBlocks.length > 0) { blocks.push(...interfaceBlocks); } @@ -1250,10 +1306,18 @@ function NetworkConfigManager() { }; // === Обработчик кнопки "Код для MikroTik" === - const handleGenerateMikrotikCode = () => { - const code = generateMikrotikRecursiveRoutes(); - setGeneratedMikrotikCode(code); - setMikrotikCodeModalOpen(true); + const handleGenerateMikrotikCode = async () => { + setLoading(true); + try { + const code = await generateMikrotikRecursiveRoutes(); + setGeneratedMikrotikCode(code); + setMikrotikCodeModalOpen(true); + } catch (error) { + console.error('Error generating MikroTik code:', error); + notify.error('Ошибка при генерации кода MikroTik'); + } finally { + setLoading(false); + } }; // === Копирование кода MikroTik === @@ -2744,11 +2808,11 @@ function NetworkConfigManager() { name="type" type="select" value={editingInterface.type} - onChange={(val) => setEditingInterface({ ...editingInterface, type: val, ipsecPasswordId: val !== 'IPSec' ? '' : editingInterface.ipsecPasswordId })} + onChange={(val) => setEditingInterface({ ...editingInterface, type: val, ipsecPasswordId: (val !== 'IPSec' && val !== 'GRE') ? '' : editingInterface.ipsecPasswordId })} options={INTERFACE_TYPES} /> - {editingInterface.type === 'IPSec' && ( + {(editingInterface.type === 'IPSec' || editingInterface.type === 'GRE') && (
@@ -2778,7 +2842,7 @@ function NetworkConfigManager() {
- Выберите сохраненный IPSec пароль или создайте новый + Выберите сохраненный IPSec пароль или создайте новый (опционально для GRE)
)} @@ -3043,7 +3107,7 @@ function NetworkConfigManager() { />
Оставьте пустым для автогенерации
- {templateType === 'IPSec' && ( + {(templateType === 'IPSec' || templateType === 'GRE') && (
@@ -3073,7 +3137,7 @@ function NetworkConfigManager() {
- Выберите сохраненный IPSec пароль или создайте новый + Выберите сохраненный IPSec пароль или создайте новый (опционально для GRE)
)}