remote desktop protocol proxy
1 TopicServer Name Indication (SNI) based RDP Proxy
Problem this snippet solves: The outlined iRule can be used to access multiple TLS enabled Remote Desktop Hosts behind a single Virtual Server. The code below, will emulate the initial RDP connection handshake to the client, till the client sends the TLS based SNI record (via Start-TLS message). It would then use a data-group to compare the SNI information with valid FQDNs. If a valid FQDN is found, it would used the data-group value to set up the backend RDP connection. It would then emulate the initial RDP connection handshake to the backend server and finally forward the original Start-TLS message to the selected backend server. If a valid FQDN couldn't be found in the Start-TLS message it would reject the RDP connection... Cheers, Kai How to use this snippet: Setup a standard Virtual Server for TCP:3389. Apply SNAT and TCP profiles as needed. You don't need to add a default_pool. Create the DG_RDP_SERVER data-group to resolves the valid FQDNs to their Nodes. Code : ltm data-group internal DG_RDP_SERVER { records { server1.itacs.de { data "192.168.1.1 3389" } server2.itacs.de { data "192.168.1.2 3389" } } type string } when CLIENT_ACCEPTED { # Init packet counter set rdp_packet 0 # Collect client side RDP data TCP::collect } when CLIENT_DATA { if { [incr rdp_packet] == 1 } then { # Directly respond to the intial RDP protocol negotiation (using fixed payload) TCP::respond [b64decode AwAAEw7QAAASNAACDwgACAAAAA==] # Drop the received client payload and collect addtional payload TCP::payload replace 0 [TCP::payload length] "" TCP::collect } elseif { $rdp_packet == 2 } then { # Match the second RDP packet (aka. Start-TLS) for known SNI records using a datagroup. if { [set node [class match -value [string tolower [TCP::payload]] contains DG_RDP_SERVER]] ne "" } then { # The Start-TLS packet contains a known SNI value. Using the datagroup result for node selection. node $node # Store the Start-TLS packet for later use. set tls_start [TCP::payload] # Replace the payload to negotiate the server side RDP connection. (using fixed payload) TCP::payload replace 0 [TCP::payload length] [b64decode AwAAEw7gAAAAAAABAAgACwAAAA==] # Release the request TCP::release } else { # Start-TLS packet didn't contain a known FQDN. Rejecting the connection... TCP::release reject } } } when SERVER_CONNECTED { # Collect server side RDP data TCP::collect } when SERVER_DATA { if { [info exist tls_start] } then { # Server Side RDP / TLS negotiation is in progress. Drop the initial RDP connection handshake, since the client has already established the connection. TCP::payload replace 0 [TCP::payload length] "" # Replay the stored Start-TLS playload to the server side. TCP::respond $tls_start unset -nocomplain tls_start } else { # Server Side RDP / TLS negotiation has completed. # Release the request TCP::release } } Tested this on version: 12.0694Views0likes0Comments