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": {
"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": {
"viewVideo": true
}
},
{
"unix": "/var/lib/moonfire-nvr/sock",
"ownUidIsPrivileged": true
}
]
}
```
Note that at this stage, Moonfire NVR's web interface is **insecure**: it
doesn't use `https` and doesn't require you to authenticate
to it. You might be comfortable starting it in this configuration to try it
out, particularly if the machine it's running on is behind a home router's
firewall. You might not; in that case read through [secure the
system](secure.md) first.
With this config, Moonfire NVR's web interface is **insecure**: it doesn't use
`https` and doesn't require you to authenticate to it. You might be comfortable
starting it in this configuration to try it out, particularly if the machine
it's running on is behind a home router's firewall. You might not; in that case
read through [secure the system](secure.md) first.
This command will start a detached Docker container for the web interface.
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> {
let sa: SocketAddr = match addr {
config::AddressConfig::Ipv4(a) => a.clone().into(),
config::AddressConfig::Ipv6(a) => a.clone().into(),
config::AddressConfig::Unix(p) => {
prepare_unix_socket(p);
return Ok(Listener::Unix(
tokio::net::UnixListener::bind(p)
.with_context(|_| format!("unable bind Unix socket {}", p.display()))?,