1use std::collections::HashMap;
5use std::net::SocketAddr;
6use std::sync::Arc;
7use tokio::net::{TcpListener, TcpStream};
8use tokio::io::{AsyncReadExt, AsyncWriteExt};
9use tokio::sync::{mpsc, Mutex};
10use crate::{Result, QsshError};
11use crate::transport::{Transport, Message, ChannelMessage, ChannelType,
12 GlobalRequestMessage, GlobalRequestType};
13
14#[derive(Debug, Clone)]
16pub enum ForwardType {
17 Local {
20 bind_addr: SocketAddr,
21 remote_host: String,
22 remote_port: u16,
23 },
24 Remote {
27 remote_bind_addr: SocketAddr,
28 local_host: String,
29 local_port: u16,
30 },
31 Dynamic {
34 bind_addr: SocketAddr,
35 },
36}
37
38type ForwardMapping = HashMap<(String, u16), (String, u16)>;
40
41#[derive(Debug, Clone)]
44pub struct RemoteForwardRegistry {
45 mappings: Arc<Mutex<ForwardMapping>>,
46}
47
48impl Default for RemoteForwardRegistry {
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54impl RemoteForwardRegistry {
55 pub fn new() -> Self {
56 Self {
57 mappings: Arc::new(Mutex::new(HashMap::new())),
58 }
59 }
60
61 pub async fn insert(&self, bind_host: String, bind_port: u16, local_host: String, local_port: u16) {
63 let mut map = self.mappings.lock().await;
64 map.insert((bind_host, bind_port), (local_host, local_port));
65 }
66
67 pub async fn lookup(&self, connected_host: &str, connected_port: u16) -> Option<(String, u16)> {
69 let map = self.mappings.lock().await;
70 map.get(&(connected_host.to_string(), connected_port)).cloned()
71 }
72
73 pub async fn remove(&self, bind_host: &str, bind_port: u16) -> Option<(String, u16)> {
75 let mut map = self.mappings.lock().await;
76 map.remove(&(bind_host.to_string(), bind_port))
77 }
78}
79
80#[derive(Debug, Clone)]
84pub struct ForwardedChannelRouter {
85 senders: Arc<Mutex<HashMap<u32, mpsc::Sender<Vec<u8>>>>>,
86}
87
88impl Default for ForwardedChannelRouter {
89 fn default() -> Self {
90 Self::new()
91 }
92}
93
94impl ForwardedChannelRouter {
95 pub fn new() -> Self {
96 Self {
97 senders: Arc::new(Mutex::new(HashMap::new())),
98 }
99 }
100
101 pub async fn register(&self, channel_id: u32, sender: mpsc::Sender<Vec<u8>>) {
103 let mut map = self.senders.lock().await;
104 map.insert(channel_id, sender);
105 }
106
107 pub async fn route_data(&self, channel_id: u32, data: Vec<u8>) -> bool {
109 let map = self.senders.lock().await;
110 if let Some(sender) = map.get(&channel_id) {
111 sender.send(data).await.is_ok()
112 } else {
113 false
114 }
115 }
116
117 pub async fn has_channel(&self, channel_id: u32) -> bool {
119 let map = self.senders.lock().await;
120 map.contains_key(&channel_id)
121 }
122
123 pub async fn remove(&self, channel_id: u32) {
125 let mut map = self.senders.lock().await;
126 map.remove(&channel_id);
127 }
128}
129
130pub struct PortForwardManager {
132 transport: Arc<Transport>,
133 forwards: Vec<ForwardType>,
134 remote_registry: RemoteForwardRegistry,
135 channel_router: ForwardedChannelRouter,
136}
137
138impl PortForwardManager {
139 pub fn new(transport: Arc<Transport>) -> Self {
140 Self {
141 transport,
142 forwards: Vec::new(),
143 remote_registry: RemoteForwardRegistry::new(),
144 channel_router: ForwardedChannelRouter::new(),
145 }
146 }
147
148 pub fn remote_registry(&self) -> RemoteForwardRegistry {
150 self.remote_registry.clone()
151 }
152
153 pub fn channel_router(&self) -> ForwardedChannelRouter {
155 self.channel_router.clone()
156 }
157
158 pub fn parse_forward_spec(spec: &str, forward_type: &str) -> Result<ForwardType> {
160 let parts: Vec<&str> = spec.split(':').collect();
161
162 match forward_type {
163 "local" => {
164 if parts.len() != 3 {
165 return Err(QsshError::Config("Invalid local forward spec. Use: local_port:remote_host:remote_port".into()));
166 }
167
168 let local_port: u16 = parts[0].parse()
169 .map_err(|_| QsshError::Config("Invalid local port".into()))?;
170 let remote_host = parts[1].to_string();
171 let remote_port: u16 = parts[2].parse()
172 .map_err(|_| QsshError::Config("Invalid remote port".into()))?;
173
174 Ok(ForwardType::Local {
175 bind_addr: ([127, 0, 0, 1], local_port).into(),
176 remote_host,
177 remote_port,
178 })
179 }
180 "remote" => {
181 if parts.len() != 3 {
182 return Err(QsshError::Config("Invalid remote forward spec. Use: remote_port:local_host:local_port".into()));
183 }
184
185 let remote_port: u16 = parts[0].parse()
186 .map_err(|_| QsshError::Config("Invalid remote port".into()))?;
187 let local_host = parts[1].to_string();
188 let local_port: u16 = parts[2].parse()
189 .map_err(|_| QsshError::Config("Invalid local port".into()))?;
190
191 Ok(ForwardType::Remote {
192 remote_bind_addr: ([0, 0, 0, 0], remote_port).into(),
193 local_host,
194 local_port,
195 })
196 }
197 "dynamic" => {
198 let port: u16 = spec.parse()
199 .map_err(|_| QsshError::Config("Invalid SOCKS port".into()))?;
200
201 Ok(ForwardType::Dynamic {
202 bind_addr: ([127, 0, 0, 1], port).into(),
203 })
204 }
205 _ => Err(QsshError::Config("Unknown forward type".into()))
206 }
207 }
208
209 pub async fn start_local_forward(
211 &self,
212 bind_addr: SocketAddr,
213 remote_host: String,
214 remote_port: u16,
215 ) -> Result<()> {
216 let listener = TcpListener::bind(bind_addr).await?;
217 let transport = self.transport.clone();
218 let channel_router = self.channel_router.clone();
219
220 log::info!("Local port forwarding: {} -> {}:{}", bind_addr, remote_host, remote_port);
221
222 tokio::spawn(async move {
223 loop {
224 match listener.accept().await {
225 Ok((stream, peer_addr)) => {
226 log::debug!("Accepted connection from {} for forwarding", peer_addr);
227
228 let transport = transport.clone();
229 let remote_host = remote_host.clone();
230 let channel_router = channel_router.clone();
231
232 tokio::spawn(async move {
233 if let Err(e) = handle_local_forward(
234 stream,
235 transport,
236 remote_host,
237 remote_port,
238 channel_router,
239 ).await {
240 log::error!("Forward error: {}", e);
241 }
242 });
243 }
244 Err(e) => {
245 log::error!("Accept error: {}", e);
246 }
247 }
248 }
249 });
250
251 Ok(())
252 }
253
254 pub async fn start_all(&mut self) -> Result<()> {
256 for forward in self.forwards.clone() {
257 match forward {
258 ForwardType::Local { bind_addr, remote_host, remote_port } => {
259 self.start_local_forward(bind_addr, remote_host, remote_port).await?;
260 }
261 ForwardType::Remote { remote_bind_addr, local_host, local_port } => {
262 self.start_remote_forward(remote_bind_addr, local_host, local_port).await?;
263 }
264 ForwardType::Dynamic { bind_addr } => {
265 self.start_socks_proxy(bind_addr).await?;
266 }
267 }
268 }
269 Ok(())
270 }
271
272 pub async fn start_remote_forward(
279 &self,
280 remote_bind_addr: SocketAddr,
281 local_host: String,
282 local_port: u16,
283 ) -> Result<()> {
284 let bind_host = remote_bind_addr.ip().to_string();
285 let bind_port = remote_bind_addr.port();
286
287 log::info!("Requesting remote forward: {}:{} (server) -> {}:{} (local)",
288 bind_host, bind_port, local_host, local_port);
289
290 let request = Message::GlobalRequest(GlobalRequestMessage {
292 request_type: GlobalRequestType::TcpipForward {
293 bind_host: bind_host.clone(),
294 bind_port,
295 },
296 want_reply: true,
297 });
298 self.transport.send_message(&request).await?;
299
300 let reply = self.transport.receive_message::<Message>().await?;
302 match reply {
303 Message::GlobalRequestSuccess(success) => {
304 let actual_port = success.bound_port;
305 log::info!("Remote forward established: server listening on {}:{}",
306 bind_host, actual_port);
307
308 self.remote_registry.insert(
310 bind_host, actual_port, local_host, local_port,
311 ).await;
312
313 Ok(())
314 }
315 Message::GlobalRequestFailure => {
316 Err(QsshError::Protocol(format!(
317 "Server refused remote forward on {}:{}", bind_host, bind_port
318 )))
319 }
320 other => {
321 Err(QsshError::Protocol(format!(
322 "Unexpected reply to TcpipForward request: {:?}", other
323 )))
324 }
325 }
326 }
327
328 pub async fn start_socks_proxy(&self, bind_addr: SocketAddr) -> Result<()> {
330 let listener = TcpListener::bind(bind_addr).await?;
331 let transport = self.transport.clone();
332 let channel_router = self.channel_router.clone();
333
334 log::info!("SOCKS proxy listening on {}", bind_addr);
335
336 tokio::spawn(async move {
337 loop {
338 match listener.accept().await {
339 Ok((stream, peer_addr)) => {
340 log::debug!("SOCKS connection from {}", peer_addr);
341
342 let transport = transport.clone();
343 let channel_router = channel_router.clone();
344 tokio::spawn(async move {
345 if let Err(e) = handle_socks_connection(stream, transport, channel_router).await {
346 log::error!("SOCKS error: {}", e);
347 }
348 });
349 }
350 Err(e) => {
351 log::error!("SOCKS accept error: {}", e);
352 }
353 }
354 }
355 });
356
357 Ok(())
358 }
359
360 pub fn add_forward(&mut self, forward: ForwardType) {
362 self.forwards.push(forward);
363 }
364}
365
366async fn handle_local_forward(
368 local_stream: TcpStream,
369 transport: Arc<Transport>,
370 remote_host: String,
371 remote_port: u16,
372 channel_router: ForwardedChannelRouter,
373) -> Result<()> {
374 let channel_id = rand::random::<u32>() % 65536;
375
376 let (data_tx, mut data_rx) = mpsc::channel::<Vec<u8>>(256);
378 channel_router.register(channel_id, data_tx).await;
379
380 let open_msg = Message::Channel(ChannelMessage::Open {
382 channel_id,
383 channel_type: ChannelType::DirectTcpip {
384 host: remote_host.clone(),
385 port: remote_port,
386 originator_host: "127.0.0.1".to_string(),
387 originator_port: local_stream.local_addr()
388 .map(|a| a.port()).unwrap_or(0),
389 },
390 window_size: 1024 * 1024,
391 max_packet_size: 32768,
392 });
393 transport.send_message(&open_msg).await?;
394
395 log::debug!("Local forward channel {} waiting for Accept", channel_id);
397 match tokio::time::timeout(std::time::Duration::from_secs(10), data_rx.recv()).await {
398 Ok(Some(data)) if data.is_empty() => {
399 log::debug!("Local forward channel {} accepted", channel_id);
400 }
401 Ok(Some(_data)) => {
402 log::debug!("Local forward channel {} got data before explicit accept", channel_id);
404 }
407 Ok(None) => {
408 log::error!("Local forward channel {} router closed before accept", channel_id);
409 channel_router.remove(channel_id).await;
410 return Err(QsshError::Protocol("Channel closed before accept".into()));
411 }
412 Err(_) => {
413 log::error!("Local forward channel {} timed out waiting for accept", channel_id);
414 channel_router.remove(channel_id).await;
415 return Err(QsshError::Protocol("Timeout waiting for channel accept".into()));
416 }
417 }
418
419 let (mut read_half, mut write_half) = local_stream.into_split();
421
422 let transport_out = transport.clone();
424 let local_to_remote = tokio::spawn(async move {
425 let mut buffer = vec![0u8; 8192];
426 loop {
427 match read_half.read(&mut buffer).await {
428 Ok(0) => break,
429 Ok(n) => {
430 let msg = Message::Channel(ChannelMessage::Data {
431 channel_id,
432 data: buffer[..n].to_vec(),
433 });
434 if transport_out.send_message(&msg).await.is_err() {
435 break;
436 }
437 }
438 Err(_) => break,
439 }
440 }
441 });
442
443 let remote_to_local = tokio::spawn(async move {
445 while let Some(data) = data_rx.recv().await {
446 if data.is_empty() { continue; } if write_half.write_all(&data).await.is_err() {
448 break;
449 }
450 }
451 });
452
453 tokio::select! {
455 _ = local_to_remote => {}
456 _ = remote_to_local => {}
457 }
458
459 channel_router.remove(channel_id).await;
461 let eof_msg = Message::Channel(ChannelMessage::Eof { channel_id });
462 let _ = transport.send_message(&eof_msg).await;
463
464 Ok(())
465}
466
467pub async fn handle_forwarded_channel(
474 channel_id: u32,
475 connected_host: String,
476 connected_port: u16,
477 transport: Arc<Transport>,
478 registry: RemoteForwardRegistry,
479 router: ForwardedChannelRouter,
480) -> Result<()> {
481 let (local_host, local_port) = registry
483 .lookup(&connected_host, connected_port)
484 .await
485 .ok_or_else(|| QsshError::Protocol(format!(
486 "No remote forward registered for {}:{}", connected_host, connected_port
487 )))?;
488
489 log::info!("Forwarded channel {} for {}:{} -> connecting to {}:{}",
490 channel_id, connected_host, connected_port, local_host, local_port);
491
492 let local_addr = format!("{}:{}", local_host, local_port);
494 let local_stream = TcpStream::connect(&local_addr).await
495 .map_err(|e| QsshError::Connection(format!(
496 "Failed to connect to local target {}: {}", local_addr, e
497 )))?;
498
499 let accept = Message::Channel(ChannelMessage::Accept {
501 channel_id,
502 sender_channel: channel_id,
503 window_size: 1024 * 1024,
504 max_packet_size: 32768,
505 });
506 transport.send_message(&accept).await?;
507
508 let (mut read_half, mut write_half) = local_stream.into_split();
510
511 let (tx, mut rx) = mpsc::channel::<Vec<u8>>(256);
513 router.register(channel_id, tx).await;
514
515 let transport_send = transport.clone();
517 let local_to_channel = tokio::spawn(async move {
518 let mut buffer = vec![0u8; 8192];
519 loop {
520 match read_half.read(&mut buffer).await {
521 Ok(0) => break,
522 Ok(n) => {
523 let data_msg = Message::Channel(ChannelMessage::Data {
524 channel_id,
525 data: buffer[..n].to_vec(),
526 });
527 if transport_send.send_message(&data_msg).await.is_err() {
528 break;
529 }
530 }
531 Err(_) => break,
532 }
533 }
534 });
535
536 let channel_to_local = tokio::spawn(async move {
538 while let Some(data) = rx.recv().await {
539 if write_half.write_all(&data).await.is_err() {
540 break;
541 }
542 }
543 });
544
545 tokio::select! {
547 _ = local_to_channel => {}
548 _ = channel_to_local => {}
549 }
550
551 router.remove(channel_id).await;
553 let eof_msg = Message::Channel(ChannelMessage::Eof { channel_id });
554 let _ = transport.send_message(&eof_msg).await;
555
556 Ok(())
557}
558
559async fn handle_socks_connection(
561 mut stream: TcpStream,
562 transport: Arc<Transport>,
563 channel_router: ForwardedChannelRouter,
564) -> Result<()> {
565 let mut buffer = vec![0u8; 1024];
567
568 let n = stream.read(&mut buffer).await?;
570 if n < 3 || buffer[0] != 0x05 {
571 return Err(QsshError::Protocol("Invalid SOCKS5 handshake".into()));
572 }
573
574 stream.write_all(&[0x05, 0x00]).await?;
576
577 let n = stream.read(&mut buffer).await?;
579 if n < 10 || buffer[0] != 0x05 || buffer[1] != 0x01 {
580 return Err(QsshError::Protocol("Invalid SOCKS5 connect request".into()));
581 }
582
583 let addr_type = buffer[3];
585 let (dest_host, dest_port) = match addr_type {
586 0x01 => {
587 let addr = format!("{}.{}.{}.{}", buffer[4], buffer[5], buffer[6], buffer[7]);
589 let port = u16::from_be_bytes([buffer[8], buffer[9]]);
590 (addr, port)
591 }
592 0x03 => {
593 let len = buffer[4] as usize;
595 let domain = String::from_utf8_lossy(&buffer[5..5+len]).to_string();
596 let port = u16::from_be_bytes([buffer[5+len], buffer[6+len]]);
597 (domain, port)
598 }
599 _ => return Err(QsshError::Protocol("Unsupported SOCKS5 address type".into())),
600 };
601
602 stream.write_all(&[0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0]).await?;
604
605 handle_local_forward(stream, transport, dest_host, dest_port, channel_router).await
607}
608
609#[cfg(test)]
610mod tests {
611 use super::*;
612
613 #[test]
614 fn test_parse_local_forward() {
615 let forward = PortForwardManager::parse_forward_spec("8080:localhost:80", "local").unwrap();
616
617 match forward {
618 ForwardType::Local { bind_addr, remote_host, remote_port } => {
619 assert_eq!(bind_addr.port(), 8080);
620 assert_eq!(remote_host, "localhost");
621 assert_eq!(remote_port, 80);
622 }
623 _ => panic!("Wrong forward type"),
624 }
625 }
626
627 #[test]
628 fn test_parse_remote_forward() {
629 let forward = PortForwardManager::parse_forward_spec("9090:localhost:8080", "remote").unwrap();
630
631 match forward {
632 ForwardType::Remote { remote_bind_addr, local_host, local_port } => {
633 assert_eq!(remote_bind_addr.port(), 9090);
634 assert_eq!(remote_bind_addr.ip().to_string(), "0.0.0.0");
635 assert_eq!(local_host, "localhost");
636 assert_eq!(local_port, 8080);
637 }
638 _ => panic!("Wrong forward type"),
639 }
640 }
641
642 #[test]
643 fn test_parse_remote_forward_different_ports() {
644 let forward = PortForwardManager::parse_forward_spec("443:127.0.0.1:3000", "remote").unwrap();
645
646 match forward {
647 ForwardType::Remote { remote_bind_addr, local_host, local_port } => {
648 assert_eq!(remote_bind_addr.port(), 443);
649 assert_eq!(local_host, "127.0.0.1");
650 assert_eq!(local_port, 3000);
651 }
652 _ => panic!("Wrong forward type"),
653 }
654 }
655
656 #[test]
657 fn test_parse_remote_forward_invalid() {
658 assert!(PortForwardManager::parse_forward_spec("9090:localhost", "remote").is_err());
660 assert!(PortForwardManager::parse_forward_spec("abc:localhost:8080", "remote").is_err());
662 }
663
664 #[test]
665 fn test_parse_dynamic_forward() {
666 let forward = PortForwardManager::parse_forward_spec("1080", "dynamic").unwrap();
667
668 match forward {
669 ForwardType::Dynamic { bind_addr } => {
670 assert_eq!(bind_addr.port(), 1080);
671 }
672 _ => panic!("Wrong forward type"),
673 }
674 }
675
676 #[tokio::test]
677 async fn test_remote_forward_registry_insert_lookup() {
678 let registry = RemoteForwardRegistry::new();
679
680 registry.insert("0.0.0.0".into(), 9090, "localhost".into(), 8080).await;
682
683 let result = registry.lookup("0.0.0.0", 9090).await;
685 assert_eq!(result, Some(("localhost".to_string(), 8080)));
686
687 let result = registry.lookup("0.0.0.0", 9999).await;
689 assert_eq!(result, None);
690 }
691
692 #[tokio::test]
693 async fn test_remote_forward_registry_remove() {
694 let registry = RemoteForwardRegistry::new();
695
696 registry.insert("0.0.0.0".into(), 9090, "localhost".into(), 8080).await;
697
698 let removed = registry.remove("0.0.0.0", 9090).await;
700 assert_eq!(removed, Some(("localhost".to_string(), 8080)));
701
702 assert_eq!(registry.lookup("0.0.0.0", 9090).await, None);
704
705 assert_eq!(registry.remove("0.0.0.0", 9090).await, None);
707 }
708
709 #[tokio::test]
710 async fn test_remote_forward_registry_multiple_entries() {
711 let registry = RemoteForwardRegistry::new();
712
713 registry.insert("0.0.0.0".into(), 9090, "localhost".into(), 8080).await;
714 registry.insert("0.0.0.0".into(), 9091, "localhost".into(), 3000).await;
715 registry.insert("127.0.0.1".into(), 443, "10.0.0.1".into(), 443).await;
716
717 assert_eq!(registry.lookup("0.0.0.0", 9090).await, Some(("localhost".to_string(), 8080)));
718 assert_eq!(registry.lookup("0.0.0.0", 9091).await, Some(("localhost".to_string(), 3000)));
719 assert_eq!(registry.lookup("127.0.0.1", 443).await, Some(("10.0.0.1".to_string(), 443)));
720 }
721
722 #[tokio::test]
723 async fn test_forwarded_channel_router() {
724 let router = ForwardedChannelRouter::new();
725
726 assert!(!router.has_channel(1).await);
728 assert!(!router.route_data(1, vec![1, 2, 3]).await);
729
730 let (tx, mut rx) = tokio::sync::mpsc::channel(16);
732 router.register(1, tx).await;
733
734 assert!(router.has_channel(1).await);
735
736 assert!(router.route_data(1, vec![42, 43]).await);
738 let received = rx.recv().await.unwrap();
739 assert_eq!(received, vec![42, 43]);
740
741 router.remove(1).await;
743 assert!(!router.has_channel(1).await);
744 }
745
746 #[tokio::test]
747 async fn test_forwarded_channel_router_multiple_channels() {
748 let router = ForwardedChannelRouter::new();
749
750 let (tx1, mut rx1) = tokio::sync::mpsc::channel(16);
751 let (tx2, mut rx2) = tokio::sync::mpsc::channel(16);
752
753 router.register(100, tx1).await;
754 router.register(200, tx2).await;
755
756 assert!(router.route_data(100, vec![1]).await);
758 assert_eq!(rx1.recv().await.unwrap(), vec![1]);
759
760 assert!(router.route_data(200, vec![2]).await);
762 assert_eq!(rx2.recv().await.unwrap(), vec![2]);
763
764 assert!(!router.route_data(300, vec![3]).await);
766 }
767
768 #[tokio::test]
769 async fn test_router_accept_signal() {
770 let router = ForwardedChannelRouter::new();
772 let (tx, mut rx) = tokio::sync::mpsc::channel(16);
773 router.register(42, tx).await;
774
775 assert!(router.route_data(42, Vec::new()).await);
777 let signal = rx.recv().await.unwrap();
778 assert!(signal.is_empty(), "Accept signal should be empty vec");
779
780 assert!(router.route_data(42, vec![0xDE, 0xAD]).await);
782 let data = rx.recv().await.unwrap();
783 assert_eq!(data, vec![0xDE, 0xAD]);
784 }
785
786 #[tokio::test]
787 async fn test_router_remove_drops_sender() {
788 let router = ForwardedChannelRouter::new();
789 let (tx, mut rx) = tokio::sync::mpsc::channel(16);
790 router.register(99, tx).await;
791
792 router.remove(99).await;
793
794 assert!(!router.route_data(99, vec![1]).await);
796 assert!(rx.recv().await.is_none());
798 }
799}