From 6a2975b83fceda4fdfc226993504e61c1fc11a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Sat, 30 May 2026 08:01:38 +0300 Subject: [PATCH] =?UTF-8?q?research:=20=D0=BE=D1=82=D0=B2=D0=B5=D1=82=20Op?= =?UTF-8?q?us=20=E2=80=94=20=D0=B1=D0=B0=D0=B3=20isSubnetOf=20=D0=B2=20?= =?UTF-8?q?=D0=B1=D0=BB=D0=BE=D0=BA=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B5,?= =?UTF-8?q?=20=D1=84=D0=B8=D0=BA=D1=81=20=D0=BF=D1=80=D0=BE=D0=BC=D0=BF?= =?UTF-8?q?=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- research/opus-review-validators.md | 67 ++++++++++++++++++++++++++++++ research/prompt-opus-validators.md | 1 + 2 files changed, 68 insertions(+) create mode 100644 research/opus-review-validators.md diff --git a/research/opus-review-validators.md b/research/opus-review-validators.md new file mode 100644 index 0000000..0d6eac2 --- /dev/null +++ b/research/opus-review-validators.md @@ -0,0 +1,67 @@ +# Ответ Claude Opus 4 — код-ревью validators.js + +> Дата: 2026-05-30 + +## 🔴 Баг 1 — запрещённые диапазоны обходятся бо́льшей подсетью (критично) + +Проверка блокировки использует `isSubnetOf(normalized, blocked)` — то есть «запись внутри запрещённого диапазона». Но не проверяется обратное направление: **запись, которая САМА содержит запрещённый диапазон**. + +Поскольку ТЗ разрешает маски вплоть до `/22`, а многие запрещённые блоки — это `/24`, их можно обойти суперсетью: + +``` +Вход: 192.0.2.0/22 +→ нормализуется в 192.0.0.0/22 (диапазон 192.0.0.0 – 192.0.3.255) +``` + +Этот `/22` **содержит** TEST-NET-1 (`192.0.2.0/24`) и IANA special (`192.0.0.0/24`), но `isSubnetOf` вернёт `false` (родитель не внутри ребёнка) → запись пройдёт валидацию. То же с `198.18.0.0/15` (Benchmarking) и др. + +**Фикс** — использовать пересечение вместо вложенности: + +```js + for (const blocked of BLOCKED_RANGES) { + if (overlaps(normalized, blocked)) { + throw new Error(`Диапазон ${normalized} пересекается с запрещённым (${blocked})`); + } + } +``` + +`overlaps` ловит оба направления (и когда запись внутри блока, и когда блок внутри записи). `isSubnetOf` после этого фикса в блокировке не нужен. + +--- + +## 🟡 Замечание 2 — parseInt глотает мусор в маске + +```js +const mask = parseInt(maskStr, 10); +``` + +`10.0.0.0/24abc` → `parseInt('24abc')` = `24`, запись принимается как `/24`. Строгая проверка: + +```js + if (!/^\d{1,2}$/.test(maskStr)) throw new Error('Некорректная маска'); + const mask = parseInt(maskStr, 10); +``` + +--- + +## 🟡 Замечание 3 — множественные слэши не отсекаются + +`10.0.0.0/24/8`.split('/') → `['10.0.0.0','24','8']`, третий элемент молча игнорируется. Добавить проверку числа частей: + +```js + const parts = cidr.split('/'); + if (parts.length !== 2) throw new Error('Некорректный формат CIDR'); + const [addr, maskStr] = parts; +``` + +--- + +## 🟢 Не баги (проверено) + +- **`overlaps`** — формула `a.start <= b.end && b.start <= a.start || b.start <= a.end && a.start <= b.start` хоть и обфусцирована, **математически эквивалентна** стандартной `a.start <= b.end && b.start <= a.end`. Работает корректно. Можно упростить для читаемости, но это не дефект. +- **Битовая арифметика** с `<<8` уходит в знаковый 32-бит, но финальный `>>> 0` всё исправляет. Корректно. +- **Маска `/0`**, `1 << (32-mask)` — безопасно, т.к. `mask` ограничен 22–32. + +--- + +**Итог:** один настоящий эксплуатируемый баг (#1 — обход TEST-NET/special через `/22`), два мелких по строгости парсинга. Главное — поправить блокировку на `overlaps`. diff --git a/research/prompt-opus-validators.md b/research/prompt-opus-validators.md index 730f2df..4c6e542 100644 --- a/research/prompt-opus-validators.md +++ b/research/prompt-opus-validators.md @@ -19,6 +19,7 @@ - Не пиши «общие рекомендации» — только конкретные места с номерами строк - Если предлагаешь исправить — напиши точный новый код - Если багов нет — так и скажи +- **ВЕСЬ ОТВЕТ ДОЛЖЕН БЫТЬ В ОДНОМ БЛОКЕ — ОДИН markdown-блок, без интерактивных элементов, без свёрток, без ссылок на файлы. Чистый текст, готовый к копированию одной операцией.** Файл: