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
// RDP Support - Send RDP preamble before TLS handshake
use crate::{Result, tls_bail};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;
/// RDP preamble for TLS negotiation
/// This is sent before the TLS handshake to initiate RDP protocol
pub struct RdpPreamble;
impl RdpPreamble {
/// Send RDP preamble to initialize RDP protocol before TLS
pub async fn send(stream: &mut TcpStream) -> Result<()> {
// RDP Connection Request (X.224)
// TPKT Header + CR_TPDU (Connection Request)
let connection_request = vec![
0x03, 0x00, // TPKT Version 3
0x00, 0x13, // Length: 19 bytes
0x0E, // Length of X.224 CR_TPDU
0xE0, // CR_TPDU code
0x00, 0x00, // Destination reference (0)
0x00, 0x00, // Source reference (0)
0x00, // Class and options
// RDP Negotiation Request (TYPE_RDP_NEG_REQ)
0x01, // Type: RDP_NEG_REQ
0x00, // Flags
0x08, 0x00, // Length: 8 bytes
0x01, 0x00, 0x00, 0x00, // Requested protocols: TLS
];
stream.write_all(&connection_request).await?;
stream.flush().await?;
// Read RDP Connection Confirm
let mut response = vec![0u8; 1024];
let n = stream.read(&mut response).await?;
if n < 11 {
tls_bail!("RDP response too short");
}
// Verify TPKT header
if response[0] != 0x03 {
tls_bail!("Invalid RDP response: not a TPKT packet");
}
// Check for CC_TPDU (Connection Confirm)
if response[5] != 0xD0 {
tls_bail!("Invalid RDP response: expected CC_TPDU");
}
Ok(())
}
/// Check if we need to send RDP preamble based on port
pub fn should_use_rdp(port: u16) -> bool {
port == 3389 // Default RDP port
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rdp_port_detection() {
assert!(RdpPreamble::should_use_rdp(3389));
assert!(!RdpPreamble::should_use_rdp(443));
}
}