fix(qualys/agents): message d'echec specifique selon cause reelle (DNS/TCP timeout/TCP refused/SSH auth) - plus de 'agent installe? OS supporte?' generique

This commit is contained in:
Pierre & Lumière 2026-04-28 02:00:21 +02:00
parent 532549072d
commit 983552a442
2 changed files with 75 additions and 4 deletions

View File

@ -910,14 +910,73 @@ def audit_qualys_agent_only(hostname):
target = _resolve(hostname) target = _resolve(hostname)
if not target: if not target:
result["status"] = "CONNECTION_FAILED" result["status"] = "CONNECTION_FAILED"
result["fail_reason"] = "DNS_NOT_RESOLVED"
result["fail_detail"] = (
f"Aucun nom DNS résolu pour {hostname} (testé sans suffixe puis avec "
f".sanef.groupe / .sanef.fr / .sanef-rec.fr / .mpcz.fr). "
"Le hostname est peut-être incorrect, le DNS interne KO, ou le serveur n'a jamais existé / a été décommissionné."
)
result["connection_method"] = f"DNS: aucun suffixe resolu ({hostname})" result["connection_method"] = f"DNS: aucun suffixe resolu ({hostname})"
return result return result
result["resolved_fqdn"] = target result["resolved_fqdn"] = target
# Test TCP/22 avant SSH pour identifier la cause précise (timeout / refused / OK)
tcp_status = "unknown"
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5)
rc = sock.connect_ex((target, 22))
sock.close()
if rc == 0:
tcp_status = "open"
elif rc in (111, 10061): # ECONNREFUSED
tcp_status = "refused"
else:
tcp_status = f"errno {rc}"
except socket.timeout:
tcp_status = "timeout"
except Exception as ex_tcp:
tcp_status = f"err: {ex_tcp}"
if tcp_status == "timeout":
result["status"] = "CONNECTION_FAILED"
result["fail_reason"] = "TCP_TIMEOUT"
result["fail_detail"] = (
f"Port 22/TCP injoignable sur {target} (timeout 5s). "
"Le serveur est probablement éteint, le flux SSH bloqué côté firewall, "
"ou la VM en panne réseau."
)
result["connection_method"] = f"DNS OK ({target}) — TCP/22 timeout"
return result
if tcp_status == "refused":
result["status"] = "CONNECTION_FAILED"
result["fail_reason"] = "TCP_REFUSED"
result["fail_detail"] = (
f"Port 22/TCP rejette la connexion sur {target} (RST/refused). "
"Le service sshd est probablement arrêté ou refuse activement. "
"Le serveur lui-même répond mais pas SSH."
)
result["connection_method"] = f"DNS OK ({target}) — TCP/22 refused"
return result
if tcp_status not in ("open",):
result["status"] = "CONNECTION_FAILED"
result["fail_reason"] = "TCP_UNKNOWN"
result["fail_detail"] = f"Test TCP/22 inattendu sur {target} : {tcp_status}"
result["connection_method"] = f"DNS OK — TCP {tcp_status}"
return result
client = _connect(target, hostname) client = _connect(target, hostname)
if not client: if not client:
result["status"] = "CONNECTION_FAILED" result["status"] = "CONNECTION_FAILED"
result["connection_method"] = f"SSH: connexion echouee a {target}" result["fail_reason"] = "SSH_AUTH_OR_HANDSHAKE_FAILED"
method_cfg = _resolve_ssh_method(hostname) or "ssh_key (default)"
result["fail_detail"] = (
f"TCP/22 ouvert sur {target} mais la connexion SSH échoue (handshake ou authentification). "
f"Méthode SSH configurée pour ce serveur : {method_cfg}. "
"Pistes : clé SSH non autorisée pour ce serveur, méthode PSMP/key/password mal configurée "
"côté PatchCenter (settings), ou compte SSH désactivé / cassé sur le serveur."
)
result["connection_method"] = f"TCP/22 OK ({target}) — SSH auth/handshake KO"
return result return result
method = _resolve_ssh_method(hostname) or "ssh_key" method = _resolve_ssh_method(hostname) or "ssh_key"

View File

@ -184,9 +184,21 @@
{% else %} {% else %}
<div class="card p-4 mb-4"> <div class="card p-4 mb-4" style="border:1px solid #ef4444;background:rgba(239,68,68,0.06)">
<p class="text-sm text-gray-400">Impossible de récupérer les informations de l'agent. Vérifie : SSH ouvert (port 22), méthode SSH configurée pour ce serveur dans la fiche serveur PatchCenter, agent installé, OS supporté.</p> {% if audit and audit.fail_reason %}
<p class="text-xs text-gray-500 mt-2"> <div class="text-cyber-red font-bold text-sm mb-2">
{% if audit.fail_reason == 'DNS_NOT_RESOLVED' %}🌐 DNS — hostname non résolu
{% elif audit.fail_reason == 'TCP_TIMEOUT' %}⏱ Port 22/TCP — timeout (serveur down ou flux bloqué)
{% elif audit.fail_reason == 'TCP_REFUSED' %}🚫 Port 22/TCP — connexion rejetée (sshd arrêté ?)
{% elif audit.fail_reason == 'SSH_AUTH_OR_HANDSHAKE_FAILED' %}🔑 SSH — handshake ou authentification échouée
{% else %}✗ Connexion impossible ({{ audit.fail_reason }}){% endif %}
</div>
<p class="text-xs text-gray-300 mb-2">{{ audit.fail_detail }}</p>
{% else %}
<p class="text-sm text-cyber-red font-bold">✗ Connexion impossible</p>
<p class="text-xs text-gray-400 mt-1">Détail indisponible.</p>
{% endif %}
<p class="text-xs text-gray-500 mt-3">
<a href="/qualys/search?field=hostname&search={{ hostname }}" class="text-cyber-accent hover:underline">→ Voir ce host dans Qualys (recherche)</a> <a href="/qualys/search?field=hostname&search={{ hostname }}" class="text-cyber-accent hover:underline">→ Voir ce host dans Qualys (recherche)</a>
</p> </p>
</div> </div>