1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! Port-forwarding building blocks used by `puressh::server` (and `client`
//! in a follow-up commit).
//!
//! Two channel types live here:
//!
//! - **`direct-tcpip`** (RFC 4254 §7.2): the client asks the server to
//! connect to a TCP destination and proxy bytes over the SSH channel.
//! This is what `ssh -L` opens. The server-side glue is
//! [`direct::DefaultDirectTcpipHandler`] plus the
//! [`crate::server::DirectTcpipHandler`] trait.
//! - **`tcpip-forward`** + **`forwarded-tcpip`** (RFC 4254 §7.1, §7.2):
//! the inbound bookend of `ssh -R`. A client global-request asks the
//! server to bind a TCP listener; once bound, the server is meant to
//! open a `forwarded-tcpip` channel back to the client for each
//! accepted connection on that port. The bind/unbind half lives in
//! [`reverse::DefaultTcpipForwardHandler`] plus the
//! [`crate::server::TcpipForwardHandler`] trait; the back-channel
//! opens land in a follow-up commit alongside the matching
//! client-side multi-channel dispatcher.
//! - **`auth-agent-req@openssh.com`** + **`auth-agent@openssh.com`**
//! (OpenSSH's ssh-agent forwarding, `ssh -A`): the client asks the
//! server to expose a Unix-domain socket inside the session env as
//! `SSH_AUTH_SOCK`. Each connection on that socket triggers an
//! `auth-agent@openssh.com` channel-open back toward the client, which
//! the client proxies to its own local agent. Server-side glue lives
//! in [`agent::DefaultAgentForwardHandler`] plus the
//! [`crate::server::AgentForwardHandler`] trait.
//! - **`direct-streamlocal@openssh.com`** (OpenSSH extension): the
//! Unix-socket analog of `direct-tcpip`. The client asks the server to
//! connect to a Unix-domain socket and proxy bytes over the SSH channel
//! (what `ssh -L local:/remote.sock` opens). Server-side glue lives in
//! [`direct_streamlocal::DefaultDirectStreamlocalHandler`] plus the
//! [`crate::server::DirectStreamlocalHandler`] trait.
//! - **`streamlocal-forward@openssh.com`** +
//! **`forwarded-streamlocal@openssh.com`** (OpenSSH extension): the
//! Unix-socket analog of `tcpip-forward` / `forwarded-tcpip`, the wire side
//! of `ssh -R /remote.sock:...`. A client global-request asks the server to
//! bind a Unix-domain listener; each accepted connection triggers a
//! `forwarded-streamlocal@openssh.com` channel-open back toward the client.
//! Server-side glue lives in
//! [`streamlocal::DefaultStreamlocalForwardHandler`] plus the
//! [`crate::server::StreamlocalForwardHandler`] trait; the client-side
//! splice helper is [`streamlocal::splice_to_unix_socket_callback`].
//! - **`x11-req`** + **`x11`** (RFC 4254 §6.3, `ssh -X` / `ssh -Y`):
//! the client asks the server to set up an X display proxy. The
//! server binds `127.0.0.1:6000+N` for some free display number `N`
//! and injects `DISPLAY=localhost:N.<screen>` into the session env.
//! Each accepted TCP connection on that port triggers an `x11`
//! channel-open back toward the client, which the client proxies to
//! its own local `$DISPLAY`. Server-side glue lives in
//! [`x11::DefaultX11ForwardHandler`] plus the
//! [`crate::server::X11ForwardHandler`] trait.
// Agent and X11 forwarding depend on Unix-domain sockets and Unix-only
// permission bits; gate them out on Windows. The other two modules
// (direct-tcpip, reverse port-forward) are TCP-only and stay portable.
//
// `direct` and `reverse` are entirely server-side handlers (no client-
// callable helpers), so they're additionally gated on `feature = "server"`.
// `agent` and `x11` straddle the line: their `Default*Handler` types are
// server-only, but they also expose `splice_to_local_*_callback` helpers the
// client binary uses, so each file uses per-item `#[cfg(feature = "server")]`
// internally rather than a single module-level gate.
// direct-streamlocal is a server-side handler over Unix-domain sockets.
// streamlocal reverse-forward straddles the line like `agent`/`x11`: the
// `Default*Handler` is server-only, but `splice_to_unix_socket_callback` is a
// client helper, so it uses per-item `#[cfg(feature = "...")]` internally.
// SOCKS dynamic-forward (`ssh -D`) is purely client-side and TCP-only, so it
// is gated on the `client` feature and stays portable across platforms.
/// A local socket a forwarded channel is spliced with.
// which splices are built depends on the features
pub
/// The channel → socket half of a splice: copy what the channel receives
/// (`Some` data; `None` is its EOF; the sender is dropped on its close) to
/// `out`. The channel's EOF half-closes the socket, as OpenSSH's, so the
/// local side can still answer (the other direction ends when it closes);
/// the channel's close, or a failed write, shuts the socket down both ways,
/// which also ends the other direction's read.
// which splices are built depends on the features
pub