copy ipv6 privacy settings into namespace

This commit is contained in:
Robin Appelman 2026-02-24 00:56:48 +01:00
commit 88f168b9e1
2 changed files with 100 additions and 2 deletions

View file

@ -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 {

90
src/namespace/sysctl.rs Normal file
View file

@ -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<NamespaceCtl, CtlError> {
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<T: FromStr, P: AsRef<Path>>(path: P) -> Result<T, CtlError>
where
<T as FromStr>::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<T: Display, P: AsRef<Path>>(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 },
}