diff --git a/backend/routes/mikrotikConfigRoutes.js b/backend/routes/mikrotikConfigRoutes.js
index 81cb039..edfeea1 100644
--- a/backend/routes/mikrotikConfigRoutes.js
+++ b/backend/routes/mikrotikConfigRoutes.js
@@ -15,7 +15,7 @@ const {
buildMikrotikRecursiveRoutes,
getParentGateway,
} = require('../utils/mikrotikInterfaceGenerator');
-const { createRosClient, applyBlock } = require('../services/mikrotikApplyService');
+const { createRosClient, applyBlock, rosPrint } = require('../services/mikrotikApplyService');
const IPSEC_PASSWORDS_KEY = 'network-config/ipsec-passwords.json';
const NETWORK_CONFIG_KEY = 'network-config.json';
@@ -1146,6 +1146,50 @@ async function runScript(req, res) {
}
}
+/**
+ * GET /api/mikrotik/address-lists?serverId=xxx
+ * Возвращает address-list списки ban и ban_counter с выбранного роутера (MikroTik).
+ */
+async function getAddressLists(req, res) {
+ try {
+ const serverId = req.query?.serverId;
+ if (!serverId) {
+ return sendError(res, 400, 'serverId is required', 'E_BAD_REQUEST');
+ }
+
+ const servers = await readServersFromS3();
+ const server = servers.find((s) => (s.id || s.dns || s.ip) === serverId);
+ if (!server || (server.type !== 'jumphost' && server.type !== 'home')) {
+ return sendError(res, 400, 'Jumphost or home server not found', 'E_NOT_FOUND');
+ }
+
+ const creds = getMikrotikCredentials(server);
+ if (!creds) {
+ return sendError(res, 400, 'MikroTik credentials not configured for this server', 'E_CREDENTIALS');
+ }
+
+ const client = createRosClient(creds);
+ const path = 'ip/firewall/address-list';
+
+ const [ban, banCounter] = await Promise.all([
+ rosPrint(client, path, { list: 'ban' }),
+ rosPrint(client, path, { list: 'ban_counter' }),
+ ]);
+
+ return sendOk(res, {
+ serverId,
+ serverLabel: server.dns || server.ip || serverId,
+ ban: Array.isArray(ban) ? ban : [],
+ ban_counter: Array.isArray(banCounter) ? banCounter : [],
+ });
+ } catch (error) {
+ const msg = error.response?.data?.detail || error.response?.data?.message || error.message || 'Ошибка получения address-list';
+ const status = error.response?.status;
+ console.error('getAddressLists:', error);
+ return sendError(res, status && status >= 400 ? status : 502, msg, 'E_ADDRESS_LISTS');
+ }
+}
+
module.exports = {
generateMikrotikConfig,
generateInterfaces,
@@ -1158,4 +1202,5 @@ module.exports = {
runPingViaRouter,
speedTestViaTunnel,
loadNetworkConfig,
+ getAddressLists,
};
diff --git a/backend/server.js b/backend/server.js
index 4bf39a1..9942158 100644
--- a/backend/server.js
+++ b/backend/server.js
@@ -467,6 +467,7 @@ app.post('/api/mikrotik/traceroute', writeLimiter, mikrotikConfigRoutes.tracerou
app.post('/api/mikrotik/speed-test', writeLimiter, mikrotikConfigRoutes.speedTestViaTunnel);
app.post('/api/mikrotik/apply', mikrotikConfigRoutes.applyMikrotikConfig);
app.post('/api/mikrotik/run-script', mikrotikConfigRoutes.runScript);
+app.get('/api/mikrotik/address-lists', mikrotikConfigRoutes.getAddressLists);
// === TRAFFIC STATS (MikroTik interfaces by jumphost) ===
app.get('/api/traffic/interface-stats', trafficRoutes.getInterfaceStats);
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 25b2506..cd2e0c8 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -24,7 +24,8 @@ import {
IconLayoutSidebarLeftExpand,
IconLayoutNavbar,
IconChartPie,
- IconClockPlay
+ IconClockPlay,
+ IconShield
} from '@tabler/icons-react';
import ServerManager from './ServerManager';
import FilterManager from './FilterManager';
@@ -44,6 +45,7 @@ import NetworkMapDashboard from './NetworkMapDashboard.jsx';
import NetworkMapSchedulerPage from './NetworkMapSchedulerPage.jsx';
import MikrotikBackupsManager from './MikrotikBackupsManager.jsx';
import PingServicesManager from './PingServicesManager.jsx';
+import FirewallPage from './FirewallPage.jsx';
import SettingsPage from './SettingsPage.jsx';
import './App.css';
import { NotifyProvider } from './components/NotifyProvider.jsx';
@@ -64,7 +66,7 @@ function LanguageProvider({ children }) {
home: 'Главная', data: 'Данные', management: 'Управление', tools: 'Инструменты',
dashboard: 'Панель', trafficTraffic: 'Расход трафика', networkMap: 'Карта сети', domains: 'Домены', ipRanges: 'IP-диапазоны', asns: 'AS',
communities: 'Community', servers: 'Серверы', filters: 'Фильтры', billing: 'Биллинг', autoUrls: 'Авто URL',
- easySwitch: 'Easy Switch', networkConfig: 'Сетевые настройки', mikrotikBackups: 'MikroTik Бэкапы', pingServices: 'Пинг сервисов',
+ easySwitch: 'Easy Switch', networkConfig: 'Сетевые настройки', mikrotikBackups: 'MikroTik Бэкапы', pingServices: 'Пинг сервисов', firewall: 'Firewall',
light: 'Светлая', dark: 'Тёмная',
layoutSidebar: 'Сайдбар', layoutHorizontal: 'Верхнее меню'
},
@@ -72,7 +74,7 @@ function LanguageProvider({ children }) {
home: 'Home', data: 'Data', management: 'Management', tools: 'Tools',
dashboard: 'Dashboard', trafficTraffic: 'Traffic Usage', networkMap: 'Network Map', domains: 'Domains', ipRanges: 'IP Ranges', asns: 'ASNs',
communities: 'Communities', servers: 'Servers', filters: 'Filters', billing: 'Billing', autoUrls: 'Auto URLs',
- easySwitch: 'Easy Switch', networkConfig: 'Network Config', mikrotikBackups: 'MikroTik Backups', pingServices: 'Ping Services',
+ easySwitch: 'Easy Switch', networkConfig: 'Network Config', mikrotikBackups: 'MikroTik Backups', pingServices: 'Ping Services', firewall: 'Firewall',
light: 'Light', dark: 'Dark',
layoutSidebar: 'Sidebar', layoutHorizontal: 'Top menu'
}
@@ -231,6 +233,7 @@ function MainLayout() {
{ id: 'auto-urls', title: t('autoUrls'), path: '/auto-urls', icon: IconDownload },
{ id: 'mikrotik-backups', title: t('mikrotikBackups'), path: '/mikrotik-backups', icon: IconDatabase },
{ id: 'mikrotik-tools', title: 'MikroTik Инструменты', path: '/mikrotik-tools', icon: IconNetwork },
+ { id: 'firewall', title: t('firewall'), path: '/firewall', icon: IconShield },
{ id: 'interface-speed', title: 'Скорость интерфейсов', path: '/interface-speed', icon: IconNetwork },
{ id: 'ping-services', title: t('pingServices'), path: '/ping-services', icon: IconNetwork },
{ id: 'scheduler', title: 'Планировщик карты сети', path: '/scheduler', icon: IconClockPlay }
@@ -400,6 +403,7 @@ function MainLayout() {
| # | +IP-адрес | +Таймаут | +Комментарий | ++ |
|---|---|---|---|---|
| {(page - 1) * PAGE_SIZE + idx + 1} | +
+
+ {entry.address || '—'}
+
+ |
+ {entry.timeout || '—'} | +{entry.comment || '—'} | ++ |
+ Выберите jumphost или home-роутер для просмотра списков ban и ban_counter. +
+Выберите сервер выше, чтобы загрузить address-list (ban и ban_counter).
+