SRV Records Pointing to CNAME Aliases: RFC 2782 Violation and Practical Implications


3 views

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:

  1. Resolver gets SRV record pointing to alias
  2. Follows CNAME to canonical name
  3. 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:

  1. Additional DNS lookups (increasing latency)
  2. Potential resolution failures during CNAME chain traversal
  3. 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