Skip to content

Commit 7c53b76

Browse files
WIP
1 parent e003be2 commit 7c53b76

File tree

5 files changed

+88
-31
lines changed

5 files changed

+88
-31
lines changed

Cargo.lock

Lines changed: 0 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

devolutions-gateway/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ job-queue = { path = "../crates/job-queue" }
2828
job-queue-libsql = { path = "../crates/job-queue-libsql" }
2929
ironrdp-pdu = { version = "0.5", features = ["std"] }
3030
ironrdp-core = { version = "0.1", features = ["std"] }
31-
ironrdp-rdcleanpath = "0.1"
3231
ironrdp-tokio = { version = "0.4", default-features = false }
3332
ironrdp-connector = { version = "0.5" }
3433
ironrdp-acceptor = { version = "0.5" }
34+
ironrdp-rdcleanpath = { path = "C:\\dev\\IronRDP\\crates\\ironrdp-rdcleanpath" }
3535
ceviche = "0.6.1"
3636
picky-krb = "0.9"
3737
network-scanner = { version = "0.0.0", path = "../crates/network-scanner" }

devolutions-gateway/src/generic_client.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ where
7777
if conf.debug.dump_tokens {
7878
debug!(token, "**DEBUG OPTION**");
7979
}
80+
info!(pdu = ?pdu, "Received preconnection blob");
8081

8182
let source_ip = client_addr.ip();
8283
let claims = extract_association_claims(token, source_ip, &conf, &token_cache, &jrl, &active_recordings)?;

devolutions-gateway/src/rd_clean_path.rs

Lines changed: 82 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ struct CleanPathResult {
157157
destination: TargetAddr,
158158
server_addr: SocketAddr,
159159
server_stream: tokio_rustls::client::TlsStream<tokio::net::TcpStream>,
160-
x224_rsp: Vec<u8>,
160+
x224_rsp: Option<Vec<u8>>,
161161
}
162162

163163
async fn process_cleanpath(
@@ -212,45 +212,99 @@ async fn process_cleanpath(
212212
debug!(%selected_target, "Connected to destination server");
213213
span.record("target", selected_target.to_string());
214214

215-
// Send preconnection blob if applicable
216-
if let Some(pcb) = cleanpath_pdu.preconnection_blob {
217-
server_stream.write_all(pcb.as_bytes()).await?;
218-
}
215+
// Preconnection Blob (PCB) is currently only used for Hyper-V VMs.
216+
//
217+
// Connection sequence with Hyper-V VMs (PCB enabled):
218+
// ┌─────────────────────┐ ┌─────────────────────────────────────────────────────────────┐
219+
// │ handled by │ │ handled by IronRDP client │
220+
// │ Gateway │ │ │
221+
// └─────────────────────┘ └─────────────────────────────────────────────────────────────┘
222+
// │PCB → TLS handshake │ → │CredSSP → X224 connection request → X224 connection response │
223+
// └─────────────────────┘ └─────────────────────────────────────────────────────────────┘
224+
//
225+
// Connection sequence without Hyper-V VMs (PCB disabled):
226+
// ┌─────────────────────────────────────────────────────────────┐ ┌──────────────────────┐
227+
// │ handled by Gateway │ │ handled by IronRDP │
228+
// │ │ │ client │
229+
// └─────────────────────────────────────────────────────────────┘ └──────────────────────┘
230+
// │X224 connection request → X224 connection response → TLS hs │ → │CredSSP → ... │
231+
// └─────────────────────────────────────────────────────────────┘ └──────────────────────┘
232+
//
233+
// Summary:
234+
// - With PCB: Gateway handles (1) sending PCB, (2) TLS handshake, then leaves CredSSP
235+
// and X224 connection request/response to IronRDP client
236+
// - Without PCB: Gateway handles (1) X224 connection request, (2) X224 connection response,
237+
// then leaves TLS handshake and CredSSP to IronRDP client
238+
let (server_stream, x224_rsp) = if let Some(pcb_string) = cleanpath_pdu.preconnection_blob {
239+
let pcb = ironrdp_pdu::pcb::PreconnectionBlob {
240+
version: ironrdp_pdu::pcb::PcbVersion::V2,
241+
id: 0,
242+
v2_payload: Some(pcb_string),
243+
};
244+
245+
let encoded = ironrdp_core::encode_vec(&pcb)
246+
.context("failed to encode preconnection blob")
247+
.map_err(CleanPathError::BadRequest)?;
248+
249+
server_stream.write_all(&encoded).await?;
250+
251+
let server_stream = crate::tls::connect(selected_target.host(), server_stream)
252+
.await
253+
.map_err(|source| CleanPathError::TlsHandshake {
254+
source,
255+
target_server: selected_target.to_owned(),
256+
})?;
219257

220-
// Send X224 connection request
221-
let x224_req = cleanpath_pdu
222-
.x224_connection_pdu
223-
.context("request is missing X224 connection PDU")
224-
.map_err(CleanPathError::BadRequest)?;
225-
server_stream.write_all(x224_req.as_bytes()).await?;
258+
(server_stream, None)
259+
} else {
260+
debug!("Preconnection blob sent");
226261

227-
// Receive server X224 connection response
262+
// Send X224 connection request
263+
let x224_req = cleanpath_pdu
264+
.x224_connection_pdu
265+
.context("request is missing X224 connection PDU")
266+
.map_err(CleanPathError::BadRequest)?;
228267

229-
trace!("Receiving X224 response");
268+
server_stream.write_all(x224_req.as_bytes()).await?;
230269

231-
let x224_rsp = read_x224_response(&mut server_stream)
232-
.await
233-
.with_context(|| format!("read X224 response from {selected_target}"))
234-
.map_err(CleanPathError::BadRequest)?;
270+
let server_stream = crate::tls::connect(selected_target.host().to_owned(), server_stream)
271+
.await
272+
.map_err(|source| CleanPathError::TlsHandshake {
273+
source,
274+
target_server: selected_target.to_owned(),
275+
})?;
276+
debug!("X224 connection request sent");
235277

236-
trace!("Establishing TLS connection with server");
278+
// Receive server X224 connection response
237279

238-
// Establish TLS connection with server
280+
trace!("Receiving X224 response");
239281

240-
let server_stream = crate::tls::connect(selected_target.host().to_owned(), server_stream)
241-
.await
242-
.map_err(|source| CleanPathError::TlsHandshake {
243-
source,
244-
target_server: selected_target.to_owned(),
245-
})?;
282+
let x224_rsp = read_x224_response(&mut server_stream)
283+
.await
284+
.with_context(|| format!("read X224 response from {selected_target}"))
285+
.map_err(CleanPathError::BadRequest)?;
286+
287+
trace!("Establishing TLS connection with server");
288+
289+
// Establish TLS connection with server
290+
291+
let server_stream = crate::tls::connect(selected_target.host(), server_stream)
292+
.await
293+
.map_err(|source| CleanPathError::TlsHandshake {
294+
source,
295+
target_server: selected_target.to_owned(),
296+
})?;
297+
298+
(server_stream, Some(x224_rsp))
299+
};
246300

247-
Ok(CleanPathResult {
301+
return Ok(CleanPathResult {
248302
destination: selected_target.to_owned(),
249303
claims,
250304
server_addr,
251305
server_stream,
252306
x224_rsp,
253-
})
307+
});
254308
}
255309

256310
#[allow(clippy::too_many_arguments)]
@@ -273,7 +327,7 @@ pub async fn handle(
273327
.await
274328
.context("couldn’t read clean cleanpath PDU")?;
275329

276-
trace!("Processing RDCleanPath");
330+
trace!(RDCleanPath = ?cleanpath_pdu,"Processing RDCleanPath");
277331

278332
let CleanPathResult {
279333
claims,

devolutions-gateway/src/rdp_pcb.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ fn decode_pcb(buf: &[u8]) -> Result<Option<(PreconnectionBlob, usize)>, io::Erro
5151
Ok(pcb) => {
5252
let pdu_size = ironrdp_core::size(&pcb);
5353
let read_len = cursor.pos();
54+
info!(
55+
pdu_size,
56+
read_len, "read preconnection blob (size: {}, read: {})", pdu_size, read_len
57+
);
5458

5559
// NOTE: sanity check (reporting the wrong number will corrupt the communication)
5660
if read_len != pdu_size {

0 commit comments

Comments
 (0)