diff --git a/frontend/src/FirewallPage.jsx b/frontend/src/FirewallPage.jsx index e927eb6..532ea52 100644 --- a/frontend/src/FirewallPage.jsx +++ b/frontend/src/FirewallPage.jsx @@ -229,6 +229,8 @@ export default function FirewallPage() { const [analysisResult, setAnalysisResult] = useState(null); const [applyConfirmOpen, setApplyConfirmOpen] = useState(false); const [applying, setApplying] = useState(false); + const [ipInfoMap, setIpInfoMap] = useState({}); + const [ipInfoLoading, setIpInfoLoading] = useState(false); const routerServers = useMemo( () => @@ -290,8 +292,41 @@ export default function FirewallPage() { setMinCountN(n); const result = analyzeBanList(data.ban, n); setAnalysisResult(result); + setIpInfoMap({}); }; + // Подгрузка AS/орг с ipinfo.io для подсетей из анализа (лимит 30, с задержкой между запросами) + useEffect(() => { + const suggestions = analysisResult?.suggestions; + if (!suggestions?.length) return; + const maxFetch = 30; + const slice = suggestions.slice(0, maxFetch); + let cancelled = false; + setIpInfoLoading(true); + (async () => { + for (let i = 0; i < slice.length && !cancelled; i++) { + const s = slice[i]; + const firstIp = s.subnet.split('/')[0]; + try { + const res = await fetch(`https://ipinfo.io/${firstIp}/json`, { method: 'GET' }); + if (!res.ok) continue; + const info = await res.json(); + if (!cancelled) { + setIpInfoMap((prev) => ({ + ...prev, + [s.subnet]: { org: info.org, country: info.country, city: info.city }, + })); + } + } catch (_) { + if (!cancelled) setIpInfoMap((prev) => ({ ...prev, [s.subnet]: null })); + } + if (i < slice.length - 1) await new Promise((r) => setTimeout(r, 180)); + } + if (!cancelled) setIpInfoLoading(false); + })(); + return () => { cancelled = true; }; + }, [analysisResult?.suggestions]); + const handleApplySummary = async () => { if (!serverId || !analysisResult?.suggestions?.length) return; setApplying(true); @@ -422,6 +457,7 @@ export default function FirewallPage() { setAnalysisOpen(false); setAnalysisResult(null); setApplyConfirmOpen(false); + setIpInfoMap({}); }} title="Анализ списка ban" size="lg" @@ -455,6 +491,9 @@ export default function FirewallPage() { <>
Найдено {analysisResult.suggestions.length} подсетей /24 для замены: удалить одиночные IP и добавить одну запись на подсеть. + {ipInfoLoading && ( + (загрузка AS/хостер с ipinfo.io…) + )}
| Подсеть | Кол-во IP | +AS / Хостер | +Ссылка | Действие |
|---|---|---|---|---|
| {s.subnet} | -{s.count} | -Удалить {s.count} записей → добавить 1 | -||
| {s.subnet} | +{s.count} | ++ {info === undefined + ? (ipInfoLoading ? '…' : '—') + : info + ? (info.org || info.country ? [info.org, info.country].filter(Boolean).join(' · ') : '—') + : '—'} + | ++ + ipinfo.io + + | +Удалить {s.count} записей → добавить 1 | +