RFC 2782 clearly states that SRV records should point directly to A or AAAA records, not to CNAME aliases. The relevant section states:
3. The format of the SRV RR Here is the format of the SRV RR, whose DNS type code is 33: _Service._Proto.Name TTL Class SRV Priority Weight Port Target
The key requirement is that the Target
field must be "the canonical hostname of the machine providing the service, and must point to one or more address records (A or AAAA)".
Here's what we commonly observe in production environments despite the RFC prohibition:
; SRV record pointing to CNAME > dig +short _xmpp-server._tcp.example.com SRV 0 5 5269 chat-server.example.com. > dig +short chat-server.example.com lb.example.net. lb.example.net. 300 IN A 192.0.2.1 lb.example.net. 300 IN A 192.0.2.2
Most DNS resolvers will follow CNAME chains when resolving SRV records:
- Resolver gets SRV record pointing to alias
- Follows CNAME to canonical name
- Resolves final A/AAAA records
Example resolution flow in code:
def resolve_srv(domain): srv = dns.resolver.resolve('_service._tcp.' + domain, 'SRV') target = srv[0].target.to_text() # This violates RFC but works in practice cname = dns.resolver.resolve(target, 'CNAME') final_a = dns.resolver.resolve(cname[0].target.to_text(), 'A') return (srv[0].port, [str(ip) for ip in final_a])
- Some strict DNS validators will flag this as an error
- DNS64/NAT64 translation may fail
- Increased resolution latency due to extra lookups
- DNSSEC validation becomes more complex
For RFC-compliant configuration, always point SRV records directly to A/AAAA hosts:
; Correct implementation _xmpp-server._tcp.example.com. 300 IN SRV 0 5 5269 server1.example.com. _xmpp-server._tcp.example.com. 300 IN SRV 0 5 5269 server2.example.com. server1.example.com. 300 IN A 192.0.2.10 server2.example.com. 300 IN A 192.0.2.11
For AWS ALB/ELB scenarios, use alias records instead of CNAMEs where possible:
; AWS Route53 alias record (not CNAME) api.example.com. 300 IN A dualstack.my-alb-123456789.us-west-2.elb.amazonaws.com.
To check your SRV record configuration:
# Check SRV records dig +short _service._tcp.domain.com SRV # Trace full resolution path dig +trace _service._tcp.domain.com SRV # Validate DNSSEC chain delv _service._tcp.domain.com SRV
While troubleshooting a DNS configuration recently, I encountered an interesting discrepancy between RFC standards and actual implementations. RFC 2782 clearly states that SRV records should point directly to A or AAAA records, not CNAME aliases. However, my dig
queries revealed multiple production environments doing exactly this:
; SRV record pointing to CNAME
_ldap._tcp.example.com. 3600 IN SRV 0 100 389 ldap-alias.example.com.
ldap-alias.example.com. 300 IN CNAME elb-1234.aws.amazon.com.
elb-1234.aws.amazon.com. 60 IN A 192.0.2.45
Modern cloud infrastructure often relies on DNS aliasing for:
- Load balancer configurations (AWS ALB/ELB, Azure Traffic Manager)
- Blue-green deployments
- Multi-cloud failover scenarios
A Python DNS lookup example showing this behavior:
import dns.resolver
def check_srv_chain(domain):
answers = dns.resolver.resolve('_service._tcp.' + domain, 'SRV')
for rdata in answers:
target = str(rdata.target).rstrip('.')
try:
cname = dns.resolver.resolve(target, 'CNAME')
print(f"Violation: {target} is CNAME to {cname[0].target}")
except dns.resolver.NoAnswer:
print(f"Compliant: {target} has direct A/AAAA records")
While these configurations often work in practice, they can cause:
- Additional DNS lookups (increasing latency)
- Potential resolution failures during CNAME chain traversal
- Unexpected behavior with DNSSEC validation
Here's a BIND zone file example showing the compliant approach:
; Compliant SRV configuration
_sip._tcp.example.com. 3600 IN SRV 10 50 5060 sipserver1.example.com.
_sip._tcp.example.com. 3600 IN SRV 20 50 5060 sipserver2.example.com.
sipserver1.example.com. 300 IN A 203.0.113.1
sipserver2.example.com. 300 IN A 203.0.113.2
When working with SRV records:
# Bash script to validate SRV-CNAME chains
dig SRV _service._tcp.domain.com +short | awk '{print $4}' | while read target; do
if dig CNAME "$target" +short | grep -q .; then
echo "WARNING: $target is a CNAME"
fi
done
For cloud deployments, consider:
- Using API-driven DNS updates when endpoints change
- Implementing health checks at the application level
- Monitoring DNS resolution times in your application