first commit
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import ipaddress
|
||||
import json
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from .intelligence import canonical_service_name, enrich_host
|
||||
from .models import Host, PortInfo
|
||||
from .naabu_runtime import BUNDLED_NAABU_PATH, NAABU_VERSION, naabu_version, trusted_root_binary
|
||||
|
||||
|
||||
SYSTEM_NAABU_CANDIDATES = (BUNDLED_NAABU_PATH,)
|
||||
|
||||
|
||||
@dataclass(slots=True, frozen=True)
|
||||
class NaabuDiagnostic:
|
||||
user_path: str | None
|
||||
admin_path: str | None
|
||||
user_detail: str
|
||||
admin_detail: str
|
||||
|
||||
|
||||
def find_naabu() -> str | None:
|
||||
"""Retourne exclusivement le moteur Naabu provisionné par LibreNet.
|
||||
|
||||
Le paquet peut provisionner un Naabu 2.6.1 dans l'espace privé de
|
||||
LibreNet comme accélérateur optionnel pour les grands ensembles d'hôtes. Ne jamais choisir silencieusement un ``naabu`` du PATH évite qu'une
|
||||
version différente modifie les options ou le comportement du profil Standard.
|
||||
Si le moteur intégré est absent ou corrompu, le scanner reste pleinement
|
||||
utilisable avec Nmap au lieu d'utiliser un binaire inconnu.
|
||||
"""
|
||||
candidate = BUNDLED_NAABU_PATH
|
||||
if os.path.isfile(candidate) and os.access(candidate, os.X_OK):
|
||||
if naabu_version(candidate) == NAABU_VERSION:
|
||||
return candidate
|
||||
return None
|
||||
|
||||
|
||||
def _trusted_system_naabu(path: str) -> bool:
|
||||
"""Même règle de confiance que le helper root, sans exécuter de privilèges."""
|
||||
return trusted_root_binary(path)
|
||||
|
||||
|
||||
def find_admin_naabu() -> str | None:
|
||||
"""Retourne le moteur LibreNet exact et sûr acceptable par le helper Polkit."""
|
||||
candidate = BUNDLED_NAABU_PATH
|
||||
if _trusted_system_naabu(candidate) and naabu_version(candidate) == NAABU_VERSION:
|
||||
return candidate
|
||||
return None
|
||||
|
||||
|
||||
def naabu_diagnostic() -> NaabuDiagnostic:
|
||||
user_path = find_naabu()
|
||||
admin_path = find_admin_naabu()
|
||||
if user_path:
|
||||
version = naabu_version(user_path)
|
||||
suffix = f" — v{version}" if version else " — version non confirmée"
|
||||
source = "moteur LibreNet intégré" if user_path == BUNDLED_NAABU_PATH else "moteur externe"
|
||||
user_detail = f"OK — {source}{suffix}"
|
||||
else:
|
||||
user_detail = "INDISPONIBLE — Nmap sera utilisé (fonctionnement normal)"
|
||||
if admin_path:
|
||||
version = naabu_version(admin_path)
|
||||
suffix = f", v{version}" if version else ", version non confirmée"
|
||||
source = "moteur LibreNet intégré" if admin_path == BUNDLED_NAABU_PATH else "moteur externe"
|
||||
admin_detail = f"OK — {source}, root, non modifiable par groupe/autres{suffix}"
|
||||
elif user_path:
|
||||
admin_detail = (
|
||||
"INDISPONIBLE — un Naabu utilisateur existe, mais le mode Admin exige "
|
||||
"le moteur LibreNet ou un Naabu système appartenant à root"
|
||||
)
|
||||
else:
|
||||
admin_detail = "INDISPONIBLE — aucun Naabu système de confiance"
|
||||
return NaabuDiagnostic(user_path, admin_path, user_detail, admin_detail)
|
||||
|
||||
|
||||
def _naabu_payload(line: str) -> dict | None:
|
||||
try:
|
||||
payload = json.loads(line)
|
||||
except (TypeError, json.JSONDecodeError):
|
||||
return None
|
||||
return payload if isinstance(payload, dict) else None
|
||||
|
||||
|
||||
def _payload_ipv4(payload: dict) -> str | None:
|
||||
value = str(payload.get("ip") or payload.get("host") or "").strip()
|
||||
try:
|
||||
address = ipaddress.ip_address(value)
|
||||
except ValueError:
|
||||
return None
|
||||
if address.version != 4:
|
||||
return None
|
||||
return str(address)
|
||||
|
||||
|
||||
def parse_naabu_host_json_line(line: str) -> Host | None:
|
||||
"""Parse une ligne JSONL issue de ``naabu -sn -json``.
|
||||
|
||||
Depuis Naabu 2.4, un scan de découverte JSON émet aussi les résultats sans port.
|
||||
LibreNet n'a besoin ici que de l'IPv4 : l'équipement est marqué actif et sera
|
||||
enrichi par ARP/neighbor/ports lors des phases suivantes.
|
||||
"""
|
||||
payload = _naabu_payload(line)
|
||||
if payload is None:
|
||||
return None
|
||||
ip = _payload_ipv4(payload)
|
||||
if not ip:
|
||||
return None
|
||||
return Host(ip=ip, status="up")
|
||||
|
||||
|
||||
def parse_naabu_json_line(line: str) -> Host | None:
|
||||
"""Transforme une ligne JSONL de scan de ports Naabu en observation LibreNet."""
|
||||
payload = _naabu_payload(line)
|
||||
if payload is None:
|
||||
return None
|
||||
ip = _payload_ipv4(payload)
|
||||
if not ip:
|
||||
return None
|
||||
try:
|
||||
port = int(payload.get("port"))
|
||||
except (ValueError, TypeError):
|
||||
return None
|
||||
if not 1 <= port <= 65535:
|
||||
return None
|
||||
protocol = str(payload.get("protocol") or "tcp").strip().lower()
|
||||
if protocol not in {"tcp", "udp"}:
|
||||
protocol = "tcp"
|
||||
service = str(payload.get("service") or "").strip()
|
||||
host = Host(
|
||||
ip=ip,
|
||||
status="up",
|
||||
ports=[
|
||||
PortInfo(
|
||||
port=port,
|
||||
protocol=protocol,
|
||||
state="open",
|
||||
service=canonical_service_name(port, protocol, service),
|
||||
)
|
||||
],
|
||||
)
|
||||
return enrich_host(host)
|
||||
Reference in New Issue
Block a user