mirror of
https://codeberg.org/icewind/netnsd.git
synced 2026-06-04 01:24:07 +02:00
proxying
This commit is contained in:
parent
78e716f949
commit
ec6c3a0a8b
7 changed files with 404 additions and 40 deletions
|
|
@ -1,20 +1,23 @@
|
|||
mod namespace;
|
||||
mod proxy;
|
||||
|
||||
use crate::config::{Config, NamespaceConfig, NamespaceName};
|
||||
use crate::config::{Config, ForwardConfig, NamespaceConfig, NamespaceName};
|
||||
use crate::daemon::namespace::{NamespaceError, NetNs};
|
||||
use futures::FutureExt;
|
||||
use futures::StreamExt;
|
||||
use futures_concurrency::stream::Merge;
|
||||
use main_error::MainResult;
|
||||
use sd_notify::{NotifyState, notify};
|
||||
use std::io::Error as IoError;
|
||||
use std::pin::pin;
|
||||
use futures::FutureExt;
|
||||
use humansize::{SizeFormatter, BINARY};
|
||||
use thiserror::Error;
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::signal::ctrl_c;
|
||||
use tokio::signal::unix::{SignalKind, signal};
|
||||
use futures::StreamExt;
|
||||
use futures_concurrency::stream::Merge;
|
||||
use tokio_stream::wrappers::SignalStream;
|
||||
use tracing::{debug, error, info};
|
||||
use crate::daemon::proxy::{ActiveProxy, ProxyError};
|
||||
|
||||
pub fn daemon(config: Config) -> MainResult {
|
||||
let rt = Runtime::new()?;
|
||||
|
|
@ -22,24 +25,21 @@ pub fn daemon(config: Config) -> MainResult {
|
|||
}
|
||||
|
||||
async fn daemon_async(mut config: Config) -> Result<(), DaemonError> {
|
||||
for namespace in &config.namespaces {
|
||||
println!("{}:", namespace.name);
|
||||
for forward in &namespace.forward {
|
||||
println!(" {} => {}", forward.source, forward.destination);
|
||||
}
|
||||
}
|
||||
|
||||
let mut state = State::default();
|
||||
state.update(&config)?;
|
||||
|
||||
// now the namespaces are setup, we can tell systemd to start any service depending on them
|
||||
notify(true, &[NotifyState::Ready]).map_err(DaemonError::Notify)?;
|
||||
|
||||
let reload_signal = signal(SignalKind::hangup()).map_err(DaemonError::ReloadSignal)?;
|
||||
let reload_signal = signal(SignalKind::hangup()).map_err(DaemonError::Signal)?;
|
||||
let reload_signal = SignalStream::new(reload_signal).map(|_| Event::Reload);
|
||||
|
||||
let info_signal = signal(SignalKind::user_defined1()).map_err(DaemonError::Signal)?;
|
||||
let info_signal = SignalStream::new(info_signal).map(|_| Event::Info);
|
||||
|
||||
let quit_signal = ctrl_c().into_stream().map(|_| Event::Quit);
|
||||
|
||||
let events = (reload_signal, quit_signal).merge();
|
||||
let events = (reload_signal, info_signal, quit_signal).merge();
|
||||
|
||||
let mut events = pin!(events);
|
||||
while let Some(event) = events.next().await {
|
||||
|
|
@ -53,18 +53,19 @@ async fn daemon_async(mut config: Config) -> Result<(), DaemonError> {
|
|||
|
||||
match NotifyState::monotonic_usec_now() {
|
||||
Ok(notify_time) => {
|
||||
notify(true, &[NotifyState::Reloading, notify_time]).map_err(DaemonError::Notify)?;
|
||||
notify(true, &[NotifyState::Reloading, notify_time])
|
||||
.map_err(DaemonError::Notify)?;
|
||||
}
|
||||
Err(error) => {
|
||||
error!(%error, "failed to get current time, not sending reload signal");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
match config.reload() {
|
||||
Ok(new_config) => {
|
||||
state.update(&new_config)?;
|
||||
config = new_config;
|
||||
},
|
||||
}
|
||||
Err(error) => {
|
||||
error!(%error, "Failed to load new config");
|
||||
}
|
||||
|
|
@ -72,6 +73,22 @@ async fn daemon_async(mut config: Config) -> Result<(), DaemonError> {
|
|||
|
||||
notify(true, &[NotifyState::Ready]).map_err(DaemonError::Notify)?;
|
||||
}
|
||||
Event::Info => {
|
||||
for namespace in &state.namespaces {
|
||||
println!("{}:", namespace.name());
|
||||
for proxy in &namespace.proxies {
|
||||
println!(
|
||||
" {} => {} {} connections ({} active), {} sent to namespace, {} received from namespace",
|
||||
proxy.source,
|
||||
proxy.destination,
|
||||
proxy.stats.total_connections(),
|
||||
proxy.stats.open_connections(),
|
||||
SizeFormatter::new(proxy.stats.written(), BINARY),
|
||||
SizeFormatter::new(proxy.stats.read(), BINARY),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,6 +99,7 @@ async fn daemon_async(mut config: Config) -> Result<(), DaemonError> {
|
|||
enum Event {
|
||||
Reload,
|
||||
Quit,
|
||||
Info,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -91,11 +109,19 @@ struct State {
|
|||
|
||||
impl State {
|
||||
pub fn update(&mut self, config: &Config) -> Result<(), DaemonError> {
|
||||
self.namespaces.retain(|existing| {
|
||||
config
|
||||
.namespaces
|
||||
.iter()
|
||||
.any(|new| &new.name == existing.name())
|
||||
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 new in &config.namespaces {
|
||||
|
|
@ -103,12 +129,12 @@ impl State {
|
|||
self.namespaces.push(ActiveNamespace::new(new)?);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn has_namespace(&self, name: &NamespaceName) -> bool {
|
||||
self
|
||||
.namespaces
|
||||
self.namespaces
|
||||
.iter()
|
||||
.any(|existing| existing.name() == name)
|
||||
}
|
||||
|
|
@ -116,12 +142,36 @@ impl State {
|
|||
|
||||
struct ActiveNamespace {
|
||||
ns: NetNs,
|
||||
proxies: Vec<ActiveProxy>,
|
||||
}
|
||||
|
||||
impl ActiveNamespace {
|
||||
pub fn new(config: &NamespaceConfig) -> Result<Self, DaemonError> {
|
||||
let ns = NetNs::new(&config.name)?;
|
||||
Ok(ActiveNamespace { ns })
|
||||
|
||||
let mut namespace = ActiveNamespace {
|
||||
ns,
|
||||
proxies: Vec::default(),
|
||||
};
|
||||
namespace.update_proxies(config)?;
|
||||
|
||||
Ok(namespace)
|
||||
}
|
||||
|
||||
pub fn update_proxies(&mut self, config: &NamespaceConfig) -> Result<(), DaemonError> {
|
||||
self.proxies.retain(|existing| config.forward.iter().any(|new| existing == new));
|
||||
|
||||
for new in &config.forward {
|
||||
if !self.has_forward(new) {
|
||||
self.proxies.push(ActiveProxy::new(new)?);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn has_forward(&self, config: &ForwardConfig) -> bool {
|
||||
self.proxies.iter().any(|existing| existing == config)
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &NamespaceName {
|
||||
|
|
@ -135,6 +185,8 @@ pub enum DaemonError {
|
|||
Namespace(#[from] NamespaceError),
|
||||
#[error("Error sending notification to systemd: {0:#}")]
|
||||
Notify(IoError),
|
||||
#[error("Error setting up reload signal listener: {0:#}")]
|
||||
ReloadSignal(IoError),
|
||||
#[error("Error setting up signal handler: {0:#}")]
|
||||
Signal(IoError),
|
||||
#[error(transparent)]
|
||||
Proxy(#[from] ProxyError),
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue