From 526c67b5b1a2fcdc0b24b28854a1c8ab41c3aa00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D1=83=D1=86=D0=B5=D0=BD=D0=BA=D0=BE=20=D0=90=D0=BD?= =?UTF-8?q?=D0=B4=D1=80=D0=B5=D0=B9=20=D0=90=D0=BD=D0=B0=D1=82=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=B5=D0=B2=D0=B8=D1=87?= Date: Fri, 10 Apr 2026 16:18:11 +1000 Subject: [PATCH] =?UTF-8?q?docs(readme):=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D1=82=D0=B0=D1=86=D0=B8=D1=8E=20=D0=BF=D0=BE=20=D0=BF=D0=BE?= =?UTF-8?q?=D1=81=D0=BB=D0=B5=D0=B4=D0=BD=D0=B8=D0=BC=20=D0=B4=D0=BE=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Добавил в README новые API и UI-возможности: IF-MIB интерфейсы, гибкий ввод CIDR, обновления по LLDP/SNMP, форматирование MAC и админ-очистку данных сканов. Made-with: Cursor --- README.md | 64 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 3ec7c04..de46b03 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,12 @@ - `GET /api/scans/{id}/ports` - результаты проверки TCP-портов по скану. - `GET /api/scans/{id}/snmp` - результаты SNMP v2c (`sysName`, `sysDescr`, `sysObjectID`). - `GET /api/scans/{id}/lldp` - LLDP соседи (если устройство отдает LLDP-MIB по SNMP). +- `GET /api/scans/{id}/interfaces?ip=` - интерфейсы устройства из IF-MIB (`ifIndex/ifName/ifDescr/ifOperStatus`). - `GET /api/scans/{id}/links` - базовые связи из LLDP с попыткой сопоставления по `remote_sys_name`. - `GET /api/scans/{id}/topology` - граф `nodes/edges` для визуализации. +- `POST /api/admin/purge-scans` - очистка всех scan-данных (защищено `X-Nettopo-Reset-Key`). - `GET /` — UI для просмотра топологии (страница встроена в бинарник через `embed`, каталог `internal/webui/`; **не зависит** от `WorkingDirectory` и папки `web/` рядом с процессом). -- Валидация CIDR и exclude IP. +- Валидация целей скана: одиночный CIDR, перечисление через запятую и диапазон `CIDR-CIDR` (IPv4). - Два backend-хранилища: in-memory и PostgreSQL. - После создания scan запускается фоновый discovery с обновлением статуса и прогресса. - Отдельный чек-лист ручной приемки: `MANUAL_TEST_CHECKLIST.md`. @@ -75,7 +77,11 @@ http://localhost:8080/ - подсветить на графе новые (`[+]`, зеленый) и пропавшие (`[-]`, красный) хосты по diff. - использовать легенду цветов и фильтр узлов: все / только новые / только пропавшие. - экспортировать topology и diff в JSON-файлы кнопками из UI. -- создать scan по CIDR из UI и дождаться завершения кнопкой "Ждать завершения". +- создать scan по целям из UI и дождаться завершения кнопкой "Ждать завершения"; +- вводить цели как: один CIDR (`192.168.1.0/24`), список через запятую (`172.16.0.0/24,192.168.160.0/24`) и диапазон (`192.168.160.0/24-192.168.190.0/24`); +- в таблице "Связи выбранного устройства" видеть не только LLDP-порты, но и все интерфейсы из IF-MIB с пометкой, где LLDP отсутствует; +- сортировать "Таблица 1. Связи" по столбцу "Локальный порт"; +- выполнять "Начать всё заново" (очистка scan-таблиц) из UI в админ-блоке при наличии секрета. По умолчанию используется `STORE_BACKEND=memory`. SNMP-проверка по умолчанию включена (`SNMP_ENABLED=true`, community `public`). @@ -84,13 +90,16 @@ SNMP-проверка по умолчанию включена (`SNMP_ENABLED=tr Один запуск scan — это **одна фоновая задача** (`runner`), без отдельных фаз «только ping» / «только LLDP» в API. -1. По полю `cidrs` строится список IP (с учётом `exclude_ips`). +1. По полю `cidrs` строится список IP (с учётом `exclude_ips`). Поддерживается: + - один CIDR; + - список CIDR через запятую; + - диапазон `CIDR-CIDR` (только IPv4, одинаковая маска, границы — сетевые адреса). 2. Параллельно (ограничение `max_parallel_hosts`) для каждого IP: - **ping** (ICMP через системную утилиту `ping`); - если хост «вверх» и включён port-scan — проверка **TCP-портов** из `options.ports`; - - если хост «вверх» и `SNMP_ENABLED=true` — **SNMP v2c** (sysName, sysDescr, sysObjectID) и сразу **обход LLDP-MIB** (соседи, локальный/удалённый порт и т.д.). Это не отдельная кнопка: LLDP выполняется в том же проходе, что и базовый SNMP. + - если хост «вверх» и `SNMP_ENABLED=true` — **SNMP v2c** (sysName, sysDescr, sysObjectID), затем **LLDP-MIB** и **IF-MIB** (`ifIndex/ifName/ifDescr/ifOperStatus`). 3. Статус задачи: `queued` → `running` (поле `progress` 0…100, `stats.hosts_total` / `stats.hosts_up`) → `done` или `failed`. -4. Результаты читаются через API: `/hosts`, `/ports`, `/snmp`, `/lldp`, агрегированный граф — `/topology`. +4. Результаты читаются через API: `/hosts`, `/ports`, `/snmp`, `/lldp`, `/interfaces`, агрегированный граф — `/topology`. В веб-UI после **«Создать scan и ждать»** опрашивается статус, показывается расшифровка в строке состояния, по завершении обновляется таблица **найденных устройств** (ping + SNMP) и строится граф по кнопке **«Загрузить»** (или автоматически после ожидания). @@ -98,6 +107,26 @@ SNMP-проверка по умолчанию включена (`SNMP_ENABLED=tr Опрос LLDP идёт по стандартному **LLDP-MIB** (`1.0.8802.1.1.2.1.4.1.1.*`) после успешного SNMP **Get** системной группы. Раньше при **GET-BULK** часть прошивок отвечала слишком долго или с ошибкой — обход обрывался, в БД не попадало ни строки («No LLDP data» в UI). Сейчас для фазы LLDP увеличен таймаут (не меньше **3 c** на запрос), снижен размер «пачки» **MaxRepetitions**, добавлен **повтор при ошибке через SNMP Walk (GetNext)**. В логах сервера ищите строки `lldp snmp BulkWalkAll` и `fallback Walk`. Проверьте с хоста nettopo: community (**`SNMP_COMMUNITY` / `public`**), доступ UDP **161** с этого сервера и что на свиче включён **SNMP v2c** (не только LLDP в L2, но и ответ агента SNMP). +### Частые замечания и пояснения + +- **CLI LLDP есть, а в UI "No LLDP data"**: это значит, что LLDP на устройстве работает локально, но в конкретном скане данные не были успешно прочитаны из `lldpRemTable` по SNMP. Быстрая проверка: `snmpwalk -v2c -c 1.0.8802.1.1.2.1.4.1`. +- **Поле "Порт соседа" вида `0x...`**: если это OctetString длиной 6 байт, теперь значение форматируется как MAC `aa:bb:cc:dd:ee:ff`; для остальных бинарных значений остаётся `0x...`. +- **SNMP "не опрашивался" при больших сканах**: `/hosts` и `/snmp` возвращают по одной актуальной записи на IP (dedupe latest), чтобы не терять устройства из-за ограничений выборки. +- **Почему раньше в "Таблица 1. Связи" были не все порты**: теперь таблица строится как IF-MIB + LLDP. Показываются все интерфейсы, а LLDP соседы подмешиваются по `ifIndex`. + +### Начать всё заново (очистка БД) + +Для полного сброса scan-данных добавлен endpoint: + +```bash +POST /api/admin/purge-scans +X-Nettopo-Reset-Key: <секрет> +``` + +- Очистка доступна только при заданном `NETTOPO_RESET_DB_SECRET`. +- В UI есть админ-блок "Начать всё заново" с ручным вводом секрета. +- Для PostgreSQL выполняется `TRUNCATE scan_jobs RESTART IDENTITY CASCADE` (очищаются все связанные таблицы: hosts/ports/snmp/lldp/interfaces). + ## PostgreSQL без Docker ### Вариант A: macOS (Homebrew) @@ -137,7 +166,7 @@ export RUN_MIGRATIONS=true go run ./cmd/server ``` -При первом запуске автоматически применится миграция `scan_jobs`. +При первом запуске автоматически применяются SQL-миграции из `internal/store/sql/` (включая таблицу `scan_interfaces`). ## Быстрая проверка API @@ -193,7 +222,7 @@ curl -s "http://localhost:8080/api/scans/diff?from=&to=" Получить результаты по хостам: ```bash -curl -s http://localhost:8080/api/scans//hosts?limit=200 +curl -s http://localhost:8080/api/scans//hosts?limit=200000 ``` Получить результаты по портам: @@ -205,25 +234,38 @@ curl -s http://localhost:8080/api/scans//ports?limit=500 Получить SNMP результаты: ```bash -curl -s http://localhost:8080/api/scans//snmp?limit=500 +curl -s http://localhost:8080/api/scans//snmp?limit=200000 ``` Получить LLDP результаты: ```bash -curl -s http://localhost:8080/api/scans//lldp?limit=1000 +curl -s http://localhost:8080/api/scans//lldp?limit=20000 +``` + +Получить интерфейсы устройства (IF-MIB): + +```bash +curl -s "http://localhost:8080/api/scans//interfaces?ip=192.168.1.10&limit=4096" ``` Получить связи: ```bash -curl -s http://localhost:8080/api/scans//links?limit=1000 +curl -s http://localhost:8080/api/scans//links?limit=20000 ``` Получить topology (nodes/edges): ```bash -curl -s http://localhost:8080/api/scans//topology?limit=2000 +curl -s http://localhost:8080/api/scans//topology?limit=5000 +``` + +Очистить все scan-данные (защищено секретом): + +```bash +curl -s -X POST http://localhost:8080/api/admin/purge-scans \ + -H "X-Nettopo-Reset-Key: " ``` ## Запуск как сервис на Linux (systemd)