# Экран адресов: ресурсоёмкие ветки list_addresses (изменение 014) Находка ревью № 4, серьёзность — средняя (DoS с ролью viewer). ## Context `GET /prefixes/{id}/addresses` (`app/api/v1/prefixes.py`, `list_addresses`): - при `status=free` собирает в память `offset + limit` свободных адресов; `offset` не ограничен → на IPv6-префиксе один запрос с `offset=10^8` занимает CPU и память воркера; - без фильтров основной запрос идёт **без LIMIT/OFFSET** — на крупных подсетях загружаются все адреса ради одной страницы. ## Решение 1. **Свободные адреса без материализации:** функция `free_page(net, occupied_sorted, offset, limit)` в `app/services.py` — идёт по занятым диапазонам, считает длины свободных промежутков арифметически, пропускает `offset` без перебора и возвращает только `limit` адресов. Для IPv4 ≤ /30 учитывает исключение адреса сети и broadcast. Занятые адреса — одним запросом `SELECT address … ORDER BY address` (для пула из 10⁵ адресов — приемлемо; при росте — курсор по ключу). 2. **Режимы:** - `status` = assigned/reserved/deprecated или поиск `q` → пагинация в SQL (`ORDER BY address LIMIT/OFFSET`, `total` — `count()`); - без фильтров и `cap <= FREE_LISTING_LIMIT` (4096) → как сейчас, смешанный список (он ограничен размером подсети); - без фильтров и `cap > FREE_LISTING_LIMIT` → только записанные адреса, пагинация в SQL (сейчас — выборка всего и срез в Python); - `status=free` → `free_page`, `total = summary.free`. 3. `offset` — верхний предел как в № 013; для `status=free` дополнительно `offset <= summary.free`. 4. Ответ API и поведение UI (кнопка «Показать ещё 100») не меняются. ## Файлы `app/services.py`, `app/api/v1/prefixes.py`, `tests/test_api.py`, `README.md`. ## Тест - Чистая функция `free_page`: IPv4 /24 с занятыми `.1–.3` → offset 0 даёт `.4…`; offset за пределами → пусто; IPv6 /64 с `offset=10^12` — мгновенно. - API: `status=free&offset=1000000` на IPv6 /64 отвечает быстро (порог времени в тесте не ставим — проверяем корректность адресов). ## Проверка `pytest -q`; экран адресов демо-префиксов `10.10.1.0/24` и `fd00::/8` в UI: списки, фильтр «Свободен», «Показать ещё 100». Замер времени ответа до/после на `/16` с 60 000 адресов (скрипт в scratchpad).