DNS and Active Directory
Why Active Directory cannot work without DNS: SRV records that locate domain controllers, AD-integrated zones, the domain name design, and the DNS problems behind many login failures.
Why Active Directory needs DNS
Active Directory (AD) is a set of services running on domain
controllers (DCs): LDAP (Lightweight Directory Access Protocol) for
directory queries, Kerberos for authentication, SMB (Server Message
Block) shares for Group Policy files, and a global catalog for
forest-wide searches. The structure behind them is explained in
Active Directory Fundamentals. A client that wants to sign in does not have a list of DC
addresses configured anywhere. It only knows the domain name, for
example ad.example.com, and asks the
DNS (Domain Name
System) where the services for that domain are.
That design makes AD flexible: you can add, move or retire DCs without touching a single client, because each DC publishes itself in DNS. The price is that DNS becomes the first dependency of everything in the domain. When DNS answers wrongly or not at all, the symptoms look like anything but DNS:
- "The trust relationship between this workstation and the primary domain failed", or a domain join that says the domain "could not be contacted";
- slow sign-in, followed by a desktop without mapped drives or policies;
-
Group Policy errors in the event log, and
gpupdatethat cannot reach a DC; - Kerberos failures that silently fall back to the weaker NTLM protocol (see Kerberos and NTLM).
General DNS (the hierarchy, record types, caching and the tools) is covered on the DNS page; this page is about what Active Directory adds on top.
SRV records: how services are published
An SRV record (service record, RFC
2782) is a DNS record that tells a client which host offers a given
service over a given protocol for a domain, on which port, and in
which order of preference. Its name has a fixed shape,
_service._protocol.name, and its data holds four
fields: priority, weight,
port and target host. An A record
answers "what is the address of this host?"; an SRV record answers
"which hosts run this service?".
Every DC registers a set of SRV records for itself. The ones a technician meets most often:
| Record name | Port | Finds |
|---|---|---|
_ldap._tcp.dc._msdcs.ad.example.com |
389 | Every DC of the domain (the record the DC locator starts with) |
_ldap._tcp.Utrecht._sites.dc._msdcs.ad.example.com
|
389 | The DCs that serve the AD site Utrecht |
_kerberos._tcp.dc._msdcs.ad.example.com |
88 | DCs running the Kerberos key distribution center |
_ldap._tcp.pdc._msdcs.ad.example.com |
389 | The DC holding the PDC emulator role (one per domain) |
_gc._tcp.ad.example.com |
3268 | Global catalog servers of the forest |
_kerberos._tcp.ad.example.com,
_kpasswd._tcp.ad.example.com
|
88, 464 | Kerberos and Kerberos password change, in the generic form that non-Windows clients (Linux, macOS) also use |
The _msdcs part is commonly expanded as "Microsoft
Domain Controller Services": records under it are specific to Active
Directory, while the shorter names follow the generic SRV
conventions any Kerberos or LDAP client understands. Querying the
records yourself is the fastest way to see what a client sees:
Resolve-DnsName -Type SRV _ldap._tcp.dc._msdcs.ad.example.com
Name Type TTL Section NameTarget Priority Weight Port ---- ---- --- ------- ---------- -------- ------ ---- _ldap._tcp.dc._msdcs.ad.example.com SRV 600 Answer dc01.ad.example.com 0 100 389 _ldap._tcp.dc._msdcs.ad.example.com SRV 600 Answer dc02.ad.example.com 0 100 389 _ldap._tcp.dc._msdcs.ad.example.com SRV 600 Answer dc03.ad.example.com 0 100 389 Name : dc01.ad.example.com QueryType : A TTL : 1200 Section : Additional IP4Address : 192.0.2.10
The same query works with nslookup -type=SRV on any
Windows machine, or dig SRV on Linux; see
the DNS tools. An
empty answer (or "Non-existent domain") means the client asks the
wrong DNS server or the DC failed to register; the
troubleshooting section shows how to
tell which.
Who registers the records
The Netlogon service on each DC registers its SRV records, and
re-registers them periodically and at every service start. The full
list a DC wants to register is written to the text file
%SystemRoot%\System32\config\netlogon.dns, which is
handy for comparing "what should exist" with "what DNS returns". By
default each DC registers priority 0 and weight 100, so all DCs are
equal; administrators can lower a DC's weight in the Netlogon
settings, for example to send fewer clients to a busy PDC emulator.
Restarting Netlogon on a DC (Restart-Service Netlogon)
is the usual way to force a re-registration after fixing a DNS
problem.
Priority and weight in Python
RFC 2782 defines how a client uses priority and weight: always try the lowest priority value first; among records with the same priority, pick randomly in proportion to the weight. The Windows DC locator adds site awareness on top (next section), but the rule is the same one used for SIP, XMPP and other SRV-based services. This sketch orders four DCs for three clients and then counts which DC 10,000 clients would try first. The random generator is seeded, so the output is identical on every run.
# Choose a server from DNS SRV records the way RFC 2782 describes.
import random
# (priority, weight, port, target) for _ldap._tcp.dc._msdcs.ad.example.com
RECORDS = [
(0, 60, 389, "dc01.ad.example.com"),
(0, 30, 389, "dc02.ad.example.com"),
(0, 10, 389, "dc03.ad.example.com"),
(10, 100, 389, "dc-dr.ad.example.com"), # disaster-recovery site
]
def srv_order(records, rng):
"""Return the targets in the order a client should try them."""
ordered = []
for priority in sorted({r[0] for r in records}): # lowest priority first
group = [r for r in records if r[0] == priority]
group.sort(key=lambda r: r[1] != 0) # weight-0 records go first
while group:
total = sum(r[1] for r in group)
pick = rng.randint(0, total) # 0..total, both ends included
running = 0
for record in group:
running += record[1]
if running >= pick:
ordered.append(record[3])
group.remove(record)
break
return ordered
rng = random.Random(2782) # seeded, so the output is the same every run
for attempt in range(1, 4):
print(f"Client {attempt}:", " -> ".join(srv_order(RECORDS, rng)))
first_choice = {}
for _ in range(10_000):
first = srv_order(RECORDS, rng)[0]
first_choice[first] = first_choice.get(first, 0) + 1
print("First choice over 10,000 clients:")
for target, count in sorted(first_choice.items()):
print(f" {target:<22}{count:>6}")
Client 1: dc01.ad.example.com -> dc03.ad.example.com -> dc02.ad.example.com -> dc-dr.ad.example.com Client 2: dc02.ad.example.com -> dc01.ad.example.com -> dc03.ad.example.com -> dc-dr.ad.example.com Client 3: dc01.ad.example.com -> dc02.ad.example.com -> dc03.ad.example.com -> dc-dr.ad.example.com First choice over 10,000 clients: dc01.ad.example.com 6017 dc02.ad.example.com 2973 dc03.ad.example.com 1010
Two things to notice. The disaster-recovery DC with priority 10 is never a first choice: it is only used when every priority-0 DC fails to answer. And weights 60, 30 and 10 give roughly 60%, 30% and 10% of the clients, which spreads load without any central balancer.
The DC locator: finding the right DC
The DC locator is the Windows process (implemented by the Netlogon service) that finds a suitable domain controller for a client by querying DNS SRV records and then checking which DC answers and which AD site the client belongs to. It runs at startup, at sign-in, when a cached DC stops responding, and whenever an application asks for a DC.
Step by step:
-
The client asks its DNS server for the SRV records of the domain.
If it already knows its site (it remembers the last one), it asks
the site-specific name
_ldap._tcp.Utrecht._sites.dc._msdcs.ad.example.comfirst; otherwise the generic one. - DNS returns the DCs, ordered by priority and weight.
- The client sends each candidate a small "LDAP ping": a connectionless LDAP query over UDP port 389.
- The first DC to answer replies with its own name and capabilities (global catalog, writable, time server, and so on) and with the site that matches the client's IP address. That mapping comes from the subnets defined in AD Sites and Services.
- If the answering DC is not in the client's site, the client repeats the query with the site-specific name.
- The client uses the DC that answers and caches it until it stops responding, the client restarts, or the periodic rediscovery (by default every 12 hours) runs.
Step 4 is why missing subnets in AD Sites and Services are a classic cause of slow sign-ins at branch offices: a client whose subnet is not mapped to any site may pick any DC in the domain, including one on the other side of the world.
AD-integrated zones and secure dynamic updates
A DNS zone can be stored in a text file on one primary server, as the zone file example on the DNS page shows. On a DC running the DNS Server role there is a better option. An AD-integrated zone is a DNS zone whose records are stored as objects in the Active Directory database instead of in a zone file, so they replicate with normal AD replication and every DC that runs DNS can accept changes to the zone.
That gives three advantages over a classic primary/secondary setup:
- Multi-master. There is no single primary server whose failure stops all updates; any DNS server on a DC can accept changes.
-
One replication system. Zone data travels with AD
replication, using its schedule and compression, instead of
separate zone transfers. The scope is configurable: all DNS
servers in the domain (the
DomainDnsZonespartition) or in the whole forest (ForestDnsZones). - Secure dynamic updates. The zone can accept updates from authenticated domain members only.
Secure dynamic updates
Domain members register their own A and AAAA records when they start
or get a new address; DCs register their SRV records the same way.
With the zone set to Secure only, a client must
authenticate with Kerberos before it may create a record, and the
record gets an access control list that makes the creating computer
its owner. Another machine cannot overwrite
fs01.ad.example.com to point users at itself. With
"Nonsecure and secure", anyone who can reach the DNS server can
register or change names, which is an open invitation for traffic
redirection. Keep AD-integrated zones on Secure only.
Dynamic registration also leaves old records behind when laptops change networks. Aging and scavenging removes records that have not been refreshed for a set time. It is off by default; switch it on deliberately, with intervals longer than your DHCP lease time (see DHCP), so records of machines that are merely on holiday are not removed.
The _msdcs zone
In a new forest, the AD-specific records of the forest root live in
a separate zone, _msdcs.ad.example.com, replicated to
every DNS server in the forest. It also holds a record per DC named
after the DC's GUID, which other DCs use to find their replication
partners. A broken _msdcs zone therefore does not only
break client sign-in; it can break replication between DCs too.
Choosing the domain name
The DNS name of an AD domain is chosen once, when the first DC is
promoted, and renaming a domain later is a complex, risky project
that many products do not support. So the name deserves a moment of
thought. The current advice: use a
subdomain of a registered domain you own, such as
ad.example.com when the organization owns
example.com.
| Choice | Verdict | Why |
|---|---|---|
ad.example.com |
Recommended | You own it, nobody else can register it, it does not overlap with public records, and public certificate authorities can issue certificates for names under it. |
example.com (the public domain itself) |
Works, with extra work |
Internal DNS must also serve copies of public records such
as www, which is split-brain DNS (below). Every
public change has to be made twice.
|
kestrel.local |
Avoid |
.local is reserved for multicast DNS (RFC
6762), which macOS, iOS and many Linux systems use for
discovery, so those clients may not send the query to your
DNS server at all. Public certificate authorities also do
not issue certificates for names that are not publicly
registered.
|
kestrel (single label) |
Avoid | A single-label domain name has no dot, so DNS clients treat it differently (they add suffixes, or refuse to register records in it), and many applications and Microsoft cloud services do not support it. |
A made-up top-level domain (.lan,
.intra)
|
Avoid | You do not control it; a name that is not public today may become a real top-level domain, after which internal names collide with the internet. |
.internal |
Possible, not recommended | Reserved by ICANN (2024) for private use, so it will never collide with a public top-level domain, but public certificate authorities still cannot issue certificates for it; a subdomain you own remains the better choice. |
Besides the DNS name, every domain also has a short NetBIOS name,
the part users see in KESTREL\amara-style sign-in
names. The promotion wizard proposes the leftmost DNS label (AD
for ad.example.com); you can pick a more meaningful
one. User principal names, the user@domain sign-in
format, can use a different suffix such as
@example.com so that sign-in names match email
addresses; see
Users, Groups and Computers.
DNS settings on clients and DCs
Every domain member, server or workstation, must use DNS servers that can answer for the AD zones, which in practice means the DCs running DNS (or internal resolvers that forward the AD zones to them). DHCP hands those addresses out to clients; servers with static addresses get them configured by hand. Internet names are then resolved by the AD DNS servers on the client's behalf.
DCs that run DNS also need care. A common Microsoft recommendation for a DC with several DCs in the domain: another DC as the preferred DNS server, and the DC's own loopback address as the alternate. Pointing a DC only at itself can leave it unable to find its partners after a restart, while its own DNS service is still loading the zones.
Forwarders and conditional forwarders
For names outside its own zones, an AD DNS server either walks the
DNS hierarchy itself (using root hints) or passes the query to a
forwarder: a resolver of the internet provider, a
filtering DNS service or the organization's own recursive resolver
(see
how a name is resolved). A conditional forwarder applies only to one
domain: "send everything for partner.example.net
to 198.51.100.53". Conditional forwarders are the usual way to make
two forests resolve each other's names before a
trust is created,
and they can be stored in AD so every DC gets them.
Split-brain DNS
When the AD domain has the same name as the public domain, internal
DNS answers for example.com and the public DNS answers
for it too, with different content: split-brain (or split-horizon)
DNS, explained on the
DNS page. It
works, but every public record that staff need (the website, the
mail server, the VPN gateway) must be copied into the internal zone
by hand, and forgetting one gives "the website works at home but not
in the office" tickets. A subdomain such as
ad.example.com avoids the problem entirely.
Troubleshooting DNS for AD
Work from the client toward the DCs. First: which DNS servers does the client use, and do they return the SRV records?
ipconfig /all # which DNS servers, which DNS suffix?
nltest /dsgetsite # which AD site does this machine think it is in?
nltest /dsgetdc:ad.example.com # run the DC locator and show the result
DC: \\DC01.ad.example.com
Address: \\192.0.2.10
Dom Guid: 3f2c9a1e-7b4d-4c1a-9e55-2d8b6a1f0c42
Dom Name: ad.example.com
Forest Name: ad.example.com
Dc Site Name: Utrecht
Our Site Name: Utrecht
Flags: PDC GC DS LDAP KDC TIMESERV WRITABLE DNS_DC DNS_DOMAIN DNS_FOREST CLOSE_SITE
The command completed successfully
"Dc Site Name" equal to "Our Site Name" and the flag
CLOSE_SITE mean the locator found a DC in the client's
own site. An error such as ERROR_NO_SUCH_DOMAIN sends
you back to DNS: query the SRV record with
Resolve-DnsName against the DNS server from
ipconfig /all. Adding /force to the
nltest command makes it skip its cache and run the
locator again.
On a DC, dcdiag tests DNS for the whole domain:
delegations, forwarders, dynamic update and whether every DC's
records are registered.
dcdiag /test:dns /v
Summary of DNS test results:
Auth Basc Forw Del Dyn RReg Ext
_________________________________________________________________
Domain: ad.example.com
DC01 PASS PASS PASS PASS PASS PASS n/a
DC02 PASS PASS FAIL PASS PASS PASS n/a
......................... ad.example.com failed test DNS
Here DC02 fails the forwarders test (Forw): it cannot
reach its configured forwarder, so clients that use DC02 cannot
resolve internet names, while sign-in still works. The verbose
output above the summary names the forwarder that failed.
| Symptom | Likely cause | Check or fix |
|---|---|---|
| Domain join: "domain could not be contacted" | Client uses a public or router DNS server | ipconfig /all; set the AD DNS servers |
| Sign-in works, but slowly at one branch | Branch subnet missing in AD Sites and Services |
nltest /dsgetsite; add the subnet to the right
site
|
| New DC is never used | Its SRV records are not registered |
Compare netlogon.dns with DNS; restart Netlogon
|
| Intermittent failures that "fix themselves" | A public resolver among the client's DNS servers | Remove it; ipconfig /flushdns |
| A server name resolves to an old address | Stale record, or a cached old answer |
ipconfig /registerdns on the server; check
scavenging
|
Broader sign-in troubleshooting, including the event logs to read, is on Monitoring and Troubleshooting Identity; general DNS problems are on the DNS page.