make Unix sockets bind reliably and add to config

This commit is contained in:
Scott Lamb 2022-03-11 11:51:28 -08:00
parent 7c453b5f9d
commit 7467b382dc
3 changed files with 35 additions and 6 deletions

View File

@ -309,6 +309,10 @@ You'll also need a `/etc/moonfire-nvr.json`:
"allowUnauthenticatedPermissions": { "allowUnauthenticatedPermissions": {
"viewVideo": true "viewVideo": true
} }
},
{
"unix": "/var/lib/moonfire-nvr/sock",
"ownUidIsPrivileged": true
} }
] ]
} }

View File

@ -268,17 +268,20 @@ You'll need to create the runtime configuration file, `/etc/moonfire-nvr.json`:
"allowUnauthenticatedPermissions": { "allowUnauthenticatedPermissions": {
"viewVideo": true "viewVideo": true
} }
},
{
"unix": "/var/lib/moonfire-nvr/sock",
"ownUidIsPrivileged": true
} }
] ]
} }
``` ```
Note that at this stage, Moonfire NVR's web interface is **insecure**: it With this config, Moonfire NVR's web interface is **insecure**: it doesn't use
doesn't use `https` and doesn't require you to authenticate `https` and doesn't require you to authenticate to it. You might be comfortable
to it. You might be comfortable starting it in this configuration to try it starting it in this configuration to try it out, particularly if the machine
out, particularly if the machine it's running on is behind a home router's it's running on is behind a home router's firewall. You might not; in that case
firewall. You might not; in that case read through [secure the read through [secure the system](secure.md) first.
system](secure.md) first.
This command will start a detached Docker container for the web interface. This command will start a detached Docker container for the web interface.
It will automatically restart when your system does. It will automatically restart when your system does.

View File

@ -184,11 +184,33 @@ async fn async_run(read_only: bool, config: &ConfigFile) -> Result<i32, Error> {
} }
} }
/// Makes a best-effort attempt to prepare a path for binding as a Unix-domain socket.
///
/// Binding to a Unix-domain socket fails with `EADDRINUSE` if the dirent already exists,
/// and the dirent isn't automatically deleted when the previous server closes. Clean up a
/// previous socket. As a defense against misconfiguration, make sure it actually is
/// a socket first.
///
/// This mechanism is inherently racy, but it's expected that the database has already
/// been locked.
fn prepare_unix_socket(p: &Path) {
use nix::sys::stat::{stat, SFlag};
let stat = match stat(p) {
Err(_) => return,
Ok(s) => s,
};
if !SFlag::from_bits_truncate(stat.st_mode).intersects(SFlag::S_IFSOCK) {
return;
}
let _ = nix::unistd::unlink(p);
}
fn make_listener(addr: &config::AddressConfig) -> Result<Listener, Error> { fn make_listener(addr: &config::AddressConfig) -> Result<Listener, Error> {
let sa: SocketAddr = match addr { let sa: SocketAddr = match addr {
config::AddressConfig::Ipv4(a) => a.clone().into(), config::AddressConfig::Ipv4(a) => a.clone().into(),
config::AddressConfig::Ipv6(a) => a.clone().into(), config::AddressConfig::Ipv6(a) => a.clone().into(),
config::AddressConfig::Unix(p) => { config::AddressConfig::Unix(p) => {
prepare_unix_socket(p);
return Ok(Listener::Unix( return Ok(Listener::Unix(
tokio::net::UnixListener::bind(p) tokio::net::UnixListener::bind(p)
.with_context(|_| format!("unable bind Unix socket {}", p.display()))?, .with_context(|_| format!("unable bind Unix socket {}", p.display()))?,