diff --git a/boltconn/src/app.rs b/boltconn/src/app.rs index 4883e5e..d95ae77 100644 --- a/boltconn/src/app.rs +++ b/boltconn/src/app.rs @@ -128,7 +128,7 @@ impl App { &outbound_iface, ))); if will_enable_tun { - // tokio::time::sleep(Duration::from_secs(10)).await; + // tokio::time::sleep(Duration::from_secs(5)).await; tun_configure .lock() .unwrap() @@ -224,7 +224,8 @@ impl App { tun_udp_rx, udp_tun_tx, dns_hijack.clone(), - ); + ) + .await?; start_inbound_services(&config.inbound, dispatcher.clone()); // start controller service @@ -466,7 +467,7 @@ fn start_instrument_services(bus: Arc, config: Option<&RawInstrument } #[allow(clippy::too_many_arguments)] -fn start_tun_services( +async fn start_tun_services( nat_addr: SocketAddr, manager: Arc, dispatcher: Arc, @@ -475,7 +476,7 @@ fn start_tun_services( tun_udp_rx: flume::Receiver, udp_tun_tx: flume::Sender, hijack_ctrl: Arc, -) { +) -> io::Result<()> { let tun_inbound_tcp = Arc::new(TunTcpInbound::new( nat_addr, manager.clone(), @@ -491,9 +492,47 @@ fn start_tun_services( hijack_ctrl, ); manager.flush_with_interval(Duration::from_secs(30)); - tokio::spawn(async move { tun_inbound_tcp.run().await }); + #[cfg(unix)] + let tcp_listener = tokio::net::TcpListener::bind(tun_inbound_tcp.nat_addr()) + .await + .or_else(|e| { + tracing::error!( + "Failed to start NAT at {}: {}", + tun_inbound_tcp.nat_addr(), + e + ); + Err(e) + })?; + #[cfg(windows)] + let tcp_listener = { + let start_time = Instant::now(); + tracing::info!( + "Starting NAT at {}, requires a few seconds...", + tun_inbound_tcp.nat_addr() + ); + loop { + match tokio::net::TcpListener::bind(tun_inbound_tcp.nat_addr()).await { + Ok(l) => break l, + Err(e) => { + if e.raw_os_error() == Some(10049) && start_time.elapsed().as_secs() < 15 { + tokio::time::sleep(Duration::from_secs(1)).await; + continue; + } else { + tracing::error!( + "Failed to start NAT at {}: {}", + tun_inbound_tcp.nat_addr(), + e + ); + return Err(e); + } + } + } + } + }; + tokio::spawn(async move { tun_inbound_tcp.run(tcp_listener).await }); tokio::spawn(async move { tun_inbound_udp.run().await }); tokio::spawn(async move { tun.run(nat_addr).await }); + Ok(()) } fn start_inbound_services(config: &RawInboundConfig, dispatcher: Arc) { diff --git a/boltconn/src/platform/sys/windows_sys.rs b/boltconn/src/platform/sys/windows_sys.rs index be0d7f0..0671dbd 100644 --- a/boltconn/src/platform/sys/windows_sys.rs +++ b/boltconn/src/platform/sys/windows_sys.rs @@ -274,7 +274,7 @@ fn from_sockaddr(sockaddr: *const SOCKADDR) -> io::Result { } } -fn get_iface_index(iface_name: &str) -> io::Result { +pub(crate) fn get_iface_index(iface_name: &str) -> io::Result { use network_interface::NetworkInterfaceConfig; network_interface::NetworkInterface::show() .map(|interfaces| { diff --git a/boltconn/src/proxy/tun_inbound.rs b/boltconn/src/proxy/tun_inbound.rs index 16a3531..c5f0504 100644 --- a/boltconn/src/proxy/tun_inbound.rs +++ b/boltconn/src/proxy/tun_inbound.rs @@ -31,8 +31,11 @@ impl TunTcpInbound { } } - pub async fn run(&self) -> Result<()> { - let tcp_listener = TcpListener::bind(self.nat_addr).await?; + pub fn nat_addr(&self) -> SocketAddr { + self.nat_addr + } + + pub async fn run(&self, tcp_listener: TcpListener) -> Result<()> { tracing::event!( tracing::Level::INFO, "[NAT] Listen TCP at {}, running...",