From 2388b5f3ff17dd591aee93186e96ade53b42251c 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 15:39:52 +1000 Subject: [PATCH] =?UTF-8?q?feat(scan):=20=D0=BD=D0=B5=D1=81=D0=BA=D0=BE?= =?UTF-8?q?=D0=BB=D1=8C=D0=BA=D0=BE=20CIDR=20=D0=B2=20=D0=BE=D0=B4=D0=BD?= =?UTF-8?q?=D0=BE=D0=BC=20=D0=BF=D0=BE=D0=BB=D0=B5,=20=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D1=87=D0=B8=D1=81=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=87?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=B7=20=D0=B7=D0=B0=D0=BF=D1=8F=D1=82=D1=83?= =?UTF-8?q?=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Made-with: Cursor --- internal/scans/cidr_parse.go | 16 +++++++++++----- internal/scans/cidr_parse_test.go | 20 ++++++++++++++++++++ internal/webui/index.html | 4 ++-- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/internal/scans/cidr_parse.go b/internal/scans/cidr_parse.go index 9f0f36f..8ab6f87 100644 --- a/internal/scans/cidr_parse.go +++ b/internal/scans/cidr_parse.go @@ -14,7 +14,7 @@ const maxCIDRSExpanded = 16384 var cidrRangeRE = regexp.MustCompile(`^\s*(?P.+?/\d+)\s*-\s*(?P.+?/\d+)\s*$`) -// expandCIDRSFromRequest раскрывает каждую строку: один CIDR или диапазон "start/end mask - end/end mask". +// expandCIDRSFromRequest раскрывает каждую строку: перечисление через запятую, один CIDR или диапазон a/b - c/d. func expandCIDRSFromRequest(inputs []string) ([]string, error) { var all []string for _, raw := range inputs { @@ -22,11 +22,17 @@ func expandCIDRSFromRequest(inputs []string) ([]string, error) { if raw == "" { continue } - part, err := expandCIDREntry(raw) - if err != nil { - return nil, err + for _, piece := range strings.Split(raw, ",") { + piece = strings.TrimSpace(piece) + if piece == "" { + continue + } + part, err := expandCIDREntry(piece) + if err != nil { + return nil, err + } + all = append(all, part...) } - all = append(all, part...) } if len(all) == 0 { return nil, errors.New("cidrs must not be empty") diff --git a/internal/scans/cidr_parse_test.go b/internal/scans/cidr_parse_test.go index 2c341f5..750708e 100644 --- a/internal/scans/cidr_parse_test.go +++ b/internal/scans/cidr_parse_test.go @@ -53,3 +53,23 @@ func TestExpandCIDRSFromRequestDedup(t *testing.T) { t.Fatalf("дедуп: %v", out) } } + +func TestExpandCIDRSFromRequestCommaList(t *testing.T) { + out, err := expandCIDRSFromRequest([]string{"172.16.0.0/24, 192.168.160.0/24 ,192.168.170.0/24"}) + if err != nil { + t.Fatal(err) + } + if len(out) != 3 { + t.Fatalf("ожидали 3 подсети, получили %d: %v", len(out), out) + } +} + +func TestExpandCIDRSFromRequestCommaAndRange(t *testing.T) { + out, err := expandCIDRSFromRequest([]string{"10.0.0.0/30,192.168.1.0/24-192.168.2.0/24"}) + if err != nil { + t.Fatal(err) + } + if len(out) != 1+2 { + t.Fatalf("ожидали /30 + 2×/24, получили %d: %v", len(out), out) + } +} diff --git a/internal/webui/index.html b/internal/webui/index.html index 2b53efd..c285345 100644 --- a/internal/webui/index.html +++ b/internal/webui/index.html @@ -35,7 +35,7 @@ Один scan = один полный проход по сети. Для каждого IP из CIDR (с исключениями): ping → для ответивших — проверка TCP-портов → если включён SNMP — опрос системы (sysName и др.) и сразу обход LLDP-MIB (соседи по портам). Отдельной кнопки «только LLDP» нет: соседи попадают в этот же цикл. Кнопка «Создать scan» ставит задачу и сама ждёт завершения, показывая прогресс в строке статуса ниже.
- +
@@ -793,7 +793,7 @@ async function createScan() { const cidr = cidrInput.value.trim(); if (!cidr) { - setStatus("Введите CIDR или диапазон подсетей (IPv4), например 192.168.1.0/24 или 192.168.160.0/24 - 192.168.190.0/24."); + setStatus("Введите CIDR(ы): один адрес, несколько через запятую или диапазон IPv4 (192.168.160.0/24 - 192.168.190.0/24)."); return; } setStatus("Отправка запроса на сервер: создание задачи scan…");