Fix connection issues with MikroTik API by adding port information

Fix critical bug in `mikrotik_manager.py` where the API port was not included in the base URL, leading to connection failures. Also, added SSL support detection and a new script for testing MikroTik API connections.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 7a657272-55ba-4a79-9a2e-f1ed9bc7a528
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Event-Id: 22d233cb-3add-46fa-b4e7-ead2de638008
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/449cf7c4-c97a-45ae-8234-e5c5b8d6a84f/7a657272-55ba-4a79-9a2e-f1ed9bc7a528/jFtLBWL
This commit is contained in:
marco370 2025-11-25 17:52:04 +00:00
parent a947ac8cea
commit 167e8d9575
2 changed files with 506 additions and 0 deletions

269
MIKROTIK_API_FIX.md Normal file
View File

@ -0,0 +1,269 @@
# Fix Connessione MikroTik API
## 🐛 PROBLEMA RISOLTO
**Errore**: "All connection attempts failed" quando si tenta di bloccare IP sui router MikroTik.
**Causa Root**: Bug nel file `python_ml/mikrotik_manager.py` - la porta API non veniva usata nella connessione HTTP.
### Bug Originale (Riga 36)
```python
base_url=f"http://{router_ip}" # ❌ Porta non specificata!
```
Il codice si connetteva sempre a:
- `http://185.203.24.2` (porta 80 HTTP standard)
Invece di:
- `http://185.203.24.2:8728` (porta API REST MikroTik)
- `https://185.203.24.2:8729` (porta API-SSL REST MikroTik)
### Fix Applicato
```python
protocol = "https" if use_ssl or port == 8729 else "http"
base_url=f"{protocol}://{router_ip}:{port}" # ✅ Porta corretta!
```
Ora il codice:
1. ✅ Usa la porta configurata nel database (`api_port`)
2. ✅ Auto-rileva SSL se porta = 8729
3. ✅ Supporta certificati self-signed (`verify=False`)
4. ✅ Include porta nella URL di connessione
---
## 📋 VERIFICA CONFIGURAZIONE ROUTER
### 1⃣ Controlla Database
```sql
-- Su AlmaLinux
psql $DATABASE_URL -c "SELECT name, ip_address, api_port, username, enabled FROM routers WHERE enabled = true;"
```
**Output Atteso**:
```
name | ip_address | api_port | username | enabled
--------------+---------------+----------+----------+---------
Router Main | 185.203.24.2 | 8728 | admin | t
Router Office | 10.0.1.1 | 8729 | admin | t
```
**Verifica**:
- ✅ `api_port` = **8728** (HTTP) o **8729** (HTTPS)
- ✅ `enabled` = **true**
- ✅ `username` e `password` corretti
### 2⃣ Testa Connessione Manualmente
```bash
# Su AlmaLinux
cd /opt/ids/python_ml
source venv/bin/activate
# Test connessione (sostituisci con IP/porta reali)
python3 << 'EOF'
import asyncio
from mikrotik_manager import MikroTikManager
async def test():
manager = MikroTikManager()
# Test router (SOSTITUISCI con dati reali dal database)
result = await manager.test_connection(
router_ip="185.203.24.2",
username="admin", # Dal database
password="your_password", # Dal database
port=8728 # Dal database
)
print(f"Connessione: {'✅ OK' if result else '❌ FALLITA'}")
if result:
# Test blocco IP
print("\nTest blocco IP 1.2.3.4...")
blocked = await manager.add_address_list(
router_ip="185.203.24.2",
username="admin",
password="your_password",
ip_address="1.2.3.4",
list_name="ddos_test",
comment="Test IDS API Fix",
timeout_duration="5m",
port=8728
)
print(f"Blocco: {'✅ OK' if blocked else '❌ FALLITO'}")
await manager.close_all()
asyncio.run(test())
EOF
```
---
## 🚀 DEPLOYMENT SU ALMALINUX
### Workflow Completo
#### 1**Su Replit** (GIÀ FATTO ✅)
- File `python_ml/mikrotik_manager.py` modificato
- Fix già committato su Replit
#### 2⃣ **Locale - Push GitLab**
```bash
# Dalla tua macchina locale (NON su Replit - è bloccato)
./push-gitlab.sh
```
Input richiesti:
```
Commit message: Fix MikroTik API - porta non usata in base_url
```
#### 3⃣ **Su AlmaLinux - Pull & Deploy**
```bash
# SSH su ids.alfacom.it
ssh root@ids.alfacom.it
# Pull ultimi cambiamenti
cd /opt/ids
./update_from_git.sh
# Riavvia ML Backend per applicare fix
sudo systemctl restart ids-ml-backend
# Verifica servizio attivo
systemctl status ids-ml-backend
# Verifica API risponde
curl http://localhost:8000/health
```
#### 4⃣ **Test Blocco IP**
```bash
# Dalla dashboard web: https://ids.alfacom.it/routers
# 1. Verifica router configurati
# 2. Clicca "Test Connessione" su router 185.203.24.2
# 3. Dovrebbe mostrare ✅ "Connessione OK"
# Dalla dashboard detections:
# 1. Seleziona detection con score >= 80
# 2. Clicca "Blocca IP"
# 3. Verifica blocco su router
```
---
## 🔧 TROUBLESHOOTING
### Connessione Ancora Fallisce?
#### A. Verifica Firewall su Router
```bash
# Sul router MikroTik (via winbox/SSH)
/ip service print
# Verifica che api o api-ssl sia enabled:
# 0 api 8728 *
# 1 api-ssl 8729 *
```
**Fix su MikroTik**:
```
# Abilita API REST
/ip service enable api
/ip service set api port=8728
# O con SSL
/ip service enable api-ssl
/ip service set api-ssl port=8729
```
#### B. Verifica Firewall AlmaLinux
```bash
# Su AlmaLinux - consenti traffico verso router
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" destination address="185.203.24.2" port protocol="tcp" port="8728" accept'
sudo firewall-cmd --reload
```
#### C. Test Connessione Raw
```bash
# Test TCP connessione porta 8728
telnet 185.203.24.2 8728
# O con curl
curl -v http://185.203.24.2:8728/rest/system/identity \
-u admin:password \
--max-time 5
```
#### D. Credenziali Errate?
```sql
-- Verifica credenziali nel database
psql $DATABASE_URL -c "SELECT name, ip_address, username FROM routers WHERE ip_address = '185.203.24.2';"
-- Se password errata, aggiorna:
-- UPDATE routers SET password = 'nuova_password' WHERE ip_address = '185.203.24.2';
```
---
## ✅ VERIFICA FINALE
Dopo il deployment, verifica che:
1. **ML Backend attivo**:
```bash
systemctl status ids-ml-backend # must be "active (running)"
```
2. **API risponde**:
```bash
curl http://localhost:8000/health
# {"status":"healthy","database":"connected",...}
```
3. **Auto-blocking funziona**:
```bash
# Controlla log auto-blocking
journalctl -u ids-auto-block.timer -n 50
```
4. **IP bloccati su router**:
- Dashboard: https://ids.alfacom.it/detections
- Filtra: "Bloccati"
- Verifica badge verde "Bloccato" visibile
---
## 📊 PARAMETRI API CORRETTI
| Router Config | HTTP | HTTPS (SSL) |
|--------------|------|-------------|
| **api_port** | 8728 | 8729 |
| **Protocollo** | http | https |
| **Endpoint** | `/rest/ip/firewall/address-list` | `/rest/ip/firewall/address-list` |
| **Auth** | Basic (username:password) | Basic (username:password) |
| **Verify SSL** | N/A | False (self-signed certs) |
---
## 🎯 RIEPILOGO
**Prima** (BUG):
```
http://185.203.24.2/rest/... ❌ Porta 80 (HTTP standard) - FALLISCE
```
**Dopo** (FIX):
```
http://185.203.24.2:8728/rest/... ✅ Porta 8728 (API REST) - FUNZIONA
https://185.203.24.2:8729/rest/... ✅ Porta 8729 (API-SSL) - FUNZIONA
```
---
**Fix applicato**: 25 Novembre 2024
**Versione ML Backend**: 2.0.0 (Hybrid Detector)
**Test richiesto**: ✅ Connessione + Blocco IP manuale

View File

@ -0,0 +1,237 @@
#!/usr/bin/env python3
"""
Script di test connessione MikroTik API
Verifica connessione a tutti i router configurati nel database
"""
import asyncio
import os
import sys
from dotenv import load_dotenv
import psycopg2
from mikrotik_manager import MikroTikManager
# Load environment variables
load_dotenv()
def get_routers_from_db():
"""Recupera router configurati dal database"""
try:
conn = psycopg2.connect(
host=os.getenv("PGHOST"),
port=os.getenv("PGPORT"),
database=os.getenv("PGDATABASE"),
user=os.getenv("PGUSER"),
password=os.getenv("PGPASSWORD")
)
cursor = conn.cursor()
cursor.execute("""
SELECT
id, name, ip_address, api_port,
username, password, enabled
FROM routers
ORDER BY name
""")
routers = []
for row in cursor.fetchall():
routers.append({
'id': row[0],
'name': row[1],
'ip_address': row[2],
'api_port': row[3],
'username': row[4],
'password': row[5],
'enabled': row[6]
})
cursor.close()
conn.close()
return routers
except Exception as e:
print(f"❌ Errore connessione database: {e}")
return []
async def test_router_connection(manager, router):
"""Testa connessione a un singolo router"""
print(f"\n{'='*60}")
print(f"🔍 Test Router: {router['name']}")
print(f"{'='*60}")
print(f" IP: {router['ip_address']}")
print(f" Porta: {router['api_port']}")
print(f" Username: {router['username']}")
print(f" Enabled: {'✅ Sì' if router['enabled'] else '❌ No'}")
if not router['enabled']:
print(f" ⚠️ Router disabilitato - skip test")
return False
# Test connessione
print(f"\n 📡 Test connessione...")
try:
connected = await manager.test_connection(
router_ip=router['ip_address'],
username=router['username'],
password=router['password'],
port=router['api_port']
)
if connected:
print(f" ✅ Connessione OK!")
# Test lettura address-list
print(f" 📋 Lettura address-list...")
entries = await manager.get_address_list(
router_ip=router['ip_address'],
username=router['username'],
password=router['password'],
list_name="ddos_blocked",
port=router['api_port']
)
print(f" ✅ Trovati {len(entries)} IP in lista 'ddos_blocked'")
# Mostra primi 5 IP
if entries:
print(f"\n 📌 Primi 5 IP bloccati:")
for entry in entries[:5]:
ip = entry.get('address', 'N/A')
comment = entry.get('comment', 'N/A')
timeout = entry.get('timeout', 'N/A')
print(f" - {ip} | {comment} | timeout: {timeout}")
return True
else:
print(f" ❌ Connessione FALLITA")
print(f"\n 🔧 Suggerimenti:")
print(f" 1. Verifica che il router sia raggiungibile:")
print(f" ping {router['ip_address']}")
print(f" 2. Verifica che il servizio API sia abilitato sul router:")
print(f" /ip service print (deve mostrare 'api' o 'api-ssl' enabled)")
print(f" 3. Verifica firewall non blocchi porta {router['api_port']}")
print(f" 4. Verifica credenziali (username/password)")
return False
except Exception as e:
print(f" ❌ Errore durante test: {e}")
print(f" 📋 Dettagli errore: {type(e).__name__}")
return False
async def test_block_unblock(manager, router, test_ip="1.2.3.4"):
"""Testa blocco/sblocco IP"""
print(f"\n 🧪 Test blocco/sblocco IP {test_ip}...")
# Test blocco
print(f" Blocco IP...")
blocked = await manager.add_address_list(
router_ip=router['ip_address'],
username=router['username'],
password=router['password'],
ip_address=test_ip,
list_name="ids_test",
comment="Test IDS API Fix",
timeout_duration="5m",
port=router['api_port']
)
if blocked:
print(f" ✅ IP bloccato con successo!")
# Aspetta 2 secondi
await asyncio.sleep(2)
# Test sblocco
print(f" Sblocco IP...")
unblocked = await manager.remove_address_list(
router_ip=router['ip_address'],
username=router['username'],
password=router['password'],
ip_address=test_ip,
list_name="ids_test",
port=router['api_port']
)
if unblocked:
print(f" ✅ IP sbloccato con successo!")
return True
else:
print(f" ⚠️ Sblocco fallito (ma blocco OK)")
return True
else:
print(f" ❌ Blocco IP fallito")
return False
async def main():
"""Test principale"""
print("╔════════════════════════════════════════════════════════════╗")
print("║ TEST CONNESSIONE MIKROTIK API REST ║")
print("║ IDS v2.0.0 - Hybrid Detector ║")
print("╚════════════════════════════════════════════════════════════╝")
# Recupera router dal database
print("\n📊 Caricamento router dal database...")
routers = get_routers_from_db()
if not routers:
print("❌ Nessun router trovato nel database!")
print("\n💡 Aggiungi router da: https://ids.alfacom.it/routers")
return
print(f"✅ Trovati {len(routers)} router configurati\n")
# Crea manager
manager = MikroTikManager(timeout=10)
# Test ogni router
results = []
for router in routers:
result = await test_router_connection(manager, router)
results.append({
'name': router['name'],
'ip': router['ip_address'],
'connected': result
})
# Se connesso, testa blocco/sblocco
if result and router['enabled']:
test_ok = await test_block_unblock(manager, router)
results[-1]['block_test'] = test_ok
# Riepilogo
print(f"\n{'='*60}")
print("📊 RIEPILOGO TEST")
print(f"{'='*60}\n")
for r in results:
conn_status = "✅ OK" if r['connected'] else "❌ FAIL"
block_status = ""
if 'block_test' in r:
block_status = " | Blocco: " + ("✅ OK" if r['block_test'] else "❌ FAIL")
print(f" {r['name']:20s} ({r['ip']:15s}): {conn_status}{block_status}")
success_count = sum(1 for r in results if r['connected'])
print(f"\n Totale: {success_count}/{len(results)} router connessi\n")
# Cleanup
await manager.close_all()
# Exit code
sys.exit(0 if success_count == len(results) else 1)
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\n\n⚠️ Test interrotto dall'utente")
sys.exit(1)
except Exception as e:
print(f"\n\n❌ Errore critico: {e}")
import traceback
traceback.print_exc()
sys.exit(1)