Skip to main content

icebox/core/proxy/
mod.rs

1use std::collections::HashMap;
2use std::net::SocketAddr;
3use std::sync::{LazyLock, RwLock};
4
5use async_trait::async_trait;
6
7pub mod netns;
8pub mod tcp;
9
10#[async_trait]
11pub trait NetworkIsolator: Send + Sync {
12    async fn setup(&self) -> anyhow::Result<()>;
13
14    async fn spawn_proxy(
15        &self,
16        target_ip: &str,
17        target_port: u16,
18    ) -> anyhow::Result<(ProxyListener, tokio::task::JoinHandle<()>)>;
19
20    async fn teardown(&self) -> anyhow::Result<()>;
21}
22
23pub struct ProxyListener {
24    pub local_addr: SocketAddr,
25    pub target_addr: SocketAddr,
26}
27
28/// Maps target host to local proxy address for egress isolation.
29static REGISTRY: LazyLock<RwLock<HashMap<String, SocketAddr>>> =
30    LazyLock::new(|| RwLock::new(HashMap::new()));
31
32pub fn bind_proxy(target: &str, local: SocketAddr) {
33    if let Ok(mut g) = REGISTRY.write() {
34        g.insert(target.to_string(), local);
35    }
36}
37
38pub fn unbind_proxy(target: &str) {
39    if let Ok(mut g) = REGISTRY.write() {
40        g.remove(target);
41    }
42}
43
44pub fn is_proxied(target: &str) -> bool {
45    REGISTRY
46        .read()
47        .map(|g| g.contains_key(target))
48        .unwrap_or(false)
49}
50
51/// Returns the proxy address for host or the direct host:port.
52pub fn resolve_dial(host: &str, port: u16) -> String {
53    if let Ok(g) = REGISTRY.read() {
54        if let Some(addr) = g.get(host) {
55            return addr.to_string();
56        }
57    }
58    format!("{host}:{port}")
59}