connectivite : ignorer ses propres adresses ; un flux sans service est une information

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-09-30 22:50:35 -04:00
parent d2e2bb8990
commit 8603ec4c19

View file

@ -16,7 +16,10 @@
# #
# CE QUE L'ERRNO DIT — mesure du 2026-09-30, depuis web-frontal-01 de Technolibre : # CE QUE L'ERRNO DIT — mesure du 2026-09-30, depuis web-frontal-01 de Technolibre :
# ouvert le flux passe -> OK # ouvert le flux passe -> OK
# ECONNREFUSED le paquet est PASSE, personne n'ecoute sur ce port -> AVERTISSEMENT # ECONNREFUSED le paquet est PASSE, personne n'ecoute sur ce port -> INFORMATION
# (pas une coupure : un flux declare que rien ne sert — p. ex. une
# interface liee en local derriere la passerelle SSO. Nomme et compte,
# mais pas en jaune : un avertissement permanent apprend a ignorer le jaune)
# EHOSTUNREACH REJETE (pare-feu Proxmox : icmp host-prohibited), ou # EHOSTUNREACH REJETE (pare-feu Proxmox : icmp host-prohibited), ou
# machine injoignable -> CRITIQUE # machine injoignable -> CRITIQUE
# delai JETE en silence (politique `drop` de nftables) -> CRITIQUE # delai JETE en silence (politique `drop` de nftables) -> CRITIQUE
@ -84,6 +87,14 @@ def lignes(cmd):
return [] return []
ecoute = {l.split()[3].rsplit(":", 1)[1] for l in lignes(["ss", "-Hltn"]) if len(l.split()) >= 4} ecoute = {l.split()[3].rsplit(":", 1)[1] for l in lignes(["ss", "-Hltn"]) if len(l.split()) >= 4}
# MES PROPRES ADRESSES : une machine qui se parle a elle-meme par son adresse (Loki sur
# obs-01, port 9096) passe par la boucle locale, jamais par un pare-feu. Vu au premier
# deploiement : `obs-01` se declarait « hors des regles » envers lui-meme.
moi = set()
for l in lignes(["ip", "-o", "addr", "show"]):
c = l.split()
if len(c) >= 4 and c[2] in ("inet", "inet6"):
moi.add(c[3].split("/")[0])
reseaux = {} reseaux = {}
for e in d.get("entrees") or []: for e in d.get("entrees") or []:
if e.get("proto") == "tcp": if e.get("proto") == "tcp":
@ -102,7 +113,7 @@ for l in lignes(["ss", "-Hnt", "state", "established"]):
adr = ipaddress.ip_address(pair) adr = ipaddress.ip_address(pair)
except ValueError: except ValueError:
continue continue
if adr.is_loopback: if adr.is_loopback or str(adr) in moi:
continue continue
permis = False permis = False
for r in reseaux.get(lport, []): for r in reseaux.get(lport, []):
@ -124,16 +135,16 @@ if coupes:
print(f"COUPE : {len(coupes)}/{len(resultats)} flux sortant(s) ne passent pas — {nomme(coupes)}. {perf}") print(f"COUPE : {len(coupes)}/{len(resultats)} flux sortant(s) ne passent pas — {nomme(coupes)}. {perf}")
sys.exit(2) sys.exit(2)
avert = [] avert = []
if personne: info = (f" ; {len(personne)} flux declare(s) sans service (rien n'ecoute) — {nomme(personne)}"
avert.append(f"{len(personne)} flux passent mais personne n'ecoute — {nomme(personne)}") if personne else "")
if hors: if hors:
avert.append(f"{len(hors)} connexion(s) entrante(s) hors des regles declarees — " avert.append(f"{len(hors)} connexion(s) entrante(s) hors des regles declarees — "
+ ", ".join(sorted(hors)[:5])) + ", ".join(sorted(hors)[:5]))
if avert: if avert:
print(f"{ouverts}/{len(resultats)} flux sortants ouverts ; " + " ; ".join(avert) + f". {perf}") print(f"{ouverts}/{len(resultats)} flux sortants ouverts{info} ; " + " ; ".join(avert) + f". {perf}")
sys.exit(1) sys.exit(1)
if not resultats: if not resultats:
print(f"Aucun flux sortant declare pour {d.get('hote', 'cet hote')} ; aucune entree hors des regles. {perf}") print(f"Aucun flux sortant declare pour {d.get('hote', 'cet hote')} ; aucune entree hors des regles. {perf}")
sys.exit(0) sys.exit(0)
print(f"Connectivite : {ouverts}/{len(resultats)} flux sortants ouverts ; aucune entree hors des regles. {perf}") print(f"Connectivite : {ouverts}/{len(resultats)} flux sortants ouverts{info} ; aucune entree hors des regles. {perf}")
PY PY