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