We run a cluster of directory
servers (4 masters, 2 hubs, 14 slaves) behind a set of
F5 Bigip load balancers. Our Bigip admins recently
decided to switch the boxes to "one-armed" mode and
that services would have to use X-Forwarded-For
headers or equivalent to get the actual client IP
address. Obviously, LDAP has no equivalent.
So, I've hacked something together and
I'm posting it looking for feedback. If the stuff
is actually usable for other folks, that's good too.
On the load balancer side, the code is
specifically for the F5 Bigips. But if other load
balancers have similar abilities to trigger on
events and can insert binary data into the
datastream, it should be adaptable.
Essentially what I've done is defined a
new LDAP Extended Operation with a payload that's a
string containing the source IP address of the
incoming connection. The load balancer sends this
LDAP operation as soon as it opens a connection to
the LDAP server, before any other traffic gets sent.
On the directory server side, I've written an
Extended Operation plugin that then logs the string.
All we need is logging, so that's good enough for
us. There's room for improvement there though, like
making the address available for IP based ACls
(which we don't use).
In order to insert an LDAP operation
into the stream, the code on the load balancer needs
to choose an LDAP message-id that hopefully the real
client isn't going to use. Going on the assumption
that the client will start at 0 and increment up, I
had the code insert a message-id of 0x70000000. I
initially thought I'd have to have the code on the
load balancer look for the response message and
throw it away so the client doesn't see it, but I've
found that the clients just seem to ignore it with
no ill effects, so I haven't bothered filtering the
response out. The less the code on the load
balancer does, the better.
There's a possibility that the client
could send it's own xff extended operation, but
since the load balancer always sends first, we can
just ignore any subsequent log entries.
On the directory server plugin side, I
needed to be able to log this to the access log, not
to the error log. The slapi_log_access function
isn't declared in the plugin header file, so I had
to declare it manually.
Here's what our log entries look like
now, for both 636 (SSL) and 389 (cleartext before
starttls):
[17/May/2016:15:34:22
-0400] conn=230843 fd=156 slot=156 SSL
connection from 130.207.167.12 to 130.207.183.16
[17/May/2016:15:34:22
-0400] conn=230843 op=0 EXT
oid="1.3.6.1.4.1.636.2.11.11.1"
name="forwarded-for extended op"
[17/May/2016:15:34:22
-0400] conn=230843 op=0 forwarded for
130.207.167.12
[17/May/2016:15:34:22
-0400] conn=230843 op=0 RESULT err=0 tag=120
nentries=0 etime=0
[17/May/2016:15:34:22
-0400] conn=230844 fd=156 slot=156 connection
from 130.207.167.12 to 130.207.183.16
[17/May/2016:15:34:22
-0400] conn=230844 op=0 EXT
oid="1.3.6.1.4.1.636.2.11.11.1"
name="forwarded-for extended op"
[17/May/2016:15:34:22
-0400] conn=230844 op=0 forwarded for
130.207.167.12
[17/May/2016:15:34:22
-0400] conn=230844 op=0 RESULT err=0 tag=120
nentries=0 etime=0
We haven't switched our Bigips yet, so
the "connection from" line still shows the actual
client IP address.
F5 Bigip code fragments are called
"irules" and are written in TCL. The tar file below
contains two different irule files, one for
cleartext streams and one for SSL streams. By SSL
streams, I mean where SSL connections from the
client are terminated at the load balancer and then
re-SSLed to the ldap server. Sorry, I'm not writing
the other kind.
This is really nice, and a big help for tracing
connections through load balancers and other similar
devices.
Are you interested in contributing this to 389?