LDAP StartTLS Extension to LDAPS Proxy

Problem this snippet solves:

The outlined iRule implements a LDAP StartTLS-Extension (see RFC2830) to traditional LDAPS proxy. The iRule can be used to add StartTLS-Extension support to LDAP instances, which do not support the StartTLS extension.

The iRule will inspect the first TCP datagram for the LDAP-StartTLS request OID. If a StartTLS request is identified, the iRule will parse the ASN.1/BER structure of the LDAP request to extract the LDAP MessageID. Once the MessageID is extracted, the iRule will respond on behalf of the LDAP server with a LDAP response containing the request MessageID and StartTLS OID and then forward the remaining server side connection to a traditional LDAPS pool.

Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_ACCEPTED>: Client 172.21.92.28%1 is Connected to VS 172.21.17.211%1:389
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_ACCEPTED>: Starting to collect LDAP TCP data.
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: Received LDAP TCP data. Searching for LDAP STARTTLS request OID.
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: Parsing 1st BER encoded message envelope (type and length).
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: Checking 1st BER encoded message type = sequence (0x30).
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: 1st BER encoded message type is sequence (0x30).
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: Checking if 1st BER encoded length value is a Multi-Byte length field.
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: Multi-Byte length field detected. Parsing the Multi-Byte length field value.
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: Adding the Multi-Byte length to scan offset.
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: Parsing 2nd BER encoded message envelope (type and length).
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: Checking 2nd BER encoded message type = integer (0x02)
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: 1st BER encoded message type is integer (0x02).
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: Checking if 1st BER encoded length value is a Multi-Byte length field.
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: Extracting 2nd BER encoded message value = MessageId.
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: Sending STARTTLS reply with matching LDAP MessageID to client.
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: Selecting LDAPS:683 pool.
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: Clearing the collected payload buffer.
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: Unset temporary array variable.
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <CLIENT_DATA>: Releasing the connection.
Mon Feb 29 09:41:42 CET 2016     debug   f5-02   tmm1[2649]      Rule /Common/LDAP_STARTTLS <SERVER_CONNECTED>: Client 172.21.92.28%1 is forwarded to 172.21.91.20%1:636

Cheers, Kai

How to use this snippet:

Usage:

  1. Create a new iRule and copy/paste the provided iRule into it.
  2. Modify the
    $static::ldaps_pool
    variable to match your LDAPS:636 pool name.
  3. Attach the iRule to your LDAP:386 Vitual Server.
  4. Test the iRule with an StartTLS aware LDAP client pointing to the LDAP:386 Vitual Server.

Code :

when RULE_INIT {
set static::ldaps_pool "INSERT_YOUR_LDAPS_POOL_NAME"
array set static::hex_filler {
1 "0000000" 2 "000000" 3 "00000" 4 "0000" 5 "000" 6 "00" 7 "0" 8 ""
}
}
when CLIENT_ACCEPTED {
log local0.debug "Client [IP::client_addr] is Connected to VS [IP::local_addr]:[TCP::local_port]"
# log local0.debug "Starting to collect LDAP TCP data."
TCP::collect
}
when CLIENT_DATA {
# log local0.debug "Received LDAP TCP data. Searching for LDAP STARTTLS request OID."
if { [TCP::payload] contains "1.3.6.1.4.1.1466.20037" } then {
if { [catch {
# log local0.debug "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
# log local0.debug "Checking 1st BER encoded message type = sequence (0x30)."
if { $temp(ber_1_type) eq "30" } then {
# log local0.debug "1st BER encoded message type is sequence (0x30)."
# log local0.debug "Checking if 1st BER encoded length value is a Multi-Byte length field."
if { [expr { $temp(ber_1_length) & 0x80 }] } then {
# log local0.debug "Multi-Byte length field detected. Parsing the Multi-Byte length field value."
# Diabled: binary scan [TCP::payload] x$temp(scan_offset)H[expr { ($temp(ber_1_length) & 0x7F) * 2 }] temp(ber_1_mlength)
# log local0.debug "Adding the Multi-Byte length to scan offset."
incr temp(scan_offset) [expr { $temp(ber_1_length) & 0x7F }]
# Diabled: log local0.debug "Formating the received HEX string to numeric value."
# Diabled: set temp(ber_1_length) [expr { [subst "0x$temp(ber_1_mlength)"] }]
}
# Diabled: log local0.debug "Extracting 1nd BER encoded message value = XXX."
# Diabled: binary scan [TCP::payload] x$temp(scan_offset)H[expr { $temp(ber_2_length) * 2 }] temp(ber_2_value)

# log local0.debug "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
# log local0.debug "Checking 2nd BER encoded message type = integer (0x02)"
if { $temp(ber_2_type) eq "02" } then {
# log local0.debug "1st BER encoded message type is integer (0x02)."
# log local0.debug "Checking if 1st BER encoded length value is a Multi-Byte length field."
if { [expr { $temp(ber_2_length) & 0x80 }] } then {
# log local0.debug "Multi-Byte length field detected. Parsing the Multi-Byte length field value."
binary scan [TCP::payload] x$temp(scan_offset)H[expr { ($temp(ber_2_length) & 0x7F) * 2 }] temp(ber_2_mlength)
# log local0.debug "Adding the Multi-Byte length to scan offset."
incr temp(scan_offset) [expr { $temp(ber_2_length) & 0x7F }]
# log local0.debug "Formating the received HEX string to numeric value."
set temp(ber_2_length) [expr { [subst "0x$temp(ber_2_mlength)"] }]
}
# log local0.debug "Extracting 2nd BER encoded message value = MessageId."
binary scan [TCP::payload] x$temp(scan_offset)H[expr { $temp(ber_2_length) * 2 }] temp(ber_2_value)
# log local0.debug "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"]
# log local0.debug "Selecting LDAPS:683 pool $static::ldaps_pool."
pool $static::ldaps_pool
# log local0.debug "Clearing the collected payload buffer."
TCP::payload replace 0 [TCP::payload length] ""
}
}
}]} then {
log local0.debug "Parsing of BER encoded message envelope raised an error."
log local0.debug "Extended ErrorInfo = [subst "\$::errorInfo"]"
}
# log local0.debug "Unset temporary array variable."
unset -nocomplain temp
}
# log local0.debug "Releasing the connection."
TCP::release
}
when SERVER_CONNECTED {
log local0.debug "Client [IP::client_addr] is forwarded to [LB::server addr]:[LB::server port]"
}

Tested this on version:

12.0
Updated Jun 06, 2023
Version 2.0

Was this article helpful?

No CommentsBe the first to comment