joeware - never stop exploring... :)

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

3/31/2019

LDAP Ping and Determining Your Machine’s Site

by @ 8:09 pm. Filed under tech

Microsoft has a specific method for returning basic information that can be used for finding what site (and what is the next closest site) for any given machine that reaches out to a domain controller with a LDAP query. Originally the query had to be performed over CLDAP (connectionless LDAP aka UDP LDAP) but sometime in the Windows Server 2003 timeframe it became available via both UDP and TCP. Personally I like the TCP ping over the UDP ping because no applications are actually using UDP to use AD and this functionality.

The "ping" is a specially crafted anonymous LDAP query that retrieves the NetLogon attribute from the RootDSE of a Domain Controller which then returns the attribute in one of several available BLOB formats. The information returned useful for bootstrapping and validation and in particular for this specific topic, finding out which AD site the client is in. The "LDAP Ping" is documented fully in section 6.3 “Publishing and Locating a Domain Controller” of the Microsoft MS-ADTS Protocol Documentation including the various BLOB structures. Note that when it says something is Big-Endian, pay attention, it is critical to getting a response back.

The key pages are:

6.3 Publishing and Locating a Domain Controller   — Base of all of the documentation

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/8ebcf782-87fd-4dc3-8585-1301569dfe4f

6.3.1 Structures and Constants

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/b3006506-4338-45ef-ac52-1e7d5c9c46e9

6.3.3. LDAP Ping

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/895a7744-aff3-4f64-bcfa-f8c05915d2e9

6.3.7 Name Compression and Decompression

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/b0ef9479-78d8-40c1-b6d2-0baad834ed39

I will be releasing a full platform agnostic anonymous DC Locator perl script in the relatively near term that has this implemented as part of the code along with the DNS lookups and some validation tests. I also have generated some notes and a DCR to implement the decoding of this data in AdFind as well. As it is, this is what AdFind will show you right now if you attempt to query for this information:

[Fri 03/29/2019 23:07:04.51]
E:\DEV\Schema>adfind -rootdseanon -f "&(host=k16tst-dc1)(ntver=\04\00\00\00)" -s one netlogon

AdFind V01.51.00cpp Joe Richards (support@joeware.net) October 2017

Using server: K16TST-DC1.k16tst.test.loc:389
Directory: Windows Server 2016

dn:
> netlogon: 1700 0000 FDF1 0100 9011 FD98 67E1 3447 A585 7981 238A 135E 066B 3136 7473 7404 7465 7374 036C 6F63 00C0 180A 4B31 3654 5354 2D44 4331 C018 064B 3136 5453 5400 0A4B 3136 5453 542D 4443 3100 0017 4465 6661 756C 742D 4669 7273 742D 5369 7465 2D4E 616D 6500 136A 6F65 6E65 746C 6F67 6F6E 7465 7374 7369 7465 0005 0000 00FF FFFF FF

1 Objects returned

This is what WireShark will show you:

SNAGHTML4475a203

Now you can also implement the “next closest site” functionality as well with the following query (and this is what jwDCLocator.pl uses)… With this one I needed to specify a specific DC in another site as well as change the ntver attribute value to include NETLOGON_NT_VERSION_WITH_CLOSEST_SITE so that the proper extra info would be sent along…

[Fri 03/29/2019 23:08:14.64]
E:\DEV\Schema>adfind -hh k16tst-scdc1.k16tst.test.loc -rootdseanon -f "&(host=k16tst-scdc1)(ntver=\14\00\00\00)" -s one netlogon

AdFind V01.51.00cpp Joe Richards (support@joeware.net) October 2017

Using server: K16TST-SCDC1.k16tst.test.loc:389
Directory: Windows Server 2016

dn:
> netlogon: 1800 0000 7CF1 0100 9011 FD98 67E1 3447 A585 7981 238A 135E 066B 3136 7473 7404 7465 7374 036C 6F63 00C0 180C 4B31 3654 5354 2D53 4344 4331 C018 064B 3136 5453 5400 0C4B 3136 5453 542D 5343 4443 3100 0005 5369 7465 3200 136A 6F65 6E65 746C 6F67 6F6E 7465 7374 7369 7465 0017 4465 6661 756C 742D 4669 7273 742D 5369 7465 2D4E 616D 6500 1500 0000 FFFF FFFF

1 Objects returned

Unfortunately WireShark gets lost for this extra data and so it doesn’t display really anything…

SNAGHTML4478f6bb

But if you look down in the packet bytes data you will see it…

SNAGHTML4479c064

which you can see three site names in it…

And of course jwDCLocator.pl knows how to decode it properly…

Dynamically determining site…
  Sending LDAP Ping to LDAP://k16tst-scdc1.k16tst.test.loc:389…
  AutoDetected Server Site             : Site2
  AutoDetected Client Site             : joenetlogontestsite
  AutoDetected Client Next Closest Site: Default-First-Site-Name
Determining site specific DNS records…

The binary (with and without the closest site flag in the query) is described by the structure that can be found at

6.3.1.9 NETLOGON_SAM_LOGON_RESPONSE_EX

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/8401a33f-34a8-40ca-bf03-c3484b66265f

Extracting the information from this structure is not quite as straightforward as what you normally get in that they are compressing the names as described in RFC 1035 – “Domain Names – Implementation and Specification” which is further described in the page mentioned above, 6.3.7 Name Compression and Decompression. Note that when I was writing my perl script I hadn’t seen this page yet so I just looked at the binary and shook my head a few times to clear cobwebs and reversed it out. That means that my original perl script may be implemented slightly differently than what is described and it also means I cannot actually vouchsafe for the pseudocode given on the page so if you use it directly, validate it versus just assume it is 100%. But that goes for all documentation from all vendors at all times. Smile 

Note that Perl has some functionality in the Net::DNS module that will decode these for you but I wanted to be as raw as possible in the code to allow people to be able to take the code and change to any language, framework, platform they wanted and be able to do something. Hiding some of the details like this by using other modules defeats that mindset a little.

Now for some samples from jwDCLocator.pl decoding some of compressed string in the structure. As the structure is decoded, a table will be created with strings that are referred to, this is used for the “compression” functionality. If the string isn’t in the table already you will get a length value and the string. If part of the string is in the table (as part of another string response) then you will get whatever part is unique as the length and string and then a pointer to the rest of the string. For clarity of the following examples, this is the table that gets built in memory as the structure is unpacked:

’24’ => ‘k16tst.test.loc’,
’41’ => ‘k16tst.test.loc’,
’43’ => ‘K16TST-SCDC1.k16tst.test.loc’,
’58’ => ‘K16TST’,
’66’ => ‘K16TST-SCDC1’
’80’ => ”,
’81’ => ‘Site2’,
’88’ => ‘joenetlogontestsite’,
‘109’ => ‘Default-First-Site-Name’,

First, the DNS Forest Name.

SNAGHTML4cf5c580

20190331-144158.89286: DEBUG: NETLOGON REMAINING=066b31367473740474657374036c6f6300c0180a4b313654535
                                                  42d444332c018064b3136545354000a4b31365453542d444332
                                                 000005536974653200136a6f656e65746c6f676f6e746573747
                                                  3697465001744656661756c742d46697273742d536974652d4e
                                                  616d650015000000ffffffff
  20190331-144158.89290: DEBUG: Enter GetCompressedName…
  20190331-144158.89293: DEBUG: +++++++++++++++++++++
  20190331-144158.89296: DEBUG: Start Data     : 066b31367473740474657374036c6f6300c0180a4b3136545354
                                                 2d444332c018064b3136545354000a4b31365453542d44433200
                                                 0005536974653200136a6f656e65746c6f676f6e746573747369
                                                 7465001744656661756c742d46697273742d536974652d4e616d
                                                 650015000000ffffffff
  20190331-144158.89299: DEBUG: Enter GetXChars…
  20190331-144158.89303: DEBUG: Short Hint     : 0
  20190331-144158.89306: DEBUG: Enter GetXChars…
  20190331-144158.89309: DEBUG: Full Hint      : 06
  20190331-144158.89313: DEBUG: Enter GetXChars…
  20190331-144158.89317: DEBUG: Enter HexToASCII…
  20190331-144158.89322: DEBUG: String         : k16tst
  20190331-144158.89330: DEBUG: Full String    : k16tst.
  20190331-144158.89338: DEBUG: ———————
  20190331-144158.89346: DEBUG: +++++++++++++++++++++
  20190331-144158.89352: DEBUG: Start Data     : 0474657374036c6f6300c0180a4b31365453542d444332c018064
                                                 b3136545354000a4b31365453542d444332000005536974653200
                                                 136a6f656e65746c6f676f6e74657374736974650017446566617
                                                 56c742d46697273742d536974652d4e616d650015000000ffffff
                                                ff
  20190331-144158.89357: DEBUG: Enter GetXChars…
  20190331-144158.89364: DEBUG: Short Hint     : 0
  20190331-144158.89370: DEBUG: Enter GetXChars…
  20190331-144158.89376: DEBUG: Full Hint      : 04
  20190331-144158.89382: DEBUG: Enter GetXChars…
  20190331-144158.89388: DEBUG: Enter HexToASCII…
  20190331-144158.89395: DEBUG: String         : test
  20190331-144158.89401: DEBUG: Full String    : k16tst.test.
  20190331-144158.89407: DEBUG: ———————
  20190331-144158.89413: DEBUG: +++++++++++++++++++++
  20190331-144158.89418: DEBUG: Start Data     : 036c6f6300c0180a4b31365453542d444332c018064b313654535
                                                 4000a4b31365453542d444332000005536974653200136a6f656e
                                                65746c6f676f6e7465737473697465001744656661756c742d466
                                                 97273742d536974652d4e616d650015000000ffffffff
  20190331-144158.89424: DEBUG: Enter GetXChars…
  20190331-144158.89431: DEBUG: Short Hint     : 0
  20190331-144158.89437: DEBUG: Enter GetXChars…
  20190331-144158.89451: DEBUG: Full Hint      : 03
  20190331-144158.89456: DEBUG: Enter GetXChars…
  20190331-144158.89459: DEBUG: Enter HexToASCII…
  20190331-144158.89463: DEBUG: String         : loc
  20190331-144158.89466: DEBUG: Full String    : k16tst.test.loc.
  20190331-144158.89468: DEBUG: ———————
  20190331-144158.89471: DEBUG: +++++++++++++++++++++
  20190331-144158.89474: DEBUG: Start Data     : 00c0180a4b31365453542d444332c018064b3136545354000a4b3
                                                1365453542d444332000005536974653200136a6f656e65746c6f
                                                 676f6e7465737473697465001744656661756c742d46697273742
                                                 d536974652d4e616d650015000000ffffffff
  20190331-144158.89478: DEBUG: Enter GetXChars…
  20190331-144158.89481: DEBUG: Short Hint     : 0
  20190331-144158.89484: DEBUG: Enter GetXChars…
  20190331-144158.89486: DEBUG: Full Hint      : 00
  20190331-144158.89490: DEBUG: FINAL Full String: k16tst.test.loc

And here is the cool part… On the next bit, getting the DNS Domain Name

SNAGHTML4d0097b4

20190328-220801.19632: DEBUG: Enter GetCompressedName…
20190328-220801.19635: DEBUG: +++++++++++++++++++++
20190328-220801.19638: DEBUG: Start Data     : c0180a4b31365453542d444331c018064b3136545354000a4b3136
                                               5453542d44433100001744656661756c742d46697273742d536974
                                                652d4e616d6500136a6f656e65746c6f676f6e7465737473697465
                                                00c04d15000000ffffffff
20190328-220801.19641: DEBUG: Enter GetXChars…
20190328-220801.19644: DEBUG: Short Hint     : c
20190328-220801.19646: DEBUG: Enter GetXChars…
20190328-220801.19649: DEBUG: Compression Offset — 0x0018 — 24
20190328-220801.19652: DEBUG: FINAL Full String: k16tst.test.loc

And then the Host’s FQDN…

SNAGHTML4d029b74

20190328-220801.19666: DEBUG: Enter GetCompressedName…
20190328-220801.19667: DEBUG: +++++++++++++++++++++
20190328-220801.19668: DEBUG: Start Data     : 0a4b31365453542d444331c018064b3136545354000a4b31365453
                                                542d44433100001744656661756c742d46697273742d536974652d
                                                4e616d6500136a6f656e65746c6f676f6e746573747369746500c0
                                                4d15000000ffffffff
20190328-220801.19669: DEBUG: Enter GetXChars…
20190328-220801.19670: DEBUG: Short Hint     : 0
20190328-220801.19671: DEBUG: Enter GetXChars…
20190328-220801.19672: DEBUG: Full Hint      : 0a
20190328-220801.19673: DEBUG: Enter GetXChars…
20190328-220801.19674: DEBUG: Enter HexToASCII…
20190328-220801.19676: DEBUG: String         : K16TST-DC1
20190328-220801.19677: DEBUG: Full String    : K16TST-DC1.
20190328-220801.19678: DEBUG: ———————
20190328-220801.19679: DEBUG: +++++++++++++++++++++
20190328-220801.19680: DEBUG: Start Data     : c018064b3136545354000a4b31365453542d444331000017446566
                                                61756c742d46697273742d536974652d4e616d6500136a6f656e65
                                                746c6f676f6e746573747369746500c04d15000000ffffffff
20190328-220801.19681: DEBUG: Enter GetXChars…
20190328-220801.19682: DEBUG: Short Hint     : c
20190328-220801.19683: DEBUG: Enter GetXChars…
20190328-220801.19684: DEBUG: Compression Offset — 0x0018 — 24
20190328-220801.19685: DEBUG: FINAL Full String: K16TST-DC1.k16tst.test.loc

Rating 4.64 out of 5

3/26/2019

And FreeBSD12 has been tested…

by @ 10:34 pm. Filed under perl, tech

No changes to the script…

$ uname -mrs
FreeBSD 12.0-RELEASE amd64
$ perl jwDCLocator_linux.pl /domain:k16tst.test.loc

jwDCLocator V01.02.00pl  Joe Richards (support@joeware.net)  March 2019

Initializing Logging to logfile 20190326-2229-jwDCLocator.log…
Reading configuration file jwDCLocator.config…
Configuration file does not exist, skipping…
Determining bootstrap domain controllers via DNS for k16tst.test.loc…
  BootStrap Hosts: k16tst-dc1.k16tst.test.loc k16tst-scdc1.k16tst.test.loc k16tst-dc2.k16tst.test.loc
Dynamically determining site…
  Sending LDAP Ping to LDAP://k16tst-dc1.k16tst.test.loc:389…
  AutoDetected Server Site             : Default-First-Site-Name
  AutoDetected Client Site             : Site2
  AutoDetected Client Next Closest Site: Default-First-Site-Name
Determining site specific DNS records…
Dynamically determining domain k16tst.test.loc site specific domain controllers for site Site2…
Dynamically determining domain k16tst.test.loc site specific domain controllers for site Default-First-Site-Name…
Validating DCs for Site2…(Order=0)
      k16tst-dc2.k16tst.test.loc…
        TCP LDAP PING…
          Sending LDAP Ping to LDAP://k16tst-dc2.k16tst.test.loc:389…
          DC Site     = Site2
          ElapsedTime = 0.006692
     Retrieving RootDSE…
          Synchronized = TRUE
          ElapsedTime  = 0.021649
      k16tst-scdc1.k16tst.test.loc…
        TCP LDAP PING…
          Sending LDAP Ping to LDAP://k16tst-scdc1.k16tst.test.loc:389…
          DC Site     = Site2
          ElapsedTime = 0.006101
     Retrieving RootDSE…
          Synchronized = TRUE
          ElapsedTime  = 0.017424
Validating DCs for Default-First-Site-Name…(Order=1)
       k16tst-dc1.k16tst.test.loc…
        TCP LDAP PING…
           Sending LDAP Ping to LDAP://k16tst-dc1.k16tst.test.loc:389…
          DC Site     = Default-First-Site-Name
          ElapsedTime = 0.013375
     Retrieving RootDSE…
          Synchronized = TRUE
          ElapsedTime  = 0.037377
Checking Validation List for PDC domain controllers
Ordering DCs by Site | Priority | Avg Elapsed Response Time…
Sorted Validated Domain Controller List
k16tst-dc2.k16tst.test.loc
k16tst-scdc1.k16tst.test.loc
k16tst-dc1.k16tst.test.loc

The command completed.
$

Rating 3.00 out of 5

3/22/2019

So very close… Reasonable Effort Platform Agnostic Perl Script That Implements the Active Directory DC Locator Process…

by @ 12:09 am. Filed under perl, tech

Getting very close to being ready to release the reasonable effort platform agnostic version perl script that will run through the DC Locator process.

Note that I intend for this to be a fairly robust script. It finds server (domain controller) site, client site, and next closest site. It polls the DCs validating them to make sure they are responding (so not behind a firewall or otherwise not responding) and have other specific items right (obviously you could tweak the validation rules as you need[1]). Once it has a list and validates the DCs on the list it then rates them based on response time performance and DNS Priority. If using multiple DCs to load balance multiple requests to multiple domain controllers (highly recommended for performance and stability for reads) you can easily see how to add in weighting logic.

The code is extremely long winded (nearly 2000 lines) with lots of comments and whitespace to make it mostly readable so people can take it and use any parts of it that are desired and convert to whatever languages are needed. The actual hardcore parts of it could be easily reduced down and in fact yanked out and put into other code. In fact that is the whole intent. In part of the code I actually have comments of:

#
# Function AnonLDAPPing
#  Requires the Net::LDAP module
#   This is where the totally cool stuff starts!!!
#   No seriously, I don’t think I have ever seen
#   this in simple basic open code anywhere before. It
#   uses the same dynamic underlying processes to
#   determine the site the client is in that is used
#   by Windows.
#  
#
sub AnonLDAPPing

Oh and that AnonLDAPPing function… It works over TCP, it doesn’t use UDP like everyone else I have seen. That is so if you have a network that likes to chop down UDP packets you don’t have to care about it. Also I think using TCP to perform the ping and get the response timings is more realistic anyway. You can change it to UDP if you like… I don’t care. Depending on the language you use it could be more or less painful.

I spent a little time the last couple of nights building a new CentOS 7 server and spending time trying to get reacquainted with CentOS and upgrading perl to 5.26. I need to do the same with FreeBSD12.0 next. Once I get done with FreeBSD12.0 then I will wrap up the specifics needed for each (use/requires/modules that need to be loaded[2]) so I can put it all in a single script. This has taken longer than expected as my real job has been excessively involved the last few months and even more so the last few weeks. I have to say writing my “for fun” code keeps me sane though. Who knows how long ago my brain would have melted down from nearly 25 years working in the Enterprise Class Fortune X company space. My first Enterprise job was at Ford when it was in the Fortune and Global 5 category, I have been in the Fortune/Global 30 or bigger since. Now I am back up in the Fortune/Global 5 again.  

I will expand more about support of the script when I finally release it but short and simple… this will be unsupported code. If you have questions you will be able to send them, I might respond; if you dump a bunch of money into my tip jar, I might be more likely to respond. The times people have done that I don’t think they have been disappointed, though “a bunch” is my definition. Smile  Anyway, my previous forays into shared source code went horribly with people making changes and compiling and then expecting me to figure out what was wrong while not telling me they changed something. I have learned a lot since then and released the perl script rdp_sec_check which was a modification of another security teams tool that made it more useful for me and I didn’t have any issues with that but just the same I still have a bad taste in my mouth about that initial code sharing… I do have to admit though that sharing this code could be VERY USEFUL for people who still need to find domain controllers since the free stuff out there, and quite frankly a lot of the expensive stuff, either can’t do this work or can’t do it well (or absolutely in a pretty shitty half ass dip the toe in the water to say they did it manner).

Good day and may the good news be yours. Just kidding

    joe

[1] …say you are pretending to be a Windows Hello for Business Client in Hybrid Key Mode and can only use Windows Server 2016 domain controllers because earlier stuff can’t process the WH4B commands properly and the later stuff (Windows Server 2019) has a code regression bug that doesn’t allow it to work either (allegedly)…

[2] There is currently, and literally, one single “use” line commented out of nearly 2000 lines of script in the CentOS7 version compared to the Windows version and I intend to get that handled so there is no difference.

Windows 10 Pro 1809

[Thu 03/21/2019 23:01:19.71]
E:\DEV\perl\jwDCLocator>perl jwDCLocator.pl /domain:k16tst.test.loc

jwDCLocator V01.01.00pl  Joe Richards (support@joeware.net)  March 2018

Initializing Logging to logfile 20190321-2301-jwDCLocator.log…
Reading configuration file jwDCLocator.config…
Processing configuration file…
Configuration file does not exist, skipping…
Determining bootstrap domain controllers via DNS for k16tst.test.loc…
  BootStrap Hosts: k16tst-scdc1.k16tst.test.loc k16tst-dc2.k16tst.test.loc k16tst-dc1.k16tst.test.loc
Dynamically determining site…
  Sending LDAP Ping to LDAP://k16tst-scdc1.k16tst.test.loc:389…
  AutoDetected Server Site             : Site2
  AutoDetected Client Site             : joenetlogontestsite
  AutoDetected Client Next Closest Site: Default-First-Site-Name
Determining site specific DNS records…
Dynamically determining domain k16tst.test.loc site specific domain controllers for site joenetlogontestsite…
Dynamically determining domain k16tst.test.loc site specific domain controllers for site Default-First-Site-Name…
Validating DCs for joenetlogontestsite…(Order=0)
      k16tst-dc1.k16tst.test.loc…
        TCP LDAP PING…
           Sending LDAP Ping to LDAP://k16tst-dc1.k16tst.test.loc:389…
          DC Site     = Default-First-Site-Name
          ElapsedTime = 0.011377
     Retrieving RootDSE…
          Synchronized = TRUE
          ElapsedTime  = 0.010118
Validating DCs for Default-First-Site-Name…(Order=1)
      k16tst-dc1.k16tst.test.loc…
        TCP LDAP PING…
          Sending LDAP Ping to LDAP://k16tst-dc1.k16tst.test.loc:389…
          DC Site     = Default-First-Site-Name
          ElapsedTime = 0.008036
      Retrieving RootDSE…
          Synchronized = TRUE
          ElapsedTime  = 0.008876
Checking Validation List for PDC domain controllers
Ordering DCs by Site | Priority | Avg Elapsed Response Time…
Sorted Validated Domain Controller List
k16tst-dc1.k16tst.test.loc
k16tst-dc1.k16tst.test.loc

The command completed.

CentOS Linux release 7.6.1810 (Core)

[joe@centos7-1 AD]$

[joe@centos7-1 AD]$ perl jwDCLocator_linux.pl /domain:k16tst.test.loc

jwDCLocator V01.02.00pl  Joe Richards (support@joeware.net)  March 2018

Initializing Logging to logfile 20190321-2329-jwDCLocator.log…
Reading configuration file jwDCLocator.config…
Processing configuration file…
Configuration file does not exist, skipping…
Determining bootstrap domain controllers via DNS for k16tst.test.loc…
  BootStrap Hosts: k16tst-dc1.k16tst.test.loc k16tst-scdc1.k16tst.test.loc k16tst-dc2.k16tst.test.loc
Dynamically determining site…
  Sending LDAP Ping to LDAP://k16tst-dc1.k16tst.test.loc:389…
  AutoDetected Server Site             : Default-First-Site-Name
  AutoDetected Client Site             : Site2
  AutoDetected Client Next Closest Site: Default-First-Site-Name
Determining site specific DNS records…
Dynamically determining domain k16tst.test.loc site specific domain controllers for site Site2…
Dynamically determining domain k16tst.test.loc site specific domain controllers for site Default-First-Site-Name…
Validating DCs for Site2…(Order=0)
       k16tst-dc2.k16tst.test.loc…
        TCP LDAP PING…
           Sending LDAP Ping to LDAP://k16tst-dc2.k16tst.test.loc:389…
          DC Site     = Site2
          ElapsedTime = 0.00778
     Retrieving RootDSE…
          Synchronized = TRUE     
          ElapsedTime  = 0.031609
      k16tst-scdc1.k16tst.test.loc…
        TCP LDAP PING…
          Sending LDAP Ping to LDAP://k16tst-scdc1.k16tst.test.loc:389…
          DC Site     = Site2
          ElapsedTime = 0.00709
     Retrieving RootDSE…     
          Synchronized = TRUE
          ElapsedTime  = 0.042098
Validating DCs for Default-First-Site-Name…(Order=1)
      k16tst-dc1.k16tst.test.loc…
        TCP LDAP PING…
          Sending LDAP Ping to LDAP://k16tst-dc1.k16tst.test.loc:389…
          DC Site     = Default-First-Site-Name
          ElapsedTime = 0.008532
     Retrieving RootDSE…
          Synchronized = TRUE
          ElapsedTime  = 0.007037
Checking Validation List for PDC domain controllers
Ordering DCs by Site | Priority | Avg Elapsed Response Time…
Sorted Validated Domain Controller List
k16tst-scdc1.k16tst.test.loc
k16tst-dc2.k16tst.test.loc
k16tst-dc1.k16tst.test.loc

The command completed.
[joe@centos7-1 AD]$

Rating 4.33 out of 5

3/19/2019

LDIF file for serviceConnectionPoint class for ADLDS

by @ 9:27 pm. Filed under LDS, tech

So you are sitting around and suddenly want to put serviceConnectionPoint objects into your LDS instance and suddenly realize that they didn’t put the SCP objectclass definition in LDS nor is it an optional LDIF file to add… So I created one using ADSchemaAnalyzer from the ADLDS install…

You can find it here

http://www.joeware.net/miscdownloads/lds/20190319_serviceConnectionPoint.ldf

and below:

Note that if you hit an “already exists” error for something in your LDS directory check out the ldif.err file and if it doesn’t look bad just add –z to the command per the notes in the file itself.

Have fun. Smile 

# ==================================================================
# 
#  This file should be imported with the following command:
#    ldifde -i -u -f scp.ldf -s server:port -b username domain password -j . -c "cn=Configuration,dc=X" #configurationNamingContext
#
#  If you get an error because something already exists, you can use the following command
#    ldifde -z -i -u -f scp.ldf -s server:port -b username domain password -j . -c "cn=Configuration,dc=X" #configurationNamingContext
#
#  LDIFDE.EXE from AD/AM V1.0 or above must be used.
#  This LDIF file should be imported into AD or AD/AM. It may not work for other directories.
# 
# ==================================================================

# ==================================================================
#  Attributes
# ==================================================================

# Attribute: appSchemaVersion
dn: cn=App-Schema-Version,cn=Schema,cn=Configuration,dc=X
changetype: add
objectClass: attributeSchema
attributeId: 1.2.840.113556.1.4.848
ldapDisplayName: appSchemaVersion
attributeSyntax: 2.5.5.9
adminDescription: App-Schema-Version
adminDisplayName: App-Schema-Version
# schemaIDGUID: 96a7dd65-9118-11d1-aebc-0000f80367c1
schemaIDGUID:: Zd2nlhiR0RGuvAAA+ANnwQ==
oMSyntax: 2
systemFlags: 16
isSingleValued: TRUE
systemOnly: FALSE

# Attribute: serviceBindingInformation
dn: cn=Service-Binding-Information,cn=Schema,cn=Configuration,dc=X
changetype: add
objectClass: attributeSchema
attributeId: 1.2.840.113556.1.4.510
ldapDisplayName: serviceBindingInformation
attributeSyntax: 2.5.5.12
adminDescription: Service-Binding-Information
adminDisplayName: Service-Binding-Information
# schemaIDGUID: b7b1311c-b82e-11d0-afee-0000f80367c1
schemaIDGUID:: HDGxty640BGv7gAA+ANnwQ==
oMSyntax: 64
systemFlags: 16
isMemberOfPartialAttributeSet: TRUE
systemOnly: FALSE

# Attribute: serviceClassName
dn: cn=Service-Class-Name,cn=Schema,cn=Configuration,dc=X
changetype: add
objectClass: attributeSchema
attributeId: 1.2.840.113556.1.4.509
ldapDisplayName: serviceClassName
attributeSyntax: 2.5.5.12
adminDescription: Service-Class-Name
adminDisplayName: Service-Class-Name
# schemaIDGUID: b7b1311d-b82e-11d0-afee-0000f80367c1
schemaIDGUID:: HTGxty640BGv7gAA+ANnwQ==
oMSyntax: 64
searchFlags: 1
systemFlags: 16
isSingleValued: TRUE
systemOnly: FALSE

# Attribute: serviceDNSName
dn: cn=Service-DNS-Name,cn=Schema,cn=Configuration,dc=X
changetype: add
objectClass: attributeSchema
attributeId: 1.2.840.113556.1.4.657
ldapDisplayName: serviceDNSName
attributeSyntax: 2.5.5.12
adminDescription: Service-DNS-Name
adminDisplayName: Service-DNS-Name
# schemaIDGUID: 28630eb8-41d5-11d1-a9c1-0000f80367c1
schemaIDGUID:: uA5jKNVB0RGpwQAA+ANnwQ==
oMSyntax: 64
systemFlags: 16
isSingleValued: TRUE
systemOnly: FALSE

# Attribute: serviceDNSNameType
dn: cn=Service-DNS-Name-Type,cn=Schema,cn=Configuration,dc=X
changetype: add
objectClass: attributeSchema
attributeId: 1.2.840.113556.1.4.659
ldapDisplayName: serviceDNSNameType
attributeSyntax: 2.5.5.12
adminDescription: Service-DNS-Name-Type
adminDisplayName: Service-DNS-Name-Type
# schemaIDGUID: 28630eba-41d5-11d1-a9c1-0000f80367c1
schemaIDGUID:: ug5jKNVB0RGpwQAA+ANnwQ==
oMSyntax: 64
systemFlags: 16
isSingleValued: TRUE
systemOnly: FALSE
rangeLower: 1
rangeUpper: 256

# Attribute: vendor
dn: cn=Vendor,cn=Schema,cn=Configuration,dc=X
changetype: add
objectClass: attributeSchema
attributeId: 1.2.840.113556.1.4.255
ldapDisplayName: vendor
attributeSyntax: 2.5.5.12
adminDescription: Vendor
adminDisplayName: Vendor
# schemaIDGUID: 281416df-1968-11d0-a28f-00aa003049e2
schemaIDGUID:: 3xYUKGgZ0BGijwCqADBJ4g==
oMSyntax: 64
systemFlags: 16
isSingleValued: TRUE
systemOnly: FALSE
rangeLower: 0
rangeUpper: 512

# Attribute: versionNumber
dn: cn=Version-Number,cn=Schema,cn=Configuration,dc=X
changetype: add
objectClass: attributeSchema
attributeId: 1.2.840.113556.1.4.141
ldapDisplayName: versionNumber
attributeSyntax: 2.5.5.9
adminDescription: Version-Number
adminDisplayName: Version-Number
# schemaIDGUID: bf967a76-0de6-11d0-a285-00aa003049e2
schemaIDGUID:: dnqWv+YN0BGihQCqADBJ4g==
oMSyntax: 2
systemFlags: 16
isMemberOfPartialAttributeSet: TRUE
isSingleValued: TRUE
systemOnly: FALSE

# Attribute: versionNumberHi
dn: cn=Version-Number-Hi,cn=Schema,cn=Configuration,dc=X
changetype: add
objectClass: attributeSchema
attributeId: 1.2.840.113556.1.4.328
ldapDisplayName: versionNumberHi
attributeSyntax: 2.5.5.9
adminDescription: Version-Number-Hi
adminDisplayName: Version-Number-Hi
# schemaIDGUID: 7d6c0e9a-7e20-11d0-afd6-00c04fd930c9
schemaIDGUID:: mg5sfSB+0BGv1gDAT9kwyQ==
oMSyntax: 2
systemFlags: 16
isSingleValued: TRUE
systemOnly: FALSE

# Attribute: versionNumberLo
dn: cn=Version-Number-Lo,cn=Schema,cn=Configuration,dc=X
changetype: add
objectClass: attributeSchema
attributeId: 1.2.840.113556.1.4.329
ldapDisplayName: versionNumberLo
attributeSyntax: 2.5.5.9
adminDescription: Version-Number-Lo
adminDisplayName: Version-Number-Lo
# schemaIDGUID: 7d6c0e9b-7e20-11d0-afd6-00c04fd930c9
schemaIDGUID:: mw5sfSB+0BGv1gDAT9kwyQ==
oMSyntax: 2
systemFlags: 16
isSingleValued: TRUE
systemOnly: FALSE

dn: 
changetype: modify
add: schemaUpdateNow
schemaUpdateNow: 1
-


# ==================================================================
#  Classes
# ==================================================================

# Class: connectionPoint
dn: cn=Connection-Point,cn=Schema,cn=Configuration,dc=X
changetype: add
objectClass: classSchema
governsID: 1.2.840.113556.1.5.14
ldapDisplayName: connectionPoint
adminDisplayName: Connection-Point
adminDescription: Connection-Point
# schemaIDGUID: 5cb41ecf-0e4c-11d0-a286-00aa003049e2
schemaIDGUID:: zx60XEwO0BGihgCqADBJ4g==
objectClassCategory: 2
defaultSecurityDescriptor:
 D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;
 RPLCLORC;;;AU)
systemOnly: FALSE
systemFlags: 16
# subclassOf: leaf
subclassOf: 1.2.840.113556.1.5.20
# rdnAttId: cn
rdnAttId: 2.5.4.3
# systemMustContain: cn
systemMustContain: 2.5.4.3
# systemMayContain: keywords
systemMayContain: 1.2.840.113556.1.4.48
# systemMayContain: managedBy
systemMayContain: 1.2.840.113556.1.4.653
# systemMayContain: msDS-Settings
systemMayContain: 1.2.840.113556.1.4.1697
# systemPossSuperiors: container
systemPossSuperiors: 1.2.840.113556.1.3.23
# defaultObjectCategory: connectionPoint
defaultObjectCategory: cn=Connection-Point,cn=Schema,cn=Configuration,dc=X

dn: 
changetype: modify
add: schemaUpdateNow
schemaUpdateNow: 1
-

# Class: serviceConnectionPoint
dn: cn=Service-Connection-Point,cn=Schema,cn=Configuration,dc=X
changetype: add
objectClass: classSchema
governsID: 1.2.840.113556.1.5.126
ldapDisplayName: serviceConnectionPoint
adminDisplayName: Service-Connection-Point
adminDescription: Service-Connection-Point
# schemaIDGUID: 28630ec1-41d5-11d1-a9c1-0000f80367c1
schemaIDGUID:: wQ5jKNVB0RGpwQAA+ANnwQ==
objectClassCategory: 1
defaultSecurityDescriptor:
 D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;CO)(A;;
 RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)
systemOnly: FALSE
systemFlags: 16
# subclassOf: connectionPoint
subclassOf: 1.2.840.113556.1.5.14
# rdnAttId: cn
rdnAttId: 2.5.4.3
# systemMayContain: appSchemaVersion
systemMayContain: 1.2.840.113556.1.4.848
# systemMayContain: serviceBindingInformation
systemMayContain: 1.2.840.113556.1.4.510
# systemMayContain: serviceClassName
systemMayContain: 1.2.840.113556.1.4.509
# systemMayContain: serviceDNSName
systemMayContain: 1.2.840.113556.1.4.657
# systemMayContain: serviceDNSNameType
systemMayContain: 1.2.840.113556.1.4.659
# systemMayContain: vendor
systemMayContain: 1.2.840.113556.1.4.255
# systemMayContain: versionNumber
systemMayContain: 1.2.840.113556.1.4.141
# systemMayContain: versionNumberHi
systemMayContain: 1.2.840.113556.1.4.328
# systemMayContain: versionNumberLo
systemMayContain: 1.2.840.113556.1.4.329
# systemPossSuperiors: container
systemPossSuperiors: 1.2.840.113556.1.3.23
# systemPossSuperiors: organizationalUnit
systemPossSuperiors: 2.5.6.5
# defaultObjectCategory: serviceConnectionPoint
defaultObjectCategory:
 cn=Service-Connection-Point,cn=Schema,cn=Configuration,dc=X

dn: 
changetype: modify
add: schemaUpdateNow
schemaUpdateNow: 1
-


# ==================================================================
#  Updating present elements
# ==================================================================

Rating 3.00 out of 5

3/16/2019

Functional Anonymous DC Locator Platform Agnostic perl script… Getting close…

by @ 4:45 pm. Filed under general, perl

[Sat 03/16/2019 16:41:06.51]
E:\DEV\perl\jwDCLocator>perl jwdclocator.pl /domain:k16tst.test.loc

jwDCLocator V01.01.00pl  Joe Richards (support@joeware.net)  March 2018

Initializing Logging to logfile 20190316-1641-jwDCLocator.log…
Reading configuration file jwDCLocator.config…
Processing configuration file…
Determining bootstrap domain controllers via DNS for k16tst.test.loc…
  BootStrap Hosts: k16tst-dc2.k16tst.test.loc k16tst-dc1.k16tst.test.loc k16tst-scdc1.k16tst.test.loc
Dynamically determining site…
  Sending LDAP Ping to LDAP://k16tst-dc2.k16tst.test.loc:389…
  AutoDetected Server Site             : Site2
  AutoDetected Client Site             : joenetlogontestsite
  AutoDetected Client Next Closest Site: Default-First-Site-Name
Determining site specific DNS records…
Dynamically determining domain k16tst.test.loc site specific domain controllers for site joenetlogontestsite…
Dynamically determining domain k16tst.test.loc site specific domain controllers for site Default-First-Site-Name…
Validating DCs for joenetlogontestsite…(Order=0)
      k16tst-dc1.k16tst.test.loc…
        TCP LDAP PING…
          Sending LDAP Ping to LDAP://k16tst-dc1.k16tst.test.loc:389…
           DC Site     = Default-First-Site-Name
          ElapsedTime = 0.018054
     Retrieving RootDSE…
          Sychronized = TRUE
          ElapsedTime = 0.126044
Validating DCs for Default-First-Site-Name…(Order=1)
      k16tst-dc1.k16tst.test.loc…
        TCP LDAP PING…
          Sending LDAP Ping to LDAP://k16tst-dc1.k16tst.test.loc:389…
          DC Site     = Default-First-Site-Name
          ElapsedTime = 0.013659
     Retrieving RootDSE…
          Sychronized = TRUE
          ElapsedTime = 0.113992
Checking Validation List for PDC domain controllers
Ordering DCs by Site | Priority | Avg Elapsed Response Time…
Sorted Validated Domain Controller List
k16tst-dc1.k16tst.test.loc
k16tst-dc1.k16tst.test.loc

The command completed.

[Sat 03/16/2019 16:41:24.64]
E:\DEV\perl\jwDCLocator>

Rating 4.00 out of 5

1/29/2019

Broken Downloads

by @ 8:33 pm. Filed under general

Apologies, the tool downloads were broken for a little bit there. It is fixed now. Smile 

    joe

Rating 4.33 out of 5

12/13/2018

Finding Domain Controllers On Any Platform Using DNS and LDAP – Alternate Working Title: Generic Platform Agnostic DC Locator

by @ 12:34 am. Filed under tech

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.

Rating 4.75 out of 5

12/7/2018

Horrible Multilevel Bullets / Numbering…

by @ 11:33 pm. Filed under general

…Yeah I know, I hate it too…

   joe

Rating 4.60 out of 5

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

by @ 11:31 pm. 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

12/6/2018

Finding Domain Controllers on Windows using the Windows LDAP (winldap.h) Library (i.e. The Easy Way)

by @ 10:07 pm. Filed under tech

0. This does not follow the previously mentioned high level steps, this method is “I hand my problem over to Microsoft to figure out on my behalf”.

1. Call ldap_sslinit specifying domain name or forest name (for Global Catalog)

    a. LDAP port

        i. LDAP* pLdap=ldap_sslinit(L"domain.forestroot.com", LDAP_PORT, false);

    b. LDAPS (SSL) port

        i. LDAP* pLdap=ldap_sslinit(L"domain.forestroot.com", LDAP_SSL_PORT, true);

    c. Global Catalog port

        i. LDAP* pLdap=ldap_sslinit(L"forestroot..com", LDAP_GC_PORT, false);

    d. Global Catalog SSL port

        i. LDAP* pLdap=ldap_sslinit(L"forestroot..com", LDAP_SSL_GC_PORT, true);

2. That was Easy™

Rating 4.80 out of 5

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