Technical Articles
F5 SMEs share good practice.
cancel
Showing results for 
Search instead for 
Did you mean: 
Colin_Walker_12
Historic F5 Account

LDAP is one of the most widely used authentication protocols around today. There are plenty of others, but LDAP is undeniably one of the big ones. It comes as no surprise then that we often hear different questions about using F5 technology with LDAP servers on the back-end. Whether people are looking for more performance, increased reliability and availability through load-balancing, or just more flexibility, there are many things that we can do to help.

A great example is improving performance. This example is driven from a client's requirements to reduce the overhead on their LDAP systems. They wanted to do so in a particular way, however. They were receiving a high-volume of very short-lived connections that all needed to query the back-end LDAP systems for information. Each one of these connections would open a new connection and as it turns out the overhead of setting up and tearing down the TCP connections was creating a fair amount of churn on their server, due to the high volume and short duration of the requests. Seeing this, they turned to their BIG-IP, looking for a solution.

As luck would have it, iRules was able to step in to help them accomplish just what they were looking for. Thanks to one of the many bright engineers here at F5, Nat Thirasuttakorn, they were able to leave server-side connections to the LDAP systems open for long periods of time and just manage the handshakes on the client side, thereby greatly reducing the overhead on the LDAP servers.

Below is the iRule that Nat was kind enough to share with me so I could pass it along to the DevCentral community. What it does is listen to the LDAP traffic, watching for an unbind to occur. Once the iRule sees an unbind from the client, which would normally be sent to the LDAP server terminating the connection, it simply uses the LB::detach command to detach the back-end connection at the BIG-IP, and tosses the unbind command itself so the LDAP server never sees it. This leaves the server's connection to the BIG-IP open and available for the next request that comes in.

It's important to understand that the LB::detach command isn't terminating any connection, even though the name might sound like it. All it's doing is detaching the current session from the connection it's established to the server in question, allowing future sessions to make use of the connection. This will, in essence, makes it look to the LDAP server that there's a single (or several), long-lived connection being held open with many requests flowing through. What's really happening is the BIG-IP brokering requests from the client and using already established back-end connections to keep overhead down to a minimum. This is the beauty of OneConnect (which is required for this solution to work) and iRules on the BIG-IP's TMOS architecture.

I don't have any performance numbers to share, but I'm willing to bet the BIG-IP is a fair amount more efficient at managing those large numbers of short-lived connections than an LDAP server is going to be. That means not only are you gaining the overhead back on your auth server, but you’re not really losing much on the BIG-IP. That makes it a win-win. Again, many thanks to Nat for sharing the below code.

when CLIENT_ACCEPTED {  
    TCP::collect
}
when CLIENT_DATA {
    binary scan [TCP::payload] xc ber_len
    if { $ber_len < 0 } {
        set ber_index [expr 2 + 128 + $ber_len]
    } else {
        set ber_index 2
    }
    # message id
    binary scan [TCP::payload] @${ber_index}xcI ber_len ber_len_ext
    if { $ber_len < 0 } {
        set ext_len [expr 128 + $ber_len]
        set ber_len [expr ($ber_len_ext & 0xffffffff) >>(4-$ext_len)*8)]
     } else {
        set ext_len 0
    }
    incr ber_index [expr 2 + $ext_len + $ber_len]
    # ldap message
    binary scan [TCP::payload] @${ber_index}c ber_type 
    if { [expr $ber_type & 0x1f] == 2 } {
        log local0. "unbind => detach"
        TCP::payload replace 0 [TCP::payload length] ""
        LB::detach
    }
    TCP::release
    TCP::collect
}
Comments
Michael_Wingend
Nimbostratus
Nimbostratus
Nice rule. What does happen if an unbind should reach the LDAP server i.e. the connection is no longer needed cause there are no more requests. Isn't that a problem for the LDAP server? Is it an implicit unbind for a LDAP server if the TCP connection closes/is lost?
Dick_Davies_754
Nimbostratus
Nimbostratus
Are you sure that's a good idea?

 

 

I though LDAP connections were authenticated when they were established; do you handle the case where an authenticated connection is left open?
tbernath_90565
Historic F5 Account
I have a similar issue where the client is connecting to a VIP on the F5, which is directed to the active of two servers. There are two issues I'm trying to fix, one is the client is binding on each request, I want to eat those on the F5 so there is just one or two to each server. The other, I want to figure out how to fail over, and do the rebind automatically. Currently the client keeps sending requests to the new server, and getting hundreds of RST responses.

 

Any ideas?

 

Thanks
Nat_Thirasuttakorn
F5 Employee
F5 Employee
answer to michaelwingender's question:

 

I believe most LDAP implementations support implicit unbind when TCP connection is closed. However, I am not LDAP expert at all. I know LDAP from Networking perspective not LDAP admin. So any feedback is very appreciated.

 

answer to rasputnik's question:

 

Yes, this iRule intends to demonstrate simple technique to keep server connection open. It is assume that servers support rebind in the same TCP connection. It is also possible to use iRule to strip off bind message.

 

This iRule is suitable for simple and secure environment such as between web-tier and application tier. To use this technique in a more secure way, security check should be added to the iRule, for example, make sure the first message from client is a bind message, restrict access to some IP addresses, etc.

 

answer to tbernath's question

 

1) the client is binding on each request, I want to eat those on the F5

 

you can use the same technique. This iRule detects unbind message type (which is 2) at the below line

 

if { [expr $ber_type & 0x1f] == 2 } {

 

You may just change it to 0. (bind request message type is one). Don't detach, swallow the bind request using TCP::payload command and send bind successful to client with TCP::respond. Here is a basic example

 

if { [expr $ber_type & 0x1f] == 0 } {

 

TCP::payload replace 0 [TCP::payload length] ""

 

TCP::respond $bind_success

 

}

 

If client always use message id 1, anonymous bind and same bind dn, this bind response message may always be the same. Otherwise, you may need to craft bind_response message on the fly.

 

2) do the rebind automatically

 

One technique that you can use is to save previous Client's bind message for reuse. Once there is a need to rebind. You can either put the saved bind message in the beginning of TCP::payload or use TCP::respond in server_connected event. here is an example:

 

TCP::payload replace 0 0 $save_bind_message

 

to save bind message, you may simply catch it in the first time that client send bind message and perform this.

 

set save_bind_message [TCP::payload]

 

(assume TCP::payload only contain bind message)

 

This technique may only work with simple authentication and not SASL. SASL may require more complicated iRule or it may not be possible at all.

 

If you have further questions, please post them to iRule forum. (Usually, I don't monitor this page and I have to sorry for late reply)

 

Thank you very much for all questions and comments,

 

Nat
Rich_Caldwell_7
Nimbostratus
Nimbostratus
As this rule was written in 2008, I wonder if, as time has passed, if this rule has been obsoleted by some other function/feature in the 10.x.x LTM code base, or if it is still completely relevant as I look to implement this type of feature on the 10.2.0 code.
Nat_Thirasuttakorn
F5 Employee
F5 Employee
This irule is still relavant. please note that it requires OneConnect profile.

 

 

However, there is a bug 🙂

 

 

this line:

 

set ber_len [expr (($ber_len_ext>>(4-$ext_len)*8)+(0x100^$ext_len))%(0x100^$ext_len)]

 

 

should be changed to:

 

set ber_len [expr ($ber_len_ext & 0xffffffff) >>(4-$ext_len)*8)]
JRahm
Community Manager
Community Manager
Nat, I updated the article with the fix you provided, thanks much!
Indrek_38497
Nimbostratus
Nimbostratus
One extra bracket.

 

I got error:

 

syntax error in expression "(16777216 & 0xffffffff) >>(4-22)*8)": extra tokens at end of expression while executing "expr ($ber_len_ext & 0xffffffff) >>(4-$ext_len)*8)"

 

 

Should be:

 

set ber_len [expr ($ber_len_ext & 0xffffffff) >>(4-$ext_len)*8]

 

 

rmd1023
Nimbostratus
Nimbostratus
Does this imply you're using SNAT? If not, how does it handle the shifting source IP address as different requests come in when it re-uses the connection?

 

 

I would think you'd want to be able to log the client source IP to track where your users are coming in from - if not for real time monitoring than for forensics after a problem. ("hey, Alice started having problems right after that ldap auth request came in from an address in China!")
neha_125523
Nimbostratus
Nimbostratus
Hi ,

 

We are facing an Issue where we use LDAP V3 and Directory Server 6.3.1.1.1 .

 

One of the Application using Domino is used by devices like iphones and ipads and making many hits on the server .

 

The hits made by the application are not clean.

 

The Application does not UNBINDS after establishing a new connection and gets closed by T1 error and this chain goes on which is impacting our infrastructure.

 

The code provided by you will it help in this case??

 

and if yes how and where should we implement this code??

 

 

Application Logs:

 

 

[27/Feb/2013:11:11:59 +0000] conn=100178 op=1 msgId=2 - UNBIND

 

[27/Feb/2013:11:11:59 +0000] conn=100178 op=1 msgId=-1 - closing from 10.71.8.19:59631 - U1 - Connection closed by unbind client -

 

[27/Feb/2013:11:11:59 +0000] conn=100178 op=-1 msgId=-1 - closed.

 

Nat_Thirasuttakorn
F5 Employee
F5 Employee
Hi Neha,

 

 

This code seems to do the opposite of what you are looking for. It prevents UNBIND message to be sent to server so that it can keep server connection open for reuse.

 

 

If I understand correctly, in your case, you might want to detect idle client connection in iRule, and try to UNBIND the connection before it is terminated by server? or please feel free to correct me if I am wrong.

 

 

maybe something like this...

 

 


    when CLIENT_ACCEPTED {
        set client_idle_time 0
        set disconnect [expr [IP::idle_timeout] * 0.8]
        after 1000 -periodic {
            incr client_idle_time
            if { $client_idle_time > $disconnect } {
                unbind
                TCP::payload replace 0 0 $static::unbind_message
            }
        }
    }
    when CLIENT_DATA {
         reset idle time when there is data
        set client_idle_time 0
    } 

 

 

the $static::unbind_message could be created in RULE_INIT

 

for example, use something like

 

 

set static::unbind_message [binary format H* "30050201034200"]

 

 

 

Nat
Version history
Last update:
‎09-Oct-2008 06:44
Updated by:
Contributors