mirror of
https://codeberg.org/icewind/netnsd.git
synced 2026-06-03 17:14:06 +02:00
don't remove namespaces on daemon exit
This commit is contained in:
parent
9af09c8669
commit
3a8b684600
6 changed files with 52 additions and 56 deletions
|
|
@ -2,6 +2,7 @@
|
||||||
name = "netnsd"
|
name = "netnsd"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
rust-version = "1.87.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread", "signal", "net", "io-util"] }
|
tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread", "signal", "net", "io-util"] }
|
||||||
|
|
|
||||||
32
flake.lock
generated
32
flake.lock
generated
|
|
@ -2,11 +2,11 @@
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"crane": {
|
"crane": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1742394900,
|
"lastModified": 1760924934,
|
||||||
"narHash": "sha256-vVOAp9ahvnU+fQoKd4SEXB2JG2wbENkpqcwlkIXgUC0=",
|
"narHash": "sha256-tuuqY5aU7cUkR71sO2TraVKK2boYrdW3gCSXUkF4i44=",
|
||||||
"owner": "ipetkov",
|
"owner": "ipetkov",
|
||||||
"repo": "crane",
|
"repo": "crane",
|
||||||
"rev": "70947c1908108c0c551ddfd73d4f750ff2ea67cd",
|
"rev": "c6b4d5308293d0d04fcfeee92705017537cad02f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -22,11 +22,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1748868585,
|
"lastModified": 1761636064,
|
||||||
"narHash": "sha256-DrrbahOQAwvNM8l5EuGxxkVS7X5/S59zcG0N9ZWQFhk=",
|
"narHash": "sha256-xAbEYL5gqPnBfXOIGToPjF6E0n9RSe8YJ6E2/ePrPaM=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "flakelight",
|
"repo": "flakelight",
|
||||||
"rev": "dfbecd12d99c1bf82906521a6a7d5b75d2aa1ca2",
|
"rev": "2c621bc66465c457b64b016bb00d575ff2e51094",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -44,11 +44,11 @@
|
||||||
"rust-overlay": "rust-overlay"
|
"rust-overlay": "rust-overlay"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1748205441,
|
"lastModified": 1762008387,
|
||||||
"narHash": "sha256-W+UUBT/l1DSTZo5G43494mRNNspJ2i9jW2QELC9JuMQ=",
|
"narHash": "sha256-Rss/bk95oJB8lcOp5ZbfzVUmRushUCWUGhfZLz9C/Lw=",
|
||||||
"ref": "refs/heads/main",
|
"ref": "refs/heads/main",
|
||||||
"rev": "dac3b74a89cebbeb21cc6602e4a346604adbee8b",
|
"rev": "ae534f62fd0a32f8e983d0a9fbfc8124d099b341",
|
||||||
"revCount": 49,
|
"revCount": 64,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://codeberg.org/icewind/mill-scale"
|
"url": "https://codeberg.org/icewind/mill-scale"
|
||||||
},
|
},
|
||||||
|
|
@ -59,11 +59,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1748708770,
|
"lastModified": 1761597516,
|
||||||
"narHash": "sha256-q8jG2HJWgooWa9H0iatZqBPF3bp0504e05MevFmnFLY=",
|
"narHash": "sha256-wxX7u6D2rpkJLWkZ2E932SIvDJW8+ON/0Yy8+a5vsDU=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "a59eb7800787c926045d51b70982ae285faa2346",
|
"rev": "daf6dc47aa4b44791372d6139ab7b25269184d55",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -88,11 +88,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1742697269,
|
"lastModified": 1761964689,
|
||||||
"narHash": "sha256-Lpp0XyAtIl1oGJzNmTiTGLhTkcUjwSkEb0gOiNzYFGM=",
|
"narHash": "sha256-Zo3LQQDz+64EQ9zor/WmeNTFLoZkjmhp0UY3G0D3seE=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "01973c84732f9275c50c5f075dd1f54cc04b3316",
|
"rev": "63d22578600f70d293aede6bc737efef60ebd97f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,10 @@ impl Config {
|
||||||
pub fn reload(&self) -> Result<Config, ConfigError> {
|
pub fn reload(&self) -> Result<Config, ConfigError> {
|
||||||
Self::load(&self.path)
|
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)]
|
#[derive(Deserialize, Debug)]
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
use crate::config::{Config, ForwardConfig, NamespaceConfig, NamespaceName};
|
use crate::config::{Config, ForwardConfig, NamespaceConfig, NamespaceName};
|
||||||
use crate::namespace::{NamespaceError, NetNs};
|
use crate::namespace::{NamespaceError, NetNs};
|
||||||
|
use crate::proxy::{ActiveProxy, ProxyError};
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use futures_concurrency::stream::Merge;
|
use futures_concurrency::stream::Merge;
|
||||||
|
use humansize::{BINARY, SizeFormatter};
|
||||||
use main_error::MainResult;
|
use main_error::MainResult;
|
||||||
use sd_notify::{NotifyState, notify};
|
use sd_notify::{NotifyState, notify};
|
||||||
use std::io::Error as IoError;
|
use std::io::Error as IoError;
|
||||||
use std::pin::pin;
|
use std::pin::pin;
|
||||||
use humansize::{SizeFormatter, BINARY};
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
use tokio::signal::ctrl_c;
|
use tokio::signal::ctrl_c;
|
||||||
use tokio::signal::unix::{SignalKind, signal};
|
use tokio::signal::unix::{SignalKind, signal};
|
||||||
use tokio_stream::wrappers::SignalStream;
|
use tokio_stream::wrappers::SignalStream;
|
||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
use crate::proxy::{ActiveProxy, ProxyError};
|
|
||||||
|
|
||||||
pub fn daemon(config: Config) -> MainResult {
|
pub fn daemon(config: Config) -> MainResult {
|
||||||
let rt = Runtime::new()?;
|
let rt = Runtime::new()?;
|
||||||
|
|
@ -111,20 +111,11 @@ struct State {
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn update(&mut self, config: &Config) -> Result<(), DaemonError> {
|
pub fn update(&mut self, config: &Config) -> Result<(), DaemonError> {
|
||||||
self.namespaces.retain_mut(|existing| {
|
for removed in self.namespaces.extract_if(.., |namespace| {
|
||||||
if let Some(new_config) =
|
config.get_namespace(namespace.name()).is_none()
|
||||||
config
|
}) {
|
||||||
.namespaces
|
removed.ns.delete()?;
|
||||||
.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 new in &config.namespaces {
|
for new in &config.namespaces {
|
||||||
if !self.has_namespace(&new.name) {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,7 +157,8 @@ impl ActiveNamespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_proxies(&mut self, config: &NamespaceConfig) -> Result<(), DaemonError> {
|
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 {
|
for new in &config.forward {
|
||||||
if !self.has_forward(new) {
|
if !self.has_forward(new) {
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,9 @@ mod raw;
|
||||||
|
|
||||||
use crate::config::NamespaceName;
|
use crate::config::NamespaceName;
|
||||||
use crate::link::{LinkError, link_up_ns};
|
use crate::link::{LinkError, link_up_ns};
|
||||||
use crate::namespace::raw::{
|
use crate::namespace::raw::{NamespaceSetupError, create_network_namespace};
|
||||||
NamespaceSetupError, create_network_namespace,
|
|
||||||
};
|
|
||||||
use nix::errno::Errno;
|
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::fs::{File, create_dir_all, remove_file};
|
||||||
use std::io::{Error as IoError, ErrorKind};
|
use std::io::{Error as IoError, ErrorKind};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
@ -40,10 +38,7 @@ impl NetNs {
|
||||||
|
|
||||||
let ns = create_network_namespace(move |ns| {
|
let ns = create_network_namespace(move |ns| {
|
||||||
bind_namespace(&ns, &path)?;
|
bind_namespace(&ns, &path)?;
|
||||||
Result::<_, NamespaceError>::Ok(NetNs {
|
Result::<_, NamespaceError>::Ok(NetNs { name, path })
|
||||||
name,
|
|
||||||
path,
|
|
||||||
})
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
ns.setup_interfaces()?;
|
ns.setup_interfaces()?;
|
||||||
|
|
@ -73,18 +68,16 @@ impl NetNs {
|
||||||
link_up_ns(&self.path, "lo")?;
|
link_up_ns(&self.path, "lo")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for NetNs {
|
pub fn delete(self) -> Result<(), NamespaceError> {
|
||||||
fn drop(&mut self) {
|
|
||||||
let name = self.path.file_name().unwrap().to_str().unwrap();
|
let name = self.path.file_name().unwrap().to_str().unwrap();
|
||||||
info!(name, "deleting network namespace");
|
info!(name, "deleting network namespace");
|
||||||
if let Err(error) = umount2(&self.path, MntFlags::MNT_DETACH) {
|
umount2(&self.path, MntFlags::MNT_DETACH).map_err(NamespaceError::UnMount)?;
|
||||||
error!(%error, path = %self.path.display(), "Failed to unmount network namespace");
|
remove_file(&self.path).map_err(|error| NamespaceError::Delete {
|
||||||
}
|
error,
|
||||||
if let Err(error) = remove_file(&self.path) {
|
path: self.path
|
||||||
error!(%error, path = %self.path.display(), "Failed to remove namespace file");
|
})?;
|
||||||
}
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,19 +87,20 @@ pub enum NamespaceError {
|
||||||
Parent(IoError),
|
Parent(IoError),
|
||||||
#[error("Failed to create namespace file {}: {error:#}", path.display())]
|
#[error("Failed to create namespace file {}: {error:#}", path.display())]
|
||||||
Create { path: PathBuf, error: IoError },
|
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:#}")]
|
#[error("Failed to setup namespace: {0:#}")]
|
||||||
Setup(#[from] NamespaceSetupError),
|
Setup(#[from] NamespaceSetupError),
|
||||||
#[error("Failed to bind-mount netns handle: {0:?}")]
|
#[error("Failed to bind-mount netns handle: {0:?}")]
|
||||||
Mount(Errno),
|
Mount(Errno),
|
||||||
|
#[error("Failed to unmount netns handle: {0:?}")]
|
||||||
|
UnMount(Errno),
|
||||||
#[error("Failed to setup loopback inside namespace: {0:#}")]
|
#[error("Failed to setup loopback inside namespace: {0:#}")]
|
||||||
Link(#[from] LinkError),
|
Link(#[from] LinkError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NamespaceError {
|
impl NamespaceError {
|
||||||
fn from_create(path: PathBuf, error: IoError) -> Self {
|
fn from_create(path: PathBuf, error: IoError) -> Self {
|
||||||
NamespaceError::Create {
|
NamespaceError::Create { path, error }
|
||||||
path,
|
|
||||||
error,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
mod tcp;
|
mod tcp;
|
||||||
|
|
||||||
use crate::config::{ForwardConfig, ForwardTarget, ForwardSource, NamespaceName};
|
use crate::config::{ForwardConfig, ForwardSource, ForwardTarget, NamespaceName};
|
||||||
use crate::proxy::tcp::Proxy;
|
use crate::proxy::tcp::Proxy;
|
||||||
use futures::future::AbortHandle;
|
use futures::future::AbortHandle;
|
||||||
use nix::sched::{CloneFlags, setns};
|
use nix::sched::{CloneFlags, setns};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue