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 yesin options to monitor RPZ performance - Consider using
qname-wait-recurse noto prevent resolution delays - Cache external lookups with proper TTL settings