]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Try to reconnect to LDAP when connection is lost
authorGrégory Oestreicher <greg@kamago.net>
Wed, 14 Sep 2016 20:51:40 +0000 (22:51 +0200)
committerGrégory Oestreicher <greg@kamago.net>
Tue, 28 Feb 2017 21:35:04 +0000 (22:35 +0100)
Actually this will only work for initial lookup()
and list() calls. If the connection is dropped
between one of those and get() the request will
fail.

docs/markdown/authoritative/backend-ldap.md
modules/ldapbackend/ldapbackend.cc
modules/ldapbackend/ldapbackend.hh
modules/ldapbackend/powerldap.cc
modules/ldapbackend/powerldap.hh

index 522e0ceb82c7536357b4bcc618ac2502cb7faca2..2dcf8f0dc06efb2920ee4346a6ecc03379309b7a 100644 (file)
@@ -60,6 +60,9 @@ In case the used LDAP client library doesn't support LDAP URIs as connection par
 ## `ldap-starttls`
 (default "no") : Use TLS encrypted connections to the LDAP server. This is only allowed if ldap-host is a <ldap://> URI or a host name / IP address.
 
+## `ldap-reconnect-attempts`
+(default: "5") : The number of attempts to make to re-establish a lost connection to the LDAP server.
+
 ## `ldap-authmethod`
 (default: "simple") : How to authenticate to the LDAP server. Actually only two methods are supported: "simple", which uses the classical DN / password, or "gssapi", which requires a Kerberos keytab.
 
index 88ffa9db503bf0d89af427a42ac8cc19feb5e2c2..f529d901159aa7de88cf9b08ad69c1014761e265 100644 (file)
@@ -52,6 +52,7 @@ LdapBackend::LdapBackend( const string &suffix )
                setArgPrefix( "ldap" + suffix );
 
                m_getdn = false;
+               m_reconnect_attempts = getArgAsNum( "reconnect-attempts" );
                m_list_fcnt = &LdapBackend::list_simple;
                m_lookup_fcnt = &LdapBackend::lookup_simple;
                m_prepare_fcnt = &LdapBackend::prepare_simple;
@@ -122,6 +123,26 @@ LdapBackend::~LdapBackend()
 
 
 
+bool LdapBackend::reconnect()
+{
+       int attempts = m_reconnect_attempts;
+       bool connected = false;
+       while ( !connected && attempts > 0 ) {
+               L << Logger::Debug << m_myname << " Reconnection attempts left: " << attempts << endl;
+               connected = m_pldap->connect();
+               if ( !connected )
+                       Utility::usleep( 250 );
+               --attempts;
+       }
+
+       if ( connected )
+               m_pldap->bind( m_authenticator );
+
+       return connected;
+}
+
+
+
 bool LdapBackend::list( const DNSName& target, int domain_id, bool include_disabled )
 {
         try
@@ -137,6 +158,14 @@ bool LdapBackend::list( const DNSName& target, int domain_id, bool include_disab
                L << Logger::Warning << m_myname << " Unable to get zone " << target << " from LDAP directory: " << lt.what() << endl;
                throw( DBException( "LDAP server timeout" ) );
         }
+        catch( LDAPNoConnection &lnc )
+        {
+               L << Logger::Warning << m_myname << " Connection to LDAP lost, trying to reconnect" << endl;
+               if ( reconnect() )
+                       this->list( target, domain_id );
+               else
+                       throw PDNSException( "Failed to reconnect to LDAP server" );
+        }
         catch( LDAPException &le )
         {
                L << Logger::Error << m_myname << " Unable to get zone " << target << " from LDAP directory: " << le.what() << endl;
@@ -217,6 +246,14 @@ void LdapBackend::lookup( const QType &qtype, const DNSName &qname, DNSPacket *d
                L << Logger::Warning << m_myname << " Unable to search LDAP directory: " << lt.what() << endl;
                throw( DBException( "LDAP server timeout" ) );
         }
+        catch( LDAPNoConnection &lnc )
+        {
+               L << Logger::Warning << m_myname << " Connection to LDAP lost, trying to reconnect" << endl;
+               if ( reconnect() )
+                       this->lookup( qtype, qname, dnspkt, zoneid );
+               else
+                       throw PDNSException( "Failed to reconnect to LDAP server" );
+        }
         catch( LDAPException &le )
         {
                L << Logger::Error << m_myname << " Unable to search LDAP directory: " << le.what() << endl;
@@ -556,6 +593,7 @@ public:
                declare( suffix, "filter-axfr", "LDAP filter for limiting AXFR results", "(:target:)" );
                declare( suffix, "filter-lookup", "LDAP filter for limiting IP or name lookups", "(:target:)" );
                declare( suffix, "disable-ptrrecord", "Deprecated, use ldap-method=strict instead", "no" );
+               declare( suffix, "reconnect-attempts", "Number of attempts to re-establish a lost LDAP connection", "5" );
         }
 
 
index b634b3073f13ba35119d168ac3ece1a5c894a847..e3aff9b73180c53cf7c1467f53080918166e9049 100644 (file)
@@ -114,6 +114,7 @@ class LdapBackend : public DNSBackend
         vector<DNSName>::iterator m_adomain;
         vector<DNSName> m_adomains;
         QType m_qtype;
+        int m_reconnect_attempts;
 
         bool (LdapBackend::*m_list_fcnt)( const DNSName&, int );
         void (LdapBackend::*m_lookup_fcnt)( const QType&, const DNSName&, DNSPacket*, int );
@@ -132,6 +133,8 @@ class LdapBackend : public DNSBackend
 
         bool getDomainInfo( const string& domain, DomainInfo& di );
 
+        bool reconnect();
+
 public:
 
         LdapBackend( const string &suffix="" );
index f91b5de68ef93acf592183fededf492e563003f6..b4d475d7d3baf92bff1902ba97f515bc46c214a3 100644 (file)
@@ -98,6 +98,20 @@ PowerLDAP::~PowerLDAP()
 }
 
 
+bool PowerLDAP::connect()
+{
+       try
+       {
+               ensureConnect();
+               return true;
+       }
+       catch( LDAPException &le )
+       {
+               return false;
+       }
+}
+
+
 void PowerLDAP::setOption( int option, int value )
 {
         ldapSetOption( d_ld, option, (void*) &value );
@@ -199,7 +213,12 @@ bool PowerLDAP::getSearchEntry( int msgid, sentry_t& entry, bool dn, int timeout
 
        if ( i == -1 ) {
                // Error while retrieving the message
-               throw LDAPException( "Error when retrieving LDAP result: " + getError() );
+               int err_code;
+               ldapGetOption( d_ld, LDAP_OPT_ERROR_NUMBER, &err_code );
+               if ( err_code == LDAP_SERVER_DOWN || err_code == LDAP_CONNECT_ERROR )
+                       throw LDAPNoConnection();
+               else
+                       throw LDAPException( "PowerLDAP::getSearchEntry(): Error when retrieving LDAP result: " + getError( err_code ) );
        }
 
        if ( i == 0 ) {
index 73014d1b60cf5b55ab7128cdcb3c53a67189b21e..612711eabb937e0d401f7c4170d87fb1b6ffb28c 100644 (file)
@@ -59,6 +59,8 @@ public:
         PowerLDAP( const string& hosts = "ldap://127.0.0.1/", uint16_t port = LDAP_PORT, bool tls = false );
         ~PowerLDAP();
 
+        bool connect();
+
         void getOption( int option, int* value );
         void setOption( int option, int value );