Hi Steve,
found some spare time today to code the mentioned LDAP:386-STARTTLS to LDAPS:636 Proxy iRule.
The currently implemented functionality will respond to LDAP-STARTTLS request on behalf of the LDAP server and then change the pool in the background to become LDAPS. On this way you could point your Linux client to a non-STARTTLS aware LDAP instance and still use LDAP:386-STARTTLS provided by the LDAPS:636 instance. If you don't even have LDAPS:636 running, then add some Client_SSL_Profiles on your Virtual Server to SSL-Offload the LDAP:389-STARTTLS traffic back to plaintext LDAP:389
when RULE_INIT {
array set static::hex_filler {
1 "0000000" 2 "000000" 3 "00000" 4 "0000" 5 "000" 6 "00" 7 "0" 8 ""
}
set static::ldaps_pool YOUR_LDAPS_POOL
}
when CLIENT_ACCEPTED {
Collecting TCP data
log local0.debug "Client [IP::client_addr] is Connected to VS [IP::local_addr]:[TCP::local_port]"
TCP::collect
}
when CLIENT_DATA {
Searching for STARTTLS OID request
if { [TCP::payload] contains "1.3.6.1.4.1.1466.20037" } then {
catch {
Parsing 1st BER encoded message envelope (type and length)
binary scan [TCP::payload] H2c temp(ber_1_type) temp(ber_1_length)
set temp(scan_offset) 2
Checking 1st BER encoded message type = sequence(30)
if { $temp(ber_1_type) eq "30" } then {
Skipping 1st BER encoded length value (aka. just adding bytes to scan_offset)
if { [expr { $temp(ber_1_length) & 0xFF }] > 127 } then {
Multi-Byte length field detected. Parsing the Multi-Byte length value
binary scan [TCP::payload] x$temp(scan_offset)H[expr { ($temp(ber_1_length) & 0x7F) * 2 }] temp(ber_1_mlength)
incr temp(scan_offset) [expr { $temp(ber_1_length) & 0x7F }]
}
Parsing 2nd BER encoded message envelope (type and length)
binary scan [TCP::payload] x$temp(scan_offset)H2c temp(ber_2_type) temp(ber_2_length)
incr temp(scan_offset) 2
Checking 2nd BER encoded message type = integer(02)
if { $temp(ber_2_type) eq "02" } then {
Inspecting 2nd BER encoded length value
if { [expr { $temp(ber_2_length) & 0xFF }] > 127 } then {
Multi-Byte length field detected. Parsing the Multi-Byte length value
binary scan [TCP::payload] x$temp(scan_offset)H[expr { ($temp(ber_2_length) & 0x7F) * 2 }] temp(ber_2_mlength)
incr temp(scan_offset) [expr { $temp(ber_2_length) & 0x7F }]
set temp(ber_2_length) [expr "0x$temp(ber_2_mlength)"]
}
Extracting 2nd BER encoded message value = MessageId (value)
binary scan [TCP::payload] x$temp(scan_offset)H[expr { $temp(ber_2_length) * 2 }] temp(ber_2_value)
Sending STARTTLS reply with matching LDAP MessageID to client
TCP::respond [binary format H* "30840000002B0204$static::hex_filler([string length $temp(ber_2_value)])$temp(ber_2_value)78840000001f0a0100040004008a16312e332e362e312e342e312e313436362e3230303337"]
Clearing the collected payload buffer
TCP::payload replace 0 [TCP::payload length] ""
Selecting LDAPS:683 pool
pool $static::ldaps_pool
}
}
}
unset -nocomplain temp
}
Releasing the connection
TCP::release
}
when SERVER_CONNECTED {
log local0.debug "Client [IP::client_addr] is forwarded to [LB::server addr]:[LB::server port]"
}
Note: The iRule seems to be stable. But keep in mind that this code is still somewhat hot smoked. Please test the iRule before using in productive environments. I'm planning to polish the iRule here and there in the comming weeks and then publish it on Codeshare. So stay tuned...
Cheers, Kai