Initial commit: iroh-forward TCP-over-Iroh forwarder
TCP-Forwarding über das Iroh-Netz (QUIC), adressiert per Public Key statt IP (Umsetzung von Option B aus recherche-vpn-vs-p2p-netzwerk.md). - server: nimmt Iroh-Verbindungen an, leitet QUIC-Streams an lokalen Port weiter - client: lauscht lokal auf TCP, öffnet pro Verbindung einen QUIC-Stream zum Peer - keygen: erzeugt Key-Datei und gibt EndpointId aus (Vorab-Verteilung) - Allowlist (--allow) erlaubter Client-EndpointIds - QUIC-Multiplexing, Reconnect mit Backoff, n0-Default-Relays + DNS-Discovery Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+63
@@ -0,0 +1,63 @@
|
||||
//! Laden/Erzeugen und Persistieren des Iroh-SecretKeys (Node-Identität).
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use data_encoding::HEXLOWER;
|
||||
use iroh::SecretKey;
|
||||
|
||||
/// Lädt den SecretKey aus `path` oder erzeugt einen neuen und speichert ihn.
|
||||
///
|
||||
/// Der Key bestimmt die EndpointId (= Public Key = Adresse im Iroh-Netz). Persistenz
|
||||
/// ist wichtig, damit der Serving Host nach einem Neustart unter derselben Adresse
|
||||
/// erreichbar bleibt.
|
||||
pub fn load_or_create_secret_key(path: &Path) -> Result<SecretKey> {
|
||||
if path.exists() {
|
||||
let hex = std::fs::read_to_string(path)
|
||||
.with_context(|| format!("Key-Datei lesen: {}", path.display()))?;
|
||||
let bytes = HEXLOWER
|
||||
.decode(hex.trim().as_bytes())
|
||||
.context("Key-Datei ist kein gültiges Hex")?;
|
||||
let arr: [u8; 32] = bytes
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.context("Key-Datei hat nicht 32 Bytes")?;
|
||||
Ok(SecretKey::from_bytes(&arr))
|
||||
} else {
|
||||
let secret_key = SecretKey::generate();
|
||||
let hex = HEXLOWER.encode(&secret_key.to_bytes());
|
||||
write_secret(path, &hex)
|
||||
.with_context(|| format!("Key-Datei schreiben: {}", path.display()))?;
|
||||
Ok(secret_key)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn write_secret(path: &Path, hex: &str) -> Result<()> {
|
||||
use std::io::Write;
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
|
||||
if let Some(parent) = path.parent() {
|
||||
if !parent.as_os_str().is_empty() {
|
||||
std::fs::create_dir_all(parent)?;
|
||||
}
|
||||
}
|
||||
let mut f = std::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.mode(0o600)
|
||||
.open(path)?;
|
||||
f.write_all(hex.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn write_secret(path: &Path, hex: &str) -> Result<()> {
|
||||
if let Some(parent) = path.parent() {
|
||||
if !parent.as_os_str().is_empty() {
|
||||
std::fs::create_dir_all(parent)?;
|
||||
}
|
||||
}
|
||||
std::fs::write(path, hex)?;
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user