FreeBSD resolvconf Operations: Reconcile DNS from DHCP, VPNs, and Local Sources
Trace resolvconf inputs, ordering, generated resolver state, and rollback when DHCP, VPN, or local DNS updates compete on FreeBSD.
An application that cannot resolve a host name may be seeing a bad resolver address, a missing search domain, a stale DHCP record, or an update from a VPN that overwrote another network’s settings. On a single-interface machine, a resolver file can look simple. On a host with several interfaces and network clients, each component may have a legitimate DNS configuration to contribute.
resolvconf is an aggregation framework for those inputs. A client submits resolver data under a key; resolvconf applies ordering and policy and regenerates resolver configuration or a local resolver’s include files. It is not a DNS server, does not test whether a nameserver is reachable, and cannot decide which network is authorized for a particular name. Treat its input records, generated output, and query result as separate layers.
Establish which implementation owns the file
FreeBSD hosts may have resolver settings written directly into /etc/resolv.conf, generated by a client, or managed through the openresolv package. Do not assume that the existence of /etc/resolv.conf proves resolvconf is active. Inspect the command, package, service clients, symlink target, and file timestamp before changing anything:
command -v resolvconf || true
pkg info -e openresolv
ls -l /etc/resolv.conf
stat -f '%Sm %Su:%Sg %Sp %N' /etc/resolv.conf
grep -v '^[[:space:]]*#' /etc/resolv.conf
Record the FreeBSD release and installed package version because the framework’s flags and configuration defaults are release and package specific. The resolvconf manual describes keys such as an interface with an optional protocol suffix, for example em0.dhcp. The file content submitted for a key uses resolver syntax, typically nameserver and search lines, rather than a shell command.
The important diagnostic question is not simply “what is in resolv.conf?” It is “which component submitted each record, what ordering policy selected it, and what file or resolver consumed the result?” A local recursive resolver may instead receive generated include files while libc continues to query 127.0.0.1.
Inspect records before changing policy
Use the installed manual to identify supported read-only listing options. In openresolv, the -i form lists known interfaces, and -l can list their resolver records. Check the exact spelling supported by the installed version:
resolvconf -i
resolvconf -l
grep -v '^[[:space:]]*#' /etc/resolv.conf
service local_unbound status
The output lets an operator compare source records with the generated file. If a DHCP record and a VPN record both list nameservers, the final contents depend on ordering and policy; simply appending a manual nameserver may be overwritten at the next lease renewal or tunnel reconnect.
The -a operation adds or replaces a record for a key from standard input. The -d operation deletes a key. The -u operation reruns update scripts from the existing records. They mutate generated resolver state, so preserve the current file and capture a before snapshot before using them on a live host:
cp -p /etc/resolv.conf /var/tmp/resolv.conf.before
resolvconf -a em0.dhcp < /var/tmp/em0-resolver.conf
resolvconf -l em0.dhcp
Use a lab file with known test addresses; do not submit an arbitrary production nameserver just to see whether the command works. To remove an incorrect test key, use the exact key recorded in the listing, then run the update action if required by the installed implementation. Removing a key may restore another source’s data, not necessarily the previous static file.
Configure ordering and domains with intent
resolvconf.conf controls how submitted records are composed. The installed manual describes options for interface order, dynamic order, static search domains, local nameservers, name-server replacement, and subscribers. Exact options have changed across openresolv versions, so use the local resolvconf.conf(5) and keep package-specific configuration separate from FreeBSD base settings.
A managed static search domain can be appropriate when every network profile uses the same internal suffix. A fixed nameserver is appropriate only when it is reachable on every path where the host is expected to resolve names. In a VPN environment, a split-DNS requirement needs policy that directs only the intended domains to the intended resolver; a flat resolv.conf list cannot necessarily express that policy. Use a local resolver with explicit forwarding or routing rules when the requirement is per-domain.
Do not infer nameserver priority from line order without checking the resolver implementation. The resolv.conf manual documents how libc interprets the generated file, including limits on the listed nameservers and resolver options. Resolver libraries may retry servers according to their own rules; an unreachable first server can therefore cause latency even if a later server is healthy.
For DHCP, identify the exact client integration before configuring resolvconf. Some DHCP clients invoke a hook to submit or delete resolver data; others may update the file through a different mechanism. When a lease renews, record the hook output and compare the source record to the generated result. When a VPN disconnects, verify its record is removed rather than leaving a stale search path or nameserver behind.
Keep local-unbound and libc boundaries clear
When local-unbound is the host’s resolver, libc can use a loopback nameserver while local-unbound has its own upstream or forwarding configuration. In that design, resolvconf may feed local-unbound’s include directory instead of directly selecting public or corporate upstream servers for libc. Editing the generated file by hand can bypass the policy and obscure which component is authoritative.
Check both layers:
grep -v '^[[:space:]]*#' /etc/resolv.conf
service local_unbound status
drill @127.0.0.1 example.com
getent hosts example.com
Replace example.com with a controlled name and use tools installed on the target host. A successful direct query to 127.0.0.1 proves that listener answered that query; getent exercises a name-service path and may involve nsswitch policy or caches. Neither test alone validates split-DNS behavior for every application.
If a daemon includes generated resolvconf files, inspect the service’s configuration and reload procedure. Avoid editing generated include output directly. Make the policy change in the owning configuration, regenerate with the documented update action, and verify that the daemon loaded the new file.
Diagnose stale, missing, and conflicting entries
For a missing nameserver, compare the source record list with the output file. If the record is absent, investigate the DHCP or VPN hook, key naming, and whether the client called resolvconf at all. If it is present in source state but absent from output, inspect ordering, exclusive/private flags, subscriber logic, and local overrides.
For a stale server, determine which key supplied it. Remove or update that source through its owner, then regenerate output. Do not make /etc/resolv.conf immutable as a generic repair: doing so can block legitimate failover, DHCP renewal, VPN setup, and local resolver integration. If policy intentionally disables automatic updates, document which component now owns the file and how it will be updated during a network change.
For wrong search domains, compare the generated search list with both the submitted records and resolvconf.conf. Short names are expanded by resolver policy, not by DNS itself; a wrong search suffix can send a valid query to an unintended namespace. Prefer fully qualified test names when verifying the upstream path.
For slow resolution, collect per-server query timing and packet traces instead of repeatedly restarting networking. DNS transport reachability, routing, firewall policy, resolver retries, and cache state are different failure domains. A ping to a nameserver does not prove that UDP or TCP port 53 queries succeed.
Change management and acceptance tests
Back up the generated file, record the current records, and change one source or ordering rule at a time. Reproduce lease renewal, interface disconnect, VPN connect/disconnect, and reboot in staging. Verify that expected records are present, stale records disappear, local resolver includes remain valid, and a known internal and external name resolve through the intended path.
Capture the exact resolver file, resolvconf record listing, service status, route to each nameserver, and a timestamped query result. Keep configuration changes in their owning package or host-management system rather than making a one-time generated-file edit. Rollback must restore the source policy and then regenerate the output; copying the old resolver file back may last only until the next event.
The acceptance boundary is explicit: the correct sources contributed the expected records, the framework applied the intended composition, the active resolver consumed that output, and both positive and negative query tests matched the expected network policy. resolvconf coordinates resolver configuration; it does not guarantee DNS availability or application correctness.
Related:
- FreeBSD local-unbound Operations: Resolver Setup and DNSSEC Checks
- FreeBSD DHCP Client Lease Lifecycle: Boot, Renewal, and Recovery
Sources: