Introduction
SRV (Service) records enable DNS-based service discovery, allowing clients to find servers for specific protocols like LDAP, Kerberos, SIP, and XMPP by querying DNS rather than hardcoding server addresses. When SRV records are missing or misconfigured, authentication systems fail, VoIP doesn't connect, and directory services become unreachable. These failures often manifest as application-level errors rather than DNS errors, making diagnosis challenging.
Symptoms
- Active Directory/LDAP authentication fails with "domain controller not found"
- Kerberos authentication errors about missing KDC
- SIP/VoIP clients can't locate servers
- XMPP/Jabber connections fail
- Email clients can't find autodiscovery/autodiscover services
- Application error logs mention "server not found" or "connection failed"
- Service-specific URLs work but DNS discovery fails
Common Causes
- SRV record missing for required service
- Incorrect priority or weight values
- Target hostname doesn't resolve (no A record)
- Wrong port number specified
- SRV record in wrong subdomain (_service._proto.domain)
- Missing underscore prefixes in service/protocol names
- Target pointing to wrong server or port
Step-by-Step Fix
- 1.Understand SRV record format and query the right location.
```bash # SRV record format: _service._protocol.domain # Example: _ldap._tcp.example.com
# Query for LDAP service dig _ldap._tcp.example.com SRV
# Query for Kerberos dig _kerberos._tcp.example.com SRV
# Query for SIP dig _sip._tcp.example.com SRV
# Output format: # Priority Weight Port Target # 10 50 389 ldap.example.com.
# Use host command host -t SRV _ldap._tcp.example.com
# nslookup nslookup -type=SRV _ldap._tcp.example.com ```
- 1.Verify SRV record target resolves to valid IP.
```bash # Get SRV record srv_result=$(dig _ldap._tcp.example.com SRV +short) echo "SRV: $srv_result"
# Extract target hostname target=$(echo "$srv_result" | awk '{print $4}') echo "Target: $target"
# Check target A record dig ${target%.} A +short
# Should return IP address # If empty, target hostname doesn't resolve - fix A record
# Verify target has correct port echo "Target IP:" dig ${target%.} A +short
# Test port connectivity target_ip=$(dig ${target%.} A +short | head -1) nc -vz $target_ip 389 # Port from SRV record ```
- 1.Check SRV record priority and weight values.
```bash # Priority: Lower value = higher preference (like MX) # Weight: Relative weight for servers with same priority
# Example correct values: # _ldap._tcp.example.com SRV: # 10 60 389 ldap1.example.com. # 10 40 389 ldap2.example.com. # 20 0 389 ldap-backup.example.com.
# Priority 10 servers are tried first # Within priority 10, weight 60:40 ratio (60% ldap1, 40% ldap2) # Priority 20 only tried if all priority 10 fail
# Check current values dig _ldap._tcp.example.com SRV +short | sort -n
# Common issues: # - All same priority, no failover (should have different priorities) # - Weight 0 for all (no load distribution) # - High priority for backup (should be lower) ```
- 1.Query specific SRV records for common services.
```bash # Active Directory / LDAP echo "=== Active Directory SRV ===" # Domain controller LDAP dig _ldap._tcp.example.com SRV +short
# Kerberos KDC dig _kerberos._tcp.example.com SRV +short dig _kerberos._udp.example.com SRV +short
# Kerberos password change dig _kpasswd._tcp.example.com SRV +short
# Global Catalog dig _gc._tcp.example.com SRV +short
# Domain controller (general) dig _dc._tcp.example.com SRV +short
# SIP/VoIP echo -e "\n=== SIP SRV ===" dig _sip._tcp.example.com SRV +short dig _sip._udp.example.com SRV +short
# XMPP/Jabber echo -e "\n=== XMPP SRV ===" dig _xmpp-server._tcp.example.com SRV +short dig _xmpp-client._tcp.example.com SRV +short
# Email autodiscover echo -e "\n=== Autodiscover SRV ===" dig _autodiscover._tcp.example.com SRV +short ```
- 1.Check for correct SRV record naming (underscore prefixes).
```bash # CRITICAL: Service and protocol MUST have underscore prefix # Format: _service._protocol.domain
# CORRECT: _ldap._tcp.example.com _kerberos._tcp.example.com _sip._tcp.example.com
# WRONG (common mistakes): ldap.tcp.example.com # Missing underscores _ldap.tcp.example.com # Protocol missing underscore ldap._tcp.example.com # Service missing underscore
# Check for underscore prefix errors dig _ldap._tcp.example.com SRV +short # Should return records
# If empty, check if you accidentally created without underscores dig ldap.tcp.example.com SRV +short # If this returns records, you have wrong naming
# Also check protocol - must be _tcp or _udp dig _ldap.tcp.example.com SRV +short # WRONG - should be _tcp ```
- 1.Verify SRV records at authoritative servers.
```bash # Check authoritative servers have the SRV records for ns in $(dig example.com NS +short); do echo "=== ${ns%.} ===" dig @${ns%.} _ldap._tcp.example.com SRV +short done
# Compare results - all should match # If some servers return different results, zone transfer issue
# Check zone file directly (BIND) grep -E "_ldap._tcp|_kerberos._tcp" /etc/bind/zones/example.com.zone
# Expected format: _ldap._tcp.example.com. 3600 IN SRV 10 50 389 ldap.example.com. ```
- 1.Create correct SRV records for your services.
```bash # BIND zone file format: # _service._protocol.domain. TTL IN SRV priority weight port target.
# Active Directory example: _ldap._tcp.example.com. 3600 IN SRV 10 50 389 dc1.example.com. _ldap._tcp.example.com. 3600 IN SRV 10 50 389 dc2.example.com. _ldap._tcp.example.com. 3600 IN SRV 20 0 389 dc-backup.example.com.
_kerberos._tcp.example.com. 3600 IN SRV 10 50 88 dc1.example.com. _kerberos._tcp.example.com. 3600 IN SRV 10 50 88 dc2.example.com.
_kerberos._udp.example.com. 3600 IN SRV 10 50 88 dc1.example.com. _kerberos._udp.example.com. 3600 IN SRV 10 50 88 dc2.example.com.
# SIP example: _sip._tcp.example.com. 3600 IN SRV 10 60 5060 sip1.example.com. _sip._tcp.example.com. 3600 IN SRV 10 40 5060 sip2.example.com.
# XMPP example: _xmpp-server._tcp.example.com. 3600 IN SRV 5 0 5269 xmpp.example.com. _xmpp-client._tcp.example.com. 3600 IN SRV 5 0 5222 xmpp.example.com.
# Control panel format: # Service: _ldap # Protocol: _tcp # Priority: 10 # Weight: 50 # Port: 389 # Target: ldap.example.com ```
- 1.Test service connectivity using SRV-discovered server.
```bash # Full discovery test for LDAP
# Get SRV record srv=$(dig _ldap._tcp.example.com SRV +short | head -1) priority=$(echo $srv | awk '{print $1}') weight=$(echo $srv | awk '{print $2}') port=$(echo $srv | awk '{print $3}') target=$(echo $srv | awk '{print $4}') target=${target%.}
echo "Discovered LDAP server:" echo " Priority: $priority" echo " Weight: $weight" echo " Port: $port" echo " Target: $target"
# Get target IP ip=$(dig $target A +short | head -1) echo " IP: $ip"
# Test LDAP connection ldapsearch -H ldap://$target -x -b "" -s base "(objectClass=*)" dn # Or test port directly nc -vz $ip $port
# Similar for Kerberos: srv=$(dig _kerberos._tcp.example.com SRV +short | head -1) target=$(echo $srv | awk '{print $4}') target=${target%.} echo "Kerberos KDC: $target" ```
- 1.Debug Active Directory-specific SRV issues.
```bash # Active Directory automatically registers SRV records # But manual intervention sometimes needed
# Check domain controller registration # On DC, verify netlogon.dns file: cat C:\Windows\System32\config\netlogon.dns
# Should contain SRV records like: # _ldap._tcp.example.com. 600 IN SRV 0 100 389 dc1.example.com.
# Force DC to re-register SRV records: # PowerShell: nltest /dsregdns /force
# Check DNS has records: dig _ldap._tcp.example.com SRV @dc-ip
# Verify site-specific SRV (for site-aware clients): dig _ldap._tcp.example-site._sites.example.com SRV
# Common AD SRV locations: _ldap._tcp.dc._msdcs.example.com # Domain controllers _ldap._tcp.example.com # LDAP servers _kerberos._tcp.dc._msdcs.example.com # KDC _kerberos._tcp.example.com # KDC _gc._tcp.example.com # Global Catalog ```
- 1.Verify weight distribution is working correctly.
```bash # Weight should influence selection proportionally # Test multiple queries to see distribution
echo "Testing weight distribution over 20 queries:" results="" for i in {1..20}; do target=$(dig _ldap._tcp.example.com SRV +short | head -1 | awk '{print $4}') results="$results $target" done
# Count occurrences echo "$results" | tr ' ' '\n' | sort | uniq -c | sort -rn
# Example output (weight 60:40): # 12 ldap1.example.com. # 8 ldap2.example.com. # Should roughly match weight ratio
# Note: Weight distribution is probabilistic # Not guaranteed exact ratio # Also affected by DNS caching
# If all queries return same server: # - Weight might not be implemented by resolver # - First server always chosen (bug in some resolvers) # - Need to check resolver behavior ```
Verification
Complete SRV verification:
```bash # 1. Check SRV records exist echo "=== SRV Records ===" for service in _ldap._tcp _kerberos._tcp _sip._tcp; do echo -n "$service.example.com: " dig $service.example.com SRV +short | wc -l echo " Records:" dig $service.example.com SRV +short done
# 2. Verify targets resolve echo -e "\n=== Target Resolution ===" for srv in $(dig _ldap._tcp.example.com SRV +short); do target=$(echo $srv | awk '{print $4}') target=${target%.} echo -n "$target: " dig $target A +short done
# 3. Check port connectivity echo -e "\n=== Port Connectivity ===" srv=$(dig _ldap._tcp.example.com SRV +short | head -1) port=$(echo $srv | awk '{print $3}') target=$(echo $srv | awk '{print $4}') target=${target%.} ip=$(dig $target A +short | head -1) echo "Testing $target:$port ($ip)" nc -vz $ip $port && echo "OK" || echo "FAILED"
# 4. Verify priority order echo -e "\n=== Priority Order ===" dig _ldap._tcp.example.com SRV +short | sort -n
# 5. Test actual service connection echo -e "\n=== Service Test ===" target=$(dig _ldap._tcp.example.com SRV +short | head -1 | awk '{print $4}') target=${target%.} ldapsearch -H ldap://$target -x -b "" -s base "(objectClass=*)" dn 2>&1 | head -5 ```
Common SRV Record Reference
```bash # Active Directory / Windows: _ldap._tcp.dc._msdcs.DOMAIN # Domain Controllers _ldap._tcp.DOMAIN # LDAP servers _kerberos._tcp.dc._msdcs.DOMAIN # KDC _kerberos._tcp.DOMAIN # KDC _kerberos._udp.DOMAIN # KDC (UDP) _kpasswd._tcp.DOMAIN # Password change _gc._tcp.DOMAIN # Global Catalog
# SIP / VoIP: _sip._tcp.DOMAIN # SIP TCP _sip._udp.DOMAIN # SIP UDP _sips._tcp.DOMAIN # SIP TLS
# XMPP / Jabber: _xmpp-client._tcp.DOMAIN # Client connections _xmpp-server._tcp.DOMAIN # Server connections
# Email: _autodiscover._tcp.DOMAIN # Outlook autodiscover _imap._tcp.DOMAIN # IMAP _pop3._tcp.DOMAIN # POP3
# Minecraft (example game): _minecraft._tcp.DOMAIN # Minecraft server ```
SRV records power automatic service discovery across many enterprise and internet services. Always verify both the SRV record and its target hostname resolution.