From: Grégory Oestreicher Date: Wed, 14 Sep 2016 20:51:40 +0000 (+0200) Subject: Try to reconnect to LDAP when connection is lost X-Git-Tag: rec-4.1.0-alpha1~170^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=635d9ddc5d0410f6dc33600bd2800393bdb67cd3;p=thirdparty%2Fpdns.git Try to reconnect to LDAP when connection is lost 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. --- diff --git a/docs/markdown/authoritative/backend-ldap.md b/docs/markdown/authoritative/backend-ldap.md index 522e0ceb82..2dcf8f0dc0 100644 --- a/docs/markdown/authoritative/backend-ldap.md +++ b/docs/markdown/authoritative/backend-ldap.md @@ -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 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. diff --git a/modules/ldapbackend/ldapbackend.cc b/modules/ldapbackend/ldapbackend.cc index 88ffa9db50..f529d90115 100644 --- a/modules/ldapbackend/ldapbackend.cc +++ b/modules/ldapbackend/ldapbackend.cc @@ -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" ); } diff --git a/modules/ldapbackend/ldapbackend.hh b/modules/ldapbackend/ldapbackend.hh index b634b3073f..e3aff9b731 100644 --- a/modules/ldapbackend/ldapbackend.hh +++ b/modules/ldapbackend/ldapbackend.hh @@ -114,6 +114,7 @@ class LdapBackend : public DNSBackend vector::iterator m_adomain; vector 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="" ); diff --git a/modules/ldapbackend/powerldap.cc b/modules/ldapbackend/powerldap.cc index f91b5de68e..b4d475d7d3 100644 --- a/modules/ldapbackend/powerldap.cc +++ b/modules/ldapbackend/powerldap.cc @@ -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 ) { diff --git a/modules/ldapbackend/powerldap.hh b/modules/ldapbackend/powerldap.hh index 73014d1b60..612711eabb 100644 --- a/modules/ldapbackend/powerldap.hh +++ b/modules/ldapbackend/powerldap.hh @@ -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 );