|
|
ebcf82 |
From 0a0d0f66409eb83e06b7dc50543c2f6c15a36bc4 Mon Sep 17 00:00:00 2001
|
|
|
ebcf82 |
From: Alexey A Nikitin <nikitin@amazon.com>
|
|
|
ebcf82 |
Date: Mon, 29 Oct 2018 20:40:36 -0700
|
|
|
ebcf82 |
Subject: [PATCH] Make 'adcli info' DC location mechanism more compliant with
|
|
|
ebcf82 |
[MS-ADTS] and [MS-NRPC]
|
|
|
ebcf82 |
|
|
|
ebcf82 |
AD specifications say that DC locator must attempt to find a suitable DC for the client. That means going through all of the DCs in SRV RRs one by one until one of them answers.
|
|
|
ebcf82 |
|
|
|
ebcf82 |
The problem with adcli's original behavior is that it queries only five DCs from SRV, ever. This becomes a problem if for any reason there is a large number of DCs in the domain from which the client cannot get a CLDAP response.
|
|
|
ebcf82 |
---
|
|
|
ebcf82 |
library/addisco.c | 146 +++++++++++++++++++++++++++++-----------------
|
|
|
ebcf82 |
1 file changed, 94 insertions(+), 52 deletions(-)
|
|
|
ebcf82 |
|
|
|
ebcf82 |
diff --git a/library/addisco.c b/library/addisco.c
|
|
|
ebcf82 |
index 8cc5bf0..6e73ead 100644
|
|
|
ebcf82 |
--- a/library/addisco.c
|
|
|
ebcf82 |
+++ b/library/addisco.c
|
|
|
ebcf82 |
@@ -41,8 +41,10 @@
|
|
|
ebcf82 |
#include <string.h>
|
|
|
ebcf82 |
#include <time.h>
|
|
|
ebcf82 |
|
|
|
ebcf82 |
-/* Number of servers to do discovery against */
|
|
|
ebcf82 |
-#define DISCO_COUNT 5
|
|
|
ebcf82 |
+/* Number of servers to do discovery against.
|
|
|
ebcf82 |
+ * For AD DS maximum number of DCs is 1200.
|
|
|
ebcf82 |
+ */
|
|
|
ebcf82 |
+#define DISCO_COUNT 1200
|
|
|
ebcf82 |
|
|
|
ebcf82 |
/* The time period in which to do rapid requests */
|
|
|
ebcf82 |
#define DISCO_FEVER 1
|
|
|
ebcf82 |
@@ -453,6 +455,51 @@ parse_disco (LDAP *ldap,
|
|
|
ebcf82 |
return usability;
|
|
|
ebcf82 |
}
|
|
|
ebcf82 |
|
|
|
ebcf82 |
+static int
|
|
|
ebcf82 |
+ldap_disco_poller (LDAP **ldap,
|
|
|
ebcf82 |
+ LDAPMessage **message,
|
|
|
ebcf82 |
+ adcli_disco **results,
|
|
|
ebcf82 |
+ const char **addrs)
|
|
|
ebcf82 |
+{
|
|
|
ebcf82 |
+ int found = ADCLI_DISCO_UNUSABLE;
|
|
|
ebcf82 |
+ int close_ldap;
|
|
|
ebcf82 |
+ int parsed;
|
|
|
ebcf82 |
+ int ret = 0;
|
|
|
ebcf82 |
+ struct timeval tvpoll = { 0, 0 };
|
|
|
ebcf82 |
+
|
|
|
ebcf82 |
+ switch (ldap_result (*ldap, LDAP_RES_ANY, 1, &tvpoll, message)) {
|
|
|
ebcf82 |
+ case LDAP_RES_SEARCH_ENTRY:
|
|
|
ebcf82 |
+ case LDAP_RES_SEARCH_RESULT:
|
|
|
ebcf82 |
+ parsed = parse_disco (*ldap, *addrs, *message, results);
|
|
|
ebcf82 |
+ if (parsed > found)
|
|
|
ebcf82 |
+ found = parsed;
|
|
|
ebcf82 |
+ ldap_msgfree (*message);
|
|
|
ebcf82 |
+ close_ldap = 1;
|
|
|
ebcf82 |
+ break;
|
|
|
ebcf82 |
+ case -1:
|
|
|
ebcf82 |
+ ldap_get_option (*ldap, LDAP_OPT_RESULT_CODE, &ret;;
|
|
|
ebcf82 |
+ close_ldap = 1;
|
|
|
ebcf82 |
+ break;
|
|
|
ebcf82 |
+ default:
|
|
|
ebcf82 |
+ ldap_msgfree (*message);
|
|
|
ebcf82 |
+ close_ldap = 0;
|
|
|
ebcf82 |
+ break;
|
|
|
ebcf82 |
+ }
|
|
|
ebcf82 |
+
|
|
|
ebcf82 |
+ if (ret != LDAP_SUCCESS) {
|
|
|
ebcf82 |
+ _adcli_ldap_handle_failure (*ldap, ADCLI_ERR_CONFIG,
|
|
|
ebcf82 |
+ "Couldn't perform discovery search");
|
|
|
ebcf82 |
+ }
|
|
|
ebcf82 |
+
|
|
|
ebcf82 |
+ /* Done with this connection */
|
|
|
ebcf82 |
+ if (close_ldap) {
|
|
|
ebcf82 |
+ ldap_unbind_ext_s (*ldap, NULL, NULL);
|
|
|
ebcf82 |
+ *ldap = NULL;
|
|
|
ebcf82 |
+ }
|
|
|
ebcf82 |
+
|
|
|
ebcf82 |
+ return found;
|
|
|
ebcf82 |
+}
|
|
|
ebcf82 |
+
|
|
|
ebcf82 |
static int
|
|
|
ebcf82 |
ldap_disco (const char *domain,
|
|
|
ebcf82 |
srvinfo *srv,
|
|
|
ebcf82 |
@@ -477,6 +524,7 @@ ldap_disco (const char *domain,
|
|
|
ebcf82 |
int num, i;
|
|
|
ebcf82 |
int ret;
|
|
|
ebcf82 |
int have_any = 0;
|
|
|
ebcf82 |
+ struct timeval interval;
|
|
|
ebcf82 |
|
|
|
ebcf82 |
if (domain) {
|
|
|
ebcf82 |
value = _adcli_ldap_escape_filter (domain);
|
|
|
ebcf82 |
@@ -540,7 +588,6 @@ ldap_disco (const char *domain,
|
|
|
ebcf82 |
version = LDAP_VERSION3;
|
|
|
ebcf82 |
ldap_set_option (ldap[num], LDAP_OPT_PROTOCOL_VERSION, &version);
|
|
|
ebcf82 |
ldap_set_option (ldap[num], LDAP_OPT_REFERRALS , 0);
|
|
|
ebcf82 |
- _adcli_info ("Sending netlogon pings to domain controller: %s", url);
|
|
|
ebcf82 |
addrs[num] = srv->hostname;
|
|
|
ebcf82 |
have_any = 1;
|
|
|
ebcf82 |
num++;
|
|
|
ebcf82 |
@@ -555,70 +602,65 @@ ldap_disco (const char *domain,
|
|
|
ebcf82 |
freeaddrinfo (res);
|
|
|
ebcf82 |
}
|
|
|
ebcf82 |
|
|
|
ebcf82 |
- /* Wait for the first response. Poor mans fd watch */
|
|
|
ebcf82 |
- for (started = now = time (NULL);
|
|
|
ebcf82 |
- have_any && found != ADCLI_DISCO_USABLE && now < started + DISCO_TIME;
|
|
|
ebcf82 |
- now = time (NULL)) {
|
|
|
ebcf82 |
+ /* Initial send and short time wait */
|
|
|
ebcf82 |
+ interval.tv_sec = 0;
|
|
|
ebcf82 |
+ for (i = 0; ADCLI_DISCO_UNUSABLE == found && i < num; ++i) {
|
|
|
ebcf82 |
+ int parsed;
|
|
|
ebcf82 |
+
|
|
|
ebcf82 |
+ if (NULL == ldap[i])
|
|
|
ebcf82 |
+ continue;
|
|
|
ebcf82 |
|
|
|
ebcf82 |
- struct timeval tvpoll = { 0, 0 };
|
|
|
ebcf82 |
- struct timeval interval;
|
|
|
ebcf82 |
+ have_any = 1;
|
|
|
ebcf82 |
+ _adcli_info ("Sending NetLogon ping to domain controller: %s", addrs[i]);
|
|
|
ebcf82 |
|
|
|
ebcf82 |
- /* If in the initial period, send feverishly */
|
|
|
ebcf82 |
- if (now < started + DISCO_FEVER) {
|
|
|
ebcf82 |
- interval.tv_sec = 0;
|
|
|
ebcf82 |
- interval.tv_usec = 100 * 1000;
|
|
|
ebcf82 |
+ ret = ldap_search_ext (ldap[i], "", LDAP_SCOPE_BASE,
|
|
|
ebcf82 |
+ filter, attrs, 0, NULL, NULL, NULL,
|
|
|
ebcf82 |
+ -1, &msgidp);
|
|
|
ebcf82 |
+
|
|
|
ebcf82 |
+ if (ret != LDAP_SUCCESS) {
|
|
|
ebcf82 |
+ _adcli_ldap_handle_failure (ldap[i], ADCLI_ERR_CONFIG,
|
|
|
ebcf82 |
+ "Couldn't perform discovery search");
|
|
|
ebcf82 |
+ ldap_unbind_ext_s (ldap[i], NULL, NULL);
|
|
|
ebcf82 |
+ ldap[i] = NULL;
|
|
|
ebcf82 |
+ }
|
|
|
ebcf82 |
+
|
|
|
ebcf82 |
+ /* From https://msdn.microsoft.com/en-us/library/ff718294.aspx first
|
|
|
ebcf82 |
+ * five DCs are given 0.4 seconds timeout, next five are given 0.2
|
|
|
ebcf82 |
+ * seconds, and the rest are given 0.1 seconds
|
|
|
ebcf82 |
+ */
|
|
|
ebcf82 |
+ if (i < 5) {
|
|
|
ebcf82 |
+ interval.tv_usec = 400000;
|
|
|
ebcf82 |
+ } else if (i < 10) {
|
|
|
ebcf82 |
+ interval.tv_usec = 200000;
|
|
|
ebcf82 |
} else {
|
|
|
ebcf82 |
- interval.tv_sec = 1;
|
|
|
ebcf82 |
- interval.tv_usec = 0;
|
|
|
ebcf82 |
+ interval.tv_usec = 100000;
|
|
|
ebcf82 |
}
|
|
|
ebcf82 |
+ select (0, NULL, NULL, NULL, &interval);
|
|
|
ebcf82 |
+
|
|
|
ebcf82 |
+ parsed = ldap_disco_poller (&(ldap[i]), &message, results, &(addrs[i]));
|
|
|
ebcf82 |
+ if (parsed > found)
|
|
|
ebcf82 |
+ found = parsed;
|
|
|
ebcf82 |
+ }
|
|
|
ebcf82 |
+
|
|
|
ebcf82 |
+ /* Wait some more until LDAP timeout (DISCO_TIME) */
|
|
|
ebcf82 |
+ for (started = now = time (NULL);
|
|
|
ebcf82 |
+ have_any && ADCLI_DISCO_UNUSABLE == found && now < started + DISCO_TIME;
|
|
|
ebcf82 |
+ now = time (NULL)) {
|
|
|
ebcf82 |
|
|
|
ebcf82 |
select (0, NULL, NULL, NULL, &interval);
|
|
|
ebcf82 |
|
|
|
ebcf82 |
have_any = 0;
|
|
|
ebcf82 |
- for (i = 0; found != ADCLI_DISCO_USABLE && i < num; i++) {
|
|
|
ebcf82 |
- int close_ldap;
|
|
|
ebcf82 |
+ for (i = 0; ADCLI_DISCO_UNUSABLE == found && i < num; ++i) {
|
|
|
ebcf82 |
int parsed;
|
|
|
ebcf82 |
|
|
|
ebcf82 |
if (ldap[i] == NULL)
|
|
|
ebcf82 |
continue;
|
|
|
ebcf82 |
|
|
|
ebcf82 |
- ret = 0;
|
|
|
ebcf82 |
have_any = 1;
|
|
|
ebcf82 |
- switch (ldap_result (ldap[i], LDAP_RES_ANY, 1, &tvpoll, &message)) {
|
|
|
ebcf82 |
- case LDAP_RES_SEARCH_ENTRY:
|
|
|
ebcf82 |
- case LDAP_RES_SEARCH_RESULT:
|
|
|
ebcf82 |
- parsed = parse_disco (ldap[i], addrs[i], message, results);
|
|
|
ebcf82 |
- if (parsed > found)
|
|
|
ebcf82 |
- found = parsed;
|
|
|
ebcf82 |
- ldap_msgfree (message);
|
|
|
ebcf82 |
- close_ldap = 1;
|
|
|
ebcf82 |
- break;
|
|
|
ebcf82 |
- case 0:
|
|
|
ebcf82 |
- ret = ldap_search_ext (ldap[i], "", LDAP_SCOPE_BASE,
|
|
|
ebcf82 |
- filter, attrs, 0, NULL, NULL, NULL,
|
|
|
ebcf82 |
- -1, &msgidp);
|
|
|
ebcf82 |
- close_ldap = (ret != 0);
|
|
|
ebcf82 |
- break;
|
|
|
ebcf82 |
- case -1:
|
|
|
ebcf82 |
- ldap_get_option (ldap[i], LDAP_OPT_RESULT_CODE, &ret;;
|
|
|
ebcf82 |
- close_ldap = 1;
|
|
|
ebcf82 |
- break;
|
|
|
ebcf82 |
- default:
|
|
|
ebcf82 |
- ldap_msgfree (message);
|
|
|
ebcf82 |
- close_ldap = 0;
|
|
|
ebcf82 |
- break;
|
|
|
ebcf82 |
- }
|
|
|
ebcf82 |
-
|
|
|
ebcf82 |
- if (ret != LDAP_SUCCESS) {
|
|
|
ebcf82 |
- _adcli_ldap_handle_failure (ldap[i], ADCLI_ERR_CONFIG,
|
|
|
ebcf82 |
- "Couldn't perform discovery search");
|
|
|
ebcf82 |
- }
|
|
|
ebcf82 |
|
|
|
ebcf82 |
- /* Done with this connection */
|
|
|
ebcf82 |
- if (close_ldap) {
|
|
|
ebcf82 |
- ldap_unbind_ext_s (ldap[i], NULL, NULL);
|
|
|
ebcf82 |
- ldap[i] = NULL;
|
|
|
ebcf82 |
- }
|
|
|
ebcf82 |
+ parsed = ldap_disco_poller (&(ldap[i]), &message, results, &(addrs[i]));
|
|
|
ebcf82 |
+ if (parsed > found)
|
|
|
ebcf82 |
+ found = parsed;
|
|
|
ebcf82 |
}
|
|
|
ebcf82 |
}
|
|
|
ebcf82 |
|
|
|
ebcf82 |
--
|
|
|
ebcf82 |
2.26.2
|
|
|
ebcf82 |
|