17827cba2SAaron LI# Generate /etc/resolv.conf
27827cba2SAaron LI# Support resolvconf(8) if available
37827cba2SAaron LI# We can merge other dhcpcd resolv.conf files into one like resolvconf,
47827cba2SAaron LI# but resolvconf is preferred as other applications like VPN clients
57827cba2SAaron LI# can readily hook into it.
67827cba2SAaron LI# Also, resolvconf can configure local nameservers such as bind
77827cba2SAaron LI# or dnsmasq. This is important as the libc resolver isn't that powerful.
87827cba2SAaron LI
97827cba2SAaron LIresolv_conf_dir="$state_dir/resolv.conf"
100aaf6155SRoy Marplesnocarrier_roaming_dir="$state_dir/roaming"
117827cba2SAaron LINL="
127827cba2SAaron LI"
137827cba2SAaron LI: ${resolvconf:=resolvconf}
14*80aa9461SRoy Marplesif command -v "$resolvconf" >/dev/null 2>&1; then
150aaf6155SRoy Marples	have_resolvconf=true
160aaf6155SRoy Marpleselse
170aaf6155SRoy Marples	have_resolvconf=false
180aaf6155SRoy Marplesfi
197827cba2SAaron LI
207827cba2SAaron LIbuild_resolv_conf()
217827cba2SAaron LI{
227827cba2SAaron LI	cf="$state_dir/resolv.conf.$ifname"
237827cba2SAaron LI
247827cba2SAaron LI	# Build a list of interfaces
257827cba2SAaron LI	interfaces=$(list_interfaces "$resolv_conf_dir")
267827cba2SAaron LI
277827cba2SAaron LI	# Build the resolv.conf
288d36e1dfSRoy Marples	header=
297827cba2SAaron LI	if [ -n "$interfaces" ]; then
307827cba2SAaron LI		# Build the header
317827cba2SAaron LI		for x in ${interfaces}; do
327827cba2SAaron LI			header="$header${header:+, }$x"
337827cba2SAaron LI		done
347827cba2SAaron LI
357827cba2SAaron LI		# Build the search list
367827cba2SAaron LI		domain=$(cd "$resolv_conf_dir"; \
377827cba2SAaron LI			key_get_value "domain " ${interfaces})
387827cba2SAaron LI		search=$(cd "$resolv_conf_dir"; \
397827cba2SAaron LI			key_get_value "search " ${interfaces})
407827cba2SAaron LI		set -- ${domain}
417827cba2SAaron LI		domain="$1"
427827cba2SAaron LI		[ -n "$2" ] && search="$search $*"
437827cba2SAaron LI		[ -n "$search" ] && search="$(uniqify $search)"
447827cba2SAaron LI		[ "$domain" = "$search" ] && search=
457827cba2SAaron LI		[ -n "$domain" ] && domain="domain $domain$NL"
467827cba2SAaron LI		[ -n "$search" ] && search="search $search$NL"
477827cba2SAaron LI
487827cba2SAaron LI		# Build the nameserver list
497827cba2SAaron LI		srvs=$(cd "$resolv_conf_dir"; \
507827cba2SAaron LI			key_get_value "nameserver " ${interfaces})
516e63cc1fSRoy Marples		for x in $(uniqify $srvs); do
527827cba2SAaron LI			servers="${servers}nameserver $x$NL"
537827cba2SAaron LI		done
547827cba2SAaron LI	fi
557827cba2SAaron LI	header="$signature_base${header:+ $from }$header"
567827cba2SAaron LI
577827cba2SAaron LI	# Assemble resolv.conf using our head and tail files
587827cba2SAaron LI	[ -f "$cf" ] && rm -f "$cf"
597827cba2SAaron LI	[ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
607827cba2SAaron LI	echo "$header" > "$cf"
617827cba2SAaron LI	if [ -f /etc/resolv.conf.head ]; then
627827cba2SAaron LI		cat /etc/resolv.conf.head >> "$cf"
637827cba2SAaron LI	else
647827cba2SAaron LI		echo "# /etc/resolv.conf.head can replace this line" >> "$cf"
657827cba2SAaron LI	fi
667827cba2SAaron LI	printf %s "$domain$search$servers" >> "$cf"
677827cba2SAaron LI	if [ -f /etc/resolv.conf.tail ]; then
687827cba2SAaron LI		cat /etc/resolv.conf.tail >> "$cf"
697827cba2SAaron LI	else
707827cba2SAaron LI		echo "# /etc/resolv.conf.tail can replace this line" >> "$cf"
717827cba2SAaron LI	fi
727827cba2SAaron LI	if change_file /etc/resolv.conf "$cf"; then
737827cba2SAaron LI		chmod 644 /etc/resolv.conf
747827cba2SAaron LI	fi
757827cba2SAaron LI	rm -f "$cf"
767827cba2SAaron LI}
777827cba2SAaron LI
787827cba2SAaron LI# Extract any ND DNS options from the RA
798d36e1dfSRoy Marples# Obey the lifetimes
807827cba2SAaron LIeval_nd_dns()
817827cba2SAaron LI{
828d36e1dfSRoy Marples
838d36e1dfSRoy Marples	eval rdnsstime=\$nd${i}_rdnss${j}_lifetime
848d36e1dfSRoy Marples	[ -z "$rdnsstime" ] && return 1
858d36e1dfSRoy Marples	ltime=$(($rdnsstime - $offset))
868d36e1dfSRoy Marples	if [ "$ltime" -gt 0 ]; then
877827cba2SAaron LI		eval rdnss=\$nd${i}_rdnss${j}_servers
887827cba2SAaron LI		[ -n "$rdnss" ] && new_rdnss="$new_rdnss${new_rdnss:+ }$rdnss"
898d36e1dfSRoy Marples	fi
908d36e1dfSRoy Marples
918d36e1dfSRoy Marples	eval dnssltime=\$nd${i}_dnssl${j}_lifetime
928d36e1dfSRoy Marples	[ -z "$dnssltime" ] && return 1
938d36e1dfSRoy Marples	ltime=$(($dnssltime - $offset))
948d36e1dfSRoy Marples	if [ "$ltime" -gt 0 ]; then
958d36e1dfSRoy Marples		eval dnssl=\$nd${i}_dnssl${j}_search
967827cba2SAaron LI		[ -n "$dnssl" ] && new_dnssl="$new_dnssl${new_dnssl:+ }$dnssl"
978d36e1dfSRoy Marples	fi
988d36e1dfSRoy Marples
997827cba2SAaron LI	j=$(($j + 1))
1007827cba2SAaron LI	return 0
1017827cba2SAaron LI}
1027827cba2SAaron LI
1037827cba2SAaron LIadd_resolv_conf()
1047827cba2SAaron LI{
1057827cba2SAaron LI	conf="$signature$NL"
1067827cba2SAaron LI	warn=true
1077827cba2SAaron LI
1087827cba2SAaron LI	# Loop to extract the ND DNS options using our indexed shell values
1097827cba2SAaron LI	i=1
1107827cba2SAaron LI	j=1
1117827cba2SAaron LI	while true; do
1128d36e1dfSRoy Marples		eval acquired=\$nd${i}_acquired
1138d36e1dfSRoy Marples		[ -z "$acquired" ] && break
1148d36e1dfSRoy Marples		eval now=\$nd${i}_now
1158d36e1dfSRoy Marples		[ -z "$now" ] && break
1168d36e1dfSRoy Marples		offset=$(($now - $acquired))
1177827cba2SAaron LI		while true; do
1187827cba2SAaron LI			eval_nd_dns || break
1197827cba2SAaron LI		done
1207827cba2SAaron LI		i=$(($i + 1))
1217827cba2SAaron LI		j=1
1227827cba2SAaron LI	done
1237827cba2SAaron LI	[ -n "$new_rdnss" ] && \
1247827cba2SAaron LI	    new_domain_name_servers="$new_domain_name_servers${new_domain_name_servers:+ }$new_rdnss"
1257827cba2SAaron LI	[ -n "$new_dnssl" ] && \
1267827cba2SAaron LI	    new_domain_search="$new_domain_search${new_domain_search:+ }$new_dnssl"
1277827cba2SAaron LI
1287827cba2SAaron LI	# Derive a new domain from our various hostname options
1297827cba2SAaron LI	if [ -z "$new_domain_name" ]; then
1307827cba2SAaron LI		if [ "$new_dhcp6_fqdn" != "${new_dhcp6_fqdn#*.}" ]; then
1317827cba2SAaron LI			new_domain_name="${new_dhcp6_fqdn#*.}"
1327827cba2SAaron LI		elif [ "$new_fqdn" != "${new_fqdn#*.}" ]; then
1337827cba2SAaron LI			new_domain_name="${new_fqdn#*.}"
1347827cba2SAaron LI		elif [ "$new_host_name" != "${new_host_name#*.}" ]; then
1357827cba2SAaron LI			new_domain_name="${new_host_name#*.}"
1367827cba2SAaron LI		fi
1377827cba2SAaron LI	fi
1387827cba2SAaron LI
1397827cba2SAaron LI	# If we don't have any configuration, remove it
1408d36e1dfSRoy Marples	if [ -z "$new_domain_name_servers" ] &&
1418d36e1dfSRoy Marples	   [ -z "$new_domain_name" ] &&
1428d36e1dfSRoy Marples	   [ -z "$new_domain_search" ]; then
1437827cba2SAaron LI		remove_resolv_conf
1447827cba2SAaron LI		return $?
1457827cba2SAaron LI	fi
1467827cba2SAaron LI
1477827cba2SAaron LI	if [ -n "$new_domain_name" ]; then
1487827cba2SAaron LI		set -- $new_domain_name
1497827cba2SAaron LI		if valid_domainname "$1"; then
1507827cba2SAaron LI			conf="${conf}domain $1$NL"
1517827cba2SAaron LI		else
1527827cba2SAaron LI			syslog err "Invalid domain name: $1"
1537827cba2SAaron LI		fi
1547827cba2SAaron LI		# If there is no search this, make this one
1557827cba2SAaron LI		if [ -z "$new_domain_search" ]; then
1567827cba2SAaron LI			new_domain_search="$new_domain_name"
1577827cba2SAaron LI			[ "$new_domain_name" = "$1" ] && warn=true
1587827cba2SAaron LI		fi
1597827cba2SAaron LI	fi
1607827cba2SAaron LI	if [ -n "$new_domain_search" ]; then
1616e63cc1fSRoy Marples		new_domain_search=$(uniqify $new_domain_search)
1627827cba2SAaron LI		if valid_domainname_list $new_domain_search; then
1637827cba2SAaron LI			conf="${conf}search $new_domain_search$NL"
1647827cba2SAaron LI		elif ! $warn; then
1657827cba2SAaron LI			syslog err "Invalid domain name in list:" \
1667827cba2SAaron LI			    "$new_domain_search"
1677827cba2SAaron LI		fi
1687827cba2SAaron LI	fi
1696e63cc1fSRoy Marples	new_domain_name_servers=$(uniqify $new_domain_name_servers)
1707827cba2SAaron LI	for x in ${new_domain_name_servers}; do
1717827cba2SAaron LI		conf="${conf}nameserver $x$NL"
1727827cba2SAaron LI	done
1730aaf6155SRoy Marples	if $have_resolvconf; then
1747827cba2SAaron LI		[ -n "$ifmetric" ] && export IF_METRIC="$ifmetric"
1757827cba2SAaron LI		printf %s "$conf" | "$resolvconf" -a "$ifname"
1767827cba2SAaron LI		return $?
1777827cba2SAaron LI	fi
1787827cba2SAaron LI
1797827cba2SAaron LI	if [ -e "$resolv_conf_dir/$ifname" ]; then
1807827cba2SAaron LI		rm -f "$resolv_conf_dir/$ifname"
1817827cba2SAaron LI	fi
1827827cba2SAaron LI	[ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
1837827cba2SAaron LI	printf %s "$conf" > "$resolv_conf_dir/$ifname"
1847827cba2SAaron LI	build_resolv_conf
1857827cba2SAaron LI}
1867827cba2SAaron LI
1877827cba2SAaron LIremove_resolv_conf()
1887827cba2SAaron LI{
1890aaf6155SRoy Marples	if $have_resolvconf; then
1907827cba2SAaron LI		"$resolvconf" -d "$ifname" -f
1917827cba2SAaron LI	else
1927827cba2SAaron LI		if [ -e "$resolv_conf_dir/$ifname" ]; then
1937827cba2SAaron LI			rm -f "$resolv_conf_dir/$ifname"
1947827cba2SAaron LI		fi
1957827cba2SAaron LI		build_resolv_conf
1967827cba2SAaron LI	fi
1977827cba2SAaron LI}
1987827cba2SAaron LI
1997827cba2SAaron LI# For ease of use, map DHCP6 names onto our DHCP4 names
2007827cba2SAaron LIcase "$reason" in
2017827cba2SAaron LIBOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
2027827cba2SAaron LI	new_domain_name_servers="$new_dhcp6_name_servers"
2037827cba2SAaron LI	new_domain_search="$new_dhcp6_domain_search"
2047827cba2SAaron LI	;;
2057827cba2SAaron LIesac
2067827cba2SAaron LI
207b2927f2bSRoy Marplesif $if_configured; then
2080aaf6155SRoy Marples	if $have_resolvconf && [ "$reason" = NOCARRIER_ROAMING ]; then
2090aaf6155SRoy Marples		# avoid calling resolvconf -c on CARRIER unless we roam
2100aaf6155SRoy Marples		mkdir -p "$nocarrier_roaming_dir"
2110aaf6155SRoy Marples		echo " " >"$nocarrier_roaming_dir/$interface"
2120aaf6155SRoy Marples		"$resolvconf" -C "$interface.*"
2130aaf6155SRoy Marples	elif $have_resolvconf && [ "$reason" = CARRIER ]; then
2140aaf6155SRoy Marples		# Not all resolvconf implementations support -c
2150aaf6155SRoy Marples		if [ -e "$nocarrier_roaming_dir/$interface" ]; then
2160aaf6155SRoy Marples			rm -f "$nocarrier_roaming_dir/$interface"
2170aaf6155SRoy Marples			"$resolvconf" -c "$interface.*"
2180aaf6155SRoy Marples		fi
2190aaf6155SRoy Marples	elif $if_up || [ "$reason" = ROUTERADVERT ]; then
2207827cba2SAaron LI		add_resolv_conf
2217827cba2SAaron LI	elif $if_down; then
2227827cba2SAaron LI		remove_resolv_conf
2237827cba2SAaron LI	fi
224b2927f2bSRoy Marplesfi
225