joeware - never stop exploring... :)

Information about joeware mixed with wild and crazy opinions...

Finding Domain Controllers on Windows using Windows API (DsGetDC.h) Calls the Long Way

by @ 11:31 pm on 12/7/2018. Filed under tech

1. Determine if your application has been configured to use a specific named Domain Controller, 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, do not Autodiscover site.

    a. For debugging purposes only

    b. Application specific (where do you keep your configuration info?)

3. If you do not have a hard-coded site and want to retrieve the name of site that your machine is in you can call DsGetSiteName

    a. Note that this is NOT required, the API calls later do not need to have the site name fed to them. If no sitename is specified the API will find the current site under the covers for you.

    b. Useful for logging

    c. DWORD dwRV=DsGetSiteName(strComputerName, &strSiteName);

    d. strComputerName can be NULL if you are running from a machine joined to any domain in the forest that you are working on. If you are trying to get information for a domain in a different forest you will need to specify a machine (or domain FQDN) in the foreign forest.

    e. If the machine has a cached site or is hardcoded to use a specific site this API call will honor that configuration.

        i. This hardcoding of the site on Windows is done via the REG_SZ registry value named "SiteName" under the following registry key:

           1. HKLM\System\CurrentControlSet\Services\NetLogon\Parameters.

4. Retrieve a single domain controller for the site using DsGetDcName.

    a. Use this if you trust Windows to give you the perfect domain controller right off the bat.

    b. DWORD dwRV=DsGetDcName(strComputerName, strDomainName, NULL, strSiteName, ulFlags, &DCInfo);

        i. strComputerName can be NULL if you are running from a machine joined to any domain in the forest that you are working on. If you are trying to get information for a domain in a different forest you will need to specify a machine (or domain FQDN) in the foreign forest.

        ii. strSiteName is optional, if it is not specified the API will look at any client level hardcoding and/or caching or even back out to any domain controller in the entire domain if nothing else is available. If you do specify a site and you get to step 10 without any valid functioning domain controllers execute this call without specifying a site.

        iii. ulFlags is used to specify the requirements for the domain controller functionality.

5. Retrieve a set of domain controllers for the site using DsGetDcOpen and DsGetDcNext to produce a list of possible candidates.

    a. Use this to get a pool of domain controllers to perform your own validation on or to spread connections across

    b. You need to call DsGetDcOpen to get a handle and then loop through the returned domain controllers with DsGetDcNext.

        i. DWORD dwRV=DsGetDcOpen(strDomainName, DS_ONLY_DO_SITE_NAME, strSiteName, NULL, NULL, ulFlags, &getDCCxt);

        ii. DWPRD dwRV=DsGetDcNext(getDCCxt, NULL, NULL, &DnsHostName);

        iii. strSiteName is optional, if it is not specified the API will look at any client level hardcoding and/or caching or even back out to any domain controller in the entire domain if nothing else is available. If you do specify a site and you get to step 10 without any valid functioning domain controllers execute this call without specifying a site.

        iv. ulFlags is used to specify the requirements for the domain controller functionality.

6. If you only retrieved a single domain controller in Step 4 continue with your trusting model, log it and just start using it.

7. Retrieve the PDC for the domain you are trying to find a domain controller for and exclude it from your list of domain controllers unless it is the only domain controller in your list.

    a. As in step 5 use DsGetDCOpen and use the Options Flag DS_PDC_REQUIRED.

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 tested 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.

9. Optionally look up the SRV records for the domain controllers you are using to determine their priority and merge that info with the list of best performing domain controllers.

10. Select as many of the domain controllers as you need (current use and spares) from the prioritized list.

      a. If you get here without any valid functional domain controllers loop back up to step 4 or 5 and don’t specify a site.

11. Use domain controller(s) from list based on previous sorting and if using multiple LDAP connections 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.

    joe

Rating 4.71 out of 5

2 Responses to “Finding Domain Controllers on Windows using Windows API (DsGetDC.h) Calls the Long Way”

  1. Klaus Wagtberg says:

    Hi Joe,

    This is a great explanation – we get a lot of questions that can be answered directly by this description.

    Do you have any code snippets available, that could be used to demo the steps?

    Best regards,

    /klaus

    • joe says:

      Hi Klause,

      No code to share at the moment but I am considering it. It is a lot of work because I would want it to be good enough to plug into massive scaling apps because I know how stuff works around code posted to the internet.

      joe

[joeware – never stop exploring… :) is proudly powered by WordPress.]