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" 10NL=" 11" 12: ${resolvconf:=resolvconf} 13 14build_resolv_conf() 15{ 16 cf="$state_dir/resolv.conf.$ifname" 17 18 # Build a list of interfaces 19 interfaces=$(list_interfaces "$resolv_conf_dir") 20 21 # Build the resolv.conf 22 if [ -n "$interfaces" ]; then 23 # Build the header 24 for x in ${interfaces}; do 25 header="$header${header:+, }$x" 26 done 27 28 # Build the search list 29 domain=$(cd "$resolv_conf_dir"; \ 30 key_get_value "domain " ${interfaces}) 31 search=$(cd "$resolv_conf_dir"; \ 32 key_get_value "search " ${interfaces}) 33 set -- ${domain} 34 domain="$1" 35 [ -n "$2" ] && search="$search $*" 36 [ -n "$search" ] && search="$(uniqify $search)" 37 [ "$domain" = "$search" ] && search= 38 [ -n "$domain" ] && domain="domain $domain$NL" 39 [ -n "$search" ] && search="search $search$NL" 40 41 # Build the nameserver list 42 srvs=$(cd "$resolv_conf_dir"; \ 43 key_get_value "nameserver " ${interfaces}) 44 for x in $(uniqify ${srvs}); do 45 servers="${servers}nameserver $x$NL" 46 done 47 fi 48 header="$signature_base${header:+ $from }$header" 49 50 # Assemble resolv.conf using our head and tail files 51 [ -f "$cf" ] && rm -f "$cf" 52 [ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir" 53 echo "$header" > "$cf" 54 if [ -f /etc/resolv.conf.head ]; then 55 cat /etc/resolv.conf.head >> "$cf" 56 else 57 echo "# /etc/resolv.conf.head can replace this line" >> "$cf" 58 fi 59 printf %s "$domain$search$servers" >> "$cf" 60 if [ -f /etc/resolv.conf.tail ]; then 61 cat /etc/resolv.conf.tail >> "$cf" 62 else 63 echo "# /etc/resolv.conf.tail can replace this line" >> "$cf" 64 fi 65 if change_file /etc/resolv.conf "$cf"; then 66 chmod 644 /etc/resolv.conf 67 fi 68 rm -f "$cf" 69} 70 71# Extract any ND DNS options from the RA 72# For now, we ignore the lifetime of the DNS options unless they 73# are absent or zero. 74# In this case they are removed from consideration. 75# See draft-gont-6man-slaac-dns-config-issues-01 for issues 76# regarding DNS option lifetime in ND messages. 77eval_nd_dns() 78{ 79 eval ltime=\$nd${i}_rdnss${j}_lifetime 80 if [ -z "$ltime" -o "$ltime" = 0 ]; then 81 rdnss= 82 else 83 eval rdnss=\$nd${i}_rdnss${j}_servers 84 fi 85 eval ltime=\$nd${i}_dnssl${j}_lifetime 86 if [ -z "$ltime" -o "$ltime" = 0 ]; then 87 dnssl= 88 else 89 eval dnssl=\$nd${i}_dnssl${j}_search 90 fi 91 92 [ -z "$rdnss" -a -z "$dnssl" ] && return 1 93 94 [ -n "$rdnss" ] && new_rdnss="$new_rdnss${new_rdnss:+ }$rdnss" 95 [ -n "$dnssl" ] && new_dnssl="$new_dnssl${new_dnssl:+ }$dnssl" 96 j=$(($j + 1)) 97 return 0 98} 99 100add_resolv_conf() 101{ 102 conf="$signature$NL" 103 warn=true 104 105 # Loop to extract the ND DNS options using our indexed shell values 106 i=1 107 j=1 108 while true; do 109 while true; do 110 eval_nd_dns || break 111 done 112 i=$(($i + 1)) 113 j=1 114 eval_nd_dns || break 115 done 116 [ -n "$new_rdnss" ] && \ 117 new_domain_name_servers="$new_domain_name_servers${new_domain_name_servers:+ }$new_rdnss" 118 [ -n "$new_dnssl" ] && \ 119 new_domain_search="$new_domain_search${new_domain_search:+ }$new_dnssl" 120 121 # Derive a new domain from our various hostname options 122 if [ -z "$new_domain_name" ]; then 123 if [ "$new_dhcp6_fqdn" != "${new_dhcp6_fqdn#*.}" ]; then 124 new_domain_name="${new_dhcp6_fqdn#*.}" 125 elif [ "$new_fqdn" != "${new_fqdn#*.}" ]; then 126 new_domain_name="${new_fqdn#*.}" 127 elif [ "$new_host_name" != "${new_host_name#*.}" ]; then 128 new_domain_name="${new_host_name#*.}" 129 fi 130 fi 131 132 # If we don't have any configuration, remove it 133 if [ -z "$new_domain_name_servers" -a \ 134 -z "$new_domain_name" -a \ 135 -z "$new_domain_search" ]; then 136 remove_resolv_conf 137 return $? 138 fi 139 140 if [ -n "$new_domain_name" ]; then 141 set -- $new_domain_name 142 if valid_domainname "$1"; then 143 conf="${conf}domain $1$NL" 144 else 145 syslog err "Invalid domain name: $1" 146 fi 147 # If there is no search this, make this one 148 if [ -z "$new_domain_search" ]; then 149 new_domain_search="$new_domain_name" 150 [ "$new_domain_name" = "$1" ] && warn=true 151 fi 152 fi 153 if [ -n "$new_domain_search" ]; then 154 if valid_domainname_list $new_domain_search; then 155 conf="${conf}search $new_domain_search$NL" 156 elif ! $warn; then 157 syslog err "Invalid domain name in list:" \ 158 "$new_domain_search" 159 fi 160 fi 161 for x in ${new_domain_name_servers}; do 162 conf="${conf}nameserver $x$NL" 163 done 164 if type "$resolvconf" >/dev/null 2>&1; then 165 [ -n "$ifmetric" ] && export IF_METRIC="$ifmetric" 166 printf %s "$conf" | "$resolvconf" -a "$ifname" 167 return $? 168 fi 169 170 if [ -e "$resolv_conf_dir/$ifname" ]; then 171 rm -f "$resolv_conf_dir/$ifname" 172 fi 173 [ -d "$resolv_conf_dir" ] || mkdir -p "$resolv_conf_dir" 174 printf %s "$conf" > "$resolv_conf_dir/$ifname" 175 build_resolv_conf 176} 177 178remove_resolv_conf() 179{ 180 if type "$resolvconf" >/dev/null 2>&1; then 181 "$resolvconf" -d "$ifname" -f 182 else 183 if [ -e "$resolv_conf_dir/$ifname" ]; then 184 rm -f "$resolv_conf_dir/$ifname" 185 fi 186 build_resolv_conf 187 fi 188} 189 190# For ease of use, map DHCP6 names onto our DHCP4 names 191case "$reason" in 192BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6) 193 new_domain_name_servers="$new_dhcp6_name_servers" 194 new_domain_search="$new_dhcp6_domain_search" 195 ;; 196esac 197 198if $if_up || [ "$reason" = ROUTERADVERT ]; then 199 add_resolv_conf 200elif $if_down; then 201 remove_resolv_conf 202fi 203