fix: human-readable advisories for TLS data_dir + port-53 EACCES #48
12
src/main.rs
12
src/main.rs
@@ -223,14 +223,10 @@ async fn main() -> numa::Result<()> {
|
|||||||
) {
|
) {
|
||||||
Ok(tls_config) => Some(ArcSwap::from(tls_config)),
|
Ok(tls_config) => Some(ArcSwap::from(tls_config)),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
match e.downcast_ref::<std::io::Error>() {
|
if let Some(advisory) = numa::tls::try_data_dir_advisory(&e, &resolved_data_dir) {
|
||||||
Some(io_err) if io_err.kind() == std::io::ErrorKind::PermissionDenied => {
|
eprint!("{}", advisory);
|
||||||
eprint!(
|
} else {
|
||||||
"{}",
|
log::warn!("TLS setup failed, HTTPS proxy disabled: {}", e);
|
||||||
numa::tls::data_dir_permission_advisory(&resolved_data_dir)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => log::warn!("TLS setup failed, HTTPS proxy disabled: {}", e),
|
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,11 +46,8 @@ pub fn discover_system_dns() -> SystemDnsInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Diagnostic advisory for port-53 bind failures. Returns `Some(msg)`
|
/// Advisory for port-53 bind failures (EADDRINUSE or EACCES); `None`
|
||||||
/// when `bind_addr` targets port 53 and `err` is a kind we can advise
|
/// if not applicable so the caller can fall back to the raw error.
|
||||||
/// on (EADDRINUSE — another process holds it; EACCES — non-root on a
|
|
||||||
/// privileged port). Returns `None` for non-53 targets or unrelated
|
|
||||||
/// error kinds, so the caller can fall back to the raw error.
|
|
||||||
pub fn try_port53_advisory(bind_addr: &str, err: &std::io::Error) -> Option<String> {
|
pub fn try_port53_advisory(bind_addr: &str, err: &std::io::Error) -> Option<String> {
|
||||||
if !is_port_53(bind_addr) {
|
if !is_port_53(bind_addr) {
|
||||||
return None;
|
return None;
|
||||||
|
|||||||
49
src/tls.rs
49
src/tls.rs
@@ -40,15 +40,16 @@ pub fn regenerate_tls(ctx: &ServerCtx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Human-readable diagnostic for TLS data-dir permission failures.
|
/// Advisory for TLS-setup failures caused by a non-writable data dir;
|
||||||
/// Triggered when numa can't write its local CA to the configured
|
/// `None` if not applicable so the caller can fall back to the raw error.
|
||||||
/// data dir (typically `/usr/local/var/numa` without root). HTTPS
|
pub fn try_data_dir_advisory(err: &crate::Error, data_dir: &Path) -> Option<String> {
|
||||||
/// proxy is disabled; DNS resolution and plain-HTTP proxy keep
|
let io_err = err.downcast_ref::<std::io::Error>()?;
|
||||||
/// working.
|
if io_err.kind() != std::io::ErrorKind::PermissionDenied {
|
||||||
pub fn data_dir_permission_advisory(data_dir: &Path) -> String {
|
return None;
|
||||||
let o = "\x1b[1;38;2;192;98;58m"; // bold orange
|
}
|
||||||
|
let o = "\x1b[1;38;2;192;98;58m";
|
||||||
let r = "\x1b[0m";
|
let r = "\x1b[0m";
|
||||||
format!(
|
Some(format!(
|
||||||
"
|
"
|
||||||
{o}Numa{r} — HTTPS proxy disabled: cannot write TLS CA to {}.
|
{o}Numa{r} — HTTPS proxy disabled: cannot write TLS CA to {}.
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ pub fn data_dir_permission_advisory(data_dir: &Path) -> String {
|
|||||||
|
|
||||||
",
|
",
|
||||||
data_dir.display()
|
data_dir.display()
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a TLS config with a cert covering all provided service names.
|
/// Build a TLS config with a cert covering all provided service names.
|
||||||
@@ -203,3 +204,33 @@ fn generate_service_cert(
|
|||||||
|
|
||||||
Ok((vec![cert_der, ca_der], key_der))
|
Ok((vec![cert_der, ca_der], key_der))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn try_data_dir_advisory_permission_denied() {
|
||||||
|
let err: crate::Error =
|
||||||
|
Box::new(std::io::Error::from(std::io::ErrorKind::PermissionDenied));
|
||||||
|
let path = PathBuf::from("/usr/local/var/numa");
|
||||||
|
let msg = try_data_dir_advisory(&err, &path).expect("should advise");
|
||||||
|
assert!(msg.contains("HTTPS proxy disabled"));
|
||||||
|
assert!(msg.contains("/usr/local/var/numa"));
|
||||||
|
assert!(msg.contains("numa install"));
|
||||||
|
assert!(msg.contains("data_dir"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn try_data_dir_advisory_skips_other_io_kinds() {
|
||||||
|
let err: crate::Error = Box::new(std::io::Error::from(std::io::ErrorKind::NotFound));
|
||||||
|
assert!(try_data_dir_advisory(&err, &PathBuf::from("/x")).is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn try_data_dir_advisory_skips_non_io_errors() {
|
||||||
|
let err: crate::Error = "rcgen failure".into();
|
||||||
|
assert!(try_data_dir_advisory(&err, &PathBuf::from("/x")).is_none());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user