Home | History | Annotate | Line # | Download | only in hooks
20-resolv.conf revision 1.8
      1 # Generate /etc/resolv.conf
      2 # Support resolvconf(8) if available
      3 # We can merge other dhcpcd resolv.conf files into one like resolvconf,
      4 # but resolvconf is preferred as other applications like VPN clients
      5 # can readily hook into it.
      6 # Also, resolvconf can configure local nameservers such as bind
      7 # or dnsmasq. This is important as the libc resolver isn't that powerful.
      8 
      9 resolv_conf_dir="$state_dir/resolv.conf"
     10 nocarrier_roaming_dir="$state_dir/roaming"
     11 NL="
     12 "
     13 : ${resolvconf:=resolvconf}
     14 if command -v "$resolvconf" >/dev/null 2>&1; then
     15 	have_resolvconf=true
     16 else
     17 	have_resolvconf=false
     18 fi
     19 
     20 build_resolv_conf()
     21 {
     22 	cf="$state_dir/resolv.conf.$ifname"
     23 
     24 	# Build a list of interfaces
     25 	interfaces=$(list_interfaces "$resolv_conf_dir")
     26 
     27 	# Build the resolv.conf
     28 	header=
     29 	if [ -n "$interfaces" ]; then
     30 		# Build the header
     31 		for x in ${interfaces}; do
     32 			header="$header${header:+, }$x"
     33 		done
     34 
     35 		# Build the search list
     36 		domain=$(cd "$resolv_conf_dir"; \
     37 			key_get_value "domain " ${interfaces})
     38 		search=$(cd "$resolv_conf_dir"; \
     39 			key_get_value "search " ${interfaces})
     40 		set -- ${domain}
     41 		domain="$1"
     42 		[ -n "$2" ] && search="$search $*"
     43 		[ -n "$search" ] && search="$(uniqify $search)"
     44 		[ "$domain" = "$search" ] && search=
     45 		[ -n "$domain" ] && domain="domain $domain$NL"
     46 		[ -n "$search" ] && search="search $search$NL"
     47 
     48 		# Build the nameserver list
     49 		srvs=$(cd "$resolv_conf_dir"; \
     50 			key_get_value "nameserver " ${interfaces})
     51 		for x in $(uniqify $srvs); do
     52 			servers="${servers}nameserver $x$NL"
     53 		done
     54 	fi
     55 	header="$signature_base${header:+ $from }$header"
     56 
     57 	# Assemble resolv.conf using our head and tail files
     58 	[ -f "$cf" ] && rm -f "$cf"
     59 	[ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
     60 	echo "$header" > "$cf"
     61 	if [ -f /etc/resolv.conf.head ]; then
     62 		cat /etc/resolv.conf.head >> "$cf"
     63 	else
     64 		echo "# /etc/resolv.conf.head can replace this line" >> "$cf"
     65 	fi
     66 	printf %s "$domain$search$servers" >> "$cf"
     67 	if [ -f /etc/resolv.conf.tail ]; then
     68 		cat /etc/resolv.conf.tail >> "$cf"
     69 	else
     70 		echo "# /etc/resolv.conf.tail can replace this line" >> "$cf"
     71 	fi
     72 	if change_file /etc/resolv.conf "$cf"; then
     73 		chmod 644 /etc/resolv.conf
     74 	fi
     75 	rm -f "$cf"
     76 }
     77 
     78 # Extract any ND DNS options from the RA
     79 # Obey the lifetimes
     80 eval_nd_dns()
     81 {
     82 
     83 	eval rdnsstime=\$nd${i}_rdnss${j}_lifetime
     84 	if [ -n "$rdnsstime" ]; then
     85 		ltime=$(($rdnsstime - $offset))
     86 		if [ "$ltime" -gt 0 ]; then
     87 			eval rdnss=\$nd${i}_rdnss${j}_servers
     88 			if [ -n "$rdnss" ]; then
     89 				new_rdnss="$new_rdnss${new_rdnss:+ }$rdnss"
     90 			fi
     91 		fi
     92 	fi
     93 
     94 	eval dnssltime=\$nd${i}_dnssl${j}_lifetime
     95 	if [ -n "$dnssltime" ]; then
     96 		ltime=$(($dnssltime - $offset))
     97 		if [ "$ltime" -gt 0 ]; then
     98 			eval dnssl=\$nd${i}_dnssl${j}_search
     99 			if [ -n "$dnssl" ]; then
    100 				new_dnssl="$new_dnssl${new_dnssl:+ }$dnssl"
    101 			fi
    102 		fi
    103 	fi
    104 
    105 	# Break when we don't have either
    106 	[ -z "$rdnsstime" ] && [ -z "$dnssltime" ] && return 1
    107 
    108 	j=$(($j + 1))
    109 	return 0
    110 }
    111 
    112 add_resolv_conf()
    113 {
    114 	conf="$signature$NL"
    115 	warn=true
    116 
    117 	# Loop to extract the ND DNS options using our indexed shell values
    118 	i=1
    119 	j=1
    120 	while true; do
    121 		eval acquired=\$nd${i}_acquired
    122 		[ -z "$acquired" ] && break
    123 		eval now=\$nd${i}_now
    124 		[ -z "$now" ] && break
    125 		offset=$(($now - $acquired))
    126 		while true; do
    127 			eval_nd_dns || break
    128 		done
    129 		i=$(($i + 1))
    130 		j=1
    131 	done
    132 	[ -n "$new_rdnss" ] && \
    133 	    new_domain_name_servers="$new_domain_name_servers${new_domain_name_servers:+ }$new_rdnss"
    134 	[ -n "$new_dnssl" ] && \
    135 	    new_domain_search="$new_domain_search${new_domain_search:+ }$new_dnssl"
    136 
    137 	# Derive a new domain from our various hostname options
    138 	if [ -z "$new_domain_name" ]; then
    139 		if [ "$new_dhcp6_fqdn" != "${new_dhcp6_fqdn#*.}" ]; then
    140 			new_domain_name="${new_dhcp6_fqdn#*.}"
    141 		elif [ "$new_fqdn" != "${new_fqdn#*.}" ]; then
    142 			new_domain_name="${new_fqdn#*.}"
    143 		elif [ "$new_host_name" != "${new_host_name#*.}" ]; then
    144 			new_domain_name="${new_host_name#*.}"
    145 		fi
    146 	fi
    147 
    148 	# If we don't have any configuration, remove it
    149 	if [ -z "$new_domain_name_servers" ] &&
    150 	   [ -z "$new_domain_name" ] &&
    151 	   [ -z "$new_domain_search" ]; then
    152 		remove_resolv_conf
    153 		return $?
    154 	fi
    155 
    156 	if [ -n "$new_domain_name" ]; then
    157 		set -- $new_domain_name
    158 		if valid_domainname "$1"; then
    159 			conf="${conf}domain $1$NL"
    160 		else
    161 			syslog err "Invalid domain name: $1"
    162 		fi
    163 		# If there is no search this, make this one
    164 		if [ -z "$new_domain_search" ]; then
    165 			new_domain_search="$new_domain_name"
    166 			[ "$new_domain_name" = "$1" ] && warn=true
    167 		fi
    168 	fi
    169 	if [ -n "$new_domain_search" ]; then
    170 		new_domain_search=$(uniqify $new_domain_search)
    171 		if valid_domainname_list $new_domain_search; then
    172 			conf="${conf}search $new_domain_search$NL"
    173 		elif ! $warn; then
    174 			syslog err "Invalid domain name in list:" \
    175 			    "$new_domain_search"
    176 		fi
    177 	fi
    178 	new_domain_name_servers=$(uniqify $new_domain_name_servers)
    179 	for x in ${new_domain_name_servers}; do
    180 		conf="${conf}nameserver $x$NL"
    181 	done
    182 	if $have_resolvconf; then
    183 		[ -n "$ifmetric" ] && export IF_METRIC="$ifmetric"
    184 		printf %s "$conf" | "$resolvconf" -a "$ifname"
    185 		return $?
    186 	fi
    187 
    188 	if [ -e "$resolv_conf_dir/$ifname" ]; then
    189 		rm -f "$resolv_conf_dir/$ifname"
    190 	fi
    191 	[ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir"
    192 	printf %s "$conf" > "$resolv_conf_dir/$ifname"
    193 	build_resolv_conf
    194 }
    195 
    196 remove_resolv_conf()
    197 {
    198 	if $have_resolvconf; then
    199 		"$resolvconf" -d "$ifname" -f
    200 	else
    201 		if [ -e "$resolv_conf_dir/$ifname" ]; then
    202 			rm -f "$resolv_conf_dir/$ifname"
    203 		fi
    204 		build_resolv_conf
    205 	fi
    206 }
    207 
    208 # For ease of use, map DHCP6 names onto our DHCP4 names
    209 case "$reason" in
    210 BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
    211 	new_domain_name_servers="$new_dhcp6_name_servers"
    212 	new_domain_search="$new_dhcp6_domain_search"
    213 	;;
    214 esac
    215 
    216 if $if_configured; then
    217 	if $have_resolvconf && [ "$reason" = NOCARRIER_ROAMING ]; then
    218 		# avoid calling resolvconf -c on CARRIER unless we roam
    219 		mkdir -p "$nocarrier_roaming_dir"
    220 		echo " " >"$nocarrier_roaming_dir/$interface"
    221 		"$resolvconf" -C "$interface.*"
    222 	elif $have_resolvconf && [ "$reason" = CARRIER ]; then
    223 		# Not all resolvconf implementations support -c
    224 		if [ -e "$nocarrier_roaming_dir/$interface" ]; then
    225 			rm -f "$nocarrier_roaming_dir/$interface"
    226 			"$resolvconf" -c "$interface.*"
    227 		fi
    228 	elif $if_up || [ "$reason" = ROUTERADVERT ]; then
    229 		add_resolv_conf
    230 	elif $if_down; then
    231 		remove_resolv_conf
    232 	fi
    233 fi
    234