ā12-14-2010 09:22 AM
Folks,
We'll be adding a farm this weekend to do some kind of balance for LDAP and LDAPs servers.
I've been thinking about what would be the best way to probe that servers.
I assume an generic TCP probe has to be created testing 389 and 636, but i honestly don't know what should i expect coming from the real servers.
Does anyone have a LDAP farm in place or something like that.. ? I've found an script on the internet, but it seems a little bit further that what i can understand.. therefore i'm not really confident to use this.
Thanks for any advices.
Andre
ā12-15-2010 07:26 AM
Hi Andre,
The ACE comes with some sample probe scripts - one of which tests LDAP by performing an anaonymous bind. I've written elsewhere in this forum (https://supportforums.cisco.com/message/458388#458388
https://supportforums.cisco.com/message/461739#461739) about how to modify the script to use non-anonymous credentials. You need to create a copy of the provided script, modify the mysterious hex sequence which is ASN.1 formatted, re-import the script and then reference it.
To help with creating magic hex strings I whipped up a small PERL script:
#
# Prepare an ASN.1 BER encoded string to do an LDAP Bind with
# username and password.
#
#
$username = "cn=AceHealthCheck,o=something";
$password = "somethingssecret";
$len_username = length($username);
$xlen_username = sprintf("%02x", $len_username);
$len_password = length($password);
$xlen_password = sprintf("%02x", $len_password);
$username =~s/(.)/sprintf("%x",ord($1))/eg;
$password =~s/(.)/sprintf("%x",ord($1))/eg;
$temp = "020103" . "04" . $xlen_username . $username . "80" . $xlen_password . $password;
$tlen = length($temp) / 2;
$xtlen = sprintf("%02x",$tlen);
$temp = "020101" . "60" . $xtlen . $temp;
$tlen = length($temp) / 2;
$xtlen = sprintf("%02x",$tlen);
$temp = "30" . $xtlen . $temp;
print $temp . "\n";
Not pretty or elegant but it does the job.
Note that if you're using Active Directory as the LDAP server then you'll either need to enable anonymous bind and you'll need to modify the script code that looks for the return code as AD uses the extended length encoding mechanism of ASN.1.
There is no easy way of checking LDAPS beyond a simple TCP probe to check that the port is open and can complete a three-way handshake.
Hope this helps
Cathy
ā12-15-2010 10:13 AM
Hi Andre,
You can use scripted ldap probe (LDAP_PROBE) available with ACE. It sends an anonymous bind request and check for bind success.
probe tcp LDAPS_Probe
port 636
probe tcp LDAP_Probe
port 389
This is how you can apply the script for LDAP port 389.
script file 1 LDAP_PROBE
!
probe scripted LDAP_PROBE_389
interval 5
passdetect interval 30
receive 5
script LDAP_PROBE
!
serverfarm host SF-LDAP-389
description SF LDAP Port 389
predictor leastconns
probe LDAP_PROBE_389
rserver LDAP-RS1-389
inservice
----------
The only supported LDAP probe on the ACE module is the unsecure scripted probe,
-------
The pre-made TCL script probes available from the Software download page also contains an LDAP probe that you can use to verify the health of the LDAP servers.
The ace_scripts.tgz zip file contains these scripts and is located at this URL:
http://www.cisco.com/pcgi-bin/tablebuild.pl/cat6500-ace
To unzip this file, use the gunzip command in Exec mode,
For your convenience, the following sample scripts for the ACE are available to support the TCL feature and are supported by Cisco TAC:
ā¢CHECKPORT_STD_SCRIPT
ā¢ECHO_PROBE_SCRIPT
ā¢FINGER_PROBE_SCRIPT
ā¢FTP_PROBE_SCRIPT
ā¢HTTP_PROBE_SCRIPT
ā¢HTTPCONTENT_PROBE
ā¢HTTPHEADER_PROBE
ā¢HTTPPROXY_PROBE
ā¢IMAP_PROBE
ā¢LDAP_PROBE -----------------> "The LDAP probe you are looking for"
ā¢MAIL_PROBE
ā¢POP3_PROBE
ā¢PROBENOTICE_PROBE
ā¢RTSP_PROBE
ā¢SSL_PROBE_SCRIPT
ā¢TFTP_PROBE
-------------
Also remember that the binding request should be send as a binary and not via ASCII. To get a packet capture of a succeessful credential binding request with username and password and then convert this to HEX value and insert it in the script.
The easiest way is to capture a packet with the authentication credentials and then replace the hex bind string in the example.
The alternative is to handcode the BER coded ASN.1 data string - which while more fun is time consuming. The remainder of the script can stay the same.
You can do this on an ACE module. You have to be aware that 300c02010160 in the example script string is a sort of "header" that holds the request id (1). This will be different in your packet capture.
If you look at the decomposition of the example you'll be able to see how it is put together and what you need to change.
0x30 The start of a universal constructed sequence
0x0c The length of the sequence minus the tag and length bytes = 12 bytes
0x02 Next field is an integer
0x01 The length of the next field (1 byte)
0x01 Value (this is the message ID)
0x60 Application, number 0, use RFC2251 to decode. This is a Bind Request
0x07 Length of data to follow.
0x02 Integer
0x01 Length 1
0x03 3 - this is the LDAP version.
0x04 String
0x00 Length 0
0x80 Simple Authentication
0x00 Length 0
Just keep the id the same in the unbind.
The string I use is:
302d02010160280201030418636e3d41636550726f78792c6f3d556e69766572736974798009ffffffffffffffffff
where I've replaced the 9 character password with 9*x'ff'.
The username for binding is AceProxy. If you want to use the same script then create that username and set the password in the string above (in hex). If for example you set the password to Example12 then you need to set the 9*x'ff' to '4578616d706c653132' - which is the hex representation of the ASCII.
Note that if you use fewer or more than 9 characters then you'll need to change other values in the string because they refer to lengths.
--
You need to create a copy of the standard LDAP probe into your own file and then replace the hex string in the "puts" line which you identified above with the new string.
Then copy the file to the ACE:
ace1/ldap# copy ftp: disk0:
Enter source filename[]? My-LDAP_PROBE
Enter the destination filename[]? [My-LDAP_PROBE]
Enter hostname for the ftp server[]?
1.2.3.4
Enter username[]? anonymous
Enter the file transfer mode[bin/ascii]: [bin]
Password:
Passive mode on.
Hash mark printing on (1024 bytes/hash mark).
##
In the context create a scripted probe definition:
probe scripted PROBE-LDAP-389
interval 60
receive 20
script My-LDAP_PROBE
Load the script into the context:
script file 10 My-LDAP_PROBE
And then add it to the serverfarm:
serverfarm host FARM-LDAP
probe PROBE-LDAP-389
The manual implies that you can pass arguments to a scripted probe, but you would then have to build the hex string dynamically - taking care that all the length values were correct.
This should be enough to enable you to implement the script.
-----------------
Find another example on this
URL:http://scuq.abyle.org/?page_id=201
#!name = ADV_LDAP_PROBE
################################################################################
########
#### > user for linux tclsh !/usr/bin/tclsh8.4
# Stefan Nistelberger
# changes to cisco's original probe
# * username and password with ldap simple bind (dynamically generated packets)
# * unable to connect exception handling
# * debug message for invalidCredentials
#-------------------------------------------
# debug procedure
# set the EXIT_MSG environment variable to help debug
# also print the debug message when debug flag is on
#-------------------------------------------
proc ace_debug { msg } {
global debug ip port EXIT_MSG
set EXIT_MSG $msg
if { [ info exists ip ] && [ info exists port ] } {
set EXIT_MSG "[ info script ]:$ip:$port: $EXIT_MSG "
}
if { [ info exists debug ] && $debug } {
puts $EXIT_MSG
}
}
#-------------------------------------------
# main
#-------------------------------------------
# parse cmd line args and initialize variables
## set debug value
set debug 1
if { [ regsub -nocase "DEBUG" $argv "" argv] } {
set debug 1
}
ace_debug "initializing variable"
set EXIT_MSG "Error config: script ADV_LDAP_PROBE \[DEBUG\]"
set ip $scriptprobe_env(realIP)
set port "0"
set ldap_start "30"
set ldap_bindheader "02010160"
set ldap_bind "0201"
set ldap_version "02"
set ldap_gap1 "04"
set ldap_gap2 "80"
set ldap_bindheader_len 5
set base_len 0c
set ldap_simple_auth "8007"
proc toASCII { char } {
scan $char %c value
return [format %-x $value]
}
set username [ lindex $argv 0 ]
set hexusername ""
set password [ lindex $argv 1 ]
set hexpassword ""
foreach char [split $username ""] {
set hexchar [toASCII $char]
append hexusername $hexchar
}
foreach char [split $password ""] {
set hexchar [toASCII $char]
append hexpassword $hexchar
}
set username_len [string length $username]
ace_debug $username_len
set password_len [string length $password]
ace_debug $password_len
set base_len [expr 0x$base_len]
set seq_len [expr $username_len + $password_len + $base_len]
set sub_seq_len [expr $seq_len - $ldap_bindheader_len]
set seq_len [format %02x $seq_len]
set sub_seq_len [format %02x $sub_seq_len]
set hexldapbindpckt ""
append hexldapbindpckt $ldap_start
append hexldapbindpckt "$seq_len"
append hexldapbindpckt $ldap_bindheader
append hexldapbindpckt $sub_seq_len
append hexldapbindpckt $ldap_bind
append hexldapbindpckt $ldap_version
append hexldapbindpckt $ldap_gap1
append hexldapbindpckt [format %02x $username_len]
append hexldapbindpckt $hexusername
append hexldapbindpckt $ldap_gap2
append hexldapbindpckt [format %02x $password_len]
append hexldapbindpckt $hexpassword
# if port is zero the use well known ldap port 389
if { $port == 0 } {
set port 389
}
#ace_debug $hexldapbindpckt
#####################
# PROBE START
#####################
set errorcode [catch {
set sock [ socket $ip $port ]
} msg ]
if {$errorcode != 0} {
ace_debug $msg
exit 30002
}
fconfigure $sock -buffering line -translation binary
# anonymous bind request
#puts -nonewline $sock [ binary format "H*" 300c020101600702010304008000 ]
puts -nonewline $sock [ binary format "H*" $hexldapbindpckt ]
set code "ffffff"
flush $sock
ace_debug "bef"
set line [read $sock 22]
ace_debug "aft"
binary scan $line H* res
binary scan $line @15H6 code
close $sock
# make probe fail by exit with 30002 if ldap reply code != success code 0x0a0100
if { $code != "0a0100" } {
if { $code == "0a0131" } {
ace_debug " probe failed : expect response code \'0a0100\' but received
\'$code\' = invalidCredentials"
} else {
ace_debug " probe failed : expect response code \'0a0100\' but received
\'$code\'"
}
exit 30002
}
## make probe success by exit with 30001
ace_debug "probe success"
exit 30001
--------------------
URL for reference:
https://cisco-support.hosted.jivesoftware.com/thread/132800?decorator=print&displayFullThread=true
HTH
Sachin Garg
ā12-17-2010 11:49 AM
Hi Andre,
Kindly update the status. If your issue resolved.
Kind Regards,
Sachin Garg
ā12-21-2010 11:59 AM
Hi Sachinga,
I'm still trying to get all teams together to implement this.. the server team put this on hold for now.. and we won't be able to execute this change until the end of this year.
Anyways.. Thanks for your help.
Regards,
ā01-27-2011 05:18 AM
Hi,
I wanted to post about my experiences in getting this probe to work with Active Directory using credentials. I did not use the Perl script to generate the HEX string for the probe, but did a capture of LDAP traffic on the ACE appliance instead.
I had to copy the capture to disk0: before copying it to my PC in order to open it in Wireshark. In Wireshark, I copied the LDAP bind request as HEX and replaced the HEX value in the LDAP_PROBE script (in puts -nonewline $sock [ binary format "H*" HEXSTRINGINSERTEDHERE ])
I also had to change the script code related to the response because Active Directory did not have the "0a0100" response at the same offset. So I changed:
# read string back from server
ace_debug "receiving ldap bind result"
set line [read $sock 14]
binary scan $line H* res
binary scan $line @7H6 code
ace_debug "recived $res with code $code"
To:
# read string back from server
ace_debug "receiving ldap bind result"
set line [read $sock 22]
binary scan $line H* res
binary scan $line @15H6 code
ace_debug "recived $res with code $code"
And now the probe works towards Active Directory using a username and password!
ā02-23-2016 08:28 AM
ā02-23-2016 10:54 PM
Hi Michal,
Time flies, it's been 5 years since I made that post. I tried to figure it out again, but I just don't have the time to do it. You are right though, the @15H6 is the offset where the scan should begin, and the response the scan is looking for is "0a0100".
So if the offset is wrong, the script won't find the "0a0100" code, that's what you're looking for.
ā03-01-2016 06:49 AM
No worries Erik,
update - so it's not really "kosher" solution, but here is how you can trick it with regex search instead of exact position search. Hope this helps someone else.
#read 20B from the sock to the line variable
set line [read $sock 20]
#convert it to the hexa mode and into res variable
binary scan $line H* res
#predefine success respond
set suc 0a0100
#find suc in the res variable, return 30001 if found
if { [regexp -nocase $suc $res match] } {
exit 30001
} else {
exit 30002
}
ā08-25-2016 01:20 AM
Hi Sachin,
I am facing the some problem...when I tried to config probe with TCP port the SF getting error PROBE_FAILED on port 389 and 636.
Probe tcp VIS_389
port 389
Probe tcp VIS_636
port 636
But when I do UDP the SF is up...Operational.
Also without probe on single port 389 its working config below:
serverfarm host VIS_389
rserver VIS1 389
inservice
rserver VIS2 389
inservice
Regards
Darshan P
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide