diff --git a/frontend/src/IPRangesManager.jsx b/frontend/src/IPRangesManager.jsx index 2f80ca8..a3c8084 100644 --- a/frontend/src/IPRangesManager.jsx +++ b/frontend/src/IPRangesManager.jsx @@ -228,7 +228,7 @@ function IPRangesManager() { const [analysisResultsOpen, setAnalysisResultsOpen] = useState(false); const [analysisPreview, setAnalysisPreview] = useState(null); const [overwriteConfirmOpen, setOverwriteConfirmOpen] = useState(false); - const [analyzeFilters, setAnalyzeFilters] = useState({ community: '', minMask: 0, maxMask: 32, type: 'any' }); + const [analyzeFilters, setAnalyzeFilters] = useState({ community: '', minMask: 0, maxMask: 32, type: 'any', supernet16: false }); const handlePreviewDiff = () => { const valid = items.filter(i => isValidCidr(i.ipRange) && isValidCommunity(i.community)) @@ -437,6 +437,7 @@ function IPRangesManager() { parts.push(`Маска: /${analyzeFilters.minMask}..../${analyzeFilters.maxMask}`); const typeLabel = analyzeFilters.type === 'any' ? 'любой' : (analyzeFilters.type === 'private' ? 'только приватные' : (analyzeFilters.type === 'public' ? 'только публичные' : 'только CGNAT')); parts.push(`Тип: ${typeLabel}`); + parts.push(`Агрегировать >2 префиксов в одном /16 до /16: ${analyzeFilters.supernet16 ? 'да' : 'нет'}`); return parts.join('\n'); }; @@ -522,6 +523,28 @@ function IPRangesManager() { return out; }; + // Агрессивная агрегация: если в одном /16 > 2 префиксов — свернуть в /16 + const get16BaseCidr = (cidr) => { + const ip = String(cidr).split('/')[0]; + const ipNum = ipToInt(ip); + const start = ipNum & (~0n << 16n); + return `${intToIp(start)}/16`; + }; + + const applySupernet16 = (cidrs) => { + const buckets = new Map(); + for (const c of cidrs) { + const base16 = get16BaseCidr(c); + if (!buckets.has(base16)) buckets.set(base16, []); + buckets.get(base16).push(c); + } + const out = []; + for (const [base16, list] of buckets) { + if (list.length > 2) out.push(base16); else out.push(...list); + } + return Array.from(new Set(out)); + }; + const runAnalysis = () => { const community = String(analyzeFilters.community || '').trim(); if (!community) { window.notify?.error?.('Выберите community'); return; } @@ -539,7 +562,10 @@ function IPRangesManager() { const unchanged = allForCommunity.filter(i => !filtered.includes(i)); const beforeCidrs = filtered.map(i => i.ipRange); - const afterCidrs = summarizeCidrs(beforeCidrs); + let afterCidrs = summarizeCidrs(beforeCidrs); + if (analyzeFilters.supernet16) { + afterCidrs = applySupernet16(afterCidrs); + } const processedBefore = beforeCidrs.length; const processedAfter = afterCidrs.length; const totalAfter = processedAfter + unchanged.length; @@ -1018,6 +1044,14 @@ function IPRangesManager() {