From 88f168b9e1324d66aa892a04fa9edcfaafe539d0 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 24 Feb 2026 00:56:48 +0100 Subject: [PATCH] copy ipv6 privacy settings into namespace --- src/namespace/mod.rs | 12 +++++- src/namespace/sysctl.rs | 90 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 src/namespace/sysctl.rs diff --git a/src/namespace/mod.rs b/src/namespace/mod.rs index 7b34443..a1e3e2c 100644 --- a/src/namespace/mod.rs +++ b/src/namespace/mod.rs @@ -1,10 +1,12 @@ mod handle; mod raw; +mod sysctl; use crate::config::{DeviceName, NamespaceName}; use crate::link::{LinkError, link_up, move_all_links, move_link_into}; pub use crate::namespace::handle::{NamespaceHandle, NamespaceHandleError}; use crate::namespace::raw::{NamespaceSetupError, create_network_namespace}; +use crate::namespace::sysctl::{CtlError, NamespaceCtl}; use either::Either; use nix::errno::Errno; use nix::mount::{MntFlags, MsFlags, mount, umount2}; @@ -154,8 +156,12 @@ impl NetNs { } fn setup_interfaces(&self) -> Result<(), NamespaceError> { - self.handle - .run_in(move || link_up("lo").map_err(NamespaceError::from))??; + let ctl = NamespaceCtl::read()?; + self.handle.run_in(move || { + link_up("lo").map_err(NamespaceError::from)?; + dbg!(ctl).apply()?; + Ok::<_, NamespaceError>(()) + })??; Ok(()) } @@ -218,6 +224,8 @@ pub enum NamespaceError { Enter(#[from] NamespaceEnterError), #[error(transparent)] Link(#[from] LinkError), + #[error("Failed to setup sysctl for namespace: {0:#}")] + Sysctl(#[from] CtlError), } impl NamespaceError { diff --git a/src/namespace/sysctl.rs b/src/namespace/sysctl.rs new file mode 100644 index 0000000..d2f6b6b --- /dev/null +++ b/src/namespace/sysctl.rs @@ -0,0 +1,90 @@ +use std::fmt::Display; +use std::fs::{File, OpenOptions}; +use std::io::Write; +use std::io::{Error as IoError, ErrorKind, Read}; +use std::path::{Path, PathBuf}; +use std::str::FromStr; +use thiserror::Error; + +#[derive(Debug)] +pub struct NamespaceCtl { + use_temp_addr: u32, + temp_valid_lft: u32, + temp_preferred_lft: u32, +} + +const PATH_TEMP_ADDR: &str = "/proc/sys/net/ipv6/conf/default/use_tempaddr"; +const PATH_VALID_LFT: &str = "/proc/sys/net/ipv6/conf/default/temp_valid_lft"; +const PATH_PREFERRED_LFT: &str = "/proc/sys/net/ipv6/conf/default/temp_prefered_lft"; + +impl NamespaceCtl { + pub fn read() -> Result { + Ok(NamespaceCtl { + use_temp_addr: read_sysctl(PATH_TEMP_ADDR)?, + temp_valid_lft: read_sysctl(PATH_VALID_LFT)?, + temp_preferred_lft: read_sysctl(PATH_PREFERRED_LFT)?, + }) + } + + pub fn apply(&self) -> Result<(), CtlError> { + write_sysctl(PATH_TEMP_ADDR, self.use_temp_addr)?; + write_sysctl(PATH_VALID_LFT, self.temp_valid_lft)?; + write_sysctl(PATH_PREFERRED_LFT, self.temp_preferred_lft)?; + Ok(()) + } +} + +fn read_sysctl>(path: P) -> Result +where + ::Err: Display, +{ + let path = path.as_ref(); + let mut buff = [0; 16]; + let mut file = File::open(path).map_err(|error| CtlError::Read { + path: path.into(), + error, + })?; + let read = file.read(&mut buff).map_err(|error| CtlError::Read { + path: path.into(), + error, + })?; + let data = &buff[0..read]; + let str = str::from_utf8(data) + .map_err(|_| CtlError::Read { + path: path.into(), + error: IoError::new(ErrorKind::InvalidData, "stream did not contain valid UTF-8"), + })? + .trim(); + T::from_str(str).map_err(|error| CtlError::Parse { + path: path.into(), + error: error.to_string(), + }) +} + +fn write_sysctl>(path: P, value: T) -> Result<(), CtlError> { + let path = path.as_ref(); + + let mut file = OpenOptions::new() + .create(false) + .truncate(true) + .write(true) + .open(path) + .map_err(|error| CtlError::Write { + path: path.into(), + error, + })?; + writeln!(&mut file, "{value}").map_err(|error| CtlError::Write { + path: path.into(), + error, + }) +} + +#[derive(Debug, Error)] +pub enum CtlError { + #[error("failed to read sysctl option {}: {error:#}", path.display())] + Read { path: PathBuf, error: IoError }, + #[error("failed to read sysctl option {}: {error}", path.display())] + Parse { path: PathBuf, error: String }, + #[error("failed to write sysctl option {}: {error:#}", path.display())] + Write { path: PathBuf, error: IoError }, +}