característica: Se introdujeron Endpoints API REST para búsqueda y verificación de IP con clasificación de tipo IP y eliminar el script de IP heredado.
This commit is contained in:
parent
3a061d8889
commit
0be508e749
173
CHANGELOG.md
Normal file
173
CHANGELOG.md
Normal file
@ -0,0 +1,173 @@
|
||||
# Changelog
|
||||
|
||||
Todos los cambios notables en este proyecto serán documentados en este archivo.
|
||||
|
||||
El formato está basado en [Keep a Changelog](https://keepachangelog.com/es-ES/1.0.0/),
|
||||
y este proyecto adhiere a [Semantic Versioning](https://semver.org/lang/es/).
|
||||
|
||||
---
|
||||
|
||||
## [1.1.0] - 2025-11-26
|
||||
|
||||
### ✨ Añadido
|
||||
|
||||
#### API REST Completa
|
||||
- **Endpoint `event.ip_request`**: Búsqueda de IPs disponibles en un segmento de red
|
||||
- Acepta parámetro `segment` para especificar el tercer octeto (0-255)
|
||||
- Retorna lista de IPs disponibles y en uso
|
||||
- Filtra automáticamente IPs administrativas (1-30, 254)
|
||||
- Incluye contadores de IPs disponibles, en uso y filtradas
|
||||
- **Endpoint `event.ip_check`**: Verificación de estado de una IP específica
|
||||
- Acepta parámetro `ip` con dirección completa (172.16.X.X)
|
||||
- Retorna estado: disponible, en uso o desconocido
|
||||
- Incluye información del tipo de IP (administrativa vs. cliente)
|
||||
- Proporciona recomendaciones de uso
|
||||
- **Soporte para webhooks**: Habilitado `supportsWebhookEvents: true` en manifest
|
||||
- **Manejo de peticiones JSON**: Detección automática de Content-Type para API vs Frontend
|
||||
|
||||
#### Arquitectura y Código
|
||||
- **Clase `ApiHandlers.php`**: Manejadores dedicados para eventos de API REST
|
||||
- `handleApiRequest()`: Router principal de eventos
|
||||
- `handleIpRequest()`: Procesamiento de búsqueda de IPs
|
||||
- `handleIpCheck()`: Procesamiento de verificación de IPs
|
||||
- **Clase `IpSearchService.php`**: Servicio de búsqueda de IPs con lógica de negocio
|
||||
- `buscarIpsDisponibles()`: Búsqueda de IPs en segmento específico
|
||||
- `obtenerIpsEnUso()`: Obtención de IPs desde API UNMS
|
||||
- `isAdminIp()`: Método estático para detectar IPs administrativas
|
||||
- `getIpType()`: Método estático para obtener información del tipo de IP
|
||||
- **Sistema de filtrado de IPs**: Clasificación automática de IPs administrativas vs. cliente
|
||||
- Rango administrativo: .1-.30 y .254
|
||||
- Rango cliente: .31-.253
|
||||
- Etiquetas visuales en frontend
|
||||
- Filtrado automático en API REST
|
||||
|
||||
#### Documentación
|
||||
- **README.md completo**: Documentación profesional del plugin
|
||||
- Guía de instalación y configuración
|
||||
- Documentación completa de API REST
|
||||
- Ejemplos de uso en múltiples lenguajes (cURL, PHP, JavaScript, Python)
|
||||
- Tabla de códigos de error
|
||||
- Troubleshooting y soporte
|
||||
- **CHANGELOG.md**: Archivo dedicado para control de versiones
|
||||
|
||||
### 🔄 Mejorado
|
||||
|
||||
- **Separación de responsabilidades**: Lógica de negocio separada en clases dedicadas
|
||||
- **Manejo de errores mejorado**: Respuestas JSON estructuradas con códigos de error descriptivos
|
||||
- **Sistema de logging**: Logs más detallados y organizados para debugging
|
||||
- Registro de tipo de petición (HTML vs JSON)
|
||||
- Logging de eventos API procesados
|
||||
- Información de errores con stack traces
|
||||
- **Compatibilidad dual**: Frontend HTML y API REST funcionan simultáneamente
|
||||
- Detección automática del tipo de petición
|
||||
- Sin interferencia entre modos
|
||||
- **Validación de datos**: Validación robusta de parámetros en API
|
||||
- Validación de formato de IP
|
||||
- Validación de rangos de segmento
|
||||
- Mensajes de error descriptivos
|
||||
|
||||
### 🔧 Técnico
|
||||
|
||||
- **Namespace PHP**: `SiipAvailableIps` para evitar conflictos
|
||||
- **Manejo global de errores**: Error handler para convertir errores PHP en respuestas JSON
|
||||
- **Configuración SSL**: Soporte para certificados autofirmados en desarrollo
|
||||
- **Timeouts configurados**: Timeouts de conexión y ejecución para API UNMS
|
||||
|
||||
---
|
||||
|
||||
## [1.0.1] - 2025-11-25
|
||||
|
||||
### ✨ Añadido
|
||||
|
||||
- **Frontend web moderno**: Interfaz de usuario con diseño responsive y atractivo
|
||||
- Diseño con gradientes y glassmorphism
|
||||
- Tipografía Google Fonts (Inter)
|
||||
- Animaciones suaves y micro-interacciones
|
||||
- Modo oscuro integrado
|
||||
- **Búsqueda de IPs por segmento**: Campo de entrada para tercer octeto
|
||||
- **Función copiar al portapapeles**: Botón de copia rápida para cada IP
|
||||
- Feedback visual al copiar
|
||||
- Compatible con navegadores modernos
|
||||
- **Estadísticas en tiempo real**: Contadores de IPs disponibles y en uso
|
||||
- Tarjetas de estadísticas visuales
|
||||
- Actualización dinámica tras búsqueda
|
||||
- **Integración con API UNMS**: Conexión directa con UISP Network
|
||||
- Obtención de IPs en uso desde dispositivos
|
||||
- Soporte para HTTPS
|
||||
- Manejo de errores de conexión
|
||||
|
||||
### 🔄 Mejorado
|
||||
|
||||
- **Conexión con API UNMS**: Optimización de peticiones HTTP
|
||||
- Timeouts configurables
|
||||
- Mejor manejo de errores de red
|
||||
- Logging de respuestas
|
||||
- **Búsqueda de IPs**: Algoritmo optimizado para comparación de rangos
|
||||
- Ordenamiento de IPs por último octeto
|
||||
- Cálculo eficiente de IPs disponibles
|
||||
- Validación de segmentos (0-255)
|
||||
|
||||
### 🐛 Corregido
|
||||
|
||||
- Mejoras en la estabilidad de conexión con API UNMS
|
||||
- Corrección de validación de segmentos fuera de rango
|
||||
- Fix en ordenamiento de IPs en tabla de resultados
|
||||
|
||||
---
|
||||
|
||||
## [1.0.0] - 2025-11-25
|
||||
|
||||
### ✨ Lanzamiento Inicial
|
||||
|
||||
#### Funcionalidades Core
|
||||
- **Búsqueda básica de IPs**: Funcionalidad principal del plugin
|
||||
- Búsqueda en rangos 172.16.X.x
|
||||
- Detección de IPs en uso
|
||||
- Cálculo de IPs disponibles
|
||||
- **Integración con UISP CRM**: Plugin nativo para UCRM
|
||||
- Instalación vía interfaz de plugins
|
||||
- Configuración desde panel de administración
|
||||
- Acceso desde menú de reportes
|
||||
- **Interfaz web básica**: Primera versión del frontend
|
||||
- Formulario de búsqueda simple
|
||||
- Tabla de resultados
|
||||
- Diseño básico responsive
|
||||
|
||||
#### Configuración
|
||||
- **Parámetros de configuración**:
|
||||
- Dirección IP/dominio del servidor
|
||||
- Token de API UCRM
|
||||
- Token de API UNMS (opcional)
|
||||
- Modo debug
|
||||
- Nivel de logging
|
||||
|
||||
#### Integración
|
||||
- **API UNMS**: Conexión con UISP Network para obtener IPs
|
||||
- **Sistema de logs**: Archivo `plugin.log` para debugging
|
||||
- **Compatibilidad**: UCRM 1.0.0+ y UNMS 1.0.0+
|
||||
|
||||
---
|
||||
|
||||
## Tipos de Cambios
|
||||
|
||||
- **✨ Añadido**: Para nuevas funcionalidades
|
||||
- **🔄 Mejorado**: Para cambios en funcionalidades existentes
|
||||
- **🐛 Corregido**: Para corrección de bugs
|
||||
- **🔧 Técnico**: Para cambios técnicos internos
|
||||
- **🗑️ Eliminado**: Para funcionalidades removidas
|
||||
- **⚠️ Deprecado**: Para funcionalidades que serán removidas
|
||||
- **🔒 Seguridad**: Para parches de seguridad
|
||||
|
||||
---
|
||||
|
||||
## Versionamiento
|
||||
|
||||
Este proyecto sigue [Semantic Versioning](https://semver.org/lang/es/):
|
||||
|
||||
- **MAJOR** (X.0.0): Cambios incompatibles con versiones anteriores
|
||||
- **MINOR** (0.X.0): Nueva funcionalidad compatible con versiones anteriores
|
||||
- **PATCH** (0.0.X): Correcciones de bugs compatibles con versiones anteriores
|
||||
|
||||
---
|
||||
|
||||
**Última actualización**: 26 de noviembre de 2025
|
||||
529
README.md
Normal file
529
README.md
Normal file
@ -0,0 +1,529 @@
|
||||
# SIIP - Buscador de IP's Disponibles UISP
|
||||
|
||||
[](manifest.json)
|
||||
[](https://uisp.com/)
|
||||
[](https://uisp.com/)
|
||||
|
||||
Plugin para UISP CRM (anteriormente UCRM) que permite buscar direcciones IP disponibles en la red UISP/UNMS y asignarlas a clientes, evitando duplicados y mejorando la gestión de direcciones IP.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Tabla de Contenidos
|
||||
|
||||
- [Características](#-características)
|
||||
- [Requisitos](#-requisitos)
|
||||
- [Instalación](#-instalación)
|
||||
- [Configuración](#️-configuración)
|
||||
- [Uso del Frontend Web](#-uso-del-frontend-web)
|
||||
- [API REST](#-api-rest)
|
||||
- [Endpoints Disponibles](#endpoints-disponibles)
|
||||
- [Ejemplos de Uso](#ejemplos-de-uso)
|
||||
- [Estructura del Proyecto](#-estructura-del-proyecto)
|
||||
- [Filtrado de IPs Administrativas](#-filtrado-de-ips-administrativas)
|
||||
- [Logs y Debugging](#-logs-y-debugging)
|
||||
- [Changelog](#-changelog)
|
||||
- [Soporte](#-soporte)
|
||||
|
||||
---
|
||||
|
||||
## ✨ Características
|
||||
|
||||
- 🔍 **Búsqueda de IPs disponibles** por segmento de red (172.16.X.x)
|
||||
- 🌐 **Interfaz web moderna** con diseño responsive y atractivo
|
||||
- 🔌 **API REST completa** para integraciones externas
|
||||
- 📋 **Copiar al portapapeles** con un solo clic
|
||||
- 🎯 **Filtrado inteligente** de IPs administrativas vs. IPs para clientes
|
||||
- 📊 **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
|
||||
- 📝 **Sistema de logs detallado** para debugging
|
||||
|
||||
---
|
||||
|
||||
## 📦 Requisitos
|
||||
|
||||
- **UISP CRM** versión 1.0.0 o superior
|
||||
- **UISP UNMS** versión 1.0.0 o superior (opcional)
|
||||
- **PHP** 7.2 o superior
|
||||
- **cURL** habilitado en PHP
|
||||
- **Token de API** de UCRM
|
||||
- **Token de API** de UNMS (opcional, para búsqueda de IPs)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Instalación
|
||||
|
||||
### Método 1: Instalación Manual
|
||||
|
||||
1. Descarga o clona este repositorio
|
||||
2. Comprime la carpeta del plugin en formato `.zip`
|
||||
3. En UISP CRM, ve a **Sistema → Plugins**
|
||||
4. Haz clic en **"Subir nuevo plugin"**
|
||||
5. Selecciona el archivo `.zip` y súbelo
|
||||
6. Activa el plugin desde la lista de plugins
|
||||
|
||||
### Método 2: Instalación desde Git
|
||||
|
||||
```bash
|
||||
cd /path/to/ucrm/data/plugins/
|
||||
git clone <repository-url> siip-available-ips
|
||||
cd siip-available-ips
|
||||
composer install
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Configuración
|
||||
|
||||
Después de instalar el plugin, configura los siguientes parámetros:
|
||||
|
||||
### Parámetros Requeridos
|
||||
|
||||
| Parámetro | Descripción | Ejemplo |
|
||||
|-----------|-------------|---------|
|
||||
| **Dirección IP o dominio del servidor** | IP o dominio donde se ejecuta UISP CRM | `172.16.5.120` o `sistema.empresa.com` |
|
||||
| **Token de la API UCRM** | Token de autenticación de UCRM (36 caracteres) | `3d3fa6c9-e268-6e8b-b4d5-aae394d99d7d` |
|
||||
|
||||
### Parámetros Opcionales
|
||||
|
||||
| Parámetro | Descripción | Uso |
|
||||
|-----------|-------------|-----|
|
||||
| **Token de la API UNMS** | Token de UNMS (34 caracteres) | Para búsqueda de IPs en dispositivos de red |
|
||||
| **Debug Mode** | Modo de depuración | Habilita logs más detallados |
|
||||
| **Enable debug logs** | Logs verbosos | Información adicional en logs |
|
||||
|
||||
### Cómo obtener los tokens:
|
||||
|
||||
#### Token UCRM:
|
||||
1. Ve a **Sistema → Seguridad → Claves de aplicación**
|
||||
2. Crea una nueva clave con permisos de lectura/escritura
|
||||
3. Copia el token generado
|
||||
|
||||
#### Token UNMS:
|
||||
1. Accede al módulo **UISP Network**
|
||||
2. Ve a **Ajustes → Usuarios → API Tokens**
|
||||
3. Genera un nuevo token
|
||||
4. Copia el token generado
|
||||
|
||||
---
|
||||
|
||||
## 🖥️ Uso del Frontend Web
|
||||
|
||||
### Acceso
|
||||
|
||||
El frontend web está disponible en:
|
||||
- **Menú UCRM**: `Reportes → Consultar IP's Disponibles`
|
||||
- **URL directa**: `https://tu-servidor/plugins/siip-available-ips/public.php`
|
||||
|
||||
### Interfaz de Usuario
|
||||
|
||||
La interfaz incluye:
|
||||
|
||||
1. **Campo de búsqueda**: Ingresa el tercer octeto del segmento (ej: `5` para buscar en `172.16.5.x`)
|
||||
2. **Botón "Buscar IPs"**: Ejecuta la búsqueda
|
||||
3. **Tabla de resultados**: Muestra las IPs disponibles con:
|
||||
- Dirección IP completa
|
||||
- Tipo de IP (Cliente / Administración)
|
||||
- Botón de copiar al portapapeles
|
||||
4. **Estadísticas**: Muestra contadores de IPs disponibles y en uso
|
||||
|
||||
### Ejemplo de Uso
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔌 API REST
|
||||
|
||||
El plugin expone una API REST completa para integraciones externas, webhooks y automatizaciones.
|
||||
|
||||
### Configuración Base
|
||||
|
||||
- **URL Base**: `https://tu-servidor/plugins/siip-available-ips/public.php`
|
||||
- **Método**: `POST`
|
||||
- **Content-Type**: `application/json`
|
||||
- **Autenticación**: No requerida (el plugin usa los tokens configurados internamente)
|
||||
|
||||
### Endpoints Disponibles
|
||||
|
||||
#### 1. Buscar IPs Disponibles
|
||||
|
||||
Busca todas las IPs disponibles en un segmento de red específico.
|
||||
|
||||
**Evento**: `event.ip_request`
|
||||
|
||||
**Request**:
|
||||
```json
|
||||
{
|
||||
"type": "event.ip_request",
|
||||
"segment": "5"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (Éxito)**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"event": "event.ip_request",
|
||||
"segment": "172.16.5.x",
|
||||
"data": {
|
||||
"available": [
|
||||
"172.16.5.31",
|
||||
"172.16.5.32",
|
||||
"172.16.5.33"
|
||||
],
|
||||
"used": [
|
||||
"172.16.5.1",
|
||||
"172.16.5.2"
|
||||
]
|
||||
},
|
||||
"count": {
|
||||
"available": 223,
|
||||
"used": 31,
|
||||
"admin_filtered": 31
|
||||
},
|
||||
"message": "Se encontraron 223 IPs aptas para clientes en el segmento 172.16.5.x (31 IPs administrativas filtradas)"
|
||||
}
|
||||
```
|
||||
|
||||
**Parámetros**:
|
||||
- `type` (string, requerido): Tipo de evento, debe ser `"event.ip_request"`
|
||||
- `segment` (string, requerido): Tercer octeto del segmento (0-255)
|
||||
|
||||
**Notas**:
|
||||
- Las IPs administrativas (1-30 y 254) son filtradas automáticamente
|
||||
- Solo se devuelven IPs aptas para asignar a clientes (31-253)
|
||||
|
||||
---
|
||||
|
||||
#### 2. Verificar Estado de una IP
|
||||
|
||||
Verifica si una IP específica está disponible o en uso.
|
||||
|
||||
**Evento**: `event.ip_check`
|
||||
|
||||
**Request**:
|
||||
```json
|
||||
{
|
||||
"type": "event.ip_check",
|
||||
"ip": "172.16.5.100"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (IP Disponible)**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"event": "event.ip_check",
|
||||
"ip": "172.16.5.100",
|
||||
"status": "available",
|
||||
"available": true,
|
||||
"used": false,
|
||||
"ip_type": {
|
||||
"type": "client",
|
||||
"label": "Apta para cliente",
|
||||
"recommended": true,
|
||||
"description": "Recomendada para asignar a clientes"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response (IP en Uso)**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"event": "event.ip_check",
|
||||
"ip": "172.16.5.1",
|
||||
"status": "IP en uso y además para uso administrativo",
|
||||
"available": false,
|
||||
"used": true,
|
||||
"ip_type": {
|
||||
"type": "admin",
|
||||
"label": "Administración",
|
||||
"recommended": false,
|
||||
"description": "No recomendada para clientes"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Parámetros**:
|
||||
- `type` (string, requerido): Tipo de evento, debe ser `"event.ip_check"`
|
||||
- `ip` (string, requerido): Dirección IP completa en formato `172.16.X.X`
|
||||
|
||||
---
|
||||
|
||||
### Ejemplos de Uso
|
||||
|
||||
#### cURL - Buscar IPs Disponibles
|
||||
|
||||
```bash
|
||||
curl -X POST https://tu-servidor/plugins/siip-available-ips/public.php \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"type": "event.ip_request",
|
||||
"segment": "5"
|
||||
}'
|
||||
```
|
||||
|
||||
#### cURL - Verificar IP Específica
|
||||
|
||||
```bash
|
||||
curl -X POST https://tu-servidor/plugins/siip-available-ips/public.php \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"type": "event.ip_check",
|
||||
"ip": "172.16.5.100"
|
||||
}'
|
||||
```
|
||||
|
||||
#### PHP - Buscar IPs Disponibles
|
||||
|
||||
```php
|
||||
<?php
|
||||
$url = 'https://tu-servidor/plugins/siip-available-ips/public.php';
|
||||
$data = [
|
||||
'type' => 'event.ip_request',
|
||||
'segment' => '5'
|
||||
];
|
||||
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
$result = json_decode($response, true);
|
||||
print_r($result);
|
||||
?>
|
||||
```
|
||||
|
||||
#### JavaScript/Node.js - Verificar IP
|
||||
|
||||
```javascript
|
||||
const axios = require('axios');
|
||||
|
||||
const checkIp = async (ip) => {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
'https://tu-servidor/plugins/siip-available-ips/public.php',
|
||||
{
|
||||
type: 'event.ip_check',
|
||||
ip: ip
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
console.log(response.data);
|
||||
} catch (error) {
|
||||
console.error('Error:', error.message);
|
||||
}
|
||||
};
|
||||
|
||||
checkIp('172.16.5.100');
|
||||
```
|
||||
|
||||
#### Python - Buscar IPs Disponibles
|
||||
|
||||
```python
|
||||
import requests
|
||||
import json
|
||||
|
||||
url = 'https://tu-servidor/plugins/siip-available-ips/public.php'
|
||||
payload = {
|
||||
'type': 'event.ip_request',
|
||||
'segment': '5'
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
url,
|
||||
json=payload,
|
||||
headers={'Content-Type': 'application/json'},
|
||||
verify=False
|
||||
)
|
||||
|
||||
result = response.json()
|
||||
print(json.dumps(result, indent=2))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Códigos de Error
|
||||
|
||||
| Código | Descripción | Solución |
|
||||
|--------|-------------|----------|
|
||||
| `Missing event type` | No se especificó el campo `type` | Incluye `"type"` en el JSON |
|
||||
| `Unknown event type` | Tipo de evento no soportado | Usa `event.ip_request` o `event.ip_check` |
|
||||
| `Missing segment` | Falta el campo `segment` | Incluye `"segment"` en el request |
|
||||
| `Missing IP address` | Falta el campo `ip` | Incluye `"ip"` en el request |
|
||||
| `Invalid IP format` | Formato de IP inválido | Usa formato `172.16.X.X` |
|
||||
| `Plugin not configured` | Configuración incompleta | Verifica tokens en configuración del plugin |
|
||||
| `IP search failed` | Error en búsqueda | Revisa logs del plugin |
|
||||
|
||||
---
|
||||
|
||||
## 📁 Estructura del Proyecto
|
||||
|
||||
```
|
||||
siip-available-ips/
|
||||
├── manifest.json # Configuración del plugin
|
||||
├── composer.json # Dependencias PHP
|
||||
├── main.php # Punto de entrada principal
|
||||
├── public.php # Frontend web + API REST
|
||||
├── README.md # Este archivo
|
||||
├── src/ # Código fuente
|
||||
│ ├── ApiHandlers.php # Manejadores de API REST
|
||||
│ └── IpSearchService.php # Servicio de búsqueda de IPs
|
||||
├── data/ # Datos del plugin
|
||||
│ ├── config.json # Configuración (generado automáticamente)
|
||||
│ └── plugin.log # Archivo de logs
|
||||
└── vendor/ # Dependencias de Composer
|
||||
```
|
||||
|
||||
### Archivos Principales
|
||||
|
||||
#### `public.php`
|
||||
- Punto de entrada para frontend web y API REST
|
||||
- Detecta automáticamente el tipo de petición (HTML vs JSON)
|
||||
- Maneja errores globales y logging
|
||||
|
||||
#### `src/ApiHandlers.php`
|
||||
Funciones para manejar peticiones API:
|
||||
- `handleApiRequest()`: Router principal de eventos
|
||||
- `handleIpRequest()`: Procesa `event.ip_request`
|
||||
- `handleIpCheck()`: Procesa `event.ip_check`
|
||||
|
||||
#### `src/IpSearchService.php`
|
||||
Clase de servicio para búsqueda de IPs:
|
||||
- `buscarIpsDisponibles()`: Busca IPs en un segmento
|
||||
- `obtenerIpsEnUso()`: Obtiene IPs desde API UNMS
|
||||
- `isAdminIp()`: Determina si una IP es administrativa
|
||||
- `getIpType()`: Obtiene información del tipo de IP
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Filtrado de IPs Administrativas
|
||||
|
||||
El plugin implementa un sistema inteligente de filtrado de IPs:
|
||||
|
||||
### Rangos de IPs
|
||||
|
||||
| Rango | Tipo | Uso | Recomendación |
|
||||
|-------|------|-----|---------------|
|
||||
| `.1 - .30` | Administrativa | Gateways, servidores, equipos de red | ❌ No asignar a clientes |
|
||||
| `.31 - .253` | Cliente | Dispositivos de clientes finales | ✅ Apto para clientes |
|
||||
| `.254` | Broadcast | Dirección de broadcast | ❌ No asignar |
|
||||
|
||||
### Comportamiento
|
||||
|
||||
- **Frontend Web**: Muestra todas las IPs con etiquetas de tipo
|
||||
- **API REST**: Filtra automáticamente IPs administrativas
|
||||
- **event.ip_check**: Indica el tipo de IP en la respuesta
|
||||
|
||||
---
|
||||
|
||||
## 📝 Logs y Debugging
|
||||
|
||||
### Ubicación de Logs
|
||||
|
||||
Los logs se guardan en:
|
||||
```
|
||||
/data/plugin.log
|
||||
```
|
||||
|
||||
### Habilitar Debug Mode
|
||||
|
||||
1. Ve a la configuración del plugin
|
||||
2. Activa **"Debug Mode"**
|
||||
3. Activa **"Enable debug logs"**
|
||||
4. Los logs incluirán información detallada de:
|
||||
- Peticiones recibidas
|
||||
- Respuestas de API UNMS
|
||||
- Errores y excepciones
|
||||
- Tiempos de ejecución
|
||||
|
||||
### Ejemplo de Log
|
||||
|
||||
```
|
||||
[2025-11-26 11:30:15] >>> Petición recibida en public.php
|
||||
[2025-11-26 11:30:15] Método: POST
|
||||
[2025-11-26 11:30:15] Content-Type: application/json
|
||||
[2025-11-26 11:30:15] Procesando evento API: event.ip_request
|
||||
[2025-11-26 11:30:15] API: Buscando IPs en segmento 5
|
||||
[2025-11-26 11:30:16] Respuesta HTTP: 200
|
||||
[2025-11-26 11:30:16] IPs obtenidas exitosamente: 254 direcciones
|
||||
[2025-11-26 11:30:16] Búsqueda de IPs en segmento 172.16.5.x - Disponibles: 223, En uso: 31
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📜 Changelog
|
||||
|
||||
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)
|
||||
|
||||
**Cambios destacados**:
|
||||
- ✨ API REST completa con endpoints `event.ip_request` y `event.ip_check`
|
||||
- 🔌 Soporte para webhooks y eventos personalizados
|
||||
- 🎯 Filtrado automático de IPs administrativas
|
||||
- 📚 Documentación completa con ejemplos en múltiples lenguajes
|
||||
|
||||
[Ver changelog completo →](CHANGELOG.md)
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Soporte
|
||||
|
||||
### Problemas Comunes
|
||||
|
||||
#### Error: "Plugin not configured"
|
||||
**Solución**: Verifica que hayas configurado correctamente los tokens de API en la configuración del plugin.
|
||||
|
||||
#### Error: "Error al conectar con la API de UISP"
|
||||
**Solución**:
|
||||
- Verifica que el servidor UNMS esté accesible
|
||||
- Comprueba que el token de API UNMS sea válido
|
||||
- Revisa los logs para más detalles
|
||||
|
||||
#### No se muestran IPs disponibles
|
||||
**Solución**:
|
||||
- Verifica que el segmento ingresado sea válido (0-255)
|
||||
- Comprueba que existan dispositivos en ese segmento en UNMS
|
||||
- Revisa los logs con debug mode activado
|
||||
|
||||
### Contacto
|
||||
|
||||
- **Sitio web**: [https://siip.mx](https://siip.mx)
|
||||
- **Autor**: SIIP Internet
|
||||
|
||||
---
|
||||
|
||||
## 📄 Licencia
|
||||
|
||||
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
|
||||
**Última actualización**: 26 de noviembre de 2025
|
||||
244
data/plugin.log
244
data/plugin.log
@ -39,3 +39,247 @@ IPs obtenidas exitosamente: 3098 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 152, En uso: 102
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":152,"ipsEnUso":102}
|
||||
<<< 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=----geckoformboundary6cbbdcac9240b1f8937236c9d112a787
|
||||
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
|
||||
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: 48793 bytes
|
||||
IPs obtenidas exitosamente: 3098 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 152, En uso: 102
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":152,"ipsEnUso":102}
|
||||
<<< Finalizando handler de búsqueda AJAX
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: POST
|
||||
POST data: {"action":"search","segment":"117"}
|
||||
GET data: []
|
||||
Content-Type: multipart/form-data; boundary=----geckoformboundary7b1ac14e8b058e23f4947656491d5038
|
||||
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: 117
|
||||
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: 48793 bytes
|
||||
IPs obtenidas exitosamente: 3098 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.117.x - Disponibles: 50, En uso: 204
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":50,"ipsEnUso":204}
|
||||
<<< Finalizando handler de búsqueda AJAX
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: POST
|
||||
POST data: {"action":"search","segment":"118"}
|
||||
GET data: []
|
||||
Content-Type: multipart/form-data; boundary=----geckoformboundary658a77374dd484eccecd0aff8be2683c
|
||||
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: 118
|
||||
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: 48793 bytes
|
||||
IPs obtenidas exitosamente: 3098 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.118.x - Disponibles: 254, En uso: 0
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":254,"ipsEnUso":0}
|
||||
<<< Finalizando handler de búsqueda AJAX
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: POST
|
||||
POST data: {"action":"search","segment":"13"}
|
||||
GET data: []
|
||||
Content-Type: multipart/form-data; boundary=----geckoformboundaryf0fe3eda5f3c2940ddc7bc14b7f17a72
|
||||
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
|
||||
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: 48760 bytes
|
||||
IPs obtenidas exitosamente: 3096 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 152, En uso: 102
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":152,"ipsEnUso":102}
|
||||
<<< Finalizando handler de búsqueda AJAX
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: POST
|
||||
POST data: []
|
||||
GET data: []
|
||||
Content-Type: application/json
|
||||
User Agent: curl/7.53.1
|
||||
>>> Petición API JSON detectada
|
||||
Raw input length: 55 bytes
|
||||
JSON parseado correctamente: {"type":"event.ip_request","segment":13}
|
||||
Procesando evento API: event.ip_request
|
||||
API: Buscando IPs en segmento 13
|
||||
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: 48760 bytes
|
||||
IPs obtenidas exitosamente: 3096 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 152, En uso: 102
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: GET
|
||||
POST data: []
|
||||
GET data: []
|
||||
Content-Type: application/json
|
||||
User Agent: PostmanRuntime/7.49.1
|
||||
Acceso a la interfaz pública de búsqueda de IPs
|
||||
=== 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=----geckoformboundarye5c616c1af6248b5a47402549548a751
|
||||
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
|
||||
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: 48760 bytes
|
||||
IPs obtenidas exitosamente: 3096 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 152, En uso: 102
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":152,"ipsEnUso":102}
|
||||
<<< Finalizando handler de búsqueda AJAX
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: POST
|
||||
POST data: []
|
||||
GET data: []
|
||||
Content-Type: application/json
|
||||
User Agent: bruno-runtime/2.13.2
|
||||
>>> Petición API JSON detectada
|
||||
Raw input length: 49 bytes
|
||||
JSON parseado correctamente: {"type":"event.ip_request","segment":13}
|
||||
Procesando evento API: event.ip_request
|
||||
API: Buscando IPs en segmento 13
|
||||
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: 48760 bytes
|
||||
IPs obtenidas exitosamente: 3096 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 152, En uso: 102
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: POST
|
||||
POST data: {"action":"search","segment":"54"}
|
||||
GET data: []
|
||||
Content-Type: multipart/form-data; boundary=----geckoformboundary760324c1fddb52943c44f65bcfecbf9d
|
||||
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: 54
|
||||
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: 48760 bytes
|
||||
IPs obtenidas exitosamente: 3096 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.54.x - Disponibles: 53, En uso: 201
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":53,"ipsEnUso":201}
|
||||
<<< 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=----geckoformboundary6a3bb83aaad5136b35d1d031633c43ce
|
||||
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
|
||||
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: 48807 bytes
|
||||
IPs obtenidas exitosamente: 3099 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 152, En uso: 102
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":152,"ipsEnUso":102}
|
||||
<<< Finalizando handler de búsqueda AJAX
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: POST
|
||||
POST data: []
|
||||
GET data: []
|
||||
Content-Type: application/json
|
||||
User Agent: bruno-runtime/2.13.2
|
||||
>>> Petición API JSON detectada
|
||||
Raw input length: 49 bytes
|
||||
JSON parseado correctamente: {"type":"event.ip_request","segment":13}
|
||||
Procesando evento API: event.ip_request
|
||||
API: Buscando IPs en segmento 13
|
||||
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: 48807 bytes
|
||||
IPs obtenidas exitosamente: 3099 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 152, En uso: 102
|
||||
API: Filtrando IPs administrativas. Total disponibles: 152, Aptas para clientes: 135
|
||||
=== 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":"12"}
|
||||
GET data: []
|
||||
Content-Type: multipart/form-data; boundary=----geckoformboundary3c043be49dc41eaeecf09ef1c525672b
|
||||
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: 12
|
||||
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: 48823 bytes
|
||||
IPs obtenidas exitosamente: 3100 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.12.x - Disponibles: 134, En uso: 120
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":134,"ipsEnUso":120}
|
||||
<<< 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=----geckoformboundaryb636200e57bd870b75c2713be943cc3c
|
||||
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
|
||||
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: 48875 bytes
|
||||
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
|
||||
|
||||
@ -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.0.1",
|
||||
"version": "1.1.0",
|
||||
"ucrmVersionCompliancy": {
|
||||
"min": "1.0.0",
|
||||
"max": null
|
||||
|
||||
87
public.php
87
public.php
@ -25,6 +25,7 @@ chdir(__DIR__);
|
||||
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
require_once __DIR__ . '/src/IpSearchService.php';
|
||||
require_once __DIR__ . '/src/ApiHandlers.php';
|
||||
|
||||
use Ubnt\UcrmPluginSdk\Service\PluginLogManager;
|
||||
use Ubnt\UcrmPluginSdk\Service\PluginConfigManager;
|
||||
@ -41,7 +42,41 @@ $log->appendLog('GET data: ' . json_encode($_GET));
|
||||
$log->appendLog('Content-Type: ' . ($_SERVER['CONTENT_TYPE'] ?? 'no definido'));
|
||||
$log->appendLog('User Agent: ' . ($_SERVER['HTTP_USER_AGENT'] ?? 'no definido'));
|
||||
|
||||
// Manejar peticiones AJAX
|
||||
// ============================================================================
|
||||
// API REST - Manejar peticiones JSON (Postman, Webhooks, etc.)
|
||||
// ============================================================================
|
||||
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
|
||||
$isJsonRequest = stripos($contentType, 'application/json') !== false;
|
||||
|
||||
if ($isJsonRequest && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$log->appendLog('>>> Petición API JSON detectada');
|
||||
|
||||
$rawInput = file_get_contents('php://input');
|
||||
$log->appendLog('Raw input length: ' . strlen($rawInput) . ' bytes');
|
||||
|
||||
$jsonData = json_decode($rawInput, true);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
$log->appendLog('ERROR: JSON inválido - ' . json_last_error_msg());
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Invalid JSON',
|
||||
'message' => json_last_error_msg()
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$log->appendLog('JSON parseado correctamente: ' . json_encode($jsonData));
|
||||
|
||||
// Procesar petición API
|
||||
handleApiRequest($jsonData, $log);
|
||||
exit;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// FRONTEND HTML - Manejar peticiones AJAX del formulario
|
||||
// ============================================================================
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'search') {
|
||||
$log->appendLog('>>> Entrando al handler de búsqueda AJAX');
|
||||
|
||||
@ -495,6 +530,27 @@ $log->appendLog('Acceso a la interfaz pública de búsqueda de IPs');
|
||||
color: #4facfe;
|
||||
}
|
||||
|
||||
.ip-type-badge {
|
||||
padding: 6px 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ip-type-admin {
|
||||
background: rgba(245, 87, 108, 0.2);
|
||||
border: 1px solid rgba(245, 87, 108, 0.4);
|
||||
color: #ff6b6b;
|
||||
}
|
||||
|
||||
.ip-type-client {
|
||||
background: rgba(79, 209, 197, 0.2);
|
||||
border: 1px solid rgba(79, 209, 197, 0.4);
|
||||
color: #4fd1c5;
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
color: var(--text-secondary);
|
||||
@ -596,6 +652,7 @@ $log->appendLog('Acceso a la interfaz pública de búsqueda de IPs');
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Dirección IP</th>
|
||||
<th>Tipo de IP</th>
|
||||
<th>Acción</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -704,10 +761,16 @@ $log->appendLog('Acceso a la interfaz pública de búsqueda de IPs');
|
||||
|
||||
// Llenar tabla
|
||||
data.data.forEach((ip, index) => {
|
||||
const ipType = getIpType(ip);
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td>${index + 1}</td>
|
||||
<td><span class="ip-address">${ip}</span></td>
|
||||
<td>
|
||||
<span class="ip-type-badge ip-type-${ipType.type}">
|
||||
${ipType.label}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn-copy" onclick="copyToClipboard('${ip}', this)">
|
||||
📋 Copiar
|
||||
@ -724,6 +787,28 @@ $log->appendLog('Acceso a la interfaz pública de búsqueda de IPs');
|
||||
showError(data.message, 'success');
|
||||
}
|
||||
|
||||
// Función para clasificar el tipo de IP
|
||||
function getIpType(ip) {
|
||||
const parts = ip.split('.');
|
||||
const lastOctet = parseInt(parts[3]);
|
||||
|
||||
// IPs administrativas: 1-30 y 254
|
||||
if ((lastOctet >= 1 && lastOctet <= 30) || lastOctet === 254) {
|
||||
return {
|
||||
type: 'admin',
|
||||
label: 'Administración',
|
||||
recommended: false
|
||||
};
|
||||
}
|
||||
|
||||
// IPs aptas para clientes: 31-253
|
||||
return {
|
||||
type: 'client',
|
||||
label: 'Apta para cliente',
|
||||
recommended: true
|
||||
};
|
||||
}
|
||||
|
||||
function showError(message, type = 'error') {
|
||||
const alertClass = type === 'success' ? 'alert-success' : 'alert-error';
|
||||
const icon = type === 'success' ? '✓' : '⚠';
|
||||
|
||||
@ -1,48 +0,0 @@
|
||||
<?php
|
||||
if ($argc != 2) {
|
||||
echo "Uso: php obtener_ip_segmento_api.php <segmento>\n";
|
||||
exit(1);
|
||||
}
|
||||
$segmento = $argv[1];
|
||||
|
||||
$api_url = "https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true";
|
||||
$token = "393eb3d0-9b46-4a47-b9b4-473e4e24a89c";
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $api_url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'accept: application/json',
|
||||
"x-auth-token: $token"
|
||||
]);
|
||||
$result = curl_exec($ch);
|
||||
if ($result === false) {
|
||||
echo "Error llamando a la API\n";
|
||||
exit(1);
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
$ips_en_uso = json_decode($result, true);
|
||||
|
||||
$segmento_prefix = "172.16.$segmento.";
|
||||
$segment_ips = [];
|
||||
foreach ($ips_en_uso as $ip) {
|
||||
if (strpos($ip, $segmento_prefix) === 0) {
|
||||
$segment_ips[] = $ip;
|
||||
}
|
||||
}
|
||||
|
||||
usort($segment_ips, function($a, $b) {
|
||||
return intval(explode('.', $a)[3]) - intval(explode('.', $b)[3]);
|
||||
});
|
||||
|
||||
$todas = [];
|
||||
for ($i=1; $i<=254; $i++) {
|
||||
$todas[] = "172.16.$segmento.$i";
|
||||
}
|
||||
$libres = array_values(array_diff($todas, $segment_ips));
|
||||
|
||||
echo "IPs disponibles en el segmento 172.16.$segmento.x:\n";
|
||||
foreach ($libres as $ip) {
|
||||
echo "$ip\n";
|
||||
}
|
||||
216
src/ApiHandlers.php
Normal file
216
src/ApiHandlers.php
Normal file
@ -0,0 +1,216 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Funciones de manejo de API REST para el plugin SIIP Available IPs
|
||||
*/
|
||||
|
||||
/**
|
||||
* Maneja las peticiones API REST basadas en eventos
|
||||
*/
|
||||
function handleApiRequest($data, $log) {
|
||||
header('Content-Type: application/json');
|
||||
|
||||
try {
|
||||
// Validar que exista el tipo de evento
|
||||
if (empty($data['type'])) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Missing event type',
|
||||
'message' => 'The "type" field is required'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$eventType = $data['type'];
|
||||
$log->appendLog("Procesando evento API: $eventType");
|
||||
|
||||
// Manejar diferentes tipos de eventos
|
||||
switch ($eventType) {
|
||||
case 'event.ip_request':
|
||||
handleIpRequest($data, $log);
|
||||
break;
|
||||
|
||||
case 'event.ip_check':
|
||||
handleIpCheck($data, $log);
|
||||
break;
|
||||
|
||||
default:
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Unknown event type',
|
||||
'message' => "Event type '$eventType' is not supported",
|
||||
'supported_events' => [
|
||||
'event.ip_request',
|
||||
'event.ip_check'
|
||||
]
|
||||
]);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$log->appendLog('Error en API request: ' . $e->getMessage());
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Internal error',
|
||||
'message' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maneja el evento event.ip_request - Buscar IPs disponibles en un segmento
|
||||
*/
|
||||
function handleIpRequest($data, $log) {
|
||||
// Validar segmento
|
||||
if (!isset($data['segment'])) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Missing segment',
|
||||
'message' => 'The "segment" field is required for event.ip_request'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$segment = $data['segment'];
|
||||
$log->appendLog("API: Buscando IPs en segmento $segment");
|
||||
|
||||
// Cargar configuración
|
||||
$configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
|
||||
$config = $configManager->loadConfig();
|
||||
|
||||
if (empty($config['ipserver']) || empty($config['unmsApiToken'])) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Plugin not configured',
|
||||
'message' => 'Plugin configuration is incomplete'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Buscar IPs
|
||||
$apiUrl = "https://{$config['ipserver']}/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true";
|
||||
$apiToken = $config['unmsApiToken'];
|
||||
|
||||
$ipService = new \SiipAvailableIps\IpSearchService($apiUrl, $apiToken, $log);
|
||||
$resultado = $ipService->buscarIpsDisponibles($segment);
|
||||
|
||||
// Formatear respuesta para API
|
||||
if ($resultado['success']) {
|
||||
// Filtrar IPs administrativas - Solo devolver IPs aptas para clientes (31-253)
|
||||
$clientAvailableIps = array_filter($resultado['data'], function($ip) {
|
||||
return !\SiipAvailableIps\IpSearchService::isAdminIp($ip);
|
||||
});
|
||||
$clientAvailableIps = array_values($clientAvailableIps); // Reindexar array
|
||||
|
||||
$log->appendLog("API: Filtrando IPs administrativas. Total disponibles: " . count($resultado['data']) . ", Aptas para clientes: " . count($clientAvailableIps));
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'event' => 'event.ip_request',
|
||||
'segment' => $resultado['segment'],
|
||||
'data' => [
|
||||
'available' => $clientAvailableIps,
|
||||
'used' => $resultado['used']
|
||||
],
|
||||
'count' => [
|
||||
'available' => count($clientAvailableIps),
|
||||
'used' => count($resultado['used']),
|
||||
'admin_filtered' => count($resultado['data']) - count($clientAvailableIps)
|
||||
],
|
||||
'message' => sprintf(
|
||||
'Se encontraron %d IPs aptas para clientes en el segmento %s (%d IPs administrativas filtradas)',
|
||||
count($clientAvailableIps),
|
||||
$resultado['segment'],
|
||||
count($resultado['data']) - count($clientAvailableIps)
|
||||
)
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'IP search failed',
|
||||
'message' => $resultado['message']
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maneja el evento event.ip_check - Verificar si una IP específica está disponible
|
||||
*/
|
||||
function handleIpCheck($data, $log) {
|
||||
// Validar parámetros
|
||||
if (!isset($data['ip'])) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Missing IP address',
|
||||
'message' => 'The "ip" field is required for event.ip_check'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$ipToCheck = $data['ip'];
|
||||
$log->appendLog("API: Verificando disponibilidad de IP $ipToCheck");
|
||||
|
||||
// Extraer segmento de la IP
|
||||
$parts = explode('.', $ipToCheck);
|
||||
if (count($parts) !== 4 || $parts[0] !== '172' || $parts[1] !== '16') {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Invalid IP format',
|
||||
'message' => 'IP must be in format 172.16.X.X'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$segment = $parts[2];
|
||||
|
||||
// Cargar configuración y buscar
|
||||
$configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
|
||||
$config = $configManager->loadConfig();
|
||||
|
||||
if (empty($config['ipserver']) || empty($config['unmsApiToken'])) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Plugin not configured',
|
||||
'message' => 'Plugin configuration is incomplete'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
$apiUrl = "https://{$config['ipserver']}/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true";
|
||||
$apiToken = $config['unmsApiToken'];
|
||||
|
||||
$ipService = new \SiipAvailableIps\IpSearchService($apiUrl, $apiToken, $log);
|
||||
$resultado = $ipService->buscarIpsDisponibles($segment);
|
||||
|
||||
if ($resultado['success']) {
|
||||
$isAvailable = in_array($ipToCheck, $resultado['data']);
|
||||
$isUsed = in_array($ipToCheck, $resultado['used']);
|
||||
$ipType = \SiipAvailableIps\IpSearchService::getIpType($ipToCheck);
|
||||
|
||||
// Determinar status con información de tipo de IP
|
||||
$status = 'unknown';
|
||||
if ($isAvailable) {
|
||||
$status = $ipType['type'] === 'admin'
|
||||
? 'IP disponible pero para uso administrativo'
|
||||
: 'available';
|
||||
} elseif ($isUsed) {
|
||||
$status = $ipType['type'] === 'admin'
|
||||
? 'IP en uso y además para uso administrativo'
|
||||
: 'used';
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'event' => 'event.ip_check',
|
||||
'ip' => $ipToCheck,
|
||||
'status' => $status,
|
||||
'available' => $isAvailable,
|
||||
'used' => $isUsed,
|
||||
'ip_type' => $ipType
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'IP check failed',
|
||||
'message' => $resultado['message']
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,13 @@ class IpSearchService
|
||||
private $apiToken;
|
||||
private $logger;
|
||||
|
||||
// Rangos de IPs administrativas (no recomendadas para clientes)
|
||||
const ADMIN_IP_RANGES = [
|
||||
'start' => 1,
|
||||
'end' => 30,
|
||||
'broadcast' => 254
|
||||
];
|
||||
|
||||
public function __construct($apiUrl, $apiToken, $logger = null)
|
||||
{
|
||||
$this->apiUrl = $apiUrl;
|
||||
@ -15,6 +22,50 @@ class IpSearchService
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determina si una IP es administrativa (no recomendada para clientes)
|
||||
*
|
||||
* @param string $ip Dirección IP completa (ej: 172.16.13.5)
|
||||
* @return bool True si es IP administrativa
|
||||
*/
|
||||
public static function isAdminIp($ip)
|
||||
{
|
||||
$parts = explode('.', $ip);
|
||||
if (count($parts) !== 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$lastOctet = (int)$parts[3];
|
||||
|
||||
return ($lastOctet >= self::ADMIN_IP_RANGES['start'] && $lastOctet <= self::ADMIN_IP_RANGES['end'])
|
||||
|| $lastOctet === self::ADMIN_IP_RANGES['broadcast'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene el tipo de IP (administrativa o cliente)
|
||||
*
|
||||
* @param string $ip Dirección IP completa
|
||||
* @return array ['type' => 'admin'|'client', 'label' => string, 'recommended' => bool]
|
||||
*/
|
||||
public static function getIpType($ip)
|
||||
{
|
||||
if (self::isAdminIp($ip)) {
|
||||
return [
|
||||
'type' => 'admin',
|
||||
'label' => 'Administración',
|
||||
'recommended' => false,
|
||||
'description' => 'No recomendada para clientes'
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'type' => 'client',
|
||||
'label' => 'Apta para cliente',
|
||||
'recommended' => true,
|
||||
'description' => 'Recomendada para asignar a clientes'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Busca IPs disponibles en un segmento de red específico
|
||||
*
|
||||
|
||||
Loading…
Reference in New Issue
Block a user