feat(#14): network isolation rust side — PRIVATE_NETWORK + veth wiring in set_nspawn_flags

This commit is contained in:
damocles 2026-05-31 21:06:07 +02:00 committed by mara
commit 3bb07b1fde
4 changed files with 185 additions and 24 deletions

View file

@ -21,8 +21,8 @@ use std::path::{Path, PathBuf};
use anyhow::{Context as _, Result, bail};
use hive_sh4re::priv_proto::{
AGENT_PREFIX, BindMount, JournalOutput, MANAGER_NAME, META_DIR, PRIV_SOCK, PrivRequest,
PrivResponse, SIBLING_CONTAINERS,
AGENT_PREFIX, BindMount, JournalOutput, MANAGER_NAME, META_DIR, NetworkIsolation, PRIV_SOCK,
PrivRequest, PrivResponse, SIBLING_CONTAINERS,
};
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::{UnixListener, UnixStream};
@ -207,13 +207,14 @@ async fn exec(req: PrivRequest) -> Result<(String, String)> {
PrivRequest::WriteNspawnFlags {
ref container,
ref binds,
ref isolation,
} => {
validate_container_system_name(container)?;
for bind in binds {
validate_bind_path(&bind.host_path)?;
validate_bind_path(&bind.container_path)?;
}
write_nspawn_flags(container, binds)?;
write_nspawn_flags(container, binds, isolation.as_ref())?;
Ok((String::new(), String::new()))
}
@ -477,9 +478,15 @@ fn validate_bind_path(path: &str) -> Result<()> {
/// Update `/etc/nixos-containers/<container>.conf`: strips network-isolation
/// vars (`PRIVATE_NETWORK`, `HOST_ADDRESS*`, `LOCAL_ADDRESS*`, `HOST_BRIDGE`,
/// `EXTRA_NSPAWN_FLAGS`), forces `PRIVATE_NETWORK=0` and blank network vars,
/// then appends `EXTRA_NSPAWN_FLAGS="<flags>"`.
fn write_nspawn_flags(container: &str, binds: &[BindMount]) -> Result<()> {
/// Update `/etc/nixos-containers/<container>.conf`: strip old network vars,
/// write network isolation settings, then append `EXTRA_NSPAWN_FLAGS`.
/// When `isolation` is `Some`, writes `PRIVATE_NETWORK=1` + veth wiring;
/// when `None`, writes `PRIVATE_NETWORK=0`.
fn write_nspawn_flags(
container: &str,
binds: &[BindMount],
isolation: Option<&NetworkIsolation>,
) -> Result<()> {
let path = format!("/etc/nixos-containers/{container}.conf");
let original = std::fs::read_to_string(&path).with_context(|| format!("read {path}"))?;
let lines: Vec<&str> = original
@ -499,12 +506,21 @@ fn write_nspawn_flags(container: &str, binds: &[BindMount]) -> Result<()> {
if !out.is_empty() {
out.push('\n');
}
out.push_str("PRIVATE_NETWORK=0\n");
out.push_str("HOST_ADDRESS=\n");
out.push_str("LOCAL_ADDRESS=\n");
out.push_str("HOST_ADDRESS6=\n");
out.push_str("LOCAL_ADDRESS6=\n");
out.push_str("HOST_BRIDGE=\n");
if let Some(iso) = isolation {
out.push_str("PRIVATE_NETWORK=1\n");
out.push_str("HOST_ADDRESS=\n");
out.push_str(&format!("LOCAL_ADDRESS={}\n", iso.agent_ip));
out.push_str("HOST_ADDRESS6=\n");
out.push_str("LOCAL_ADDRESS6=\n");
out.push_str(&format!("HOST_BRIDGE={}\n", iso.bridge));
} else {
out.push_str("PRIVATE_NETWORK=0\n");
out.push_str("HOST_ADDRESS=\n");
out.push_str("LOCAL_ADDRESS=\n");
out.push_str("HOST_ADDRESS6=\n");
out.push_str("LOCAL_ADDRESS6=\n");
out.push_str("HOST_BRIDGE=\n");
}
let flags: Vec<String> = binds
.iter()
.map(|b| {