diff --git a/CHANGELOG.md b/CHANGELOG.md index 12d85ee..94882d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,61 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/lang/es/). --- +## [1.2.0] - 2025-11-26 + +### ✨ Añadido + +#### Verificación por Ping +- **Clase `PingService.php`**: Servicio de verificación de IPs mediante ping + - Ping paralelo a múltiples IPs simultáneamente (hasta 30 IPs por lote) + - Timeout configurable (default: 1 segundo) + - Detección automática de disponibilidad del comando ping + - Procesamiento en lotes para evitar sobrecarga de red + - Fallback graceful si ping no está disponible +- **Parámetro de configuración `enablePingVerification`**: Control global de verificación por ping + - Modo opcional: usuario decide en cada búsqueda + - Checkbox condicional en frontend (solo visible si está habilitado) + - Parámetro `verify_ping` en API REST +- **Detección de dispositivos no registrados**: Identifica IPs que responden a ping pero no están en UISP + - Filtra automáticamente IPs que responden + - Advertencias en logs para IPs no registradas + - Estadísticas de ping en respuestas + +#### Integración +- **Frontend**: Checkbox "Verificar con ping" (condicional según configuración) + - Solo visible si `enablePingVerification` está habilitado + - Integrado en formulario de búsqueda + - Indicador de progreso durante verificación +- **API REST**: Soporte para parámetro `verify_ping` en ambos endpoints + - `event.ip_request`: Incluye estadísticas de ping en respuesta + - `event.ip_check`: Indica si IP específica responde a ping + - Campo `ping_verified` en todas las respuestas + - Campo `ping_stats` con métricas detalladas + +### 🔄 Mejorado + +- **`IpSearchService::buscarIpsDisponibles()`**: Ahora acepta parámetro `$verifyPing` + - Integración transparente con `PingService` + - Filtrado automático de IPs que responden + - Logging detallado de resultados de ping +- **Respuestas de API**: Información enriquecida con datos de ping + - Estadísticas: total verificado, respondiendo, no respondiendo + - Tiempo de ejecución de verificación + - Lista de IPs que responden (posibles conflictos) + +### 🔧 Técnico + +- **Ping paralelo**: Implementación usando procesos en background + - Archivos temporales para capturar resultados + - Espera asíncrona con timeout + - Limpieza automática de archivos temporales +- **Performance**: Optimizado para grandes rangos de IPs + - Procesamiento en lotes de 30 IPs + - Timeout total controlado + - Mínimo impacto en tiempo de respuesta + +--- + ## [1.1.0] - 2025-11-26 ### ✨ Añadido diff --git a/README.md b/README.md index 059032e..46dabdf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SIIP - Buscador de IP's Disponibles UISP -[](manifest.json) +[](manifest.json) [](https://uisp.com/) [](https://uisp.com/) @@ -33,6 +33,7 @@ Plugin para UISP CRM (anteriormente UCRM) que permite buscar direcciones IP disp - 🔌 **API REST completa** para integraciones externas - 📋 **Copiar al portapapeles** con un solo clic - 🎯 **Filtrado inteligente** de IPs administrativas vs. IPs para clientes +- 🏓 **Verificación por ping** para detectar dispositivos no registrados (opcional) - 📊 **Estadísticas en tiempo real** de IPs disponibles y en uso - 🔐 **Integración nativa** con UISP CRM y UNMS - 🪝 **Soporte para webhooks** y eventos personalizados @@ -89,6 +90,7 @@ Después de instalar el plugin, configura los siguientes parámetros: | Parámetro | Descripción | Uso | |-----------|-------------|-----| | **Token de la API UNMS** | Token de UNMS (34 caracteres) | Para búsqueda de IPs en dispositivos de red | +| **Habilitar verificación por Ping** | Activa modo de verificación por ping | Permite verificar disponibilidad real de IPs | | **Debug Mode** | Modo de depuración | Habilita logs más detallados | | **Enable debug logs** | Logs verbosos | Información adicional en logs | @@ -131,12 +133,27 @@ La interfaz incluye: ``` 1. Ingresa "5" en el campo de búsqueda -2. Haz clic en "Buscar IPs" -3. Se mostrarán todas las IPs disponibles en el rango 172.16.5.x -4. Haz clic en el botón "Copiar" junto a la IP deseada -5. La IP se copia automáticamente al portapapeles +2. (Opcional) Marca "Verificar con ping" si está habilitado +3. Haz clic en "Buscar IPs" +4. Se mostrarán todas las IPs disponibles en el rango 172.16.5.x +5. Haz clic en el botón "Copiar" junto a la IP deseada +6. La IP se copia automáticamente al portapapeles ``` +### Verificación por Ping (Opcional) + +Si está habilitada en la configuración, aparecerá un checkbox "🔍 Verificar con ping" en el formulario. + +**¿Qué hace?** +- Verifica que las IPs reportadas como disponibles realmente no respondan a ping +- Detecta dispositivos no registrados en UISP (computadoras, impresoras, cámaras, etc.) +- Filtra automáticamente IPs que responden (posibles conflictos) + +**¿Cuándo usarlo?** +- ✅ Antes de asignar IPs a clientes nuevos (máxima seguridad) +- ✅ En redes con dispositivos no gestionados +- ❌ Para búsquedas rápidas donde no importa la verificación + --- ## 🔌 API REST @@ -195,10 +212,42 @@ Busca todas las IPs disponibles en un segmento de red específico. **Parámetros**: - `type` (string, requerido): Tipo de evento, debe ser `"event.ip_request"` - `segment` (string, requerido): Tercer octeto del segmento (0-255) +- `verify_ping` (boolean, opcional): Si es `true`, verifica IPs con ping antes de reportarlas + +**Ejemplo con verificación por ping**: +```json +{ + "type": "event.ip_request", + "segment": "5", + "verify_ping": true +} +``` + +**Response con ping**: +```json +{ + "success": true, + "event": "event.ip_request", + "segment": "172.16.5.x", + "data": { + "available": ["172.16.5.31", "172.16.5.32"], + "used": ["172.16.5.1"] + }, + "ping_verified": true, + "ping_stats": { + "total_checked": 223, + "responding": 1, + "not_responding": 222, + "execution_time": "2.3s" + }, + "ping_responding": ["172.16.5.50"] +} +``` **Notas**: - Las IPs administrativas (1-30 y 254) son filtradas automáticamente - Solo se devuelven IPs aptas para asignar a clientes (31-253) +- Si `verify_ping` es `true`, las IPs que responden a ping se filtran automáticamente --- @@ -386,7 +435,8 @@ siip-available-ips/ ├── README.md # Este archivo ├── src/ # Código fuente │ ├── ApiHandlers.php # Manejadores de API REST -│ └── IpSearchService.php # Servicio de búsqueda de IPs +│ ├── IpSearchService.php # Servicio de búsqueda de IPs +│ └── PingService.php # Servicio de verificación por ping ├── data/ # Datos del plugin │ ├── config.json # Configuración (generado automáticamente) │ └── plugin.log # Archivo de logs @@ -413,6 +463,13 @@ Clase de servicio para búsqueda de IPs: - `isAdminIp()`: Determina si una IP es administrativa - `getIpType()`: Obtiene información del tipo de IP +#### `src/PingService.php` +Clase de servicio para verificación por ping: +- `pingMultipleIps()`: Ping paralelo a múltiples IPs +- `pingIp()`: Ping a una sola IP +- `processPingResults()`: Procesa resultados de ping +- `isAvailable()`: Verifica si ping está disponible + --- ## 🎯 Filtrado de IPs Administrativas @@ -474,9 +531,13 @@ Los logs se guardan en: Para ver el historial completo de cambios y versiones, consulta el archivo **[CHANGELOG.md](CHANGELOG.md)**. -### Versión Actual: 1.1.0 (2025-11-26) +### Versión Actual: 1.2.0 (2025-11-26) **Cambios destacados**: +- 🏓 Verificación por ping para detectar dispositivos no registrados +- ⚡ Ping paralelo de hasta 30 IPs simultáneamente +- 🎛️ Control opcional vía configuración +- 📊 Estadísticas detalladas de verificación - ✨ API REST completa con endpoints `event.ip_request` y `event.ip_check` - 🔌 Soporte para webhooks y eventos personalizados - 🎯 Filtrado automático de IPs administrativas @@ -516,14 +577,8 @@ Para ver el historial completo de cambios y versiones, consulta el archivo **[CH Este plugin es propiedad de **SIIP Internet**. Todos los derechos reservados. ---- - -## 🙏 Agradecimientos - -- Equipo de UISP/Ubiquiti por la plataforma -- Comunidad de desarrolladores de plugins UCRM --- -**Versión**: 1.1.0 +**Versión**: 1.2.0 **Última actualización**: 26 de noviembre de 2025 diff --git a/data/config.json b/data/config.json index 30da030..68ba53a 100644 --- a/data/config.json +++ b/data/config.json @@ -1 +1 @@ -{"ipserver":"sistema.siip.mx","apitoken":"393eb3d0-9b46-4a47-b9b4-473e4e24a89c","unmsApiToken":"393eb3d0-9b46-4a47-b9b4-473e4e24a89c","debugMode":true,"logging_level":true} \ No newline at end of file +{"ipserver":"sistema.siip.mx","apitoken":"393eb3d0-9b46-4a47-b9b4-473e4e24a89c","unmsApiToken":"393eb3d0-9b46-4a47-b9b4-473e4e24a89c","debugMode":true,"logging_level":true,"enablePingVerification":true} \ No newline at end of file diff --git a/data/plugin.log b/data/plugin.log index b44e099..2f4116c 100644 --- a/data/plugin.log +++ b/data/plugin.log @@ -283,3 +283,99 @@ IPs obtenidas exitosamente: 3103 direcciones Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 153, En uso: 101 Resultado de búsqueda: {"success":true,"ipsDisponibles":153,"ipsEnUso":101} <<< Finalizando handler de búsqueda AJAX +=== NUEVA PETICIÓN === +Método: GET +POST data: [] +GET data: [] +Content-Type: +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +Acceso a la interfaz pública de búsqueda de IPs +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"search","segment":"13"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundaryd3584f1ed3d6519fada0a6a78880083b +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de búsqueda AJAX +Configuración cargada: {"ipserver":"sistema.siip.mx","hasUnmsToken":true,"hasApiToken":true} +Buscando IPs en segmento: 13 (sin verificación por ping) +URL de API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true +Iniciando conexión a API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true +Respuesta HTTP: 200 +Longitud de respuesta: 48906 bytes +IPs obtenidas exitosamente: 3105 direcciones +Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 153, En uso: 101 +Resultado de búsqueda: {"success":true,"ipsDisponibles":153,"ipsEnUso":101} +<<< Finalizando handler de búsqueda AJAX +=== NUEVA PETICIÓN === +Método: GET +POST data: [] +GET data: [] +Content-Type: +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +Acceso a la interfaz pública de búsqueda de IPs +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"search","segment":"13"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundaryc20a33e19ccea953d03471341f409046 +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de búsqueda AJAX +Configuración cargada: {"ipserver":"sistema.siip.mx","hasUnmsToken":true,"hasApiToken":true} +Buscando IPs en segmento: 13 (sin verificación por ping) +URL de API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true +Iniciando conexión a API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true +Respuesta HTTP: 200 +Longitud de respuesta: 48906 bytes +IPs obtenidas exitosamente: 3105 direcciones +Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 153, En uso: 101 +Resultado de búsqueda: {"success":true,"ipsDisponibles":153,"ipsEnUso":101} +<<< Finalizando handler de búsqueda AJAX +=== NUEVA PETICIÓN === +Método: GET +POST data: [] +GET data: [] +Content-Type: +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +Acceso a la interfaz pública de búsqueda de IPs +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"search","segment":"100"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundary974266b1e07d3862a10f25b4f522b48d +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de búsqueda AJAX +Configuración cargada: {"ipserver":"sistema.siip.mx","hasUnmsToken":true,"hasApiToken":true} +Buscando IPs en segmento: 100 (sin verificación por ping) +URL de API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true +Iniciando conexión a API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true +Respuesta HTTP: 200 +Longitud de respuesta: 48906 bytes +IPs obtenidas exitosamente: 3105 direcciones +Búsqueda de IPs en segmento 172.16.100.x - Disponibles: 123, En uso: 131 +Resultado de búsqueda: {"success":true,"ipsDisponibles":123,"ipsEnUso":131} +<<< Finalizando handler de búsqueda AJAX +=== NUEVA PETICIÓN === +Método: GET +POST data: [] +GET data: [] +Content-Type: +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +Acceso a la interfaz pública de búsqueda de IPs +=== NUEVA PETICIÓN === +Método: POST +POST data: {"action":"search","segment":"100"} +GET data: [] +Content-Type: multipart/form-data; boundary=----geckoformboundaryd936e6e93d946c44900218614f60b9c7 +User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0 +>>> Entrando al handler de búsqueda AJAX +Configuración cargada: {"ipserver":"sistema.siip.mx","hasUnmsToken":true,"hasApiToken":true} +Buscando IPs en segmento: 100 (sin verificación por ping) +URL de API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true +Iniciando conexión a API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true +Respuesta HTTP: 200 +Longitud de respuesta: 48906 bytes +IPs obtenidas exitosamente: 3105 direcciones +Búsqueda de IPs en segmento 172.16.100.x - Disponibles: 123, En uso: 131 +Resultado de búsqueda: {"success":true,"ipsDisponibles":123,"ipsEnUso":131} +<<< Finalizando handler de búsqueda AJAX diff --git a/manifest.json b/manifest.json index ff47967..19d4e4b 100644 --- a/manifest.json +++ b/manifest.json @@ -5,7 +5,7 @@ "displayName": "SIIP - Buscador de IP's Disponibles UISP", "description": "Este plugin permite buscar IP's disponibles en UISP (UNMS) y asignarlas a los clientes en UCRM. Evitando así la asignación de IP's duplicadas y mejorando la gestión de direcciones IP en la red.", "url": "https://siip.mx", - "version": "1.1.0", + "version": "1.2.0", "ucrmVersionCompliancy": { "min": "1.0.0", "max": null @@ -51,6 +51,13 @@ "description": "Make the plugin more verbose - Hace el plugin mas verboso.", "type": "checkbox", "required": 0 + }, + { + "key": "enablePingVerification", + "label": "Habilitar verificación por Ping", + "description": "Permite verificar la disponibilidad real de las IPs mediante ping. Cuando está habilitado, el usuario puede elegir si desea verificar las IPs con ping antes de mostrarlas como disponibles. Esto ayuda a detectar dispositivos no registrados en UISP.", + "required": 0, + "type": "checkbox" } ], "menu": [ diff --git a/public.php b/public.php index c341ed7..42bd8dc 100644 --- a/public.php +++ b/public.php @@ -25,6 +25,7 @@ chdir(__DIR__); require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/src/IpSearchService.php'; +require_once __DIR__ . '/src/PingService.php'; require_once __DIR__ . '/src/ApiHandlers.php'; use Ubnt\UcrmPluginSdk\Service\PluginLogManager; @@ -113,7 +114,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST[' } $segmento = $_POST['segment'] ?? ''; - $log->appendLog("Buscando IPs en segmento: $segmento"); + $verifyPing = isset($_POST['verify_ping']) && $_POST['verify_ping'] === 'true'; + + if ($verifyPing) { + $log->appendLog("Buscando IPs en segmento: $segmento (con verificación por ping)"); + } else { + $log->appendLog("Buscando IPs en segmento: $segmento (sin verificación por ping)"); + } // URL de la API de UISP - Usar HTTPS $apiUrl = "https://{$config['ipserver']}/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true"; @@ -123,7 +130,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST[' // Crear instancia del servicio y buscar IPs $ipService = new IpSearchService($apiUrl, $apiToken, $log); - $resultado = $ipService->buscarIpsDisponibles($segmento); + $resultado = $ipService->buscarIpsDisponibles($segmento, $verifyPing); $log->appendLog('Resultado de búsqueda: ' . json_encode([ 'success' => $resultado['success'], @@ -164,6 +171,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST[' // Log de acceso público $log->appendLog('Acceso a la interfaz pública de búsqueda de IPs'); +// Cargar configuración para verificar si ping está habilitado +$configManager = PluginConfigManager::create(); +$config = $configManager->loadConfig(); +$pingEnabled = isset($config['enablePingVerification']) && $config['enablePingVerification'] === '1'; + ?> @@ -617,6 +629,14 @@ $log->appendLog('Acceso a la interfaz pública de búsqueda de IPs'); > + +