Problem: UCS@school - Windows Clients not resolving via DNS - Missing aRecords in Samba

Problem

In a school environment, DNS resolution of Windows clients via dig or nslookup no longer worked because the corresponding A record from the local DNS zone of the respective organizational unit (school) could not be resolved.

What was unusual was that not all Windows clients were affected, but rather many individual systems sporadically.

root@:~# dig CLIENT01.example.intranet

; <<>> DiG 9.18.x <<>> CLIENT01.example.intranet
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 26325
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; QUESTION SECTION:
;CLIENT01.example.intranet.       IN      A

;; AUTHORITY SECTION:
example.intranet.         3600    IN      SOA     .example.intranet. root.example.intranet. 47582 28800 7200 604800 3600

;; Query time: 0 msec

Root Cause

The affected clients and computer objects still existed in both the local LDAP directory and the local Samba database. What was missing were the A records of the affected clients. As a result, the systems could no longer be resolved via dig or nslookup.

root@:~# samba-tool dns query localhost example.intranet CLIENT01 A -P
ERROR(runtime): Record or zone does not exist. [WERR_DNS_ERROR_NAME_DOES_NOT_EXIST]

The reason for the missing A records was a Group Policy Object (GPO) configuration in the environment that disabled Dynamic DNS (DDNS) updates for Windows clients.

With this configuration enabled:

  • Windows clients could no longer perform DDNS updates
  • No DNS updates were sent to the configured Samba Domain Controller
  • Samba no longer received network-specific updates from clients

As a result, the DNS records in Samba became outdated or disappeared entirely.


Solution

The easiest and recommended solution is to allow DDNS updates again for Windows clients so that DNS records are continuously refreshed.

The corresponding GPO setting is located here:

Computer Configuration
 └── Administrative Templates
     └── Network
         └── DNS Client
             └── Dynamic Update = Enabled

Investigation

The issue was investigated in more detail to understand why DNS resolution via dig failed for specific clients.

The local LDAP directory still contained both:

  • the computer object
  • the DNS object

However, Samba only contained the computer object, while the DNS record itself was missing.

Since the environment used dns/backend=samba, successful DNS resolution required the records to exist in the Samba DNS database.

Below is an example of the DNS record in the local LDAP directory:

root@:~# univention-ldapsearch -LLL relativeDomainName=CLIENT01
dn: relativeDomainName=CLIENT01,zoneName=example.intranet,cn=dns,dc=example,dc=intranet
objectClass: dNSZone
objectClass: univentionObject
objectClass: top
univentionObjectType: dns/host_record
zoneName: example.intranet
aRecord: 10.10.10.20
relativeDomainName: CLIENT01

The Samba DNS query showed that the DNS record did not exist in Samba:

root@:~# samba-tool dns query localhost example.intranet CLIENT01 A -P
ERROR(runtime): Record or zone does not exist. [WERR_DNS_ERROR_NAME_DOES_NOT_EXIST]

Example output of a correctly existing DNS record:

root@:~# ldbsearch -H /var/lib/samba/private/sam.ldb --cross-ncs "dc=CLIENT02"

# record 1
dn: DC=CLIENT02,DC=example.intranet,CN=MicrosoftDNS,DC=DomainDnsZones,DC=example,DC=intranet
objectClass: top
objectClass: dnsNode
instanceType: 4
whenCreated: 20250101010101.0Z
whenChanged: 20250101010101.0Z
dnsRecord:: BAABAAXwAAABAAAAAAADhAAAAAAAAAAACkUgXA==
dc: CLIENT02

The DNS record was resolvable correctly:

root@:~# samba-tool dns query localhost example.intranet CLIENT02 A -P
  Name=, Records=1, Children=0
    A: 10.10.10.21 (flags=f0, serial=1, ttl=900)

Verification of DNS Scavenging

It was verified whether DNS scavenging had been configured on the Samba Domain Controller.

This configuration was not enabled:

root@:~# testparm -sv | grep scav
        dns zone scavenging = No

This raised the question:

Why were the A records automatically removed from Samba over time?


Why the DNS Records Were Removed

Samba 4 does not automatically delete DNS records in its default configuration unless DNS scavenging is enabled.

If records disappear sporadically, an active delete operation must have been sent directly to Samba.

The Role of Timestamps (whenCreated vs. dnsRecord)

In Active Directory and Samba 4, two completely different timestamp mechanisms exist for DNS entries.

Administrative LDAP Metadata

The following attributes are administrative metadata only:

  • whenCreated
  • whenChanged

These values only indicate when the LDAP object was created or modified.

They have no influence on DNS aging or DNS record cleanup.

Internal DNS Timestamp (dwTimeStamp)

The actual DNS information is stored in the binary dnsRecord attribute.

Inside this attribute, Samba stores an internal timestamp measured in hours since the year 1601.

  • 0 → static DNS record
  • >0 → dynamic DNS record

Since the affected Windows clients previously used DDNS before the GPO was applied, the records were stored in Samba as dynamic DNS entries with valid timestamps.


The Windows “Active Unregister” Effect

Disabling DDNS via GPO does not always prevent Windows from sending DNS delete requests.

The Windows DNS Client service (Dnscache) may still send deregistration requests during:

  • system shutdown
  • DHCP lease release
  • network changes
  • switching between LAN and WLAN

In these cases, Windows sends a DNS DELETE update to the Samba Domain Controller.

Samba accepts the request and marks the DNS object as tombstoned.

The OpenLDAP directory is unaware of this deletion because the update bypasses the S4 Connector entirely.


Why This Happens Even Though DDNS Was Disabled

One would expect:

“If DDNS is disabled via GPO, Windows should stop sending any DNS updates.”

However, Windows networking behaves differently internally.

There are two documented scenarios where Windows still sends DNS DELETE updates.

1. Cleanup Behavior When the GPO Becomes Active

When the GPO disables DNS registration, Windows detects that:

  • it may no longer register itself in DNS
  • but an older dynamic DNS record still exists

To prevent stale DNS entries from remaining in the environment, Windows performs a final cleanup operation.

The DNS Client service sends a DNS DELETE request for its own A record to the configured DNS server.

Since future DDNS registrations are blocked by the GPO, the record disappears permanently.

2. DHCP Client Interaction (Option 81)

The GPO mainly affects the Windows DNS Client service.

However, DHCP interactions remain relevant.

Windows clients negotiate DNS update responsibilities using DHCP Option 81 (Client FQDN).

When:

  • a DHCP lease expires
  • the client shuts down cleanly
  • the network changes

the DHCP subsystem may trigger a DNS deregistration process.

Depending on the DHCP configuration:

  • either the client itself
  • or the DHCP server on behalf of the client

sends a DNS DELETE request to Samba.

For more Information:

Why the Problem Appeared Sporadically

This behavior explains why the problem occurred only gradually over time.

Sequence of events:

  1. The GPO disabling DDNS was deployed.
  2. Not all clients processed the GPO simultaneously.
  3. DNS records only disappeared after specific network events occurred.
  4. Samba removed the records after receiving DELETE requests.
  5. LDAP still retained the original DNS objects.

This resulted in an inconsistent state between LDAP and Samba DNS.


Tombstoned DNS Objects

The deleted DNS records appeared in Samba as tombstoned objects:

root@:~# univention-s4search --cross-ncs dNSTombstoned=TRUE

dn: DC=CLIENT01,DC=example.intranet,CN=MicrosoftDNS,DC=DomainDnsZones,DC=example,DC=intranet

After some time, Samba permanently removed the tombstoned objects because no new DDNS updates recreated them.

Example Samba log output:

/var/log/samba/log.samba:  dns_delete_tombstones: The tombstoned dns node DC=CLIENT01,DC=univention.de,CN=MicrosoftDNS,DC=DomainDnsZones,DC=univention,DC=de has 2 dns records, expected one.
/var/log/samba/log.samba:  dns_delete_tombstones: The tombstoned dns node DC=CLIENT01,DC=univention.de,CN=MicrosoftDNS,DC=DomainDnsZones,DC=univention,DC=de has 2 dns records, expected one.

S4 Connector

A related issue may also affect recovery of tombstoned DNS objects from the S4-Connector.

The following fix may help restore tombstoned objects through the S4 Connector if DDNS is enabled again on the Windows clients.

Related bug report:

Bug 57174


Conclusion

Re-enabling DDNS was the correct solution.

Windows clients in Active Directory environments are designed to manage their DNS records dynamically.

Disabling DDNS without implementing an alternative DNS lifecycle strategy inevitably leads to:

  • inconsistent Samba DNS records
  • tombstoned DNS objects
  • stale LDAP entries
  • failed DNS resolution

Additional Notes

The following Bash script can be used to compare DNS records stored in LDAP with records available in Samba DNS.

If a record is missing in Samba, it is recreated automatically.

Important:

The script only restores missing records in the Samba DB.
It does not solve the underlying issue caused by disabled DDNS.
If DDNS remains disabled, records may disappear again later.

#!/bin/bash

# 1. Determine UCS domain
DOMAIN=$(ucr get domainname)

if [ -z "$DOMAIN" ]; then
    echo "Failed to determine UCS domain."
    exit 1
fi

# 2. Ask for Administrator password (needed for samba-tool dns)
read -s -p "Enter UCS Administrator password: " ADMIN_PASS
echo ""
echo "Starting synchonization for domain: $DOMAIN"
echo "---------------------------------------------------"

# 3. Univention-ldapsearch for aRecords from Windows Clients 
# We filter directly for the required attributes 'cn' and 'aRecord'
univention-ldapsearch -LLL "(&(objectClass=univentionWindows)(aRecord=*))" cn aRecord | awk '
/^dn:/ { cn=""; ip="" }
/^cn:/ { cn=$2 }
/^aRecord:/ { ip=$2; print cn, ip }
' | while read -r HOSTNAME IP; do

    # Catch empty variables (in case parsing errors occur)
    if [ -z "$HOSTNAME" ] || [ -z "$IP" ]; then
        continue
    fi

    # 4. Check whether the record is already resolvable in the local DNS (Samba)
    EXISTING_IP=$(dig @localhost +short "$HOSTNAME.$DOMAIN" A)

    if [ "$EXISTING_IP" == "$IP" ]; then
        echo "[OK] $HOSTNAME ($IP) already exists in Samba DNS. Skipping."
    elif [ -n "$EXISTING_IP" ]; then
        echo "[WARNUNG] $HOSTNAME Exists in Samba DNS, but has a different IP ($EXISTING_IP instead $IP). Skipping."
    else
        echo "[ADD] Add $HOSTNAME ($IP) to Samba-DNS"
        # 5. Add entry via samba-tool
        samba-tool dns add localhost "$DOMAIN" "$HOSTNAME" A "$IP" -U "Administrator" --password="$ADMIN_PASS"

        # Check if successful
        if [ $? -eq 0 ]; then
            echo "  -> Added successfully."
        else
            echo "  -> Failure while adding from $HOSTNAME."
        fi
    fi
done

echo "---------------------------------------------------"
echo "Finished the Run."