openssh/
port_forwarding.rs

1#[cfg(feature = "native-mux")]
2use super::native_mux_impl;
3
4#[cfg(feature = "process-mux")]
5use std::ffi::OsStr;
6
7use std::borrow::Cow;
8use std::fmt;
9use std::net::{self, IpAddr, SocketAddr};
10use std::path::{Path, PathBuf};
11
12/// Type of forwarding
13#[derive(Copy, Clone, Debug, Eq, PartialEq)]
14pub enum ForwardType {
15    /// Forward requests to a port on the local machine to remote machine.
16    Local,
17
18    /// Forward requests to a port on the remote machine to local machine.
19    Remote,
20}
21
22#[cfg(feature = "native-mux")]
23impl From<ForwardType> for native_mux_impl::ForwardType {
24    fn from(fwd_type: ForwardType) -> Self {
25        use native_mux_impl::ForwardType::*;
26
27        match fwd_type {
28            ForwardType::Local => Local,
29            ForwardType::Remote => Remote,
30        }
31    }
32}
33
34/// TCP/Unix socket
35#[derive(Clone, Debug, Eq, PartialEq, Hash)]
36pub enum Socket<'a> {
37    /// Unix socket.
38    #[cfg(unix)]
39    #[cfg_attr(docsrs, doc(cfg(unix)))]
40    UnixSocket {
41        /// Filesystem path
42        path: Cow<'a, Path>,
43    },
44
45    /// Tcp socket.
46    TcpSocket {
47        /// Hostname.
48        host: Cow<'a, str>,
49        /// Port.
50        port: u16,
51    },
52}
53
54impl From<SocketAddr> for Socket<'static> {
55    fn from(addr: SocketAddr) -> Self {
56        let host = match addr.ip() {
57            IpAddr::V4(v4) => v4.to_string(),
58            IpAddr::V6(v6) => format!("[{v6}]"),
59        };
60        Socket::TcpSocket {
61            host: host.into(),
62            port: addr.port(),
63        }
64    }
65}
66
67macro_rules! impl_from_addr {
68    ($ip:ty) => {
69        impl From<($ip, u16)> for Socket<'static> {
70            fn from((ip, port): ($ip, u16)) -> Self {
71                SocketAddr::new(ip.into(), port).into()
72            }
73        }
74    };
75}
76
77impl_from_addr!(net::IpAddr);
78impl_from_addr!(net::Ipv4Addr);
79impl_from_addr!(net::Ipv6Addr);
80
81impl<'a> From<Cow<'a, Path>> for Socket<'a> {
82    fn from(path: Cow<'a, Path>) -> Self {
83        Socket::UnixSocket { path }
84    }
85}
86
87impl<'a> From<&'a Path> for Socket<'a> {
88    fn from(path: &'a Path) -> Self {
89        Socket::UnixSocket {
90            path: Cow::Borrowed(path),
91        }
92    }
93}
94
95impl From<PathBuf> for Socket<'static> {
96    fn from(path: PathBuf) -> Self {
97        Socket::UnixSocket {
98            path: Cow::Owned(path),
99        }
100    }
101}
102
103impl From<Box<Path>> for Socket<'static> {
104    fn from(path: Box<Path>) -> Self {
105        Socket::UnixSocket {
106            path: Cow::Owned(path.into()),
107        }
108    }
109}
110
111impl Socket<'_> {
112    /// Create a new TcpSocket
113    pub fn new<'a, S>(host: S, port: u16) -> Socket<'a>
114    where
115        S: Into<Cow<'a, str>>,
116    {
117        Socket::TcpSocket {
118            host: host.into(),
119            port,
120        }
121    }
122
123    #[cfg(feature = "process-mux")]
124    pub(crate) fn as_os_str(&self) -> Cow<'_, OsStr> {
125        match self {
126            #[cfg(unix)]
127            Socket::UnixSocket { path } => Cow::Borrowed(path.as_os_str()),
128            Socket::TcpSocket { host, port } => Cow::Owned(format!("{host}:{port}").into()),
129        }
130    }
131}
132
133#[cfg(feature = "native-mux")]
134impl<'a> From<Socket<'a>> for native_mux_impl::Socket<'a> {
135    fn from(socket: Socket<'a>) -> Self {
136        use native_mux_impl::Socket::*;
137
138        match socket {
139            #[cfg(unix)]
140            Socket::UnixSocket { path } => UnixSocket { path },
141            Socket::TcpSocket { host, port } => TcpSocket {
142                host,
143                port: port as u32,
144            },
145        }
146    }
147}
148
149impl<'a> fmt::Display for Socket<'a> {
150    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151        match self {
152            #[cfg(unix)]
153            Socket::UnixSocket { path } => {
154                write!(f, "{}", path.display())
155            }
156            Socket::TcpSocket { host, port } => write!(f, "{host}:{port}"),
157        }
158    }
159}