rfc2830
1 TopicLDAP 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: Create a new iRule and copy/paste the provided iRule into it. Modify the $static::ldaps_pool variable to match your LDAPS:636 pool name. Attach the iRule to your LDAP:386 Vitual Server. 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.0514Views0likes0Comments