mirror of
https://codeberg.org/icewind/netnsd.git
synced 2026-06-03 09:04:07 +02:00
support reverse forwarding
This commit is contained in:
parent
53f5f45865
commit
d8d1bc17df
6 changed files with 65 additions and 21 deletions
|
|
@ -77,4 +77,10 @@ name = "test2"
|
||||||
# listening on a specific address instead of 0.0.0.0
|
# listening on a specific address instead of 0.0.0.0
|
||||||
source = "127.0.0.1:9091"
|
source = "127.0.0.1:9091"
|
||||||
target = 80
|
target = 80
|
||||||
|
|
||||||
|
[[namespace.forward]]
|
||||||
|
# forward from inside the namespace to outside instead
|
||||||
|
reverse = true
|
||||||
|
source = 80
|
||||||
|
target = 80
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -26,3 +26,9 @@ name = "test2"
|
||||||
# listening on a specific address instead of 0.0.0.0
|
# listening on a specific address instead of 0.0.0.0
|
||||||
source = "127.0.0.1:9091"
|
source = "127.0.0.1:9091"
|
||||||
target = 80
|
target = 80
|
||||||
|
|
||||||
|
[[namespace.forward]]
|
||||||
|
# forward from inside the namespace to outside instead
|
||||||
|
reverse = true
|
||||||
|
source = 80
|
||||||
|
target = 80
|
||||||
|
|
@ -48,6 +48,7 @@ in {
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
description = "ports to forward into the namespace";
|
description = "ports to forward into the namespace";
|
||||||
|
default = [];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,8 @@ pub struct NamespaceConfig {
|
||||||
pub struct ForwardConfig {
|
pub struct ForwardConfig {
|
||||||
pub source: ForwardSource,
|
pub source: ForwardSource,
|
||||||
pub target: ForwardTarget,
|
pub target: ForwardTarget,
|
||||||
|
#[serde(default)]
|
||||||
|
pub reverse: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use nix::sched::{CloneFlags, setns};
|
||||||
use std::fs::{File, remove_file};
|
use std::fs::{File, remove_file};
|
||||||
use std::io::Error as IoError;
|
use std::io::Error as IoError;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicU64, Ordering};
|
use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
use std::thread::spawn;
|
use std::thread::spawn;
|
||||||
|
|
@ -45,32 +45,53 @@ impl ActiveProxy {
|
||||||
config: &ForwardConfig,
|
config: &ForwardConfig,
|
||||||
namespace: &NamespaceName,
|
namespace: &NamespaceName,
|
||||||
) -> Result<ActiveProxy, ProxyError> {
|
) -> Result<ActiveProxy, ProxyError> {
|
||||||
let proxy = Proxy::listen(config.source.clone())?;
|
|
||||||
let stats = ProxyStats::default();
|
let stats = ProxyStats::default();
|
||||||
|
|
||||||
let (abort, abort_reg) = AbortHandle::new_pair();
|
let (abort, abort_reg) = AbortHandle::new_pair();
|
||||||
|
|
||||||
let destination = config.target.clone();
|
let destination = config.target.clone();
|
||||||
let run_stats = stats.clone();
|
let run_stats = stats.clone();
|
||||||
let ns_path = PathBuf::from(format!("/var/run/netns/{namespace}"));
|
|
||||||
let ns_handle = File::open(&ns_path).map_err(|error| ProxyError::OpenNamespace {
|
let ns_handle = open_namespace(format!("/var/run/netns/{namespace}"))?;
|
||||||
error,
|
let self_ns_handle = open_namespace("/proc/self/ns/net")?;
|
||||||
path: ns_path,
|
|
||||||
})?;
|
let (listen_namespace, target_namespace) = if config.reverse {
|
||||||
spawn(move || match setns(ns_handle, CloneFlags::CLONE_NEWNET) {
|
(Some(ns_handle), self_ns_handle)
|
||||||
Ok(_) => {
|
} else {
|
||||||
let rt = match Builder::new_current_thread().enable_io().build() {
|
(None, ns_handle)
|
||||||
Ok(rt) => rt,
|
};
|
||||||
|
|
||||||
|
let source = config.source.clone();
|
||||||
|
spawn(move || {
|
||||||
|
let rt = match Builder::new_current_thread().enable_io().build() {
|
||||||
|
Ok(rt) => rt,
|
||||||
|
Err(error) => {
|
||||||
|
error!(%error, "Error setting up tokio runtime");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
rt.block_on(async {
|
||||||
|
if let Some(listen_namespace) = listen_namespace {
|
||||||
|
if let Err(error) = setns(listen_namespace, CloneFlags::CLONE_NEWNET) {
|
||||||
|
error!(%error, "Failed to join listen network namespace for proxy");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let proxy = match Proxy::listen(&source) {
|
||||||
|
Ok(proxy) => proxy,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
error!(%error, "Error setting up tokio runtime");
|
error!(%error, "Failed to listen to {source}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
rt.block_on(proxy.run(destination, abort_reg, run_stats));
|
|
||||||
}
|
if let Err(error) = setns(target_namespace, CloneFlags::CLONE_NEWNET) {
|
||||||
Err(error) => {
|
error!(%error, "Failed to join target network namespace for proxy");
|
||||||
error!(%error, "Failed to join network namespace for proxy");
|
return;
|
||||||
}
|
}
|
||||||
|
proxy.run(destination, abort_reg, run_stats).await;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(ActiveProxy {
|
Ok(ActiveProxy {
|
||||||
|
|
@ -145,3 +166,11 @@ impl ProxyStats {
|
||||||
self.bytes_written.load(Ordering::Relaxed)
|
self.bytes_written.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn open_namespace(path: impl AsRef<Path>) -> Result<File, ProxyError> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
File::open(path).map_err(|error| ProxyError::OpenNamespace {
|
||||||
|
error,
|
||||||
|
path: path.into(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,8 @@ fn bind_tcp(addr: SocketAddr) -> Result<TcpListener, IoError> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Proxy {
|
impl Proxy {
|
||||||
pub fn listen(bind: ForwardSource) -> Result<Self, ProxyError> {
|
pub fn listen(bind: &ForwardSource) -> Result<Self, ProxyError> {
|
||||||
let socket = match &bind {
|
let socket = match bind {
|
||||||
ForwardSource::Unix(path) => {
|
ForwardSource::Unix(path) => {
|
||||||
let _ = remove_file(path);
|
let _ = remove_file(path);
|
||||||
UnixListener::bind(path).map(|listener| {
|
UnixListener::bind(path).map(|listener| {
|
||||||
|
|
@ -51,7 +51,7 @@ impl Proxy {
|
||||||
ForwardSource::Ip(addr) => bind_tcp(*addr).map(ProxyListener::Tcp),
|
ForwardSource::Ip(addr) => bind_tcp(*addr).map(ProxyListener::Tcp),
|
||||||
}
|
}
|
||||||
.map_err(|error| ProxyError::Bind {
|
.map_err(|error| ProxyError::Bind {
|
||||||
address: bind,
|
address: bind.clone(),
|
||||||
error,
|
error,
|
||||||
})?;
|
})?;
|
||||||
debug!("Created TCP socket");
|
debug!("Created TCP socket");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue