Skip to content

Commit

Permalink
Merge pull request #79 from BloodHoundAD/serverdown_retry
Browse files Browse the repository at this point in the history
ServerDown Retry Logic
  • Loading branch information
rvazarkar authored Oct 12, 2023
2 parents 6f3dfed + 96cce99 commit 90fab4c
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/CommonLib/Enums/LdapErrorCodes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ public enum LdapErrorCodes : int
{
Success = 0,
Busy = 51,
ServerDown = 81
}
}
53 changes: 51 additions & 2 deletions src/CommonLib/LDAPUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,22 @@ public IEnumerable<ISearchResultEntry> QueryLDAP(string ldapFilter, SearchScope
if (response != null)
pageResponse = (PageResultResponseControl) response.Controls
.Where(x => x is PageResultResponseControl).DefaultIfEmpty(null).FirstOrDefault();
}catch (LdapException le) when (le.ErrorCode == (int)LdapErrorCodes.ServerDown &&
retryCount < MaxRetries)
{
retryCount++;
Thread.Sleep(backoffDelay);
backoffDelay = TimeSpan.FromSeconds(Math.Min(
backoffDelay.TotalSeconds * BackoffDelayMultiplier.TotalSeconds, MaxBackoffDelay.TotalSeconds));
conn = CreateNewConnection(domainName, globalCatalog, skipCache);
if (conn == null)
{
_log.LogError("Unable to create replacement ldap connection for ServerDown exception. Breaking loop");
yield break;
}

_log.LogInformation("Created new LDAP connection after receiving ServerDown from server");
continue;
}catch (LdapException le) when (le.ErrorCode == (int)LdapErrorCodes.Busy && retryCount < MaxRetries) {
retryCount++;
Thread.Sleep(backoffDelay);
Expand Down Expand Up @@ -887,6 +903,22 @@ public IEnumerable<ISearchResultEntry> QueryLDAP(string ldapFilter, SearchScope
}
}

private LdapConnection CreateNewConnection(string domainName = null, bool globalCatalog = false, bool skipCache = false)
{
var task = globalCatalog
? Task.Run(() => CreateGlobalCatalogConnection(domainName, _ldapConfig.AuthType))
: Task.Run(() => CreateLDAPConnection(domainName, skipCache, _ldapConfig.AuthType));

try
{
return task.ConfigureAwait(false).GetAwaiter().GetResult();
}
catch
{
return null;
}
}

/// <summary>
/// Performs an LDAP query using the parameters specified by the user.
/// </summary>
Expand Down Expand Up @@ -937,9 +969,9 @@ public virtual IEnumerable<ISearchResultEntry> QueryLDAP(string ldapFilter, Sear
try
{
_log.LogTrace("Sending LDAP request for {Filter}", ldapFilter);
response = (SearchResponse) conn.SendRequest(request);
response = (SearchResponse)conn.SendRequest(request);
if (response != null)
pageResponse = (PageResultResponseControl) response.Controls
pageResponse = (PageResultResponseControl)response.Controls
.Where(x => x is PageResultResponseControl).DefaultIfEmpty(null).FirstOrDefault();
}
catch (LdapException le) when (le.ErrorCode == (int)LdapErrorCodes.Busy && retryCount < MaxRetries)
Expand All @@ -950,6 +982,23 @@ public virtual IEnumerable<ISearchResultEntry> QueryLDAP(string ldapFilter, Sear
backoffDelay.TotalSeconds * BackoffDelayMultiplier.TotalSeconds, MaxBackoffDelay.TotalSeconds));
continue;
}
catch (LdapException le) when (le.ErrorCode == (int)LdapErrorCodes.ServerDown &&
retryCount < MaxRetries)
{
retryCount++;
Thread.Sleep(backoffDelay);
backoffDelay = TimeSpan.FromSeconds(Math.Min(
backoffDelay.TotalSeconds * BackoffDelayMultiplier.TotalSeconds, MaxBackoffDelay.TotalSeconds));
conn = CreateNewConnection(domainName, globalCatalog, skipCache);
if (conn == null)
{
_log.LogError("Unable to create replacement ldap connection for ServerDown exception. Breaking loop");
yield break;
}

_log.LogInformation("Created new LDAP connection after receiving ServerDown from server");
continue;
}
catch (LdapException le)
{
if (le.ErrorCode != 82)
Expand Down

0 comments on commit 90fab4c

Please sign in to comment.