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 9resolv_conf_dir="$state_dir/resolv.conf" 10nocarrier_roaming_dir="$state_dir/roaming" 11NL=" 12" 13: ${resolvconf:=resolvconf} 14if type "$resolvconf" >/dev/null 2>&1; then 15 have_resolvconf=true 16else 17 have_resolvconf=false 18fi 19 20build_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 80eval_nd_dns() 81{ 82 83 eval rdnsstime=\$nd${i}_rdnss${j}_lifetime 84 [ -z "$rdnsstime" ] && return 1 85 ltime=$(($rdnsstime - $offset)) 86 if [ "$ltime" -gt 0 ]; then 87 eval rdnss=\$nd${i}_rdnss${j}_servers 88 [ -n "$rdnss" ] && new_rdnss="$new_rdnss${new_rdnss:+ }$rdnss" 89 fi 90 91 eval dnssltime=\$nd${i}_dnssl${j}_lifetime 92 [ -z "$dnssltime" ] && return 1 93 ltime=$(($dnssltime - $offset)) 94 if [ "$ltime" -gt 0 ]; then 95 eval dnssl=\$nd${i}_dnssl${j}_search 96 [ -n "$dnssl" ] && new_dnssl="$new_dnssl${new_dnssl:+ }$dnssl" 97 fi 98 99 j=$(($j + 1)) 100 return 0 101} 102 103add_resolv_conf() 104{ 105 conf="$signature$NL" 106 warn=true 107 108 # Loop to extract the ND DNS options using our indexed shell values 109 i=1 110 j=1 111 while true; do 112 eval acquired=\$nd${i}_acquired 113 [ -z "$acquired" ] && break 114 eval now=\$nd${i}_now 115 [ -z "$now" ] && break 116 offset=$(($now - $acquired)) 117 while true; do 118 eval_nd_dns || break 119 done 120 i=$(($i + 1)) 121 j=1 122 done 123 [ -n "$new_rdnss" ] && \ 124 new_domain_name_servers="$new_domain_name_servers${new_domain_name_servers:+ }$new_rdnss" 125 [ -n "$new_dnssl" ] && \ 126 new_domain_search="$new_domain_search${new_domain_search:+ }$new_dnssl" 127 128 # Derive a new domain from our various hostname options 129 if [ -z "$new_domain_name" ]; then 130 if [ "$new_dhcp6_fqdn" != "${new_dhcp6_fqdn#*.}" ]; then 131 new_domain_name="${new_dhcp6_fqdn#*.}" 132 elif [ "$new_fqdn" != "${new_fqdn#*.}" ]; then 133 new_domain_name="${new_fqdn#*.}" 134 elif [ "$new_host_name" != "${new_host_name#*.}" ]; then 135 new_domain_name="${new_host_name#*.}" 136 fi 137 fi 138 139 # If we don't have any configuration, remove it 140 if [ -z "$new_domain_name_servers" ] && 141 [ -z "$new_domain_name" ] && 142 [ -z "$new_domain_search" ]; then 143 remove_resolv_conf 144 return $? 145 fi 146 147 if [ -n "$new_domain_name" ]; then 148 set -- $new_domain_name 149 if valid_domainname "$1"; then 150 conf="${conf}domain $1$NL" 151 else 152 syslog err "Invalid domain name: $1" 153 fi 154 # If there is no search this, make this one 155 if [ -z "$new_domain_search" ]; then 156 new_domain_search="$new_domain_name" 157 [ "$new_domain_name" = "$1" ] && warn=true 158 fi 159 fi 160 if [ -n "$new_domain_search" ]; then 161 new_domain_search=$(uniqify $new_domain_search) 162 if valid_domainname_list $new_domain_search; then 163 conf="${conf}search $new_domain_search$NL" 164 elif ! $warn; then 165 syslog err "Invalid domain name in list:" \ 166 "$new_domain_search" 167 fi 168 fi 169 new_domain_name_servers=$(uniqify $new_domain_name_servers) 170 for x in ${new_domain_name_servers}; do 171 conf="${conf}nameserver $x$NL" 172 done 173 if $have_resolvconf; then 174 [ -n "$ifmetric" ] && export IF_METRIC="$ifmetric" 175 printf %s "$conf" | "$resolvconf" -a "$ifname" 176 return $? 177 fi 178 179 if [ -e "$resolv_conf_dir/$ifname" ]; then 180 rm -f "$resolv_conf_dir/$ifname" 181 fi 182 [ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir" 183 printf %s "$conf" > "$resolv_conf_dir/$ifname" 184 build_resolv_conf 185} 186 187remove_resolv_conf() 188{ 189 if $have_resolvconf; then 190 "$resolvconf" -d "$ifname" -f 191 else 192 if [ -e "$resolv_conf_dir/$ifname" ]; then 193 rm -f "$resolv_conf_dir/$ifname" 194 fi 195 build_resolv_conf 196 fi 197} 198 199# For ease of use, map DHCP6 names onto our DHCP4 names 200case "$reason" in 201BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6) 202 new_domain_name_servers="$new_dhcp6_name_servers" 203 new_domain_search="$new_dhcp6_domain_search" 204 ;; 205esac 206 207if $if_configured; then 208 if $have_resolvconf && [ "$reason" = NOCARRIER_ROAMING ]; then 209 # avoid calling resolvconf -c on CARRIER unless we roam 210 mkdir -p "$nocarrier_roaming_dir" 211 echo " " >"$nocarrier_roaming_dir/$interface" 212 "$resolvconf" -C "$interface.*" 213 elif $have_resolvconf && [ "$reason" = CARRIER ]; then 214 # Not all resolvconf implementations support -c 215 if [ -e "$nocarrier_roaming_dir/$interface" ]; then 216 rm -f "$nocarrier_roaming_dir/$interface" 217 "$resolvconf" -c "$interface.*" 218 fi 219 elif $if_up || [ "$reason" = ROUTERADVERT ]; then 220 add_resolv_conf 221 elif $if_down; then 222 remove_resolv_conf 223 fi 224fi 225