xref: /freebsd/contrib/openresolv/libc.in (revision f6a3b357e9be4c6423c85eff9a847163a0d307c8)
1#!/bin/sh
2# Copyright (c) 2007-2016 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	local key="$1" x= line=
40
41	shift
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	local key x line found
62
63	while read -r line; do
64		found=false
65		for key do
66			case "$line" in
67			"$key"*|"#"*|" "*|"	"*|"") found=true;;
68			esac
69			$found && break
70		done
71		$found || echo "$line"
72	done
73}
74
75local_nameservers="127.* 0.0.0.0 255.255.255.255 ::1"
76
77# Support original resolvconf configuration layout
78# as well as the openresolv config file
79if [ -f "$SYSCONFDIR"/resolvconf.conf ]; then
80	. "$SYSCONFDIR"/resolvconf.conf
81elif [ -d "$SYSCONFDIR"/resolvconf ]; then
82	SYSCONFDIR="$SYSCONFDIR/resolvconf/resolv.conf.d"
83	base="$SYSCONFDIR/resolv.conf.d/base"
84	if [ -f "$base" ]; then
85		prepend_nameservers="$(key_get_value "nameserver " "$base")"
86		domain="$(key_get_value "domain " "$base")"
87		prepend_search="$(key_get_value "search " "$base")"
88		resolv_conf_options="$(key_get_value "options " "$base")"
89		resolv_conf_sortlist="$(key_get_value "sortlist " "$base")"
90	fi
91	if [ -f "$SYSCONFDIR"/resolv.conf.d/head ]; then
92		resolv_conf_head="$(cat "${SYSCONFDIR}"/resolv.conf.d/head)"
93	fi
94	if [ -f "$SYSCONFDIR"/resolv.conf.d/tail ]; then
95		resolv_conf_tail="$(cat "$SYSCONFDIR"/resolv.conf.d/tail)"
96	fi
97fi
98: ${resolv_conf:=/etc/resolv.conf}
99: ${libc_service:=nscd}
100: ${list_resolv:=@SBINDIR@/resolvconf -l}
101if [ "${resolv_conf_head-x}" = x -a -f "$SYSCONFDIR"/resolv.conf.head ]; then
102	resolv_conf_head="$(cat "${SYSCONFDIR}"/resolv.conf.head)"
103fi
104if [ "${resolv_conf_tail-x}" = x -a -f "$SYSCONFDIR"/resolv.conf.tail ]; then
105	resolv_conf_tail="$(cat "$SYSCONFDIR"/resolv.conf.tail)"
106fi
107
108backup=true
109signature="# Generated by resolvconf"
110
111uniqify()
112{
113	local result=
114	while [ -n "$1" ]; do
115		case " $result " in
116		*" $1 "*);;
117		*) result="$result $1";;
118		esac
119		shift
120	done
121	echo "${result# *}"
122}
123
124case "${resolv_conf_passthrough:-NO}" in
125[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
126	backup=false
127	newest=
128	for conf in "$IFACEDIR"/*; do
129		if [ -z "$newest" -o "$conf" -nt "$newest" ]; then
130			newest="$conf"
131		fi
132	done
133	[ -z "$newest" ] && exit 0
134	newconf="$(cat "$newest")$NL"
135	;;
136/dev/null|[Nn][Uu][Ll][Ll])
137	: ${resolv_conf_local_only:=NO}
138	if [ "$local_nameservers" = "127.* 0.0.0.0 255.255.255.255 ::1" ]; then
139		local_nameservers=
140	fi
141	# Need to overwrite our variables.
142	eval "$(@SBINDIR@/resolvconf -V)"
143	;;
144
145*)
146	[ -z "$RESOLVCONF" ] && eval "$(@SBINDIR@/resolvconf -v)"
147	;;
148esac
149case "${resolv_conf_passthrough:-NO}" in
150[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;;
151*)
152	: ${domain:=$DOMAIN}
153	newsearch="$(uniqify $prepend_search $SEARCH $append_search)"
154	NS="$LOCALNAMESERVERS $NAMESERVERS"
155	newns=
156	gotlocal=false
157	for n in $(uniqify $prepend_nameservers $NS $append_nameservers); do
158		add=true
159		islocal=false
160		for l in $local_nameservers; do
161			case "$n" in
162			$l) islocal=true; gotlocal=true; break;;
163			esac
164		done
165		if ! $islocal; then
166			case "${resolv_conf_local_only:-YES}" in
167			[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
168				$gotlocal && add=false;;
169			esac
170		fi
171		$add && newns="$newns $n"
172	done
173
174	# Hold our new resolv.conf in a variable to save on temporary files
175	newconf="$signature$NL"
176	if [ -n "$resolv_conf_head" ]; then
177		newconf="$newconf$resolv_conf_head$NL"
178	fi
179
180	[ -n "$domain" ] && newconf="${newconf}domain $domain$NL"
181	if [ -n "$newsearch" -a "$newsearch" != "$domain" ]; then
182		newconf="${newconf}search $newsearch$NL"
183	fi
184	for n in $newns; do
185		newconf="${newconf}nameserver $n$NL"
186	done
187
188	# Now add anything we don't care about such as sortlist and options
189	stuff="$($list_resolv | keys_remove nameserver domain search)"
190	if [ -n "$stuff" ]; then
191		newconf="$newconf$stuff$NL"
192	fi
193
194	# Append any user defined ones
195	if [ -n "$resolv_conf_options" ]; then
196		newconf="${newconf}options $resolv_conf_options$NL"
197	fi
198	if [ -n "$resolv_conf_sortlist" ]; then
199		newconf="${newconf}sortlist $resolv_conf_sortlist$NL"
200	fi
201
202	if [ -n "$resolv_conf_tail" ]; then
203		newconf="$newconf$resolv_conf_tail$NL"
204	fi
205	;;
206esac
207
208# Check if the file has actually changed or not
209if [ -e "$resolv_conf" ]; then
210	[ "$(cat "$resolv_conf")" = "$(printf %s "$newconf")" ] && exit 0
211fi
212
213# Change is good.
214# If the old file does not have our signature, back it up.
215# If the new file just has our signature, restore the backup.
216if $backup; then
217	if [ "$newconf" = "$signature$NL" ]; then
218		if [ -e "$resolv_conf.bak" ]; then
219			newconf="$(cat "$resolv_conf.bak")$NL"
220		fi
221	elif [ -e "$resolv_conf" ]; then
222		read line <"$resolv_conf"
223		if [ "$line" != "$signature" ]; then
224			cp "$resolv_conf" "$resolv_conf.bak"
225		fi
226	fi
227fi
228
229# Create our resolv.conf now
230(umask 022; echo "$newconf" >"$resolv_conf")
231if [ -n "$libc_restart" ]; then
232	eval $libc_restart
233elif [ -n "$RESTARTCMD" ]; then
234	set -- ${libc_service}
235	eval $RESTARTCMD
236else
237	@SBINDIR@/resolvconf -r ${libc_service}
238fi
239
240retval=0
241# Notify users of the resolver
242for script in "$LIBEXECDIR"/libc.d/*; do
243	if [ -f "$script" ]; then
244		if [ -x "$script" ]; then
245			"$script" "$@"
246		else
247			(. "$script")
248		fi
249		retval=$(($retval + $?))
250	fi
251done
252exit $retval
253