aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-08-04 23:28:02 +0200
committerHimbeer <himbeer@disroot.org>2024-08-04 23:28:02 +0200
commit51ca2c8568fa4a239950d0f547f1c6eb49146e0d (patch)
treecade4d6caae8022936f41198dad808a429c04cb4
parent5ae59dedf142b625d8ba19ebbbd23f1645c312f3 (diff)
Add WAN connection information
-rw-r--r--src-tauri/src/main.rs157
-rw-r--r--src/wan.html6
-rw-r--r--src/wan.js20
3 files changed, 182 insertions, 1 deletions
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index 64992e0..77b3a8f 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -1,6 +1,7 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
+use std::net::{Ipv4Addr, Ipv6Addr};
use std::sync::Mutex;
use tauri::State;
@@ -34,6 +35,75 @@ struct WanCredentialFile {
password: String,
}
+#[derive(Debug, Serialize)]
+struct ConnectionStatus {
+ session: String,
+ ipv4: String,
+ ipv6: String,
+}
+
+#[derive(Debug, Default, Deserialize)]
+struct ConnectionFile {
+ v4: Option<Ipv4Connection>,
+ v6: Option<Ipv6Connection>,
+}
+
+impl ConnectionFile {
+ fn session_summary(&self) -> String {
+ if self.v4.is_some() && self.v6.is_some() {
+ String::from("Einwahlstatus: ✅ Dual Stack")
+ } else if self.v6.is_some() {
+ String::from(
+ r#"Einwahlstatus: ✅ IPv6 | ggf. DS-Lite-Status unter "DHCPv6" überprüfen"#,
+ )
+ } else if self.v4.is_some() {
+ String::from(
+ r#"Einwahlstatus: ⚠ IPv4 | Eigene Server nicht von außen erreichbar, kleine Teile des modernen Internets nicht erreichbar. Internetanbieter um Freischaltung von IPv6 (bevorzugt "Dual Stack" bzw. mit öffentlicher IPv4-Adresse <i>und</i> IPv6, aber nicht zwingend nötig) bitten."#,
+ )
+ } else {
+ String::from("Einwahlstatus: ❌ Keine Einwahl | Router und Modem neu starten. Bei weiterem Bestehen Diagnoseprotokolle konsultieren oder Internetanbieter kontaktieren.")
+ }
+ }
+
+ fn ipv4_summary(&self) -> String {
+ if let Some(v4) = &self.v4 {
+ format!("IPv4: 🟢 Verbunden | Öffentliche Adresse: {}/32 | Primärer DNS-Server (nicht verwendet): {} | Sekundärer DNS-Server (nicht verwendet): {}",v4.addr,v4.dns1,v4.dns2)
+ } else if self.v6.is_some() {
+ String::from(
+ r#"IPv4: 🟡 Nicht verfügbar (ggf. DS-Lite-Status unter "DHCPv6" überprüfen)"#,
+ )
+ } else {
+ String::from("IPv4: 🔴 Nicht verbunden")
+ }
+ }
+
+ fn ipv6_summary(&self) -> String {
+ if let Some(v6) = &self.v6 {
+ format!(
+ "IPv6: 🟢 Verbunden | Verbindungslokale Adresse: {}/128 | Standardgateway: {}",
+ v6.laddr, v6.raddr
+ )
+ } else if self.v4.is_some() {
+ String::from("IPv6: 🟡 Nicht verfügbar | Bitte freischalten lassen (s. oben)")
+ } else {
+ String::from("IPv6: 🔴 Nicht verbunden")
+ }
+ }
+}
+
+#[derive(Debug, Deserialize)]
+struct Ipv4Connection {
+ addr: Ipv4Addr,
+ dns1: Ipv4Addr,
+ dns2: Ipv4Addr,
+}
+
+#[derive(Debug, Deserialize)]
+struct Ipv6Connection {
+ laddr: Ipv6Addr,
+ raddr: Ipv6Addr,
+}
+
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
#[tauri::command]
async fn connect(
@@ -267,6 +337,90 @@ fn handle_kill_response(response: Response) -> String {
}
}
+#[tauri::command]
+async fn connection_status(state: State<'_, Mutex<Session>>) -> Result<ConnectionStatus, ()> {
+ let (client, instance) = {
+ let state = state.lock().unwrap();
+ (state.client.clone(), state.instance.clone())
+ };
+ let instance = match instance {
+ Some(instance) => instance,
+ None => {
+ return Ok(ConnectionStatus {
+ session: String::from("❗ Keine Instanz ausgewählt, bitte melden Sie sich neu an!"),
+ ipv4: String::from("❗ Keine Instanz ausgewählt, bitte melden Sie sich neu an!"),
+ ipv6: String::from("❗ Keine Instanz ausgewählt, bitte melden Sie sich neu an!"),
+ })
+ }
+ };
+
+ let response = client
+ .get(instance.url.join("/data/read").unwrap())
+ .query(&[("path", "/tmp/pppoe.ip_config")])
+ .basic_auth("rustkrazy", Some(&instance.password))
+ .send();
+
+ Ok(match response.await {
+ Ok(response) => handle_connection_status_response(response).await,
+ Err(e) => ConnectionStatus {
+ session: format!("❗ Abfrage fehlgeschlagen: {}", e),
+ ipv4: format!("❗ Abfrage fehlgeschlagen: {}", e),
+ ipv6: format!("❗ Abfrage fehlgeschlagen: {}", e),
+ },
+ })
+}
+
+async fn handle_connection_status_response(response: Response) -> ConnectionStatus {
+ let status = response.status();
+ if status.is_success() {
+ match response.json::<ConnectionFile>().await {
+ Ok(connection) => ConnectionStatus {
+ session: connection.session_summary(),
+ ipv4: connection.ipv4_summary(),
+ ipv6: connection.ipv6_summary(),
+ },
+ Err(e) => ConnectionStatus {
+ session: format!("❗ Fehlerhafte Parameterdatei. Fehler: {}", e),
+ ipv4: format!("❗ Fehlerhafte Parameterdatei. Fehler: {}", e),
+ ipv6: format!("❗ Fehlerhafte Parameterdatei. Fehler: {}", e),
+ },
+ }
+ } else if status == StatusCode::UNAUTHORIZED {
+ ConnectionStatus {
+ session: String::from(
+ "❗ Ungültiges Verwaltungspasswort, bitte melden Sie sich neu an!",
+ ),
+ ipv4: String::from("❗ Ungültiges Verwaltungspasswort, bitte melden Sie sich neu an!"),
+ ipv6: String::from("❗ Ungültiges Verwaltungspasswort, bitte melden Sie sich neu an!"),
+ }
+ } else if status == StatusCode::NOT_FOUND {
+ let connection = ConnectionFile::default();
+ ConnectionStatus {
+ session: connection.session_summary(),
+ ipv4: connection.ipv4_summary(),
+ ipv6: connection.ipv6_summary(),
+ }
+ } else if status.is_client_error() {
+ ConnectionStatus {
+ session: format!("❗ Clientseitiger Fehler: {}", status),
+ ipv4: format!("❗ Clientseitiger Fehler: {}", status),
+ ipv6: format!("❗ Clientseitiger Fehler: {}", status),
+ }
+ } else if status.is_server_error() {
+ ConnectionStatus {
+ session: format!("❗ Serverseitiger Fehler: {}", status),
+ ipv4: format!("❗ Serverseitiger Fehler: {}", status),
+ ipv6: format!("❗ Serverseitiger Fehler: {}", status),
+ }
+ } else {
+ ConnectionStatus {
+ session: format!("❗ Unerwarteter Statuscode: {}", status),
+ ipv4: format!("❗ Unerwarteter Statuscode: {}", status),
+ ipv6: format!("❗ Unerwarteter Statuscode: {}", status),
+ }
+ }
+}
+
fn main() {
tauri::Builder::default()
.manage(Mutex::new(Session {
@@ -281,7 +435,8 @@ fn main() {
disconnect,
load_wan_credentials,
change_wan_credentials,
- kill
+ kill,
+ connection_status
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
diff --git a/src/wan.html b/src/wan.html
index f52193e..b8b533b 100644
--- a/src/wan.html
+++ b/src/wan.html
@@ -49,6 +49,12 @@
<fieldset>
<legend>Einwahl</legend>
+ <span class="row" id="connection-status">Einwahlstatus: ❓ Abfrage...</span>
+ <span class="row" id="connection-ipv4">IPv4: ❓ Abfrage...</span>
+ <span class="row" id="connection-ipv6">IPv6: ❓ Abfrage...</span>
+
+ <br />
+
<div class="row">
<button id="connection-warm-reconnect">🔄 Verbindungsparameter neu synchronisieren</button>
<button id="connection-cold-reconnect">☎ Neu einwählen</button>
diff --git a/src/wan.js b/src/wan.js
index 60ba0b7..0605ee7 100644
--- a/src/wan.js
+++ b/src/wan.js
@@ -1,11 +1,23 @@
const { invoke } = window.__TAURI__.tauri;
const { ask, message } = window.__TAURI__.dialog;
+let connectionStatusEl;
+let connectionIpv4El;
+let connectionIpv6El;
+
let credentialsUsernameEl;
let credentialsPasswordEl;
let credentialsSubmitEl;
let credentialsStatusEl;
+async function refreshConnectionStatus() {
+ const connectionStatus = await invoke("connection_status", {});
+
+ connectionStatusEl.innerText = connectionStatus.session;
+ connectionIpv4El.innerText = connectionStatus.ipv4;
+ connectionIpv6El.innerText = connectionStatus.ipv6;
+}
+
async function warmReconnect() {
const error = await invoke("kill", { process: "rsdsl_pppoe3", signal: "hup" });
@@ -93,6 +105,12 @@ async function changeCredentials() {
}
window.addEventListener("DOMContentLoaded", () => {
+ refreshConnectionStatus();
+
+ connectionStatusEl = document.querySelector("#connection-status");
+ connectionIpv4El = document.querySelector("#connection-ipv4");
+ connectionIpv6El = document.querySelector("#connection-ipv6");
+
document.querySelector("#connection-warm-reconnect").addEventListener("click", (e) => {
e.preventDefault();
warmReconnect();
@@ -123,3 +141,5 @@ window.addEventListener("DOMContentLoaded", () => {
loadCredentials();
});
+
+setInterval(refreshConnectionStatus, 3000);