1. Determine if your application has been configured to use a specific named Domain Controller, if so use it.
a. For debugging purposes only
b. Application specific (where do you keep your configuration info?)
2. Determine if your application has been configured to use a specific named Site at startup, if so do not Autodiscover site.
a. For debugging purposes only
b. Application specific (where do you keep your configuration info?)
3. Determine if your client has been configured (hardcoded) to use a specific AD Site.
a. For debugging purposes only
b. Platform specific
i. Windows
1. REG_SZ registry value "SiteName" under HKLM\System\CurrentControlSet\Services\NetLogon\Parameters
4. Determine if your client has "cached" a previously used AD Site.
a. Used to improve efficiency
b. Platform specific
i. Windows
1. REG_SZ registry value "DynamicSiteName" under HKLM\System\CurrentControlSet\Services\NetLogon\Parameters
5. If you have not ascertained the site from steps 1-4 then you need to dynamically determine the site the machine is in before you can request the DNS records for the closest site.
a. Active Directory supports an anonymous UDP (optionally TCP) RootDSE query to return basic information from Active Directory. This is generally called an LDAP “Ping” and is part of the DC Locator process used by all Windows machines. This will be the subject of a future blog post.
b. To find an initial domain controller to bootstrap this step you can either use the domain FQDN or perform a DNS SRV lookup of the _ldap._tcp.<DOMAIN FQDN> record as illustrated in step 6c. Be prepared to be able to use either/or because it is possible that some “unique” local design decisions could make one or the other unavailable with the domain group host record FQDN being the most likely to be unavailable. If both are unavailable you probably have no choice but to ask someone in the AD space for a bootstrap server.
c. The LDAP “Ping” query will return useful information about the domain controller including:
i. DC Flags
1. Some examples:
a. Is the PDC
b. Is in the same site as client
c. Is Writable
d. Is RODC
e. DS Major version (DS_6,DS_7,DS_10, etc)
ii. Forest Name
iii. Domain Name
iv. DNS HostName of Domain Controller
v. IP address of Domain Controller
vi. NetBIOS Domain Name
vii. NetBIOS Domain Controller Name
viii. Site Name of Domain Controller
ix. Site Name of Client
d. LDAP Search parameters
i. IP Protocol: Either but UDP is lighter/faster and way fewer packets (duh)
ii. Search Credentials: Anonymous
iii. Search Base: NULL
iv. Search Scope: BASE
v. Search Filter: (&(DnsDomain=FQDN)(NtVer=\FF\00\00\00))
1. Really this value varies based on options.
vi. Search Attributes to return: NetLogon
e. The NetLogon attribute returned is a BLOB attribute. The structures of the BLOBs that can be returned are dependent on NtVer parameter in the LDAP query and details are available in the link in the next bullet.
f. Additional Detail can be found in the MS-ADTS: Active Directory Technical Specification of the Windows Protocol documents, specifically section 6.3 under Structures and Constants and LDAP Ping
i. https://msdn.microsoft.com/en-us/library/cc223799.aspx
6. Retrieve a list of the domain controllers or global catalog domain controllers servicing the site (previously determined) for the domain we need a domain controller for from DNS.
a. Domain Controllers:
i. Query DNS for SRV records
1. _ldap._tcp.<SITENAME>._sites.dc._msdcs.<DOMAIN FQDN>.
2. You want hostnames, priority, and weight.
3. Example using nslookup
a. nslookup -type=srv _ldap._tcp.site2._sites.dc._msdcs.child.k16tst.test.loc
b. Global Catalogs:
i. Query DNS for SRV records
1. _gc._tcp.<SITENAME>._sites.<FOREST ROOT FQDN>.
2. You want hostnames, priority, and weight.
3. Example using nslookup
a. nslookup -type=srv _gc._tcp.site2._sites.k16tst.test.loc
c. If no domain controllers are found in the site you need that fit your criteria you will either have to select a different site OR open your location process to ANY domain controller in the domain.
i. Query DNS for SRV records
1. _ldap._tcp.<DOMAIN FQDN>
2. You want hostnames, priority, and weight.
3. Example using nslookup
a. nslookup -type=srv _ldap._tcp. child.k16tst.test.loc
d. If no Global Catalogs are found in the site you need that fit your criteria you will either have to select a different site OR open your location process to ANY global catalog in the entire forest.
i. Query DNS for SRV records
1. _gc._tcp.<DOMAIN FQDN>
2. You want hostnames, priority, and weight.
3. Example using nslookup
a. nslookup -type=srv _gc._tcp.k16tst.test.loc
7. Find the PDC for the domain of the domain controllers you are looking at and exclude it from your list of domain controllers for consideration UNLESS that is the only domain controller available in the site that meets your criteria.
a. Query DNS for SRV records
i. _ldap._tcp.pdc._msdcs.<DOMAIN FQDN>
ii. Example using nslookup
1. nslookup -type=srv _ldap._tcp.pdc._msdcs.k16tst.test.loc
8. Validate the list of domain controllers to produce a final list of functioning validated domain controllers sorted by validation performance and DNS SRV record priority.
a. Validation can vary greatly based on needs. Some minimal validation steps to consider:
i. Anonymous UDP LDAP Ping or other basic RootDSE query with short timeout (1 second – configurable)
1. This should be a configuration that can optionally be disabled in case UDP 389 is blocked.
2. Better than ICMP ping because ping is often blocked by firewalls.
3. Track response time.
ii. Anonymous TCP RootDSE query with short timeout (1 second – configurable)
1. TCP should be used because all normal requests will be TCP based.
2. Track response time.
3. Validate isSynchronized is TRUE
4. Validate isGlobalCatalogReady is TRUE if looking for GC.
5. Validate defaultNamingContext is what you need if not looking for GC.
6. Validate supportedControl if any special needs.
7. Validate forestFunctionality if specific forest mode is needed
8. Validate domainFunctionality if specific domain mode is needed
9. Validate domainControllerFunctionality if specific domain controller mode is needed
iii. If using LDAPS for binds/queries perform an LDAPS RootDSE query with short timeout (1 second – configurable)
1. Validates that LDAPS is functioning.
a. LDAP could be working fine between client and server and LDAPS not be working because of a multitude of reasons
b. Great for troubleshooting (LDAP works but LDAPS doesn’t)
2. Performance of LDAPS varies from LDAP, more overhead on client and domain controller.
3. Track response time.
b. If no domain controllers (or Global Catalogs if that is what you are looking for) pass your criteria validation checks then you need to go back to step 6 and either use a different site OR look up machines for the whole domain or forest as indicated.
9. Merge the list of the highest performing domain controllers with the DNS SRV record priority.
10. Select as many of the domain controllers as you need (current use and spares) from the highest performing domain controllers.
11. Use domain controller(s) from list based on previous sorting and if using multiple LDAP connections also by DNS SRV record weight (if available).
12. Repeat the process regularly (every few hours) or anytime you hit a failure to connect or return a result set or performance drags.
And you can see why most applications simply ask for a single IP. Doing it right is hard, unless you’re able to leverage the libraries that do it right for you.
I disagree, it isn’t very hard, especially when you consider that other LDAP directories are using SRV records now too. It goes back to what I said back earlier, if they can’t handle this level of work and doing it right, can you depend on the rest of their code?
Great series, thank you!