diff --git a/numa.toml b/numa.toml index 6a523ac..4fa0a3d 100644 --- a/numa.toml +++ b/numa.toml @@ -54,7 +54,7 @@ enabled = true port = 80 tls_port = 443 tld = "numa" -# bind_addr = "127.0.0.1" # default; auto 0.0.0.0 when [lan] enabled +# bind_addr = "127.0.0.1" # default; set to "0.0.0.0" for LAN access to .numa services # Pre-configured services (numa.numa is always added automatically) # [[services]] diff --git a/src/ctx.rs b/src/ctx.rs index b21e20b..4e80b16 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -108,12 +108,17 @@ pub async fn handle_query( } else if !ctx.proxy_tld_suffix.is_empty() && (qname.ends_with(&ctx.proxy_tld_suffix) || qname == ctx.proxy_tld) { - // Resolve .numa: local services → 127.0.0.1, LAN peers → peer IP + // Resolve .numa: remote clients get LAN IP (can't reach 127.0.0.1), local get loopback let service_name = qname.strip_suffix(&ctx.proxy_tld_suffix).unwrap_or(&qname); + let is_remote = !src_addr.ip().is_loopback(); let resolve_ip = { let local = ctx.services.lock().unwrap(); if local.lookup(service_name).is_some() { - std::net::Ipv4Addr::LOCALHOST + if is_remote { + *ctx.lan_ip.lock().unwrap() + } else { + std::net::Ipv4Addr::LOCALHOST + } } else { let mut peers = ctx.lan_peers.lock().unwrap(); peers diff --git a/src/main.rs b/src/main.rs index 3066fdd..5505392 100644 --- a/src/main.rs +++ b/src/main.rs @@ -208,7 +208,6 @@ async fn main() -> numa::Result<()> { }); let zone_count: usize = ctx.zone_map.values().map(|m| m.len()).sum(); - // Build banner rows, then size the box to fit the longest value let api_url = format!("http://localhost:{}", api_port); let proxy_label = if config.proxy.enabled { @@ -308,6 +307,17 @@ async fn main() -> numa::Result<()> { ); if let Some(ref label) = proxy_label { row("Proxy", g, label); + if config.proxy.bind_addr == "127.0.0.1" { + let y = "\x1b[38;2;204;176;59m"; // yellow + row( + "", + y, + &format!( + "⚠ proxy on 127.0.0.1 — .{} not LAN reachable", + config.proxy.tld + ), + ); + } } if config.lan.enabled { row("LAN", g, "mDNS (_numa._tcp.local)"); @@ -375,16 +385,11 @@ async fn main() -> numa::Result<()> { axum::serve(listener, app).await.unwrap(); }); - // Proxy binds 0.0.0.0 when LAN is enabled (cross-machine access), otherwise config value - let proxy_bind: std::net::Ipv4Addr = if config.lan.enabled { - std::net::Ipv4Addr::UNSPECIFIED - } else { - config - .proxy - .bind_addr - .parse() - .unwrap_or(std::net::Ipv4Addr::LOCALHOST) - }; + let proxy_bind: std::net::Ipv4Addr = config + .proxy + .bind_addr + .parse() + .unwrap_or(std::net::Ipv4Addr::LOCALHOST); // Spawn HTTP reverse proxy for .numa domains if config.proxy.enabled {