Version courante : v1.1.5 (publiée le 2026-07-02, compte company Ops-Lorva)
Licence : MIT
Repo : https://github.com/Ops-Lorva/lanprobe
Page produit : https://lorva.dev/lanprobe
LanProbe est une application de monitoring et diagnostic réseau. Elle remplace plusieurs outils séparés (ping, nmap, speedtest, profils IP) par une interface cohérente. Elle fonctionne en deux modes :
lanprobe-server) — binaire standalone, sans interface graphique, déployable sur Raspberry Pi ou VM Debian, accessible depuis n'importe quel navigateur du LAN via HTTPS| Module | Description |
|---|---|
| Profils réseau | Configurations IP statique ou DHCP nommées, applicables en un clic. Gère le changement d'interface sans ressaisie manuelle |
| Ping Monitor | Surveillance ICMP continue de plusieurs hôtes en parallèle. Graphique de latence en temps réel. Seuils d'alerte configurables. Ring buffer 3600 samples (≈1h à 1s/tick) |
| SLA | Uptime %, avg/min/max/P95 de latence par hôte. Exportable en CSV. Blackout automatique après changement de profil réseau (faux outages évités) |
| Découverte réseau | Scan CIDR asynchrone en chunks parallèles (128 IPs/chunk Linux, 32 Windows). Résout IP, hostname et MAC via table ARP + ping sweep, plus le fabricant (vendor) résolu hors-ligne depuis une base OUI IEEE embarquée (MA-L/M/S, ~53k entrées) ; scroll horizontal des tableaux sur tous les layouts |
| Port Scan | Scan TCP avec profils intégrés (common, web, full) et profils personnalisés. Scan UDP applicatif sur les ports DNS/NTP/NetBIOS/SNMP/SSDP/mDNS |
| Speed Test | Ookla CLI bindé à l'interface sélectionnée via IP_BOUND_IF/SO_BINDTODEVICE. Fallback iperf3. Moteur ("ookla" ou "iperf3") dans le champ engine |
| Statut Internet | Double sonde ICMP (1.1.1.1) + HTTP (connectivitycheck.gstatic.com/generate_204) + DNS. États : Online / Limited / Offline. Fenêtre d'uptime 720 samples (~1h à 5s/tick) |
| Mode serveur web | Expose l'UI LanProbe complète en HTTPS sur le LAN. Disponible dans le desktop (Settings → Mode serveur) ou comme binaire standalone (lanprobe-server) |
| InfluxDB export | Export temps réel des métriques vers InfluxDB v1 ou v2. Micro-batching 1s, buffer cap 10k points. Hot-reload sur changement de config (v1.1.0) |
| Scheduler | Auto-run speedtest/discovery/portscan à intervalles configurables. CAS atomique pour mutex avec scans manuels. Hot-reload par JoinHandle::abort() (v1.1.0) |
| i18n | Interface en anglais, français, espagnol via svelte-i18n |
| Thème | Glass & Depth UI. Dark/Light/System. 6 palettes d'accent : Indigo, Cyan, Emerald, Rose, Amber, Slate |
| Auto-updater | Vérification des releases GitHub. Mise à jour en un clic depuis la bannière de notification |
| Couche | Technologie |
|---|---|
| Backend | Rust 1.85+ (edition 2024), tokio, axum, reqwest |
| Shell desktop | Tauri 2.x |
| Frontend | Svelte 5 + TypeScript |
| Icônes | SVG inline (style Lucide, sans dépendance runtime) |
| Thème | CSS custom properties, adaptatif OS + override manuel |
| Stockage | JSON via tauri-plugin-store (desktop) / /var/lib/lanprobe (serveur) |
| Internationalisation | svelte-i18n — EN / FR / ES |
| TLS | rustls + certificat auto-signé généré au premier démarrage |
| Bundles | .exe NSIS, .dmg / .pkg (signé + notarisé), .deb desktop, .deb headless |
lanprobe/
├── src-tauri/ # Shell Tauri — enregistrement des commandes, cycle de vie app
│ └── src/
│ ├── lib.rs # Toutes les commandes #[tauri::command]
│ ├── main.rs
│ └── updater.rs # Check + apply update via GitHub Releases API
├── crates/
│ ├── lanprobe-core/ # Logique async partagée — aucune dépendance Tauri
│ │ └── src/
│ │ ├── ping.rs # ICMP async (ping_async)
│ │ ├── discovery.rs # Scan CIDR + ARP table
│ │ ├── ports.rs # Scan TCP/UDP
│ │ ├── sla.rs # Calcul uptime%, P95 latence
│ │ ├── speedtest.rs # Ookla CLI + iperf3
│ │ ├── internet.rs # Double sonde ICMP+HTTP+DNS
│ │ ├── public_ip.rs # IP publique
│ │ ├── interfaces.rs # Liste + détails interfaces réseau
│ │ ├── configure.rs # Appliquer IP statique / DHCP
│ │ ├── permissions.rs # CAP_NET_RAW / sudoers macOS
│ │ ├── proc.rs # Helpers async_cmd / sync_cmd
│ │ └── updater.rs # Check GitHub Releases
│ └── lanprobe-server/ # Serveur HTTPS headless standalone
│ └── src/
│ ├── lib.rs # start() / ServerHandle / has_account / set_initial_account
│ ├── main.rs # CLI (clap) + tokio::main
│ ├── state.rs # AppState partagé (broadcast, monitoring, discovery, portscan…)
│ ├── routes.rs # POST /api/invoke/<cmd> — shim Tauri ↔ HTTP
│ ├── influxdb.rs # Export InfluxDB v1/v2 (v1.1.0)
│ ├── scheduler.rs # Planificateur automatique (v1.1.0)
│ ├── auth.rs # AuthStore (users.json, bcrypt)
│ ├── config.rs # ConfigStore (app_config.json)
│ ├── tls.rs # Certificat TLS auto-signé (rustls)
│ ├── web.rs # Router axum + WebSocket bridge
│ └── assets.rs # Frontend Svelte embarqué via rust-embed
└── src/ # Frontend Svelte 5
└── lib/
├── components/ # Un composant par module (Settings.svelte, Dashboard.svelte…)
├── stores/ # Svelte stores (profiles, monitoring, influxdb, scheduler…)
└── i18n/ # en / fr / es
L'AppState est le pivot central entre le shell Tauri, le serveur HTTP embarqué et les clients WebSocket. Il est instancié une seule fois par processus et partagé via Arc<AppState>.
| Champ | Type | Rôle |
|---|---|---|
selected_interface |
Arc<Mutex<Option<String>>> |
Interface réseau active |
ping_stop |
Arc<Mutex<HashMap<String, bool>>> |
Stop par IP des monitorings ping |
scan_cancel |
Arc<AtomicBool> |
Mutex atomique entre scans (true=idle, false=scan en cours) |
internet |
Arc<InternetHistory> |
Historique de la sonde internet |
discovery |
Arc<DiscoveryStateInner> |
Map IP→hôte de la dernière découverte |
monitoring |
Arc<MonitoringStateInner> |
Ring buffer ping par IP (max 3600 samples) |
portscan |
Arc<PortScanStateInner> |
Résultats TCP/UDP par IP |
speedtest |
Arc<SpeedTestStateInner> |
Dernier résultat speedtest + flag running |
events |
broadcast::Sender<BroadcastEvent> |
Bus d'events (WebSocket + Tauri emit) |
auth |
Arc<AuthStore> |
Authentification (users.json, bcrypt) |
config |
Arc<ConfigStore> |
Configuration app (app_config.json) |
monitoring_blackout_until |
Arc<Mutex<Option<Instant>>> |
Fenêtre de silence post-changement de profil |
Le canal broadcast a une capacité de 256 messages. Chaque client WebSocket souscrit à ce bus et reçoit tous les events en temps réel.
Fichier : crates/lanprobe-server/src/influxdb.rs
config:update) si InfluxDB est désactivé au démarragetokio::select! : bufférisation des points + flush toutes les secondesconfig:update : rechargement à chaud. Si désactivé, vidage du buffer + retour à l'attente| Event source | Measurement | Tags | Fields |
|---|---|---|---|
ping:tick |
ping_latency |
host, ip | latency_ms (si alive), alive |
internet:tick |
internet_status |
host | state, icmp_ms, http_ms, dns_ms, uptime_pct, icmp_ok, http_ok, dns_ok |
speedtest:result |
speedtest |
host, engine | download_mbps, upload_mbps, latency_ms, jitter_ms |
discovery:done |
discovery |
host, cidr | hosts_found |
portscan:update |
port_scan |
host, ip | open_tcp, open_udp (seulement quand in_progress=false) |
app_config.json){
"influxdb": {
"enabled": false,
"version": "v2",
"url": "http://influxdb:8086",
"instance_label": "",
"v1": {
"database": "lanprobe",
"username": "",
"password": ""
},
"v2": {
"org": "myorg",
"bucket": "lanprobe",
"token": "my-token"
}
}
}
instance_label : surcharge le hostname détecté automatiquement pour le tag host=Fichier : crates/lanprobe-server/src/scheduler.rs
Le scheduler orchestre trois sous-tâches Tokio indépendantes. Il écoute config:update et redémarre les sous-tâches via JoinHandle::abort() si la configuration change.
| Sous-tâche | Paramètres | Comportement |
|---|---|---|
| Speedtest | speedtest_interval_min |
Lance Ookla ou iperf3 selon speedtestEngine dans la config |
| Discovery | discovery_interval_min, discovery_cidr |
Scan CIDR (auto-détecté si vide). CAS sur scan_cancel pour éviter la concurrence avec les scans manuels. ARP initial → ping sweep en chunks → ARP final pour MACs |
| Port Scan | portscan_interval_min, portscan_targets |
Scan TCP avec profil par défaut sur chaque IP. Désactivé si portscan_targets est vide, même si l'intervalle est > 0 |
scan_cancelscan_cancel est un AtomicBool initialisé à true (idle). Les trois points d'entrée de scan (commande HTTP, commande Tauri, scheduler) utilisent compare_exchange(true, false). Si le CAS échoue, un scan est déjà en cours et le déclencheur retourne une erreur ou saute le tick.
{
"scheduler": {
"speedtest_interval_min": 0,
"discovery_interval_min": 0,
"discovery_cidr": "",
"portscan_interval_min": 0,
"portscan_targets": []
}
}
Intervalles à 0 = désactivé. discovery_cidr vide = auto-détection depuis l'interface sélectionnée (fallback get_local_network_cidr).
curl -fsSL https://raw.githubusercontent.com/Ops-Lorva/lanprobe/main/install-server.sh | sudo bash
Le script installe le .deb, crée l'utilisateur système lanprobe, pose les capabilities CAP_NET_RAW + CAP_NET_ADMIN sur le binaire, et démarre le service systemd.
lanprobe-server
--host 0.0.0.0 # interface d'écoute (défaut : 0.0.0.0)
--port 8443 # port HTTPS (défaut : 8443)
--config-dir PATH # dossier de config (défaut : ~/.config/lanprobe)
Au premier démarrage, le serveur génère un certificat TLS auto-signé stocké dans config-dir. Le navigateur affiche un avertissement à accepter manuellement. Le serveur détecte les connexions HTTP claires (premier octet ≠ 0x16) et répond un 301 Moved Permanently vers HTTPS.
L'accès à https://<server-ip>:8443 affiche un écran de setup pour créer le compte administrateur. Les credentials sont stockés dans users.json (bcrypt).
sudo dpkg -i lanprobe-server_vX.Y.Z_amd64.deb
# dpkg arrête, remplace et redémarre le service automatiquement
sudo apt remove lanprobe-server
L'application desktop peut activer un serveur HTTPS embarqué depuis Settings → Mode serveur. Elle réutilise le même AppState que le desktop : un client web connecté voit en temps réel les scans et monitorings lancés depuis l'interface Tauri, et inversement.
ip neigh show sur Linux, arp -a sur macOS/Windows)ping_once_fast_retry avec 3 tentativesdiscovery:done avec { "cidr": "...", "hosts_found": N }Ookla CLI :
/usr/local/bin/speedtest, etc.). Fallback final : téléchargement automatique depuis Ookla.-i <ip> (bind par adresse source, évite le bug "Failed binding local connection end"). macOS/Linux utilisent -I <ifname>.iperf3 :
resources/linux/iperf3 ou resources/macos/iperf3.GET http://connectivitycheck.gstatic.com/generate_204 (Android/Chrome pattern, léger, sans TLS, répond 204)cloudflare.comOnline si HTTP ok, Limited si ICMP seul (portail captif ou pare-feu), Offline sinon| OS | Version | Architecture |
|---|---|---|
| Windows | 10, 11 | x64 |
| macOS | 12 Monterey+ | Intel, Apple Silicon, universal |
| Linux (desktop) | Debian 12+, Ubuntu 22.04+ | x64 |
| Linux (serveur headless) | Debian 11+, Ubuntu 20.04+, toute distro systemd | x64 |
Un seul workflow GitHub Actions (release.yml) déclenché sur push d'un tag v*.*.*. Les 4 jobs de build tournent en parallèle, puis le job release collecte les artefacts et publie la GitHub Release.
| Job | Runner | Artefact |
|---|---|---|
build-linux |
ubuntu-24.04 | lanprobe_vX.Y.Z_amd64.deb |
build-linux-server |
ubuntu-24.04 | lanprobe-server_vX.Y.Z_amd64.deb |
build-windows |
windows-latest | lanprobe_vX.Y.Z_x64-setup.exe |
build-macos |
macos-latest | lanprobe_vX.Y.Z_universal.dmg + lanprobe_vX.Y.Z_universal.pkg |
release |
ubuntu-24.04 | Collecte + GitHub Release |
Versionning : La version est injektée au moment du build en remplaçant "0.0.0" dans Cargo.toml et tauri.conf.json par le tag Git (ex: 1.1.0). Le binaire expose la version dans une section .rodata (constante LANPROBE_BUILD_VERSION) lisible par strings.
Créer une release :
git tag v1.1.0 && git push origin v1.1.0
Le job CI macOS :
--target universal-apple-darwin --bundles app,dmg — Tauri codesigne, notarise et staple le .app et le .dmg.pkg via pkgbuild avec BundleIsRelocatable=false (évite l'installation "en place" au lieu de /Applications) et un script postinstall qui provisionne l'entrée sudoers.pkg via xcrun notarytoolSecrets CI requis : APPLE_CERTIFICATE, APPLE_CERTIFICATE_PASSWORD, APPLE_INSTALLER_CERTIFICATE, APPLE_INSTALLER_CERTIFICATE_PASSWORD, APPLE_SIGNING_IDENTITY, APPLE_ID, APPLE_PASSWORD, APPLE_TEAM_ID
✅ Ces secrets sont gérés par Infisical (projet
lanprobe) → sync automatique vers les secrets Actions deOps-Lorva/lanprobe. Voir Coffre / Secrets.
La page produit (/lanprobe) est une page HTML statique hébergée sur lorva.dev (/home/benjamin/projects/LORVA/lorva-website/html/lanprobe/index.html).
Les release notes sont chargées dynamiquement via un appel à /api/releases/lanprobe (API du serveur lorva-website). Depuis v1.1.4, la source est le CHANGELOG.md du repo (sections ### English / ### Français par version, parsées en notes_en / notes_fr) — comme Klibri. La page est bilingue EN/FR avec bascule stockée dans localStorage. Pour publier des notes : éditer CHANGELOG.md et pousser sur main.
La page présente les 4 fonctionnalités clés de v1.1.0 : découverte réseau, surveillance d'état, export InfluxDB, planificateur intégré.
git clone https://github.com/Ops-Lorva/lanprobe.git
cd lanprobe
npm install
# Desktop avec hot-reload
npm run tauri dev
# TypeScript / Svelte type check
npm run check
# Tests unitaires Rust (lanprobe-core)
cargo test -p lanprobe-core
# Serveur headless en local
npm run build
cargo run -p lanprobe-server -- --host 0.0.0.0 --port 8443
| Plateforme | Dépendances |
|---|---|
| Linux desktop | libwebkit2gtk-4.1-dev libgtk-3-dev librsvg2-dev libssl-dev pkg-config |
| Linux serveur seulement | libssl-dev pkg-config (sans GUI) |
| macOS | xcode-select --install |
| Windows | WebView2 (pré-installé sur Windows 11) |
| Tous | Rust ≥ 1.85, Node.js ≥ 18 |
tauri icon) — ces dernières n'arrivent dans les builds installables qu'avec un tag de release, d'où l'attente jusqu'au reset des minutes GitHub Actions Ops-Lorva (1er juillet 2026).v1.1.5 (le push de tag seul ne lance pas le workflow ; la version vient de GITHUB_REF_NAME). Build vert sur tous les jobs (macOS DMG+PKG, Windows NSIS, Linux .deb desktop + headless), 7 assets publiés.Ops-Lorva/lanprobe (c'est le seul repo public de l'org, tous les autres sont privés) : Wiki GitHub désactivé, Projects désactivé, GITHUB_TOKEN par défaut passé en lecture seule (le job release garde son permissions: contents: write explicite). Issues conservées (rapports de bug OSS). Les secrets CI (certs Apple, clé signature) ne sont pas exposés dans les logs publics (chiffrés/masqués, référencés via ${{ secrets.* }}) ; il n'est pas possible de masquer les logs Actions d'un repo public sans le rendre privé.include_str!, lookup par préfixe le plus long 36->28->24 bits, module lanprobe-core/src/oui.rs). Aucun appel internet.scheduler.off.Ops-Lorva (migration depuis le compte perso ; secrets Apple désormais centralisés dans Infisical)scan_cancel initialisé à true (idle) au lieu de false — correction de la sémantique du CAS pour tous les points d'entréediscovery:done payload enrichi avec { "cidr": "...", "hosts_found": N }SpeedResult inclut le champ engine: String ("ookla" ou "iperf3")| Chemin | Description |
|---|---|
/home/benjamin/projects/LORVA/LanProbe/ |
Racine du projet |
crates/lanprobe-core/src/ |
Logique réseau partagée (ping, discovery, ports, speedtest, internet, sla) |
crates/lanprobe-server/src/influxdb.rs |
Export InfluxDB |
crates/lanprobe-server/src/scheduler.rs |
Planificateur automatique |
crates/lanprobe-server/src/state.rs |
AppState partagé |
crates/lanprobe-server/src/routes.rs |
API HTTP (shim Tauri ↔ HTTP) |
src-tauri/src/lib.rs |
Commandes Tauri desktop |
src/lib/components/Settings.svelte |
UI Settings (InfluxDB + Scheduler) |
src/lib/stores/influxdb.ts + scheduler.ts |
Stores Svelte |
.github/workflows/release.yml |
Pipeline CI/CD complet |
install-server.sh |
Script d'installation one-liner du serveur headless |
/home/benjamin/projects/LORVA/lorva-website/html/lanprobe/index.html |
Page produit lorva.dev |