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"
107827cba2SAaron LINL="
117827cba2SAaron LI"
127827cba2SAaron LI: ${resolvconf:=resolvconf}
137827cba2SAaron LI
147827cba2SAaron LIbuild_resolv_conf()
157827cba2SAaron LI{
167827cba2SAaron LI	cf="$state_dir/resolv.conf.$ifname"
177827cba2SAaron LI
187827cba2SAaron LI	# Build a list of interfaces
197827cba2SAaron LI	interfaces=$(list_interfaces "$resolv_conf_dir")
207827cba2SAaron LI
217827cba2SAaron LI	# Build the resolv.conf
228d36e1dfSRoy Marples	header=
237827cba2SAaron LI	if [ -n "$interfaces" ]; then
247827cba2SAaron LI		# Build the header
257827cba2SAaron LI		for x in ${interfaces}; do
267827cba2SAaron LI			header="$header${header:+, }$x"
277827cba2SAaron LI		done
287827cba2SAaron LI
297827cba2SAaron LI		# Build the search list
307827cba2SAaron LI		domain=$(cd "$resolv_conf_dir"; \
317827cba2SAaron LI			key_get_value "domain " ${interfaces})
327827cba2SAaron LI		search=$(cd "$resolv_conf_dir"; \
337827cba2SAaron LI			key_get_value "search " ${interfaces})
347827cba2SAaron LI		set -- ${domain}
357827cba2SAaron LI		domain="$1"
367827cba2SAaron LI		[ -n "$2" ] && search="$search $*"
377827cba2SAaron LI		[ -n "$search" ] && search="$(uniqify $search)"
387827cba2SAaron LI		[ "$domain" = "$search" ] && search=
397827cba2SAaron LI		[ -n "$domain" ] && domain="domain $domain$NL"
407827cba2SAaron LI		[ -n "$search" ] && search="search $search$NL"
417827cba2SAaron LI
427827cba2SAaron LI		# Build the nameserver list
437827cba2SAaron LI		srvs=$(cd "$resolv_conf_dir"; \
447827cba2SAaron LI			key_get_value "nameserver " ${interfaces})
456e63cc1fSRoy Marples		for x in $(uniqify $srvs); do
467827cba2SAaron LI			servers="${servers}nameserver $x$NL"
477827cba2SAaron LI		done
487827cba2SAaron LI	fi
497827cba2SAaron LI	header="$signature_base${header:+ $from }$header"
507827cba2SAaron LI
517827cba2SAaron LI	# Assemble resolv.conf using our head and tail files
527827cba2SAaron LI	[ -f "$cf" ] && rm -f "$cf"
537827cba2SAaron LI	[ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
547827cba2SAaron LI	echo "$header" > "$cf"
557827cba2SAaron LI	if [ -f /etc/resolv.conf.head ]; then
567827cba2SAaron LI		cat /etc/resolv.conf.head >> "$cf"
577827cba2SAaron LI	else
587827cba2SAaron LI		echo "# /etc/resolv.conf.head can replace this line" >> "$cf"
597827cba2SAaron LI	fi
607827cba2SAaron LI	printf %s "$domain$search$servers" >> "$cf"
617827cba2SAaron LI	if [ -f /etc/resolv.conf.tail ]; then
627827cba2SAaron LI		cat /etc/resolv.conf.tail >> "$cf"
637827cba2SAaron LI	else
647827cba2SAaron LI		echo "# /etc/resolv.conf.tail can replace this line" >> "$cf"
657827cba2SAaron LI	fi
667827cba2SAaron LI	if change_file /etc/resolv.conf "$cf"; then
677827cba2SAaron LI		chmod 644 /etc/resolv.conf
687827cba2SAaron LI	fi
697827cba2SAaron LI	rm -f "$cf"
707827cba2SAaron LI}
717827cba2SAaron LI
727827cba2SAaron LI# Extract any ND DNS options from the RA
738d36e1dfSRoy Marples# Obey the lifetimes
747827cba2SAaron LIeval_nd_dns()
757827cba2SAaron LI{
768d36e1dfSRoy Marples
778d36e1dfSRoy Marples	eval rdnsstime=\$nd${i}_rdnss${j}_lifetime
788d36e1dfSRoy Marples	[ -z "$rdnsstime" ] && return 1
798d36e1dfSRoy Marples	ltime=$(($rdnsstime - $offset))
808d36e1dfSRoy Marples	if [ "$ltime" -gt 0 ]; then
817827cba2SAaron LI		eval rdnss=\$nd${i}_rdnss${j}_servers
827827cba2SAaron LI		[ -n "$rdnss" ] && new_rdnss="$new_rdnss${new_rdnss:+ }$rdnss"
838d36e1dfSRoy Marples	fi
848d36e1dfSRoy Marples
858d36e1dfSRoy Marples	eval dnssltime=\$nd${i}_dnssl${j}_lifetime
868d36e1dfSRoy Marples	[ -z "$dnssltime" ] && return 1
878d36e1dfSRoy Marples	ltime=$(($dnssltime - $offset))
888d36e1dfSRoy Marples	if [ "$ltime" -gt 0 ]; then
898d36e1dfSRoy Marples		eval dnssl=\$nd${i}_dnssl${j}_search
907827cba2SAaron LI		[ -n "$dnssl" ] && new_dnssl="$new_dnssl${new_dnssl:+ }$dnssl"
918d36e1dfSRoy Marples	fi
928d36e1dfSRoy Marples
937827cba2SAaron LI	j=$(($j + 1))
947827cba2SAaron LI	return 0
957827cba2SAaron LI}
967827cba2SAaron LI
977827cba2SAaron LIadd_resolv_conf()
987827cba2SAaron LI{
997827cba2SAaron LI	conf="$signature$NL"
1007827cba2SAaron LI	warn=true
1017827cba2SAaron LI
1027827cba2SAaron LI	# Loop to extract the ND DNS options using our indexed shell values
1037827cba2SAaron LI	i=1
1047827cba2SAaron LI	j=1
1057827cba2SAaron LI	while true; do
1068d36e1dfSRoy Marples		eval acquired=\$nd${i}_acquired
1078d36e1dfSRoy Marples		[ -z "$acquired" ] && break
1088d36e1dfSRoy Marples		eval now=\$nd${i}_now
1098d36e1dfSRoy Marples		[ -z "$now" ] && break
1108d36e1dfSRoy Marples		offset=$(($now - $acquired))
1117827cba2SAaron LI		while true; do
1127827cba2SAaron LI			eval_nd_dns || break
1137827cba2SAaron LI		done
1147827cba2SAaron LI		i=$(($i + 1))
1157827cba2SAaron LI		j=1
1167827cba2SAaron LI	done
1177827cba2SAaron LI	[ -n "$new_rdnss" ] && \
1187827cba2SAaron LI	    new_domain_name_servers="$new_domain_name_servers${new_domain_name_servers:+ }$new_rdnss"
1197827cba2SAaron LI	[ -n "$new_dnssl" ] && \
1207827cba2SAaron LI	    new_domain_search="$new_domain_search${new_domain_search:+ }$new_dnssl"
1217827cba2SAaron LI
1227827cba2SAaron LI	# Derive a new domain from our various hostname options
1237827cba2SAaron LI	if [ -z "$new_domain_name" ]; then
1247827cba2SAaron LI		if [ "$new_dhcp6_fqdn" != "${new_dhcp6_fqdn#*.}" ]; then
1257827cba2SAaron LI			new_domain_name="${new_dhcp6_fqdn#*.}"
1267827cba2SAaron LI		elif [ "$new_fqdn" != "${new_fqdn#*.}" ]; then
1277827cba2SAaron LI			new_domain_name="${new_fqdn#*.}"
1287827cba2SAaron LI		elif [ "$new_host_name" != "${new_host_name#*.}" ]; then
1297827cba2SAaron LI			new_domain_name="${new_host_name#*.}"
1307827cba2SAaron LI		fi
1317827cba2SAaron LI	fi
1327827cba2SAaron LI
1337827cba2SAaron LI	# If we don't have any configuration, remove it
1348d36e1dfSRoy Marples	if [ -z "$new_domain_name_servers" ] &&
1358d36e1dfSRoy Marples	   [ -z "$new_domain_name" ] &&
1368d36e1dfSRoy Marples	   [ -z "$new_domain_search" ]; then
1377827cba2SAaron LI		remove_resolv_conf
1387827cba2SAaron LI		return $?
1397827cba2SAaron LI	fi
1407827cba2SAaron LI
1417827cba2SAaron LI	if [ -n "$new_domain_name" ]; then
1427827cba2SAaron LI		set -- $new_domain_name
1437827cba2SAaron LI		if valid_domainname "$1"; then
1447827cba2SAaron LI			conf="${conf}domain $1$NL"
1457827cba2SAaron LI		else
1467827cba2SAaron LI			syslog err "Invalid domain name: $1"
1477827cba2SAaron LI		fi
1487827cba2SAaron LI		# If there is no search this, make this one
1497827cba2SAaron LI		if [ -z "$new_domain_search" ]; then
1507827cba2SAaron LI			new_domain_search="$new_domain_name"
1517827cba2SAaron LI			[ "$new_domain_name" = "$1" ] && warn=true
1527827cba2SAaron LI		fi
1537827cba2SAaron LI	fi
1547827cba2SAaron LI	if [ -n "$new_domain_search" ]; then
1556e63cc1fSRoy Marples		new_domain_search=$(uniqify $new_domain_search)
1567827cba2SAaron LI		if valid_domainname_list $new_domain_search; then
1577827cba2SAaron LI			conf="${conf}search $new_domain_search$NL"
1587827cba2SAaron LI		elif ! $warn; then
1597827cba2SAaron LI			syslog err "Invalid domain name in list:" \
1607827cba2SAaron LI			    "$new_domain_search"
1617827cba2SAaron LI		fi
1627827cba2SAaron LI	fi
1636e63cc1fSRoy Marples	new_domain_name_servers=$(uniqify $new_domain_name_servers)
1647827cba2SAaron LI	for x in ${new_domain_name_servers}; do
1657827cba2SAaron LI		conf="${conf}nameserver $x$NL"
1667827cba2SAaron LI	done
1677827cba2SAaron LI	if type "$resolvconf" >/dev/null 2>&1; then
1687827cba2SAaron LI		[ -n "$ifmetric" ] && export IF_METRIC="$ifmetric"
1697827cba2SAaron LI		printf %s "$conf" | "$resolvconf" -a "$ifname"
1707827cba2SAaron LI		return $?
1717827cba2SAaron LI	fi
1727827cba2SAaron LI
1737827cba2SAaron LI	if [ -e "$resolv_conf_dir/$ifname" ]; then
1747827cba2SAaron LI		rm -f "$resolv_conf_dir/$ifname"
1757827cba2SAaron LI	fi
1767827cba2SAaron LI	[ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
1777827cba2SAaron LI	printf %s "$conf" > "$resolv_conf_dir/$ifname"
1787827cba2SAaron LI	build_resolv_conf
1797827cba2SAaron LI}
1807827cba2SAaron LI
1817827cba2SAaron LIremove_resolv_conf()
1827827cba2SAaron LI{
1837827cba2SAaron LI	if type "$resolvconf" >/dev/null 2>&1; then
1847827cba2SAaron LI		"$resolvconf" -d "$ifname" -f
1857827cba2SAaron LI	else
1867827cba2SAaron LI		if [ -e "$resolv_conf_dir/$ifname" ]; then
1877827cba2SAaron LI			rm -f "$resolv_conf_dir/$ifname"
1887827cba2SAaron LI		fi
1897827cba2SAaron LI		build_resolv_conf
1907827cba2SAaron LI	fi
1917827cba2SAaron LI}
1927827cba2SAaron LI
1937827cba2SAaron LI# For ease of use, map DHCP6 names onto our DHCP4 names
1947827cba2SAaron LIcase "$reason" in
1957827cba2SAaron LIBOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
1967827cba2SAaron LI	new_domain_name_servers="$new_dhcp6_name_servers"
1977827cba2SAaron LI	new_domain_search="$new_dhcp6_domain_search"
1987827cba2SAaron LI	;;
1997827cba2SAaron LIesac
2007827cba2SAaron LI
2017827cba2SAaron LIif $if_up || [ "$reason" = ROUTERADVERT ]; then
2027827cba2SAaron LI	add_resolv_conf
2037827cba2SAaron LIelif $if_down; then
2047827cba2SAaron LI	remove_resolv_conf
2057827cba2SAaron LIfi
206