use std::process::Stdio;
pub fn lan_ip() -> String {
use std::net::UdpSocket;
UdpSocket::bind("0.0.0.0:0")
.and_then(|s| {
s.connect("8.8.8.8:80")?;
Ok(s.local_addr()?.ip().to_string())
})
.unwrap_or_else(|_| "127.0.0.1".to_string())
}
pub fn advertise_lan(host: &str, ip: &str) -> Option<std::process::Child> {
let label = host.split('.').next().unwrap_or(host);
let local = format!("{label}.local");
#[cfg(target_os = "macos")]
let mut cmd = {
let mut c = std::process::Command::new("dns-sd");
c.args(["-P", label, "_http._tcp", "local", "80", &local, ip]);
c
};
#[cfg(not(target_os = "macos"))]
let mut cmd = {
let mut c = std::process::Command::new("avahi-publish-address");
c.args([&local, ip]);
c
};
match cmd.stdout(Stdio::null()).stderr(Stdio::null()).spawn() {
Ok(child) => {
println!("LAN: advertising {local} -> {ip}");
Some(child)
}
Err(e) => {
eprintln!("LAN: could not advertise {local} (is the mDNS tool installed?): {e}");
None
}
}
}
pub fn tailscale_serve(proxy_port: u16) -> bool {
let status = std::process::Command::new("tailscale")
.args(["serve", "--bg", &proxy_port.to_string()])
.status();
match status {
Ok(s) if s.success() => {
println!("Tailscale: serving the proxy on your tailnet (see `tailscale serve status`).");
true
}
Ok(s) => {
eprintln!("tailscale serve failed ({s}); is Tailscale up with HTTPS enabled?");
false
}
Err(e) => {
eprintln!("tailscale not found ({e}); install the Tailscale CLI to use --tailscale.");
false
}
}
}