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