don't remove namespaces on daemon exit

This commit is contained in:
Robin Appelman 2025-11-01 15:58:25 +01:00
commit 3a8b684600
6 changed files with 52 additions and 56 deletions

View file

@ -40,6 +40,10 @@ impl Config {
pub fn reload(&self) -> Result<Config, ConfigError> {
Self::load(&self.path)
}
pub fn get_namespace<'a>(&'a self, name: &NamespaceName) -> Option<&'a NamespaceConfig> {
self.namespaces.iter().find(|namespace| &namespace.name == name)
}
}
#[derive(Deserialize, Debug)]

View file

@ -1,20 +1,20 @@
use crate::config::{Config, ForwardConfig, NamespaceConfig, NamespaceName};
use crate::namespace::{NamespaceError, NetNs};
use crate::proxy::{ActiveProxy, ProxyError};
use futures::FutureExt;
use futures::StreamExt;
use futures_concurrency::stream::Merge;
use humansize::{BINARY, SizeFormatter};
use main_error::MainResult;
use sd_notify::{NotifyState, notify};
use std::io::Error as IoError;
use std::pin::pin;
use humansize::{SizeFormatter, BINARY};
use thiserror::Error;
use tokio::runtime::Runtime;
use tokio::signal::ctrl_c;
use tokio::signal::unix::{SignalKind, signal};
use tokio_stream::wrappers::SignalStream;
use tracing::{debug, error, info};
use crate::proxy::{ActiveProxy, ProxyError};
pub fn daemon(config: Config) -> MainResult {
let rt = Runtime::new()?;
@ -91,7 +91,7 @@ async fn daemon_async(mut config: Config) -> Result<(), DaemonError> {
}
}
}
let _ = notify(false, &[NotifyState::Stopping]);
Ok(())
@ -111,20 +111,11 @@ struct State {
impl State {
pub fn update(&mut self, config: &Config) -> Result<(), DaemonError> {
self.namespaces.retain_mut(|existing| {
if let Some(new_config) =
config
.namespaces
.iter()
.find(|new| &new.name == existing.name()) {
if let Err(error) = existing.update_proxies(new_config) {
error!(%error, "Failed to update proxies for namespace");
}
true
} else {
false
}
});
for removed in self.namespaces.extract_if(.., |namespace| {
config.get_namespace(namespace.name()).is_none()
}) {
removed.ns.delete()?;
}
for new in &config.namespaces {
if !self.has_namespace(&new.name) {
@ -132,6 +123,11 @@ impl State {
}
}
for namespace in &mut self.namespaces {
let config = config.get_namespace(namespace.name()).unwrap();
namespace.update_proxies(config)?;
}
Ok(())
}
@ -161,7 +157,8 @@ impl ActiveNamespace {
}
pub fn update_proxies(&mut self, config: &NamespaceConfig) -> Result<(), DaemonError> {
self.proxies.retain(|existing| config.forward.iter().any(|new| existing == new));
self.proxies
.retain(|existing| config.forward.iter().any(|new| existing == new));
for new in &config.forward {
if !self.has_forward(new) {

View file

@ -2,11 +2,9 @@ mod raw;
use crate::config::NamespaceName;
use crate::link::{LinkError, link_up_ns};
use crate::namespace::raw::{
NamespaceSetupError, create_network_namespace,
};
use crate::namespace::raw::{NamespaceSetupError, create_network_namespace};
use nix::errno::Errno;
use nix::mount::{MsFlags, mount, umount2, MntFlags};
use nix::mount::{MntFlags, MsFlags, mount, umount2};
use std::fs::{File, create_dir_all, remove_file};
use std::io::{Error as IoError, ErrorKind};
use std::path::{Path, PathBuf};
@ -40,10 +38,7 @@ impl NetNs {
let ns = create_network_namespace(move |ns| {
bind_namespace(&ns, &path)?;
Result::<_, NamespaceError>::Ok(NetNs {
name,
path,
})
Result::<_, NamespaceError>::Ok(NetNs { name, path })
})?;
ns.setup_interfaces()?;
@ -73,18 +68,16 @@ impl NetNs {
link_up_ns(&self.path, "lo")?;
Ok(())
}
}
impl Drop for NetNs {
fn drop(&mut self) {
pub fn delete(self) -> Result<(), NamespaceError> {
let name = self.path.file_name().unwrap().to_str().unwrap();
info!(name, "deleting network namespace");
if let Err(error) = umount2(&self.path, MntFlags::MNT_DETACH) {
error!(%error, path = %self.path.display(), "Failed to unmount network namespace");
}
if let Err(error) = remove_file(&self.path) {
error!(%error, path = %self.path.display(), "Failed to remove namespace file");
}
umount2(&self.path, MntFlags::MNT_DETACH).map_err(NamespaceError::UnMount)?;
remove_file(&self.path).map_err(|error| NamespaceError::Delete {
error,
path: self.path
})?;
Ok(())
}
}
@ -94,19 +87,20 @@ pub enum NamespaceError {
Parent(IoError),
#[error("Failed to create namespace file {}: {error:#}", path.display())]
Create { path: PathBuf, error: IoError },
#[error("Failed to delete namespace file {}: {error:#}", path.display())]
Delete { path: PathBuf, error: IoError },
#[error("Failed to setup namespace: {0:#}")]
Setup(#[from] NamespaceSetupError),
#[error("Failed to bind-mount netns handle: {0:?}")]
Mount(Errno),
#[error("Failed to unmount netns handle: {0:?}")]
UnMount(Errno),
#[error("Failed to setup loopback inside namespace: {0:#}")]
Link(#[from] LinkError),
}
impl NamespaceError {
fn from_create(path: PathBuf, error: IoError) -> Self {
NamespaceError::Create {
path,
error,
}
NamespaceError::Create { path, error }
}
}

View file

@ -1,6 +1,6 @@
mod tcp;
use crate::config::{ForwardConfig, ForwardTarget, ForwardSource, NamespaceName};
use crate::config::{ForwardConfig, ForwardSource, ForwardTarget, NamespaceName};
use crate::proxy::tcp::Proxy;
use futures::future::AbortHandle;
use nix::sched::{CloneFlags, setns};