summaryrefslogblamecommitdiffstats
path: root/dhcpcd/dhcpcd-hooks/20-resolv.conf
blob: 05316c9fff43ab1c705fd94d927e13ff7e3a6806 (plain) (tree)




































































































































































                                                                                                  
# 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="
"

build_resolv_conf()
{
	local cf="$state_dir/resolv.conf.$ifname"
	local interfaces= header= search= srvs= servers= x=

	# Build a list of interfaces
	interfaces=$(list_interfaces "$resolv_conf_dir")

	# Build the resolv.conf
	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"
}

add_resolv_conf()
{
	local x= conf="$signature$NL" i=${ra_count:-0} ra=

	while [ $i -ne 0 ]; do
		eval ra=\$ra${i}_rdnss
		new_domain_name_servers="$new_domain_name_servers${new_domain_name_servers:+ }$ra"
		eval ra=\$ra${i}_dnssl
		new_domain_search="$new_domain_search${new_domain_search:+ }$ra"
		i=$(($i - 1))
	done

	# If we don't have any configuration, remove it
	if [ -z "$new_domain_name_servers" -a \
		-z "$new_domain_name" -a \
		-z "$new_domain_search" ]; then
		remove_resolv_conf
		return $?
	fi

	# 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 [ -n "$new_domain_name" ]; then
		set -- $new_domain_name
		new_domain_name="$1"
		if valid_domainname "$new_domain_name"; then
			conf="${conf}domain $new_domain_name$NL"
		else
			syslog err "Invalid domain name: $new_domain_name"
		fi
		# Support RFC violating search in domain
		if [ -z "$new_domain_search" -a -n "$2" ]; then
			new_domain_search="$*"
		fi
	fi
	if [ -n "$new_domain_search" -a \
	    "$new_domain_search" != "$new_domain_name" ]
	then
		if valid_domainname_list $new_domain_search; then
			conf="${conf}search $new_domain_search$NL"
		else
			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