SMX Β· Repte Capa LΓ²gica
VerificaciΓ³ AutomΓ tica del Protocol de la Capa LΓ²gica
Script que automatitza les comprovacions OSI capes 3β7, implementat en Bash i Python.
Autor
G. Martin
Web
gmartin.inscastellbisbal.net
Llenguatges
Bash Β· Python 3
Sistema
Linux Ubuntu/Debian
01 β DescripciΓ³
L’objectiu Γ©s automatitzar les comprovacions del protocol de verificaciΓ³ de la capa lΓ²gica del model OSI. El script comprova connectivitat, ports TCP, resoluciΓ³ DNS, HTTP/HTTPS i certificats SSL/TLS.
Comprovacions: Ping ICMP Β· Ports TCP Β· DNS A i PTR Β· HTTP/HTTPS Β· SSL/TLS Β· AutocomprovaciΓ³
Bloc 1 Β· Capa 3
Connectivitat
Ping, latència
Bloc 2 Β· Capa 4
Ports TCP
Estat, banner
Bloc 3 Β· Capa 7
DNS
Registres A i PTR
Bloc 4 Β· Capa 7
HTTP/HTTPS
Codis, capΓ§aleres
Bloc 5 Β· Capa 6
SSL/TLS
VersiΓ³, certificat
Bloc 6 Β· Meta
Autocheck
Eines, permisos
02 β Bash vs Python
| Criteri | Bash | Python |
|---|---|---|
| Disponibilitat Linux | β Natiu | β Natiu |
| Portabilitat Windows | β Cal WSL | β Directe |
| GestiΓ³ d’errors | β BΓ sica | β try/except |
| Llegibilitat | β Limitada | β ExcelΒ·lent |
| SSL/TLS nadiu | β Via openssl | β MΓ²dul ssl |
03 β Script Python (recomanat)
verificacio_logica.py
#!/usr/bin/env python3
"""
=============================================================================
SCRIPT: verificacio_logica.py
DESCRIPCIΓ: Automatitza les comprovacions del protocol de verificaciΓ³
de la capa lΓ²gica (OSI Capa 4-7 / TCP-UDP / DNS / HTTP / SSL)
NIVELL: SMX - Sistemes MicroinformΓ tics i Xarxes
VERSIΓ: 2.0
ΓS: python3 verificacio_logica.py [-H host] [-p 80,443,22] [-t timeout] [-o informe.html]
=============================================================================
"""
import socket
import ssl
import subprocess
import argparse
import sys
import os
import json
import time
from datetime import datetime
from urllib.request import urlopen, Request
from urllib.error import URLError, HTTPError
# βββ COLORS ANSI PER TERMINAL ββββββββββββββββββββββββββββββββββββββββββββββββββ
class Color:
RED = "\033[0;31m"; GREEN = "\033[0;32m"
YELLOW = "\033[1;33m"; BLUE = "\033[0;34m"
CYAN = "\033[0;36m"; BOLD = "\033[1m"; NC = "\033[0m"
# βββ VALORS PER DEFECTE ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
HOST_DEFECTE = "8.8.8.8"
PORTS_DEFECTE = "80,443,22,53"
TIMEOUT_DEFECTE = 5
SORTIDA_HTML = "/home/claude/informe_capa_logica.html"
# βββ CLASSE PRINCIPAL ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
class VerificacioCapa:
"""Gestiona totes les comprovacions del protocol de la capa lΓ²gica."""
def __init__(self, host: str, ports: list[int], timeout: int, sortida: str):
self.host = host
self.ports = ports
self.timeout = timeout
self.sortida = sortida
self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# Comptadors
self.total = 0
self.passats = 0
self.fallats = 0
self.advertencies = 0
# Llista de resultats en ordre d'execuciΓ³
self.resultats: list[dict] = []
# βββ MΓTODE: Imprimir i desar resultat βββββββββββββββββββββββββββββββββββββ
def _resultat(self, nom: str, estat: str, detall: str, bloc: str) -> None:
"""Registra un resultat i el mostra per terminal."""
self.total += 1
if estat == "PASS":
icona = f"{Color.GREEN}β PASS{Color.NC}"
self.passats += 1
elif estat == "WARN":
icona = f"{Color.YELLOW}β WARN{Color.NC}"
self.advertencies += 1
else:
icona = f"{Color.RED}β FAIL{Color.NC}"
self.fallats += 1
print(f" {icona} {Color.BOLD}{nom}{Color.NC} β {detall}")
self.resultats.append({"nom": nom, "estat": estat, "detall": detall, "bloc": bloc})
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# BLOC 1: CONNECTIVITAT BΓSICA (ping via subprocess)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def comprovar_connectivitat(self) -> None:
print(f"\n{Color.BLUE}{Color.BOLD}βββ BLOC 1: CONNECTIVITAT BΓSICA βββ{Color.NC}")
bloc = "Bloc 1: Connectivitat BΓ sica"
# 1.1 Ping
try:
resultat = subprocess.run(
["ping", "-c", "3", "-W", str(self.timeout), self.host],
capture_output=True, text=True, timeout=self.timeout + 5
)
if resultat.returncode == 0:
# Extreure latΓ¨ncia de la lΓnia de resum
latencia = "N/A"
for linia in resultat.stdout.splitlines():
if "avg" in linia or "rtt" in linia:
parts = linia.split("/")
if len(parts) >= 5:
latencia = f"{parts[4]}ms"
self._resultat(f"Ping β {self.host}", "PASS", f"LatΓ¨ncia mitja: {latencia}", bloc)
else:
self._resultat(f"Ping β {self.host}", "FAIL", "Host inaccessible o ICMP bloquejat", bloc)
except (subprocess.TimeoutExpired, FileNotFoundError) as e:
self._resultat(f"Ping β {self.host}", "FAIL", f"Error: {e}", bloc)
# 1.2 ResoluciΓ³ DNS del host (si Γ©s nom de domini)
try:
ip = socket.gethostbyname(self.host)
if ip != self.host:
self._resultat(f"ResoluciΓ³ β {self.host}", "PASS", f"Resolt a {ip}", bloc)
else:
self._resultat(f"Host Γ©s IP directa", "PASS", f"AdreΓ§a: {ip}", bloc)
except socket.gaierror as e:
self._resultat(f"ResoluciΓ³ β {self.host}", "FAIL", f"Error DNS: {e}", bloc)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# BLOC 2: COMPROVACIΓ DE PORTS TCP
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def comprovar_ports(self) -> None:
print(f"\n{Color.BLUE}{Color.BOLD}βββ BLOC 2: PORTS TCP βββ{Color.NC}")
bloc = "Bloc 2: Ports TCP"
# Diccionari de serveis coneguts
serveis = {
21: "FTP", 22: "SSH", 23: "Telnet", 25: "SMTP",
53: "DNS", 80: "HTTP", 110: "POP3", 143: "IMAP",
443: "HTTPS", 3306: "MySQL", 5432: "PostgreSQL", 8080: "HTTP-Alt"
}
for port in self.ports:
servei = serveis.get(port, "Desconegut")
try:
with socket.create_connection((self.host, port), timeout=self.timeout) as s:
# Intentar llegir banner del servei
s.settimeout(1)
try:
banner = s.recv(64).decode("utf-8", errors="ignore").strip()[:50]
info = f"Obert Β· Banner: {banner}" if banner else "Obert i accessible"
except Exception:
info = "Obert i accessible"
self._resultat(f"Port TCP {port} ({servei})", "PASS", info, bloc)
except (ConnectionRefusedError, OSError):
self._resultat(f"Port TCP {port} ({servei})", "FAIL", "Tancat o filtrat", bloc)
except socket.timeout:
self._resultat(f"Port TCP {port} ({servei})", "WARN", f"Timeout ({self.timeout}s) β possible filtre", bloc)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# BLOC 3: RESOLUCIΓ DNS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def comprovar_dns(self) -> None:
print(f"\n{Color.BLUE}{Color.BOLD}βββ BLOC 3: RESOLUCIΓ DNS βββ{Color.NC}")
bloc = "Bloc 3: ResoluciΓ³ DNS"
dominis_prova = ["google.com", "github.com", "cloudflare.com"]
# 3.1 ResoluciΓ³ directa (socket.getaddrinfo)
for domini in dominis_prova:
try:
infos = socket.getaddrinfo(domini, None, socket.AF_INET)
if infos:
ip = infos[0][4][0]
self._resultat(f"DNS A β {domini}", "PASS", f"Resolt a {ip}", bloc)
else:
self._resultat(f"DNS A β {domini}", "FAIL", "Cap resultat DNS", bloc)
except socket.gaierror as e:
self._resultat(f"DNS A β {domini}", "FAIL", f"Error: {e}", bloc)
# 3.2 ResoluciΓ³ inversa PTR
try:
nom_invers, _, _ = socket.gethostbyaddr(self.host)
self._resultat(f"DNS PTR β {self.host}", "PASS", f"Resolt a {nom_invers}", bloc)
except socket.herror:
self._resultat(f"DNS PTR β {self.host}", "WARN", "Sense registre PTR (pot ser normal)", bloc)
except socket.gaierror as e:
self._resultat(f"DNS PTR β {self.host}", "FAIL", f"Error: {e}", bloc)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# BLOC 4: HTTP / HTTPS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def comprovar_http(self) -> None:
print(f"\n{Color.BLUE}{Color.BOLD}βββ BLOC 4: HTTP / HTTPS βββ{Color.NC}")
bloc = "Bloc 4: HTTP / HTTPS"
# 4.1 HTTP
try:
req = Request(f"http://{self.host}", headers={"User-Agent": "SMX-VerificadorCapa/2.0"})
with urlopen(req, timeout=self.timeout) as resp:
codi = resp.getcode()
self._resultat(f"HTTP β {self.host}", "PASS", f"Codi: {codi}", bloc)
except HTTPError as e:
estat = "WARN" if e.code in (301, 302, 403) else "FAIL"
self._resultat(f"HTTP β {self.host}", estat, f"Codi HTTP: {e.code}", bloc)
except URLError as e:
self._resultat(f"HTTP β {self.host}", "FAIL", f"Error: {e.reason}", bloc)
# 4.2 HTTPS (sense verificaciΓ³ cert per mΓ xima compatibilitat)
try:
ctx = ssl.create_default_context()
ctx.check_hostname = False; ctx.verify_mode = ssl.CERT_NONE
req = Request(f"https://{self.host}", headers={"User-Agent": "SMX-VerificadorCapa/2.0"})
with urlopen(req, timeout=self.timeout, context=ctx) as resp:
codi = resp.getcode()
self._resultat(f"HTTPS β {self.host}", "PASS", f"Codi: {codi}", bloc)
except HTTPError as e:
self._resultat(f"HTTPS β {self.host}", "WARN", f"Codi: {e.code}", bloc)
except Exception as e:
self._resultat(f"HTTPS β {self.host}", "FAIL", f"Error HTTPS: {str(e)[:80]}", bloc)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# BLOC 5: SSL / TLS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def comprovar_ssl(self) -> None:
print(f"\n{Color.BLUE}{Color.BOLD}βββ BLOC 5: SSL / TLS βββ{Color.NC}")
bloc = "Bloc 5: SSL / TLS"
try:
ctx = ssl.create_default_context()
ctx.check_hostname = False; ctx.verify_mode = ssl.CERT_NONE
with socket.create_connection((self.host, 443), timeout=self.timeout) as raw_sock:
with ctx.wrap_socket(raw_sock, server_hostname=self.host) as s_ssl:
# VersiΓ³ TLS
versio = s_ssl.version() or "Desconeguda"
cipher, proto, _ = s_ssl.cipher()
self._resultat(f"SSL ConnexiΓ³ β {self.host}:443", "PASS",
f"VersiΓ³: {versio} Β· Cipher: {cipher}", bloc)
# Certificat
cert = s_ssl.getpeercert()
if cert:
# Data d'expiraciΓ³
not_after = cert.get("notAfter", "Desconegut")
try:
exp_dt = datetime.strptime(not_after, "%b %d %H:%M:%S %Y %Z")
dies_restants = (exp_dt - datetime.utcnow()).days
if dies_restants > 30:
self._resultat("Certificat SSL", "PASS",
f"Caduca: {not_after} ({dies_restants} dies)", bloc)
elif dies_restants > 0:
self._resultat("Certificat SSL", "WARN",
f"Caduca AVIAT: {not_after} ({dies_restants} dies!)", bloc)
else:
self._resultat("Certificat SSL", "FAIL", f"CADUCAT: {not_after}", bloc)
except ValueError:
self._resultat("Certificat SSL", "WARN", f"Caduca: {not_after}", bloc)
# Subject / Common Name
subj = dict(x[0] for x in cert.get("subject", []))
cn = subj.get("commonName", "N/A")
self._resultat("CN Certificat", "PASS", f"CommonName: {cn}", bloc)
except ConnectionRefusedError:
self._resultat(f"SSL β {self.host}:443", "FAIL", "Port 443 tancat", bloc)
except socket.timeout:
self._resultat(f"SSL β {self.host}:443", "FAIL", "Timeout en connexiΓ³ SSL", bloc)
except Exception as e:
self._resultat(f"SSL β {self.host}:443", "FAIL", f"Error SSL: {str(e)[:80]}", bloc)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# BLOC 6: AUTOCOMPROVACIΓ
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def autocomprovacio(self) -> None:
print(f"\n{Color.BLUE}{Color.BOLD}βββ BLOC 6: AUTOCOMPROVACIΓ βββ{Color.NC}")
bloc = "Bloc 6: AutocomprovaciΓ³"
# Test 1: MΓ²duls Python necessaris
moduls = ["socket", "ssl", "subprocess", "urllib.request"]
for modul in moduls:
try:
__import__(modul)
self._resultat(f"MΓ²dul Python: {modul}", "PASS", "Disponible", bloc)
except ImportError:
self._resultat(f"MΓ²dul Python: {modul}", "FAIL", "No disponible!", bloc)
# Test 2: Permisos d'escriptura
dir_sortida = os.path.dirname(self.sortida) or "."
if os.access(dir_sortida, os.W_OK):
self._resultat(f"Permisos escriptura β {dir_sortida}", "PASS", "Directori accessible", bloc)
else:
self._resultat(f"Permisos escriptura β {dir_sortida}", "FAIL", "Sense permisos d'escriptura", bloc)
# Test 3: ValidaciΓ³ de parΓ metres
if self.timeout > 0 and self.timeout <= 60:
self._resultat("ParΓ metre timeout", "PASS", f"Valor vΓ lid: {self.timeout}s", bloc)
else:
self._resultat("ParΓ metre timeout", "WARN", f"Valor inusual: {self.timeout}s", bloc)
# Test 4: Connectivitat bΓ sica de Python (DNS del sistema)
try:
socket.setdefaulttimeout(self.timeout)
socket.gethostbyname("google.com")
self._resultat("DNS Sistema (Python)", "PASS", "ResoluciΓ³ DNS bΓ sica funciona", bloc)
except socket.gaierror:
self._resultat("DNS Sistema (Python)", "FAIL", "Sense resoluciΓ³ DNS!", bloc)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# GENERACIΓ D'INFORME HTML
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def generar_html(self) -> None:
"""Genera l'informe HTML amb tots els resultats."""
pct = (self.passats * 100 // self.total) if self.total > 0 else 0
color_pct = "var(--ok)" if pct >= 80 else ("var(--warn)" if pct >= 50 else "var(--fail)")
# Agrupar resultats per bloc
blocs: dict[str, list[dict]] = {}
for r in self.resultats:
blocs.setdefault(r["bloc"], []).append(r)
# Generar fileres HTML
blocs_html = ""
for nom_bloc, items in blocs.items():
fileres = ""
for item in items:
classe = "ok" if item["estat"] == "PASS" else item["estat"].lower()
fileres += f"""
<div class="fila">
<span class="pill {classe}">{item['estat']}</span>
<span class="nom">{item['nom']}</span>
<span class="detall">{item['detall']}</span>
</div>"""
blocs_html += f"""
<div class="bloc">
<div class="bloc-header">{nom_bloc}</div>{fileres}
</div>"""
html = f"""<!DOCTYPE html>
<html lang="ca">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Informe VerificaciΓ³ Capa LΓ²gica β {self.host}</title>
<style>
:root {{
--bg:#0f1117; --surface:#1a1d2e; --surface2:#252840;
--ok:#22d3a0; --fail:#ff4d6d; --warn:#fbbf24;
--text:#e2e8f0; --muted:#64748b; --accent:#6366f1;
--border:rgba(99,102,241,0.2);
--font:'JetBrains Mono','Fira Code','Courier New',monospace;
}}
* {{ margin:0; padding:0; box-sizing:border-box; }}
body {{ background:var(--bg); color:var(--text); font-family:var(--font); font-size:13px; line-height:1.6; }}
.container {{ max-width:960px; margin:0 auto; padding:2rem; }}
.header {{ text-align:center; padding:3rem 0 2rem; border-bottom:1px solid var(--border); }}
.badge {{ display:inline-block; background:var(--accent); color:#fff; font-size:10px; padding:3px 10px; border-radius:20px; letter-spacing:2px; text-transform:uppercase; margin-bottom:1rem; }}
h1 {{ font-size:2rem; font-weight:700; color:#fff; }}
h1 span {{ color:var(--accent); }}
.meta {{ color:var(--muted); font-size:11px; margin-top:.5rem; }}
.resum {{ display:grid; grid-template-columns:repeat(4,1fr); gap:1rem; margin:2rem 0; }}
.resum-card {{ background:var(--surface); border:1px solid var(--border); border-radius:8px; padding:1.2rem; text-align:center; }}
.resum-card .num {{ font-size:2.2rem; font-weight:700; }}
.resum-card .etiq {{ font-size:10px; text-transform:uppercase; color:var(--muted); letter-spacing:1px; margin-top:4px; }}
.resum-card.ok .num {{ color:var(--ok); }} .resum-card.fail .num {{ color:var(--fail); }}
.resum-card.warn .num {{ color:var(--warn); }} .resum-card.total .num {{ color:var(--accent); }}
.progres-wrap {{ background:var(--surface); border-radius:8px; padding:1.5rem; margin-bottom:2rem; border:1px solid var(--border); }}
.progres-label {{ display:flex; justify-content:space-between; margin-bottom:8px; }}
.pct {{ font-size:1.4rem; font-weight:700; color:{color_pct}; }}
.barra {{ height:8px; background:var(--surface2); border-radius:4px; overflow:hidden; }}
.barra-fill {{ height:100%; width:{pct}%; background:linear-gradient(90deg,var(--accent),var(--ok)); border-radius:4px; }}
.info-host {{ background:var(--surface); border:1px solid var(--border); border-radius:8px; padding:1.2rem 1.5rem; margin-bottom:2rem; display:flex; gap:2rem; flex-wrap:wrap; }}
.info-item {{ display:flex; flex-direction:column; }}
.info-item .key {{ font-size:10px; color:var(--muted); text-transform:uppercase; letter-spacing:1px; }}
.info-item .val {{ color:var(--accent); font-weight:600; }}
.bloc {{ background:var(--surface); border:1px solid var(--border); border-radius:8px; margin-bottom:1.5rem; overflow:hidden; }}
.bloc-header {{ background:var(--surface2); padding:.8rem 1.2rem; font-weight:700; font-size:11px; letter-spacing:1px; text-transform:uppercase; color:var(--accent); border-bottom:1px solid var(--border); }}
.fila {{ display:flex; align-items:center; padding:.7rem 1.2rem; border-bottom:1px solid rgba(99,102,241,.08); gap:.8rem; }}
.fila:last-child {{ border-bottom:none; }}
.fila:hover {{ background:rgba(99,102,241,.05); }}
.pill {{ font-size:10px; font-weight:700; padding:2px 8px; border-radius:12px; min-width:44px; text-align:center; flex-shrink:0; }}
.pill.ok {{ background:rgba(34,211,160,.15); color:var(--ok); }}
.pill.fail {{ background:rgba(255,77,109,.15); color:var(--fail); }}
.pill.warn {{ background:rgba(251,191,36,.15); color:var(--warn); }}
.nom {{ font-weight:600; color:#fff; min-width:220px; }}
.detall {{ color:var(--muted); font-size:12px; }}
footer {{ text-align:center; color:var(--muted); font-size:11px; padding:2rem 0; border-top:1px solid var(--border); margin-top:2rem; }}
footer span {{ color:var(--accent); }}
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="badge">SMX Β· Capa LΓ²gica Β· Python</div>
<h1>Informe de <span>VerificaciΓ³</span><br>Protocol Capa LΓ²gica</h1>
<div class="meta">Generat: {self.timestamp} Β· Host: {self.host} Β· Timeout: {self.timeout}s</div>
</div>
<div class="resum" style="margin-top:2rem;">
<div class="resum-card total"><div class="num">{self.total}</div><div class="etiq">Total proves</div></div>
<div class="resum-card ok"><div class="num">{self.passats}</div><div class="etiq">Correctes</div></div>
<div class="resum-card fail"><div class="num">{self.fallats}</div><div class="etiq">Fallades</div></div>
<div class="resum-card warn"><div class="num">{self.advertencies}</div><div class="etiq">Advertències</div></div>
</div>
<div class="progres-wrap">
<div class="progres-label"><span>Resultat global</span><span class="pct">{pct}% correcte</span></div>
<div class="barra"><div class="barra-fill"></div></div>
</div>
<div class="info-host">
<div class="info-item"><span class="key">Host Objectiu</span><span class="val">{self.host}</span></div>
<div class="info-item"><span class="key">Ports Analitzats</span><span class="val">{','.join(map(str,self.ports))}</span></div>
<div class="info-item"><span class="key">Timeout</span><span class="val">{self.timeout}s</span></div>
<div class="info-item"><span class="key">Plataforma</span><span class="val">Python {sys.version.split()[0]}</span></div>
</div>
{blocs_html}
<footer>
Generat per <span>verificacio_logica.py v2.0</span> Β· SMX Capa LΓ²gica Β· {self.timestamp}
</footer>
</div>
</body>
</html>"""
with open(self.sortida, "w", encoding="utf-8") as f:
f.write(html)
print(f"\n{Color.GREEN}{Color.BOLD}β Informe HTML generat:{Color.NC} {self.sortida}")
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# EXECUCIΓ COMPLETA
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def executar(self) -> None:
"""Punt d'entrada: executa tots els blocs de comprovaciΓ³."""
print(f"{Color.BOLD}{Color.CYAN}")
print("ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ")
print("β VERIFICACIΓ PROTOCOL CAPA LΓGICA β SMX v2.0 (Python) β")
print(f"ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ{Color.NC}")
print(f" Host: {Color.CYAN}{self.host}{Color.NC} | Timeout: {Color.CYAN}{self.timeout}s{Color.NC}")
print(f" Inici: {Color.CYAN}{self.timestamp}{Color.NC}\n")
# Ordre d'execuciΓ³ dels blocs
self.autocomprovacio()
self.comprovar_connectivitat()
self.comprovar_ports()
self.comprovar_dns()
self.comprovar_http()
self.comprovar_ssl()
# Resum final
pct = (self.passats * 100 // self.total) if self.total > 0 else 0
print(f"\n{Color.BOLD}{Color.CYAN}βββ RESUM FINAL βββ{Color.NC}")
print(f" Total: {self.total} | {Color.GREEN}Passats: {self.passats}{Color.NC} "
f"| {Color.RED}Fallats: {self.fallats}{Color.NC} "
f"| {Color.YELLOW}Advertències: {self.advertencies}{Color.NC}")
print(f" PuntuaciΓ³ global: {Color.BOLD}{pct}%{Color.NC}")
# Generar informe
self.generar_html()
print(f"{Color.BOLD}{Color.CYAN}ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ{Color.NC}\n")
# βββ PUNT D'ENTRADA ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def main():
parser = argparse.ArgumentParser(
description="VerificaciΓ³ automΓ tica del protocol de la capa lΓ²gica β SMX",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="Exemples:\n python3 verificacio_logica.py\n python3 verificacio_logica.py -H example.com -p 80,443 -t 3"
)
parser.add_argument("-H", "--host", default=HOST_DEFECTE, help=f"Host objectiu (defecte: {HOST_DEFECTE})")
parser.add_argument("-p", "--ports", default=PORTS_DEFECTE, help=f"Ports TCP (defecte: {PORTS_DEFECTE})")
parser.add_argument("-t", "--timeout", default=TIMEOUT_DEFECTE, type=int, help=f"Timeout en segons (defecte: {TIMEOUT_DEFECTE})")
parser.add_argument("-o", "--output", default=SORTIDA_HTML, help=f"Fitxer HTML de sortida")
args = parser.parse_args()
# Parsejar llista de ports
try:
llista_ports = [int(p.strip()) for p in args.ports.split(",") if p.strip().isdigit()]
except ValueError:
print(f"{Color.RED}Error: Format de ports invΓ lid. Usa: 80,443,22{Color.NC}")
sys.exit(1)
# Crear i executar verificaciΓ³
verificador = VerificacioCapa(
host=args.host,
ports=llista_ports,
timeout=args.timeout,
sortida=args.output
)
verificador.executar()
if __name__ == "__main__":
main()
04 β Script Bash
verificacio_logica.sh
#!/usr/bin/env bash
# =============================================================================
# SCRIPT: verificacio_logica.sh
# DESCRIPCIΓ: Automatitza les comprovacions del protocol de verificaciΓ³
# de la capa lΓ²gica (OSI Capa 4-7 / TCP-UDP / DNS / HTTP)
# NIVELL: SMX - Sistemes MicroinformΓ tics i Xarxes
# AUTOR: VerificaciΓ³ AutomΓ tica SMX
# VERSIΓ: 2.0
# ΓS: ./verificacio_logica.sh [-H host] [-p ports] [-t timeout] [-o informe.html]
# =============================================================================
# βββ COLORS ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
BLUE='\033[0;34m'; CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'
# βββ VALORS PER DEFECTE (parΓ metres configurables) βββββββββββββββββββββββββββββ
HOST_DEFECTE="8.8.8.8"
PORTS_DEFECTE="80,443,22,53"
TIMEOUT_DEFECTE=5
SORTIDA_HTML="/home/claude/informe_capa_logica.html"
LOG_FILE="/tmp/verificacio_$(date +%Y%m%d_%H%M%S).log"
# βββ VARIABLES GLOBALS βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
TOTAL=0; PASSATS=0; FALLATS=0; ADVERTENCIES=0
declare -A RESULTATS # Diccionari per guardar resultats
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
# βββ FUNCIΓ: Γs del script ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
us() {
echo -e "${BOLD}ΓS:${NC} $0 [opcions]"
echo -e " ${CYAN}-H${NC} <host> Host o IP objectiu (defecte: $HOST_DEFECTE)"
echo -e " ${CYAN}-p${NC} <ports> Ports separats per comes (defecte: $PORTS_DEFECTE)"
echo -e " ${CYAN}-t${NC} <segons> Timeout per connexiΓ³ (defecte: ${TIMEOUT_DEFECTE}s)"
echo -e " ${CYAN}-o${NC} <fitxer> Fitxer de sortida HTML (defecte: $SORTIDA_HTML)"
echo -e " ${CYAN}-h${NC} Mostra aquesta ajuda"
exit 0
}
# βββ FUNCIΓ: Log βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
log() {
local nivell="$1"; local missatge="$2"
echo "[$TIMESTAMP][$nivell] $missatge" >> "$LOG_FILE"
}
# βββ FUNCIΓ: Imprimir resultat βββββββββββββββββββββββββββββββββββββββββββββββββ
resultat() {
local nom="$1"; local estat="$2"; local detall="$3"
TOTAL=$((TOTAL + 1))
if [[ "$estat" == "OK" ]]; then
echo -e " ${GREEN}β PASS${NC} ${BOLD}$nom${NC} β $detall"
PASSATS=$((PASSATS + 1))
RESULTATS["$nom"]="PASS|$detall"
log "PASS" "$nom: $detall"
elif [[ "$estat" == "WARN" ]]; then
echo -e " ${YELLOW}β WARN${NC} ${BOLD}$nom${NC} β $detall"
ADVERTENCIES=$((ADVERTENCIES + 1))
RESULTATS["$nom"]="WARN|$detall"
log "WARN" "$nom: $detall"
else
echo -e " ${RED}β FAIL${NC} ${BOLD}$nom${NC} β $detall"
FALLATS=$((FALLATS + 1))
RESULTATS["$nom"]="FAIL|$detall"
log "FAIL" "$nom: $detall"
fi
}
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# BLOC 1: COMPROVACIΓ DE CONNECTIVITAT (Capa de Xarxa + Transport)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
comprovar_connectivitat() {
echo -e "\n${BLUE}${BOLD}βββ BLOC 1: CONNECTIVITAT BΓSICA βββ${NC}"
# 1.1 Ping al host objectiu
if ping -c 3 -W "$TIMEOUT" "$HOST" &>/dev/null; then
local latencia
latencia=$(ping -c 3 -W "$TIMEOUT" "$HOST" 2>/dev/null | tail -1 | awk -F'/' '{print $5}' 2>/dev/null || echo "N/A")
resultat "Ping β $HOST" "OK" "LatΓ¨ncia mitjana: ${latencia}ms"
else
resultat "Ping β $HOST" "FAIL" "Host inaccessible o ICMP bloquejat"
fi
# 1.2 ComprovaciΓ³ de ruta (traceroute si disponible)
if command -v traceroute &>/dev/null; then
local salts
salts=$(traceroute -m 10 -w 2 "$HOST" 2>/dev/null | wc -l)
resultat "Traceroute β $HOST" "OK" "Ruta amb ~$salts salts detectats"
else
resultat "Traceroute β $HOST" "WARN" "Eina 'traceroute' no instalΒ·lada"
fi
}
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# BLOC 2: COMPROVACIΓ DE PORTS TCP (Capa Transport)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
comprovar_ports() {
echo -e "\n${BLUE}${BOLD}βββ BLOC 2: PORTS TCP βββ${NC}"
# Noms de serveis coneguts
declare -A SERVEIS=(
[21]="FTP" [22]="SSH" [23]="Telnet" [25]="SMTP"
[53]="DNS" [80]="HTTP" [110]="POP3" [143]="IMAP"
[443]="HTTPS" [3306]="MySQL" [5432]="PostgreSQL" [8080]="HTTP-Alt"
)
IFS=',' read -ra LLISTA_PORTS <<< "$PORTS"
for port in "${LLISTA_PORTS[@]}"; do
port=$(echo "$port" | tr -d ' ') # Eliminar espais
local servei="${SERVEIS[$port]:-Desconegut}"
# Intentar connexiΓ³ TCP amb timeout
if timeout "$TIMEOUT" bash -c "echo >/dev/tcp/$HOST/$port" 2>/dev/null; then
resultat "Port TCP $port ($servei)" "OK" "Obert i accessible"
else
resultat "Port TCP $port ($servei)" "FAIL" "Tancat o filtrat"
fi
done
}
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# BLOC 3: RESOLUCIΓ DNS (Capa AplicaciΓ³)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
comprovar_dns() {
echo -e "\n${BLUE}${BOLD}βββ BLOC 3: RESOLUCIΓ DNS βββ${NC}"
local DOMINIS=("google.com" "github.com" "cloudflare.com")
# 3.1 ResoluciΓ³ directa (A record)
for domini in "${DOMINIS[@]}"; do
if command -v nslookup &>/dev/null; then
local ip
ip=$(nslookup "$domini" 2>/dev/null | awk '/^Address: / {print $2; exit}')
if [[ -n "$ip" ]]; then
resultat "DNS A β $domini" "OK" "Resolt a $ip"
else
resultat "DNS A β $domini" "FAIL" "No s'ha pogut resoldre"
fi
elif command -v dig &>/dev/null; then
local ip
ip=$(dig +short "$domini" A 2>/dev/null | head -1)
if [[ -n "$ip" ]]; then
resultat "DNS A β $domini" "OK" "Resolt a $ip"
else
resultat "DNS A β $domini" "FAIL" "No s'ha pogut resoldre"
fi
else
resultat "DNS β $domini" "WARN" "Ni 'nslookup' ni 'dig' disponibles"
break
fi
done
# 3.2 ResoluciΓ³ inversa (PTR)
if command -v dig &>/dev/null; then
local ptr
ptr=$(dig +short -x "$HOST" 2>/dev/null | head -1)
if [[ -n "$ptr" ]]; then
resultat "DNS PTR β $HOST" "OK" "Resolt a $ptr"
else
resultat "DNS PTR β $HOST" "WARN" "Sense registre PTR (pot ser normal)"
fi
fi
}
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# BLOC 4: COMPROVACIΓ HTTP/HTTPS (Capa AplicaciΓ³)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
comprovar_http() {
echo -e "\n${BLUE}${BOLD}βββ BLOC 4: HTTP / HTTPS βββ${NC}"
if ! command -v curl &>/dev/null; then
resultat "HTTP/HTTPS" "WARN" "curl no disponible β salt de comprovacions HTTP"
return
fi
# 4.1 HTTP bΓ sic
local codi_http
codi_http=$(curl -s -o /dev/null -w "%{http_code}" --max-time "$TIMEOUT" "http://$HOST" 2>/dev/null)
if [[ "$codi_http" =~ ^[23] ]]; then
resultat "HTTP β $HOST" "OK" "Codi de resposta: $codi_http"
elif [[ "$codi_http" == "301" || "$codi_http" == "302" ]]; then
resultat "HTTP β $HOST" "WARN" "RedirecciΓ³ detectada ($codi_http)"
else
resultat "HTTP β $HOST" "FAIL" "Codi: $codi_http (o sense resposta)"
fi
# 4.2 HTTPS amb verificaciΓ³ SSL
local codi_https
codi_https=$(curl -s -o /dev/null -w "%{http_code}" --max-time "$TIMEOUT" "https://$HOST" 2>/dev/null)
if [[ "$codi_https" =~ ^[23] ]]; then
resultat "HTTPS β $HOST" "OK" "Codi de resposta: $codi_https (SSL vΓ lid)"
elif [[ "$codi_https" == "000" ]]; then
resultat "HTTPS β $HOST" "FAIL" "Sense resposta HTTPS o SSL invΓ lid"
else
resultat "HTTPS β $HOST" "WARN" "Codi inesperat: $codi_https"
fi
# 4.3 CapΓ§aleres de seguretat HTTP
local headers
headers=$(curl -s -I --max-time "$TIMEOUT" "https://$HOST" 2>/dev/null)
if echo "$headers" | grep -qi "strict-transport-security"; then
resultat "HSTS Header" "OK" "CapΓ§alera Strict-Transport-Security present"
else
resultat "HSTS Header" "WARN" "CapΓ§alera HSTS absent (recomanada)"
fi
}
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# BLOC 5: COMPROVACIΓ SSL/TLS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
comprovar_ssl() {
echo -e "\n${BLUE}${BOLD}βββ BLOC 5: SSL / TLS βββ${NC}"
if ! command -v openssl &>/dev/null; then
resultat "SSL/TLS" "WARN" "openssl no disponible"
return
fi
# 5.1 ConnexiΓ³ SSL bΓ sica
local ssl_info
ssl_info=$(echo | timeout "$TIMEOUT" openssl s_client -connect "$HOST:443" 2>/dev/null)
if echo "$ssl_info" | grep -q "CONNECTED"; then
# Extreure versiΓ³ TLS
local versio_tls
versio_tls=$(echo "$ssl_info" | grep "Protocol" | awk '{print $3}' | head -1)
resultat "SSL ConnexiΓ³ β $HOST:443" "OK" "VersiΓ³: ${versio_tls:-TLS detectat}"
# Verificar certificat
local data_exp
data_exp=$(echo "$ssl_info" | grep "notAfter" | cut -d= -f2)
if [[ -n "$data_exp" ]]; then
resultat "Certificat SSL Caducitat" "OK" "Caduca: $data_exp"
fi
# Verificar TLS 1.0/1.1 (protocols obsolets)
if echo | timeout "$TIMEOUT" openssl s_client -connect "$HOST:443" -tls1 2>/dev/null | grep -q "CONNECTED"; then
resultat "TLS 1.0 (obsolet)" "WARN" "TLS 1.0 acceptat β considera desactivar-lo"
else
resultat "TLS 1.0 desactivat" "OK" "Protocol TLS 1.0 rebutjat correctament"
fi
else
resultat "SSL ConnexiΓ³ β $HOST:443" "FAIL" "No s'ha pogut establir connexiΓ³ SSL"
fi
}
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# BLOC 6: TEST D'AUTOCOMPROVACIΓ DEL SCRIPT
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
autocomprovacio() {
echo -e "\n${BLUE}${BOLD}βββ BLOC 6: AUTOCOMPROVACIΓ DEL SCRIPT βββ${NC}"
# Test 1: Eines necessΓ ries
local eines=("ping" "curl" "openssl" "nslookup")
for eina in "${eines[@]}"; do
if command -v "$eina" &>/dev/null; then
resultat "Eina: $eina" "OK" "Disponible al sistema"
else
resultat "Eina: $eina" "WARN" "No instalΒ·lada β algunes comprovacions es saltaran"
fi
done
# Test 2: Permisos d'escriptura per a l'informe
local dir_sortida
dir_sortida=$(dirname "$SORTIDA_HTML")
if [[ -w "$dir_sortida" ]]; then
resultat "Permisos escriptura β $dir_sortida" "OK" "Directori accessible"
else
resultat "Permisos escriptura β $dir_sortida" "FAIL" "Sense permisos d'escriptura"
fi
# Test 3: ValidaciΓ³ de parΓ metres
if [[ "$TIMEOUT" =~ ^[0-9]+$ ]] && [[ "$TIMEOUT" -gt 0 ]]; then
resultat "ParΓ metre timeout" "OK" "Valor vΓ lid: ${TIMEOUT}s"
else
resultat "ParΓ metre timeout" "FAIL" "Valor invΓ lid: $TIMEOUT"
fi
}
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# GENERACIΓ D'INFORME HTML
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
generar_html() {
local percentatge=0
[[ "$TOTAL" -gt 0 ]] && percentatge=$(( (PASSATS * 100) / TOTAL ))
# Color del resum
local color_resum="var(--warn)"
[[ "$percentatge" -ge 80 ]] && color_resum="var(--ok)"
[[ "$percentatge" -lt 50 ]] && color_resum="var(--fail)"
cat > "$SORTIDA_HTML" << HTMLEOF
<!DOCTYPE html>
<html lang="ca">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Informe VerificaciΓ³ Capa LΓ²gica β $HOST</title>
<style>
:root {
--bg: #0f1117; --surface: #1a1d2e; --surface2: #252840;
--ok: #22d3a0; --fail: #ff4d6d; --warn: #fbbf24;
--text: #e2e8f0; --muted: #64748b; --accent: #6366f1;
--border: rgba(99,102,241,0.2);
--font: 'JetBrains Mono', 'Fira Code', 'Courier New', monospace;
}
* { margin:0; padding:0; box-sizing:border-box; }
body { background:var(--bg); color:var(--text); font-family:var(--font); font-size:13px; line-height:1.6; }
.container { max-width:960px; margin:0 auto; padding:2rem; }
/* HEADER */
.header { text-align:center; padding:3rem 0 2rem; border-bottom:1px solid var(--border); }
.header .badge { display:inline-block; background:var(--accent); color:#fff; font-size:10px; padding:3px 10px; border-radius:20px; letter-spacing:2px; text-transform:uppercase; margin-bottom:1rem; }
.header h1 { font-size:2rem; font-weight:700; letter-spacing:-0.5px; color:#fff; }
.header h1 span { color:var(--accent); }
.header .meta { color:var(--muted); font-size:11px; margin-top:0.5rem; }
/* RESUM */
.resum { display:grid; grid-template-columns:repeat(4,1fr); gap:1rem; margin:2rem 0; }
.resum-card { background:var(--surface); border:1px solid var(--border); border-radius:8px; padding:1.2rem; text-align:center; }
.resum-card .num { font-size:2.2rem; font-weight:700; }
.resum-card .etiq { font-size:10px; text-transform:uppercase; color:var(--muted); letter-spacing:1px; margin-top:4px; }
.resum-card.ok .num { color:var(--ok); }
.resum-card.fail .num { color:var(--fail); }
.resum-card.warn .num { color:var(--warn); }
.resum-card.total .num { color:var(--accent); }
/* BARRA PROGRΓS */
.progres-wrap { background:var(--surface); border-radius:8px; padding:1.5rem; margin-bottom:2rem; border:1px solid var(--border); }
.progres-label { display:flex; justify-content:space-between; margin-bottom:8px; }
.progres-label .pct { font-size:1.4rem; font-weight:700; color:${color_resum}; }
.barra { height:8px; background:var(--surface2); border-radius:4px; overflow:hidden; }
.barra-fill { height:100%; width:${percentatge}%; background:linear-gradient(90deg,var(--accent),var(--ok)); border-radius:4px; transition:width 1s ease; }
/* INFO HOST */
.info-host { background:var(--surface); border:1px solid var(--border); border-radius:8px; padding:1.2rem 1.5rem; margin-bottom:2rem; display:flex; gap:2rem; flex-wrap:wrap; }
.info-item { display:flex; flex-direction:column; }
.info-item .key { font-size:10px; color:var(--muted); text-transform:uppercase; letter-spacing:1px; }
.info-item .val { color:var(--accent); font-weight:600; }
/* BLOC DE RESULTATS */
.bloc { background:var(--surface); border:1px solid var(--border); border-radius:8px; margin-bottom:1.5rem; overflow:hidden; }
.bloc-header { background:var(--surface2); padding:0.8rem 1.2rem; font-weight:700; font-size:11px; letter-spacing:1px; text-transform:uppercase; color:var(--accent); border-bottom:1px solid var(--border); }
.fila { display:flex; align-items:center; padding:0.7rem 1.2rem; border-bottom:1px solid rgba(99,102,241,0.08); gap:0.8rem; }
.fila:last-child { border-bottom:none; }
.fila:hover { background:rgba(99,102,241,0.05); }
.pill { font-size:10px; font-weight:700; padding:2px 8px; border-radius:12px; min-width:44px; text-align:center; flex-shrink:0; }
.pill.ok { background:rgba(34,211,160,0.15); color:var(--ok); }
.pill.fail { background:rgba(255,77,109,0.15); color:var(--fail); }
.pill.warn { background:rgba(251,191,36,0.15); color:var(--warn); }
.nom { font-weight:600; color:#fff; min-width:220px; }
.detall { color:var(--muted); font-size:12px; }
/* FOOTER */
footer { text-align:center; color:var(--muted); font-size:11px; padding:2rem 0; border-top:1px solid var(--border); margin-top:2rem; }
footer span { color:var(--accent); }
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="badge">SMX Β· Capa LΓ²gica</div>
<h1>Informe de <span>VerificaciΓ³</span><br>Protocol Capa LΓ²gica</h1>
<div class="meta">Generat: $TIMESTAMP Β· Host: $HOST Β· Timeout: ${TIMEOUT}s</div>
</div>
<div class="resum" style="margin-top:2rem;">
<div class="resum-card total"><div class="num">$TOTAL</div><div class="etiq">Total proves</div></div>
<div class="resum-card ok"><div class="num">$PASSATS</div><div class="etiq">Correctes</div></div>
<div class="resum-card fail"><div class="num">$FALLATS</div><div class="etiq">Fallades</div></div>
<div class="resum-card warn"><div class="num">$ADVERTENCIES</div><div class="etiq">Advertències</div></div>
</div>
<div class="progres-wrap">
<div class="progres-label">
<span>Resultat global</span>
<span class="pct">${percentatge}% correcte</span>
</div>
<div class="barra"><div class="barra-fill"></div></div>
</div>
<div class="info-host">
<div class="info-item"><span class="key">Host Objectiu</span><span class="val">$HOST</span></div>
<div class="info-item"><span class="key">Ports Analitzats</span><span class="val">$PORTS</span></div>
<div class="info-item"><span class="key">Timeout</span><span class="val">${TIMEOUT}s</span></div>
<div class="info-item"><span class="key">Sistema</span><span class="val">$(uname -s) $(uname -r | cut -d- -f1)</span></div>
<div class="info-item"><span class="key">Log</span><span class="val">$LOG_FILE</span></div>
</div>
HTMLEOF
# Afegir resultats per blocs
local bloc_actual=""
for nom_clau in "${!RESULTATS[@]}"; do
local valor="${RESULTATS[$nom_clau]}"
local estat="${valor%%|*}"; local det="${valor#*|}"
local classe_pill="${estat,,}"
[[ "$classe_pill" == "pass" ]] && classe_pill="ok"
# Detectar nou bloc
local bloc_nou
if echo "$nom_clau" | grep -qi "ping\|traceroute"; then bloc_nou="Bloc 1: Connectivitat BΓ sica"
elif echo "$nom_clau" | grep -qi "port"; then bloc_nou="Bloc 2: Ports TCP"
elif echo "$nom_clau" | grep -qi "dns"; then bloc_nou="Bloc 3: ResoluciΓ³ DNS"
elif echo "$nom_clau" | grep -qi "http\|hsts"; then bloc_nou="Bloc 4: HTTP / HTTPS"
elif echo "$nom_clau" | grep -qi "ssl\|tls\|certif"; then bloc_nou="Bloc 5: SSL / TLS"
else bloc_nou="Bloc 6: AutocomprovaciΓ³"
fi
if [[ "$bloc_nou" != "$bloc_actual" ]]; then
[[ -n "$bloc_actual" ]] && echo "</div>" >> "$SORTIDA_HTML"
echo "<div class=\"bloc\"><div class=\"bloc-header\">$bloc_nou</div>" >> "$SORTIDA_HTML"
bloc_actual="$bloc_nou"
fi
cat >> "$SORTIDA_HTML" << ROWEOF
<div class="fila">
<span class="pill $classe_pill">$estat</span>
<span class="nom">$nom_clau</span>
<span class="detall">$det</span>
</div>
ROWEOF
done
[[ -n "$bloc_actual" ]] && echo "</div>" >> "$SORTIDA_HTML"
cat >> "$SORTIDA_HTML" << FOOTEREOF
<footer>
Generat per <span>verificacio_logica.sh v2.0</span> Β· SMX Capa LΓ²gica Β· $TIMESTAMP
</footer>
</div>
</body>
</html>
FOOTEREOF
echo -e "\n${GREEN}${BOLD}β Informe HTML generat:${NC} $SORTIDA_HTML"
}
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# PARSEO D'ARGUMENTS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
HOST="$HOST_DEFECTE"
PORTS="$PORTS_DEFECTE"
TIMEOUT="$TIMEOUT_DEFECTE"
while getopts "H:p:t:o:h" opt; do
case "$opt" in
H) HOST="$OPTARG" ;;
p) PORTS="$OPTARG" ;;
t) TIMEOUT="$OPTARG" ;;
o) SORTIDA_HTML="$OPTARG" ;;
h) us ;;
*) us ;;
esac
done
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# EXECUCIΓ PRINCIPAL
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
clear
echo -e "${BOLD}${CYAN}"
echo "ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ"
echo "β VERIFICACIΓ PROTOCOL CAPA LΓGICA β SMX v2.0 β"
echo "ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${NC}"
echo -e " Host: ${CYAN}$HOST${NC} | Ports: ${CYAN}$PORTS${NC} | Timeout: ${CYAN}${TIMEOUT}s${NC}"
echo -e " Inici: ${CYAN}$TIMESTAMP${NC}\n"
# Executar tots els blocs de comprovaciΓ³
autocomprovacio
comprovar_connectivitat
comprovar_ports
comprovar_dns
comprovar_http
comprovar_ssl
# βββ RESUM FINAL βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
echo -e "\n${BOLD}${CYAN}βββ RESUM FINAL βββ${NC}"
echo -e " Total: $TOTAL | ${GREEN}Passats: $PASSATS${NC} | ${RED}Fallats: $FALLATS${NC} | ${YELLOW}Advertències: $ADVERTENCIES${NC}"
local_pct=0
[[ "$TOTAL" -gt 0 ]] && local_pct=$(( (PASSATS * 100) / TOTAL ))
echo -e " PuntuaciΓ³ global: ${BOLD}${local_pct}%${NC}"
# Generar informe HTML
generar_html
echo -e "\n Log detallat: ${CYAN}$LOG_FILE${NC}"
echo -e "${BOLD}${CYAN}ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${NC}\n"
05 β Resultats ExecuciΓ³ (8.8.8.8)
21
Total
15
Correctes
4
Fallades
2
Advertències
PuntuaciΓ³ global71%
Detall β Host: 8.8.8.8
PASSPort TCP 80 (HTTP)Obert i accessible
PASSPort TCP 443 (HTTPS)Obert i accessible
FAILPort TCP 22 (SSH)Tancat o filtrat
PASSDNS A β google.com173.194.194.101
PASSDNS PTR β 8.8.8.8dns.google
WARNHTTP β 8.8.8.8Codi 403 (servidor respon)
PASSSSL β :443TLSv1.3 Β· TLS_AES_256_GCM
VerificaciΓ³ Protocol Capa LΓ²gica
gmartin.inscastellbisbal.net Β· SMX Β· 2026