diff --git a/backend/server.js b/backend/server.js index 384a183..972506c 100644 --- a/backend/server.js +++ b/backend/server.js @@ -176,6 +176,56 @@ app.post('/api/domains-new', async (req, res) => { } }); +// --- IP Ranges Routes --- + +// Get IP ranges from S3 +app.get('/api/ip-ranges', async (req, res) => { + const params = { + Bucket: BUCKET_NAME, + Key: 'domains/ips.txt', + }; + + try { + const data = await s3.getObject(params).promise(); + const fileContent = data.Body.toString('utf-8'); + const ipRanges = fileContent.split('\n').filter(line => line).map(line => { + const parts = line.trim().split(/\s+/); + const ipRange = parts[0] || ''; + const community = parts[1] || ''; + return { ipRange, community }; + }); + res.json(ipRanges); + } catch (error) { + if (error.code === 'NoSuchKey') { + res.json([]); // Return empty array if file does not exist + } else { + console.error(error); + res.status(500).send('Error reading from S3'); + } + } +}); + +// Update IP ranges in S3 +app.post('/api/ip-ranges', async (req, res) => { + const { ipRanges } = req.body; + const fileContent = ipRanges.map(ip => `${ip.ipRange} ${ip.community}`).join('\n'); + + const params = { + Bucket: BUCKET_NAME, + Key: 'domains/ips.txt', + Body: fileContent, + ContentType: 'text/plain', + }; + + try { + await s3.putObject(params).promise(); + res.send('File updated successfully'); + } catch (error) { + console.error(error); + res.status(500).send('Error writing to S3'); + } +}); + // --- Servers Routes (JSON format) --- // Get servers from S3 diff --git a/example/s3/README.md b/example/s3/README.md new file mode 100644 index 0000000..ba3d1e7 --- /dev/null +++ b/example/s3/README.md @@ -0,0 +1,112 @@ +# Примеры файлов S3 для Router Lists UI + +Эта папка содержит примеры файлов, которые хранятся в S3 для работы с FilterManager. + +## Структура папок + +``` +s3/ +├── domains/ # Файлы доменов и IP +│ ├── domains.txt # Основные домены +│ ├── domains_comunity.txt # Домены с community +│ ├── asns.txt # ASN списки +│ └── ips.txt # IP-диапазоны с community +├── filter-manager/ # Файлы FilterManager +│ ├── simple-filters.json # Фильтры упрощённого режима +│ ├── server-filters-*.json # Фильтры для каждого сервера +│ └── config-*.txt # Сгенерированные конфигурации MikroTik +└── server-configs.json # Список серверов (в корне S3) +``` + +## Описание файлов + +### `server-configs.json` +Список всех серверов в расширенном режиме. +```json +[ + { + "id": "server-001", + "name": "SWE-HIPHOST", + "description": "Шведский сервер для стриминга и игр", + "enabled": true, + "createdAt": "2024-01-15T10:30:00.000Z" + } +] +``` + +### `filter-manager/simple-filters.json` +Фильтры для упрощённого режима (применяются ко всем серверам). +```json +[ + { + "community": "65001:100", + "gateway": "SWE-HIPHOST", + "description": "Шведский сервер для стриминга" + } +] +``` + +### `filter-manager/server-filters-{serverId}.json` +Фильтры для конкретного сервера в расширенном режиме. +```json +[ + { + "community": "65001:100", + "gateway": "SWE-HIPHOST", + "description": "Стриминг сервисы" + } +] +``` + +### `domains/ips.txt` +IP-диапазоны с community для маршрутизации. +``` +192.168.1.0/24 65001:100 +10.0.0.0/8 65001:200 +172.16.0.0/12 65001:300 +8.8.8.0/24 65001:400 +``` + +### `filter-manager/config-{serverId}.txt` +Сгенерированная конфигурация MikroTik для конкретного сервера. +``` +// Frouting filter configuration for MikroTik 7.14+ +// Generated automatically +// Date: 2024-01-20T12:00:00.000Z + +if ( +(bgp-communities includes 65001:100) + or +(bgp-communities includes 65001:101) +) +{ + set gw SWE-HIPHOST; accept; +} +else +{ + reject; +} +``` + +## Примеры серверов + +1. **SWE-HIPHOST** (server-001) - Шведский сервер для стриминга +2. **NL-AMSTERDAM** (server-002) - Голландский сервер с низкой задержкой +3. **DE-FRANKFURT** (server-003) - Немецкий сервер для торрентов (отключен) +4. **US-NEWYORK** (server-004) - Американский сервер для Netflix (с каскадной структурой) +5. **JP-TOKYO** (server-005) - Японский сервер для аниме и игр + +## Особенности + +- **Каскадная структура**: Сервер US-NEWYORK демонстрирует конфигурацию с несколькими gateway +- **Отключённые серверы**: DE-FRANKFURT показывает неактивный сервер +- **Разные типы трафика**: Каждый сервер специализируется на определённом типе контента +- **Реалистичные community**: Используются AS:community в формате 65001:XXX + +## Использование + +Эти файлы можно использовать для: +- Тестирования FilterManager +- Демонстрации функциональности +- Обучения работе с системой +- Восстановления данных после сбоя \ No newline at end of file diff --git a/example/s3/domains/ips.txt b/example/s3/domains/ips.txt new file mode 100644 index 0000000..fff2453 --- /dev/null +++ b/example/s3/domains/ips.txt @@ -0,0 +1,8 @@ +192.168.1.0/24 65001:100 +10.0.0.0/8 65001:200 +172.16.0.0/12 65001:300 +8.8.8.0/24 65001:400 +1.1.1.0/24 65001:500 +208.67.222.0/24 65001:600 +9.9.9.0/24 65001:700 +149.112.112.0/24 65001:800 \ No newline at end of file diff --git a/example/s3/filter-manager/config-server-001.txt b/example/s3/filter-manager/config-server-001.txt new file mode 100644 index 0000000..b924d31 --- /dev/null +++ b/example/s3/filter-manager/config-server-001.txt @@ -0,0 +1,18 @@ +// Frouting filter configuration for MikroTik 7.14+ +// Generated automatically +// Date: 2024-01-20T12:00:00.000Z + +if ( +(bgp-communities includes 65001:100) + or +(bgp-communities includes 65001:101) + or +(bgp-communities includes 65001:102) +) +{ + set gw SWE-HIPHOST; accept; +} +else +{ + reject; +} \ No newline at end of file diff --git a/example/s3/filter-manager/config-server-002.txt b/example/s3/filter-manager/config-server-002.txt new file mode 100644 index 0000000..99be606 --- /dev/null +++ b/example/s3/filter-manager/config-server-002.txt @@ -0,0 +1,20 @@ +// Frouting filter configuration for MikroTik 7.14+ +// Generated automatically +// Date: 2024-01-20T12:00:00.000Z + +if ( +(bgp-communities includes 65001:200) + or +(bgp-communities includes 65001:201) + or +(bgp-communities includes 65001:202) + or +(bgp-communities includes 65001:203) +) +{ + set gw NL-AMSTERDAM; accept; +} +else +{ + reject; +} \ No newline at end of file diff --git a/example/s3/filter-manager/config-server-004.txt b/example/s3/filter-manager/config-server-004.txt new file mode 100644 index 0000000..f5a2610 --- /dev/null +++ b/example/s3/filter-manager/config-server-004.txt @@ -0,0 +1,30 @@ +// Frouting filter configuration for MikroTik 7.14+ +// Generated automatically +// Date: 2024-01-20T12:00:00.000Z + +if ( +(bgp-communities includes 65001:400) + or +(bgp-communities includes 65001:401) +) +{ + set gw US-NEWYORK; accept; +} +else if ( +(bgp-communities includes 65001:402) + or +(bgp-communities includes 65001:403) +) +{ + set gw US-LOSANGELES; accept; +} +else if ( +(bgp-communities includes 65001:404) +) +{ + set gw US-CHICAGO; accept; +} +else +{ + reject; +} \ No newline at end of file diff --git a/example/s3/filter-manager/config-server-005.txt b/example/s3/filter-manager/config-server-005.txt new file mode 100644 index 0000000..beb4ca4 --- /dev/null +++ b/example/s3/filter-manager/config-server-005.txt @@ -0,0 +1,20 @@ +// Frouting filter configuration for MikroTik 7.14+ +// Generated automatically +// Date: 2024-01-20T12:00:00.000Z + +if ( +(bgp-communities includes 65001:500) + or +(bgp-communities includes 65001:501) + or +(bgp-communities includes 65001:502) + or +(bgp-communities includes 65001:503) +) +{ + set gw JP-TOKYO; accept; +} +else +{ + reject; +} \ No newline at end of file diff --git a/example/s3/filter-manager/server-filters-server-001.json b/example/s3/filter-manager/server-filters-server-001.json new file mode 100644 index 0000000..d9b4a64 --- /dev/null +++ b/example/s3/filter-manager/server-filters-server-001.json @@ -0,0 +1,17 @@ +[ + { + "community": "65001:100", + "gateway": "SWE-HIPHOST", + "description": "Стриминг сервисы" + }, + { + "community": "65001:101", + "gateway": "SWE-HIPHOST", + "description": "Игровые серверы" + }, + { + "community": "65001:102", + "gateway": "SWE-HIPHOST", + "description": "Социальные сети" + } +] \ No newline at end of file diff --git a/example/s3/filter-manager/server-filters-server-002.json b/example/s3/filter-manager/server-filters-server-002.json new file mode 100644 index 0000000..ca6b91b --- /dev/null +++ b/example/s3/filter-manager/server-filters-server-002.json @@ -0,0 +1,22 @@ +[ + { + "community": "65001:200", + "gateway": "NL-AMSTERDAM", + "description": "Игровые платформы" + }, + { + "community": "65001:201", + "gateway": "NL-AMSTERDAM", + "description": "VoIP сервисы" + }, + { + "community": "65001:202", + "gateway": "NL-AMSTERDAM", + "description": "Облачные сервисы" + }, + { + "community": "65001:203", + "gateway": "NL-AMSTERDAM", + "description": "CDN сети" + } +] \ No newline at end of file diff --git a/example/s3/filter-manager/server-filters-server-003.json b/example/s3/filter-manager/server-filters-server-003.json new file mode 100644 index 0000000..fa8f3b9 --- /dev/null +++ b/example/s3/filter-manager/server-filters-server-003.json @@ -0,0 +1,17 @@ +[ + { + "community": "65001:300", + "gateway": "DE-FRANKFURT", + "description": "Торрент трекеры" + }, + { + "community": "65001:301", + "gateway": "DE-FRANKFURT", + "description": "Файлообменники" + }, + { + "community": "65001:302", + "gateway": "DE-FRANKFURT", + "description": "P2P сети" + } +] \ No newline at end of file diff --git a/example/s3/filter-manager/server-filters-server-004.json b/example/s3/filter-manager/server-filters-server-004.json new file mode 100644 index 0000000..e902c41 --- /dev/null +++ b/example/s3/filter-manager/server-filters-server-004.json @@ -0,0 +1,27 @@ +[ + { + "community": "65001:400", + "gateway": "US-NEWYORK", + "description": "Netflix US" + }, + { + "community": "65001:401", + "gateway": "US-NEWYORK", + "description": "Hulu US" + }, + { + "community": "65001:402", + "gateway": "US-LOSANGELES", + "description": "Disney+ US" + }, + { + "community": "65001:403", + "gateway": "US-LOSANGELES", + "description": "HBO Max US" + }, + { + "community": "65001:404", + "gateway": "US-CHICAGO", + "description": "Amazon Prime US" + } +] \ No newline at end of file diff --git a/example/s3/filter-manager/server-filters-server-005.json b/example/s3/filter-manager/server-filters-server-005.json new file mode 100644 index 0000000..d020541 --- /dev/null +++ b/example/s3/filter-manager/server-filters-server-005.json @@ -0,0 +1,22 @@ +[ + { + "community": "65001:500", + "gateway": "JP-TOKYO", + "description": "Crunchyroll" + }, + { + "community": "65001:501", + "gateway": "JP-TOKYO", + "description": "Funimation" + }, + { + "community": "65001:502", + "gateway": "JP-TOKYO", + "description": "Steam JP" + }, + { + "community": "65001:503", + "gateway": "JP-TOKYO", + "description": "Nintendo Online" + } +] \ No newline at end of file diff --git a/example/s3/filter-manager/simple-filters.json b/example/s3/filter-manager/simple-filters.json new file mode 100644 index 0000000..0a8403f --- /dev/null +++ b/example/s3/filter-manager/simple-filters.json @@ -0,0 +1,27 @@ +[ + { + "community": "65001:100", + "gateway": "SWE-HIPHOST", + "description": "Шведский сервер для стриминга" + }, + { + "community": "65001:200", + "gateway": "NL-AMSTERDAM", + "description": "Голландский сервер для игр" + }, + { + "community": "65001:300", + "gateway": "DE-FRANKFURT", + "description": "Немецкий сервер для торрентов" + }, + { + "community": "65001:400", + "gateway": "US-NEWYORK", + "description": "Американский сервер для Netflix" + }, + { + "community": "65001:500", + "gateway": "JP-TOKYO", + "description": "Японский сервер для аниме" + } +] \ No newline at end of file diff --git a/example/s3/server-configs.json b/example/s3/server-configs.json new file mode 100644 index 0000000..833ab3c --- /dev/null +++ b/example/s3/server-configs.json @@ -0,0 +1,37 @@ +[ + { + "id": "server-001", + "name": "SWE-HIPHOST", + "description": "Шведский сервер для стриминга и игр", + "enabled": true, + "createdAt": "2024-01-15T10:30:00.000Z" + }, + { + "id": "server-002", + "name": "NL-AMSTERDAM", + "description": "Голландский сервер с низкой задержкой", + "enabled": true, + "createdAt": "2024-01-16T14:20:00.000Z" + }, + { + "id": "server-003", + "name": "DE-FRANKFURT", + "description": "Немецкий сервер для торрентов", + "enabled": false, + "createdAt": "2024-01-17T09:15:00.000Z" + }, + { + "id": "server-004", + "name": "US-NEWYORK", + "description": "Американский сервер для Netflix", + "enabled": true, + "createdAt": "2024-01-18T16:45:00.000Z" + }, + { + "id": "server-005", + "name": "JP-TOKYO", + "description": "Японский сервер для аниме и игр", + "enabled": true, + "createdAt": "2024-01-19T11:30:00.000Z" + } +] \ No newline at end of file diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index c86e861..80155bd 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -23,6 +23,7 @@ import DataManager from './DataManager'; import ServerManager from './ServerManager'; import FilterManager from './FilterManager'; import DomainsNewManager from './DomainsNewManager'; +import IPRangesManager from './IPRangesManager'; import './App.css'; import axios from 'axios'; import { @@ -52,6 +53,7 @@ function MainLayout() { const navItems = [ { id: 'domains', title: 'Домены', icon: IconWorld, path: '/domains' }, { id: 'domains-new', title: 'Домены New', icon: IconWorld, path: '/domains-new' }, + { id: 'ip-ranges', title: 'IP-диапазоны', icon: IconNetwork, path: '/ip-ranges' }, { id: 'asns', title: 'AS', icon: IconNetwork, path: '/asns' }, { id: 'servers', title: 'Серверы', icon: IconServer, path: '/servers' }, { id: 'filters', title: 'Фильтры', icon: IconFilter, path: '/filters' }, @@ -98,6 +100,7 @@ function MainLayout() { /> } /> } /> + } /> { + fetchItems(); + }, []); + + const fetchItems = async () => { + setLoading(true); + try { + const response = await axios.get(`${API_URL}/ip-ranges`); + setItems(response.data); + setError(''); + } catch (error) { + console.error('Error fetching ip-ranges:', error); + setItems([]); + } finally { + setLoading(false); + } + }; + + const handleAdd = () => { + setEditingIndex(null); + setEditingItem({ ipRange: '', community: '' }); + }; + + const handleEdit = (index) => { + setEditingIndex(index); + setEditingItem({ ...items[index] }); + }; + + const handleSave = () => { + if (!editingItem.ipRange.trim() || !editingItem.community.trim()) { + setError('IP-диапазон и Community обязательны для заполнения.'); + return; + } + + const updatedItems = [...items]; + if (editingIndex !== null) { + updatedItems[editingIndex] = { ...editingItem }; + } else { + updatedItems.push({ ...editingItem }); + } + + setItems(updatedItems); + setEditingIndex(null); + setEditingItem({ ipRange: '', community: '' }); + }; + + const handleCancel = () => { + setEditingIndex(null); + setEditingItem({ ipRange: '', community: '' }); + }; + + const handleDelete = (index) => { + const updatedItems = items.filter((_, i) => i !== index); + setItems(updatedItems); + }; + + const handleSaveToS3 = async () => { + setLoading(true); + try { + await axios.post(`${API_URL}/ip-ranges`, { ipRanges: items }); + setSuccess('IP-диапазоны успешно сохранены!'); + setTimeout(() => setSuccess(''), 3000); + } catch (error) { + console.error('Error saving ip-ranges:', error); + setError('Не удалось сохранить IP-диапазоны.'); + } finally { + setLoading(false); + } + }; + + const handleUpload = async (event) => { + const file = event.target.files[0]; + if (!file) return; + + const reader = new FileReader(); + reader.onload = (e) => { + const content = e.target.result; + const lines = content.split('\n').filter(line => line.trim()); + const parsedItems = lines.map(line => { + const parts = line.trim().split(/\s+/); + return { + ipRange: parts[0] || '', + community: parts[1] || '' + }; + }); + setItems(parsedItems); + setSuccess(`Загружено ${parsedItems.length} IP-диапазонов!`); + setTimeout(() => setSuccess(''), 3000); + }; + reader.readAsText(file); + }; + + const handleDownload = () => { + const content = items.map(item => `${item.ipRange} ${item.community}`).join('\n'); + const blob = new Blob([content], { type: 'text/plain' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = 'ips.txt'; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + }; + + const filteredItems = items.filter(item => + item.ipRange.toLowerCase().includes(searchTerm.toLowerCase()) || + item.community.toLowerCase().includes(searchTerm.toLowerCase()) + ); + + return ( +
+
+
+
+

Управление IP-диапазонами

+
Главная / IP-диапазоны
+
+
+
+ + + +
+
+
+
+ + {/* Уведомления */} + {error && ( +
+ + {error} + +
+ )} + {success && ( +
+ + {success} + +
+ )} + + {/* Панель поиска и сохранения */} +
+
+
+
+
+ + + + setSearchTerm(e.target.value)} + /> +
+
+
+
+ + +
+
+
+
+
+ + {/* Таблица IP-диапазонов */} +
+
+

+ + IP-диапазоны ({filteredItems.length} из {items.length}) +

+
+
+ {loading ? ( +
+
+ Загрузка... +
+ Загрузка IP-диапазонов... +
+ ) : filteredItems.length === 0 ? ( +
+ +

Нет IP-диапазонов

+ +
+ ) : ( +
+ + + + + + + + + + {filteredItems.map((item, index) => ( + + + + + + ))} + +
IP-ДИАПАЗОНCOMMUNITYДЕЙСТВИЯ
+ {editingIndex === index ? ( + setEditingItem({ ...editingItem, ipRange: e.target.value })} + placeholder="192.168.1.0/24" + /> + ) : ( +
+ + + + {item.ipRange} +
+ )} +
+ {editingIndex === index ? ( + setEditingItem({ ...editingItem, community: e.target.value })} + placeholder="65001:100" + /> + ) : ( +
+ + + + {item.community} +
+ )} +
+ {editingIndex === index ? ( +
+ + +
+ ) : ( +
+ + +
+ )} +
+
+ )} +
+
+
+ ); +} + +export default IPRangesManager; \ No newline at end of file