How to Override Specific DNS Records in BIND While Maintaining External Resolution for Internal Networks


3 views

When managing an internal network with BIND DNS servers, administrators often need to resolve certain domain records to internal IP addresses while maintaining external resolution for other records. This becomes particularly challenging when dealing with domains that have both public and private resources.

The typical solution of creating individual zone files for each host (like host1.example.com) works for specific records but breaks down when you need to:

# Current working but limited configuration
zone "host1.example.com" {
    type master;
    file "/etc/bind/zones/db.host1.example.com";
};

zone "host2.example.com" {
    type master;
    file "/etc/bind/zones/db.host2.example.com";
};

The problem emerges when attempting to override the apex record (example.com) while preserving external resolution for other records in the same domain.

The proper solution involves configuring BIND to act as a delegating nameserver for specific records while forwarding others:

zone "example.com" {
    type master;
    file "/etc/bind/zones/db.example.com.internal";
    allow-query { any; };
};

Then in your zone file (db.example.com.internal):

$TTL 86400
@       IN      SOA     ns1.example.com. admin.example.com. (
                        2023081501 ; Serial
                        3600       ; Refresh
                        1800       ; Retry
                        604800     ; Expire
                        86400      ; Minimum TTL
)

; Name servers
        IN      NS      ns1.example.com.
        IN      NS      ns2.example.com.

; Internal records
@       IN      A       192.168.1.1
host1   IN      A       192.168.1.2
host2   IN      A       192.168.1.3
www     IN      CNAME   host1

; Delegation for other records
*       IN      NS      external-ns.example.com.
external-ns IN   A      203.0.113.1

For more complex scenarios, consider using BIND's Response Policy Zones feature:

options {
    response-policy { 
        zone "rpz.example.com";
    };
};

zone "rpz.example.com" {
    type master;
    file "/etc/bind/zones/db.rpz.example.com";
    allow-query { none; };
};

RPZ file content:

$TTL 3600
@               IN      SOA     localhost. root.localhost. (
                                2023081501 ; serial
                                1h         ; refresh
                                30m        ; retry
                                1w         ; expire
                                1h         ; minimum
                            )
                IN      NS      localhost.

; Override specific records
host1.example.com   A   192.168.1.2
host2.example.com   A   192.168.1.3
example.com         A   192.168.1.1

After implementing either solution, verify your configuration:

# Check configuration syntax
named-checkconf

# Test resolution from internal clients
dig host1.example.com
dig otherhost.example.com
dig example.com

When implementing these solutions:

  • Use proper TTL values to balance cache efficiency and responsiveness
  • Consider implementing DNS caching for external queries
  • Monitor query response times for both internal and external records

Remember to:

  • Restrict zone transfers
  • Implement proper ACLs for queries
  • Regularly update BIND to the latest stable version

When running an internal BIND DNS server, you might need to override certain public DNS records (like host1.example.com) to point to internal IPs while preserving external resolution for other records (like otherhost.example.com). The challenge arises when trying to override the domain apex (example.com) without hijacking all subdomains.

Creating a zone for example.com in BIND makes it authoritative for all records under that domain, causing resolution failures for non-overridden records. This happens because:

zone "example.com" {
    type master;
    file "db.example.com"; # Now responsible for ALL example.com queries
};

BIND provides two effective approaches:

Method 1: Per-Host Zones with Empty Non-Terminal Wildcards

# Override specific hosts
zone "host1.example.com" {
    type master;
    file "db.host1.example.com";
};

zone "host2.example.com" {
    type master;
    file "db.host2.example.com";
};

# Allow other queries to resolve externally
zone "example.com" {
    type forward;
    forwarders { 8.8.8.8; 8.8.4.4; };
};

In each host zone file (db.host1.example.com):

$TTL 3600
@ IN SOA ns1.example.com. admin.example.com. (
    2023081501 ; serial
    3600       ; refresh
    900        ; retry
    604800     ; expire
    86400      ; minimum
)
@ IN NS ns1.example.com.
@ IN A 192.168.1.10
* IN CNAME . # Wildcard that doesn't match non-terminals

Method 2: Response Policy Zones (RPZ)

More scalable for multiple overrides:

options {
    response-policy {
        zone "rpz-example";
    };
};

zone "rpz-example" {
    type master;
    file "db.rpz-example";
    allow-query { none; };
};

RPZ zone file (db.rpz-example):

$TTL 3600
@ IN SOA localhost. root.localhost. (1 3600 1200 604800 10800)
@ IN NS localhost.

; Override rules
host1.example.com A 192.168.1.10
host2.example.com A 192.168.1.20
example.com A 192.168.1.1

Always verify with:

dig +norecurse host1.example.com @localhost
dig otherhost.example.com @localhost

For large-scale deployments:

  • Use zone-stats yes in options to monitor RPZ performance
  • Consider using qname-wait-recurse no to prevent resolution delays
  • Cache external lookups with proper TTL settings