1#!/bin/sh 2# Copyright (c) 2007-2023 Roy Marples 3# All rights reserved 4 5# libc subscriber for resolvconf 6 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# * Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# * Redistributions in binary form must reproduce the above 13# copyright notice, this list of conditions and the following 14# disclaimer in the documentation and/or other materials provided 15# with the distribution. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29SYSCONFDIR=@SYSCONFDIR@ 30LIBEXECDIR=@LIBEXECDIR@ 31VARDIR=@VARDIR@ 32IFACEDIR="$VARDIR/interfaces" 33NL=" 34" 35 36# sed may not be available, and this is faster on small files 37key_get_value() 38{ 39 key="$1" 40 shift 41 42 if [ $# -eq 0 ]; then 43 while read -r line; do 44 case "$line" in 45 "$key"*) echo "${line##$key}";; 46 esac 47 done 48 else 49 for x do 50 while read -r line; do 51 case "$line" in 52 "$key"*) echo "${line##$key}";; 53 esac 54 done < "$x" 55 done 56 fi 57} 58 59keys_remove() 60{ 61 while read -r line; do 62 found=false 63 for key do 64 case "$line" in 65 "$key"*|"#"*|" "*|" "*|"") found=true;; 66 esac 67 $found && break 68 done 69 $found || echo "$line" 70 done 71} 72 73local_nameservers="127.* 0.0.0.0 255.255.255.255 ::1" 74 75# Support original resolvconf configuration layout 76# as well as the openresolv config file 77if [ -f "$SYSCONFDIR"/resolvconf.conf ]; then 78 . "$SYSCONFDIR"/resolvconf.conf 79elif [ -d "$SYSCONFDIR"/resolvconf ]; then 80 SYSCONFDIR="$SYSCONFDIR/resolvconf" 81 base="$SYSCONFDIR/resolv.conf.d/base" 82 if [ -f "$base" ]; then 83 prepend_nameservers="$(key_get_value "nameserver " "$base")" 84 domain="$(key_get_value "domain " "$base")" 85 prepend_search="$(key_get_value "search " "$base")" 86 resolv_conf_options="$(key_get_value "options " "$base")" 87 resolv_conf_sortlist="$(key_get_value "sortlist " "$base")" 88 fi 89 if [ -f "$SYSCONFDIR"/resolv.conf.d/head ]; then 90 resolv_conf_head="$(cat "${SYSCONFDIR}"/resolv.conf.d/head)" 91 fi 92 if [ -f "$SYSCONFDIR"/resolv.conf.d/tail ]; then 93 resolv_conf_tail="$(cat "$SYSCONFDIR"/resolv.conf.d/tail)" 94 fi 95fi 96: ${resolv_conf:=/etc/resolv.conf} 97: ${resolv_conf_tmp:="$resolv_conf.$$.openresolv"} 98: ${libc_service:=nscd} 99: ${list_resolv:=@SBINDIR@/resolvconf -l} 100if [ "${resolv_conf_head-x}" = x ] && [ -f "$SYSCONFDIR"/resolv.conf.head ] 101then 102 resolv_conf_head="$(cat "${SYSCONFDIR}"/resolv.conf.head)" 103fi 104if [ "${resolv_conf_tail-x}" = x ] && [ -f "$SYSCONFDIR"/resolv.conf.tail ] 105then 106 resolv_conf_tail="$(cat "$SYSCONFDIR"/resolv.conf.tail)" 107fi 108 109backup=true 110signature="# Generated by resolvconf" 111 112uniqify() 113{ 114 result= 115 while [ -n "$1" ]; do 116 case " $result " in 117 *" $1 "*);; 118 *) result="$result $1";; 119 esac 120 shift 121 done 122 echo "${result# *}" 123} 124 125case "${resolv_conf_passthrough:-NO}" in 126[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 127 backup=false 128 newest= 129 for conf in "$IFACEDIR"/*; do 130 if [ -z "$newest" ] || [ "$conf" -nt "$newest" ]; then 131 newest="$conf" 132 fi 133 done 134 [ -z "$newest" ] && exit 0 135 newconf="$(cat "$newest")$NL" 136 ;; 137/dev/null|[Nn][Uu][Ll][Ll]) 138 : ${resolv_conf_local_only:=NO} 139 if [ "$local_nameservers" = "127.* 0.0.0.0 255.255.255.255 ::1" ]; then 140 local_nameservers= 141 fi 142 # Need to overwrite our variables. 143 eval "$(@SBINDIR@/resolvconf -V)" 144 ;; 145 146*) 147 [ -z "$RESOLVCONF" ] && eval "$(@SBINDIR@/resolvconf -v)" 148 ;; 149esac 150case "${resolv_conf_passthrough:-NO}" in 151[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;; 152*) 153 : ${domain:=$DOMAIN} 154 newsearch="$(uniqify $prepend_search $SEARCH $append_search)" 155 NS="$LOCALNAMESERVERS $NAMESERVERS" 156 newns= 157 gotlocal=false 158 for n in $(uniqify $prepend_nameservers $NS $append_nameservers); do 159 add=true 160 islocal=false 161 for l in $local_nameservers; do 162 case "$n" in 163 $l) islocal=true; gotlocal=true; break;; 164 esac 165 done 166 if ! $islocal; then 167 case "${resolv_conf_local_only:-YES}" in 168 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 169 $gotlocal && add=false;; 170 esac 171 fi 172 $add && newns="$newns $n" 173 done 174 175 # Hold our new resolv.conf in a variable to save on temporary files 176 newconf="$signature$NL" 177 if [ -n "$resolv_conf_head" ]; then 178 newconf="$newconf$resolv_conf_head$NL" 179 fi 180 181 [ -n "$domain" ] && newconf="${newconf}domain $domain$NL" 182 if [ -n "$newsearch" ] && [ "$newsearch" != "$domain" ]; then 183 newconf="${newconf}search $newsearch$NL" 184 fi 185 for n in $newns; do 186 newconf="${newconf}nameserver $n$NL" 187 done 188 189 # Now add anything we don't care about such as sortlist and options 190 stuff="$($list_resolv | keys_remove nameserver domain search)" 191 if [ -n "$stuff" ]; then 192 newconf="$newconf$stuff$NL" 193 fi 194 195 # Append any user defined ones 196 if [ -n "$resolv_conf_options" ]; then 197 newconf="${newconf}options $resolv_conf_options$NL" 198 fi 199 if [ -n "$resolv_conf_sortlist" ]; then 200 newconf="${newconf}sortlist $resolv_conf_sortlist$NL" 201 fi 202 203 if [ -n "$resolv_conf_tail" ]; then 204 newconf="$newconf$resolv_conf_tail$NL" 205 fi 206 ;; 207esac 208 209# Check if the file has actually changed or not 210if [ -e "$resolv_conf" ]; then 211 [ "$(cat "$resolv_conf")" = "$(printf %s "$newconf")" ] && exit 0 212fi 213 214# Change is good. 215# If the old file does not have our signature, back it up. 216# If the new file just has our signature, restore the backup. 217if $backup; then 218 if [ "$newconf" = "$signature$NL" ]; then 219 if [ -e "$resolv_conf.bak" ]; then 220 newconf="$(cat "$resolv_conf.bak")$NL" 221 fi 222 elif [ -e "$resolv_conf" ]; then 223 read line <"$resolv_conf" 224 if [ "$line" != "$signature" ]; then 225 cp "$resolv_conf" "$resolv_conf.bak" 226 fi 227 fi 228fi 229 230# There are pros and cons for writing directly to resolv.conf 231# instead of a temporary file and then moving it over. 232# The default is to write to resolv.conf as it has the least 233# issues and has been the long standing default behaviour. 234case "${resolv_conf_mv:-NO}" in 235[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 236 # Protect against symlink attack, ensure new file does not exist 237 rm -f "$resolv_conf_tmp" 238 # Keep original file owner, group and mode 239 [ -r "$resolv_conf" ] && cp -p "$resolv_conf" "$resolv_conf_tmp" 240 # Create our resolv.conf now 241 if (umask 022; printf %s "$newconf" >"$resolv_conf_tmp"); then 242 mv "$resolv_conf_tmp" "$resolv_conf" 243 fi 244 ;; 245*) 246 (umask 022; printf %s "$newconf" >"$resolv_conf") 247 ;; 248esac 249 250if [ -n "$libc_restart" ]; then 251 eval $libc_restart 252elif [ -n "$RESTARTCMD" ]; then 253 set -- ${libc_service} 254 eval "$RESTARTCMD" 255else 256 @SBINDIR@/resolvconf -r ${libc_service} 257fi 258 259retval=0 260# Notify users of the resolver 261for script in "$LIBEXECDIR"/libc.d/*; do 262 if [ -f "$script" ]; then 263 if [ -x "$script" ]; then 264 "$script" "$@" 265 else 266 (. "$script") 267 fi 268 retval=$(($retval + $?)) 269 fi 270done 271exit $retval 272