feat: Добавить опцию агрессивной агрегации для IP-диапазонов, позволяющую сворачивать более 2 префиксов в одном /16; обновить интерфейс для управления этой настройкой
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m52s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m52s
This commit is contained in:
@@ -228,7 +228,7 @@ function IPRangesManager() {
|
|||||||
const [analysisResultsOpen, setAnalysisResultsOpen] = useState(false);
|
const [analysisResultsOpen, setAnalysisResultsOpen] = useState(false);
|
||||||
const [analysisPreview, setAnalysisPreview] = useState(null);
|
const [analysisPreview, setAnalysisPreview] = useState(null);
|
||||||
const [overwriteConfirmOpen, setOverwriteConfirmOpen] = useState(false);
|
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 handlePreviewDiff = () => {
|
||||||
const valid = items.filter(i => isValidCidr(i.ipRange) && isValidCommunity(i.community))
|
const valid = items.filter(i => isValidCidr(i.ipRange) && isValidCommunity(i.community))
|
||||||
@@ -437,6 +437,7 @@ function IPRangesManager() {
|
|||||||
parts.push(`Маска: /${analyzeFilters.minMask}..../${analyzeFilters.maxMask}`);
|
parts.push(`Маска: /${analyzeFilters.minMask}..../${analyzeFilters.maxMask}`);
|
||||||
const typeLabel = analyzeFilters.type === 'any' ? 'любой' : (analyzeFilters.type === 'private' ? 'только приватные' : (analyzeFilters.type === 'public' ? 'только публичные' : 'только CGNAT'));
|
const typeLabel = analyzeFilters.type === 'any' ? 'любой' : (analyzeFilters.type === 'private' ? 'только приватные' : (analyzeFilters.type === 'public' ? 'только публичные' : 'только CGNAT'));
|
||||||
parts.push(`Тип: ${typeLabel}`);
|
parts.push(`Тип: ${typeLabel}`);
|
||||||
|
parts.push(`Агрегировать >2 префиксов в одном /16 до /16: ${analyzeFilters.supernet16 ? 'да' : 'нет'}`);
|
||||||
return parts.join('\n');
|
return parts.join('\n');
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -522,6 +523,28 @@ function IPRangesManager() {
|
|||||||
return out;
|
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 runAnalysis = () => {
|
||||||
const community = String(analyzeFilters.community || '').trim();
|
const community = String(analyzeFilters.community || '').trim();
|
||||||
if (!community) { window.notify?.error?.('Выберите community'); return; }
|
if (!community) { window.notify?.error?.('Выберите community'); return; }
|
||||||
@@ -539,7 +562,10 @@ function IPRangesManager() {
|
|||||||
const unchanged = allForCommunity.filter(i => !filtered.includes(i));
|
const unchanged = allForCommunity.filter(i => !filtered.includes(i));
|
||||||
|
|
||||||
const beforeCidrs = filtered.map(i => i.ipRange);
|
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 processedBefore = beforeCidrs.length;
|
||||||
const processedAfter = afterCidrs.length;
|
const processedAfter = afterCidrs.length;
|
||||||
const totalAfter = processedAfter + unchanged.length;
|
const totalAfter = processedAfter + unchanged.length;
|
||||||
@@ -1018,6 +1044,14 @@ function IPRangesManager() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="form-text">Определение типа по первому IP в CIDR.</div>
|
<div className="form-text">Определение типа по первому IP в CIDR.</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label className="form-label">Агрессивная агрегация</label>
|
||||||
|
<label className="form-check">
|
||||||
|
<input className="form-check-input" type="checkbox" checked={analyzeFilters.supernet16} onChange={e => setAnalyzeFilters(f => ({ ...f, supernet16: e.target.checked }))} />
|
||||||
|
<span className="form-check-label">Если в одном /16 более 2 префиксов — свернуть в /16</span>
|
||||||
|
</label>
|
||||||
|
<div className="form-text">Например: 157.240.12.0/23, 157.240.15.0/24, 157.240.16.0/23 → 157.240.0.0/16</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user