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
|
||||
source = "127.0.0.1:9091"
|
||||
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
|
||||
source = "127.0.0.1:9091"
|
||||
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";
|
||||
default = [];
|
||||
};
|
||||
};
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ pub struct NamespaceConfig {
|
|||
pub struct ForwardConfig {
|
||||
pub source: ForwardSource,
|
||||
pub target: ForwardTarget,
|
||||
#[serde(default)]
|
||||
pub reverse: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use nix::sched::{CloneFlags, setns};
|
|||
use std::fs::{File, remove_file};
|
||||
use std::io::Error as IoError;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::thread::spawn;
|
||||
|
|
@ -45,20 +45,23 @@ impl ActiveProxy {
|
|||
config: &ForwardConfig,
|
||||
namespace: &NamespaceName,
|
||||
) -> Result<ActiveProxy, ProxyError> {
|
||||
let proxy = Proxy::listen(config.source.clone())?;
|
||||
let stats = ProxyStats::default();
|
||||
|
||||
let (abort, abort_reg) = AbortHandle::new_pair();
|
||||
|
||||
let destination = config.target.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 {
|
||||
error,
|
||||
path: ns_path,
|
||||
})?;
|
||||
spawn(move || match setns(ns_handle, CloneFlags::CLONE_NEWNET) {
|
||||
Ok(_) => {
|
||||
|
||||
let ns_handle = open_namespace(format!("/var/run/netns/{namespace}"))?;
|
||||
let self_ns_handle = open_namespace("/proc/self/ns/net")?;
|
||||
|
||||
let (listen_namespace, target_namespace) = if config.reverse {
|
||||
(Some(ns_handle), self_ns_handle)
|
||||
} else {
|
||||
(None, ns_handle)
|
||||
};
|
||||
|
||||
let source = config.source.clone();
|
||||
spawn(move || {
|
||||
let rt = match Builder::new_current_thread().enable_io().build() {
|
||||
Ok(rt) => rt,
|
||||
Err(error) => {
|
||||
|
|
@ -66,11 +69,29 @@ impl ActiveProxy {
|
|||
return;
|
||||
}
|
||||
};
|
||||
rt.block_on(proxy.run(destination, abort_reg, run_stats));
|
||||
|
||||
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) => {
|
||||
error!(%error, "Failed to join network namespace for proxy");
|
||||
error!(%error, "Failed to listen to {source}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(error) = setns(target_namespace, CloneFlags::CLONE_NEWNET) {
|
||||
error!(%error, "Failed to join target network namespace for proxy");
|
||||
return;
|
||||
}
|
||||
proxy.run(destination, abort_reg, run_stats).await;
|
||||
});
|
||||
});
|
||||
|
||||
Ok(ActiveProxy {
|
||||
|
|
@ -145,3 +166,11 @@ impl ProxyStats {
|
|||
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 {
|
||||
pub fn listen(bind: ForwardSource) -> Result<Self, ProxyError> {
|
||||
let socket = match &bind {
|
||||
pub fn listen(bind: &ForwardSource) -> Result<Self, ProxyError> {
|
||||
let socket = match bind {
|
||||
ForwardSource::Unix(path) => {
|
||||
let _ = remove_file(path);
|
||||
UnixListener::bind(path).map(|listener| {
|
||||
|
|
@ -51,7 +51,7 @@ impl Proxy {
|
|||
ForwardSource::Ip(addr) => bind_tcp(*addr).map(ProxyListener::Tcp),
|
||||
}
|
||||
.map_err(|error| ProxyError::Bind {
|
||||
address: bind,
|
||||
address: bind.clone(),
|
||||
error,
|
||||
})?;
|
||||
debug!("Created TCP socket");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue