# Generate /etc/resolv.conf
# Support resolvconf(8) if available
# We can merge other dhcpcd resolv.conf files into one like resolvconf,
# but resolvconf is preferred as other applications like VPN clients
# can readily hook into it.
# Also, resolvconf can configure local nameservers such as bind
# or dnsmasq. This is important as the libc resolver isn't that powerful.
resolv_conf_dir="$state_dir/resolv.conf"
NL="
"
: ${resolvconf:=resolvconf}
build_resolv_conf()
{
cf="$state_dir/resolv.conf.$ifname"
# Build a list of interfaces
interfaces=$(list_interfaces "$resolv_conf_dir")
# Build the resolv.conf
header=
if [ -n "$interfaces" ]; then
# Build the header
for x in ${interfaces}; do
header="$header${header:+, }$x"
done
# Build the search list
domain=$(cd "$resolv_conf_dir"; \
key_get_value "domain " ${interfaces})
search=$(cd "$resolv_conf_dir"; \
key_get_value "search " ${interfaces})
set -- ${domain}
domain="$1"
[ -n "$2" ] && search="$search $*"
[ -n "$search" ] && search="$(uniqify $search)"
[ "$domain" = "$search" ] && search=
[ -n "$domain" ] && domain="domain $domain$NL"
[ -n "$search" ] && search="search $search$NL"
# Build the nameserver list
srvs=$(cd "$resolv_conf_dir"; \
key_get_value "nameserver " ${interfaces})
for x in $(uniqify ${srvs}); do
servers="${servers}nameserver $x$NL"
done
fi
header="$signature_base${header:+ $from }$header"
# Assemble resolv.conf using our head and tail files
[ -f "$cf" ] && rm -f "$cf"
[ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
echo "$header" > "$cf"
if [ -f /etc/resolv.conf.head ]; then
cat /etc/resolv.conf.head >> "$cf"
else
echo "# /etc/resolv.conf.head can replace this line" >> "$cf"
fi
printf %s "$domain$search$servers" >> "$cf"
if [ -f /etc/resolv.conf.tail ]; then
cat /etc/resolv.conf.tail >> "$cf"
else
echo "# /etc/resolv.conf.tail can replace this line" >> "$cf"
fi
if change_file /etc/resolv.conf "$cf"; then
chmod 644 /etc/resolv.conf
fi
rm -f "$cf"
}
# Extract any ND DNS options from the RA
# Obey the lifetimes
eval_nd_dns()
{
eval rdnsstime=\$nd${i}_rdnss${j}_lifetime
[ -z "$rdnsstime" ] && return 1
ltime=$(($rdnsstime - $offset))
if [ "$ltime" -gt 0 ]; then
eval rdnss=\$nd${i}_rdnss${j}_servers
[ -n "$rdnss" ] && new_rdnss="$new_rdnss${new_rdnss:+ }$rdnss"
fi
eval dnssltime=\$nd${i}_dnssl${j}_lifetime
[ -z "$dnssltime" ] && return 1
ltime=$(($dnssltime - $offset))
if [ "$ltime" -gt 0 ]; then
eval dnssl=\$nd${i}_dnssl${j}_search
[ -n "$dnssl" ] && new_dnssl="$new_dnssl${new_dnssl:+ }$dnssl"
fi
j=$(($j + 1))
return 0
}
add_resolv_conf()
{
conf="$signature$NL"
warn=true
# Loop to extract the ND DNS options using our indexed shell values
i=1
j=1
while true; do
eval acquired=\$nd${i}_acquired
[ -z "$acquired" ] && break
eval now=\$nd${i}_now
[ -z "$now" ] && break
offset=$(($now - $acquired))
while true; do
eval_nd_dns || break
done
i=$(($i + 1))
j=1
done
[ -n "$new_rdnss" ] && \
new_domain_name_servers="$new_domain_name_servers${new_domain_name_servers:+ }$new_rdnss"
[ -n "$new_dnssl" ] && \
new_domain_search="$new_domain_search${new_domain_search:+ }$new_dnssl"
# Derive a new domain from our various hostname options
if [ -z "$new_domain_name" ]; then
if [ "$new_dhcp6_fqdn" != "${new_dhcp6_fqdn#*.}" ]; then
new_domain_name="${new_dhcp6_fqdn#*.}"
elif [ "$new_fqdn" != "${new_fqdn#*.}" ]; then
new_domain_name="${new_fqdn#*.}"
elif [ "$new_host_name" != "${new_host_name#*.}" ]; then
new_domain_name="${new_host_name#*.}"
fi
fi
# If we don't have any configuration, remove it
if [ -z "$new_domain_name_servers" ] &&
[ -z "$new_domain_name" ] &&
[ -z "$new_domain_search" ]; then
remove_resolv_conf
return $?
fi
if [ -n "$new_domain_name" ]; then
set -- $new_domain_name
if valid_domainname "$1"; then
conf="${conf}domain $1$NL"
else
syslog err "Invalid domain name: $1"
fi
# If there is no search this, make this one
if [ -z "$new_domain_search" ]; then
new_domain_search="$new_domain_name"
[ "$new_domain_name" = "$1" ] && warn=true
fi
fi
if [ -n "$new_domain_search" ]; then
if valid_domainname_list $new_domain_search; then
conf="${conf}search $new_domain_search$NL"
elif ! $warn; then
syslog err "Invalid domain name in list:" \
"$new_domain_search"
fi
fi
for x in ${new_domain_name_servers}; do
conf="${conf}nameserver $x$NL"
done
if type "$resolvconf" >/dev/null 2>&1; then
[ -n "$ifmetric" ] && export IF_METRIC="$ifmetric"
printf %s "$conf" | "$resolvconf" -a "$ifname"
return $?
fi
if [ -e "$resolv_conf_dir/$ifname" ]; then
rm -f "$resolv_conf_dir/$ifname"
fi
[ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
printf %s "$conf" > "$resolv_conf_dir/$ifname"
build_resolv_conf
}
remove_resolv_conf()
{
if type "$resolvconf" >/dev/null 2>&1; then
"$resolvconf" -d "$ifname" -f
else
if [ -e "$resolv_conf_dir/$ifname" ]; then
rm -f "$resolv_conf_dir/$ifname"
fi
build_resolv_conf
fi
}
# For ease of use, map DHCP6 names onto our DHCP4 names
case "$reason" in
BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
new_domain_name_servers="$new_dhcp6_name_servers"
new_domain_search="$new_dhcp6_domain_search"
;;
esac
if $if_up || [ "$reason" = ROUTERADVERT ]; then
add_resolv_conf
elif $if_down; then
remove_resolv_conf
fi