summaryrefslogtreecommitdiffstats
path: root/lib/probes/LDAP.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/probes/LDAP.pm')
-rw-r--r--lib/probes/LDAP.pm184
1 files changed, 184 insertions, 0 deletions
diff --git a/lib/probes/LDAP.pm b/lib/probes/LDAP.pm
new file mode 100644
index 0000000..b7e5342
--- /dev/null
+++ b/lib/probes/LDAP.pm
@@ -0,0 +1,184 @@
+package probes::LDAP;
+
+=head1 NAME
+
+probes::LDAP - a LDAP probe for SmokePing
+
+=head1 OVERVIEW
+
+Measures LDAP search latency for SmkoePing
+
+=head1 SYNOPSYS
+
+ *** Probes ***
+ + LDAP
+
+ passwordfile = /usr/share/smokeping/etc/password # optional
+ sleeptime = 0.5 # optional, 1 second by default
+
+ *** Targets ***
+
+ probe = LDAP
+
+ + PROBE_CONF
+ port = 389 # optional
+ version = 3 # optional
+ start_tls = 1 # disabled by default
+ timeout = 60 # optional
+
+ base = dc=foo,dc=bar # optional
+ filter = uid=testuser # the actual search
+ attrs = uid,someotherattr
+
+ # if binddn isn't present, the LDAP bind is unauthenticated
+ binddn = uid=testuser,dc=foo,dc=bar
+ password = mypass # if not present in <passwordfile>
+
+=head1 DESCRIPTION
+
+This probe measures LDAP query latency for SmokePing.
+The query is specified by the target-specific variable `filter' and,
+optionally, by the target-specific variable `base'. The attributes
+queried can be specified in the comma-separated list `attrs'.
+
+The TCP port of the LDAP server and the LDAP version to be used can
+be specified by the variables `port' and `version'.
+
+The probe can issue the starttls command to convert the connection
+into encrypted mode, if so instructed by the `start_tls' variable.
+It can also optionally do an authenticated LDAP bind, if the `binddn'
+variable is present. The password to be used can be specified by the
+target-specific variable `password' or in an external file.
+The location of this file is given in the probe-specific variable
+`passwordfile'. See probes::passwordchecker(3pm) for the format
+of this file (summary: colon-separated triplets of the form
+`<host>:<bind-dn>:<password>')
+
+The probe tries to be nice to the server and sleeps for the probe-specific
+variable `sleeptime' (one second by default) between each authentication
+request.
+
+=head1 AUTHOR
+
+Niko Tyni E<lt>ntyni@iki.fiE<gt>
+
+=head1 BUGS
+
+There should be a way of specifying TLS options, such as the certificates
+involved etc.
+
+The probe has an ugly way of working around the fact that the
+IO::Socket::SSL class complains if start_tls() is done more than once
+in the same program. But It Works For Me (tm).
+
+=cut
+
+use strict;
+use probes::passwordchecker;
+use Net::LDAP;
+use Time::HiRes qw(gettimeofday sleep);
+use base qw(probes::passwordchecker);
+use IO::Socket::SSL;
+
+sub ProbeDesc {
+ return "LDAP queries";
+}
+
+sub new {
+ my $proto = shift;
+ my $class = ref($proto) || $proto;
+ my $self = $class->SUPER::new(@_);
+
+ my $sleeptime = $self->{properties}{sleeptime};
+ $sleeptime = 1 unless defined $sleeptime;
+ $self->sleeptime($sleeptime);
+
+ return $self;
+}
+
+sub sleeptime {
+ my $self = shift;
+ my $newval = shift;
+
+ $self->{sleeptime} = $newval if defined $newval;
+ return $self->{sleeptime};
+}
+
+
+sub pingone {
+ my $self = shift;
+ my $target = shift;
+ my $host = $target->{addr};
+ my $vars = $target->{vars};
+
+ my $version = $vars->{version} || 3;
+ my $port = $vars->{port};
+
+ my $binddn = $vars->{binddn};
+
+ my $timeout = $vars->{timeout};
+
+ my $password = $vars->{password} || $self->password($host, $binddn) if defined $binddn;
+
+ my $start_tls = $vars->{start_tls};
+
+ my $filter = $vars->{filter};
+
+ my $base = $vars->{base};
+
+ my $attrs = $vars->{attrs};
+
+ my @attrs = split(/,/, $attrs);
+
+ my @times;
+
+ for (1..$self->pings($target)) {
+ local $IO::Socket::SSL::SSL_Context_obj; # ugly but necessary
+ sleep $self->sleeptime unless $_ == 1; # be nice
+ my $start = gettimeofday();
+ my $ldap = new Net::LDAP($host, port => $port, version => $version, timeout => $timeout)
+ or do {
+ $self->do_log("connection error on $host: $!");
+ next;
+ };
+ my $mesg;
+ if ($start_tls) {
+ $mesg = $ldap->start_tls;
+ $mesg->code and do {
+ $self->do_log("start_tls error on $host: " . $mesg->error);
+ $ldap->unbind;
+ next;
+ }
+ }
+ if (defined $binddn and defined $password) {
+ $mesg = $ldap->bind($binddn, password => $password);
+ } else {
+ if (defined $binddn and not defined $password) {
+ $self->do_debug("No password specified for $binddn, doing anonymous bind instead");
+ }
+ $mesg = $ldap->bind();
+ }
+ $mesg->code and do {
+ $self->do_log("bind error on $host: " . $mesg->error);
+ $ldap->unbind;
+ next;
+ };
+ $mesg = $ldap->search(base => $base, filter => $filter, attrs => [ @attrs ]);
+ $mesg->code and do {
+ $self->do_log("filter error on $host: " . $mesg->error);
+ $ldap->unbind;
+ next;
+ };
+ $ldap->unbind;
+ my $end = gettimeofday();
+ my $elapsed = $end - $start;
+
+ $self->do_debug("$host: LDAP query $_ took $elapsed seconds");
+
+ push @times, $elapsed;
+ }
+ return sort { $a <=> $b } @times;
+}
+
+
+1;