3 # Copyright (c) 2013 Dag-Erling Smørgrav
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
9 # 1. Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 # notice, this list of conditions and the following disclaimer in the
13 # documentation and/or other materials provided with the distribution.
15 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 # Configuration variables
51 self=$(basename $(realpath "$0"))
52 bkext=$(date "+%Y%m%d.%H%M%S")
55 # Set default values for unset configuration variables.
59 : ${workdir:=/var/unbound}
60 : ${confdir:=${workdir}/conf.d}
61 : ${unbound_conf:=${workdir}/unbound.conf}
62 : ${forward_conf:=${workdir}/forward.conf}
63 : ${lanzones_conf:=${workdir}/lan-zones.conf}
64 : ${anchor:=${workdir}/root.key}
65 : ${pidfile:=/var/run/local_unbound.pid}
66 : ${resolv_conf:=/etc/resolv.conf}
67 : ${resolvconf_conf:=/etc/resolvconf.conf}
68 : ${service:=local_unbound}
69 : ${start_unbound:=yes}
73 # Verify that the configuration files are inside the working
74 # directory, and if so, set the chroot directory accordingly.
77 chrootdir="${workdir}"
78 for file in "${unbound_conf}" "${forward_conf}" \
79 "${lanzones_conf}" "${anchor}" ; do
80 if [ "${file#${workdir%/}/}" = "${file}" ] ; then
81 echo "warning: ${file} is outside ${workdir}" >&2
85 if [ -z "${chrootdir}" ] ; then
86 echo "warning: disabling chroot" >&2
91 # Scan through /etc/resolv.conf looking for uncommented nameserver
92 # lines that don't point to localhost and return their values.
96 local bareline=${line%%\#*}
97 local key=${bareline%% *}
98 local value=${bareline#* }
102 127.0.0.1|::1|localhost|localhost.*)
114 # Scan through /etc/resolv.conf looking for uncommented nameserver
115 # lines. Comment out any that don't point to localhost. Finally,
116 # append a nameserver line that points to localhost, if there wasn't
117 # one already, and enable the edns0 option.
123 local bareline=${line%%\#*}
124 local key=${bareline%% *}
125 local value=${bareline#* }
129 127.0.0.1|::1|localhost|localhost.*)
147 if [ "${localhost}" = "no" ] ; then
148 echo "nameserver 127.0.0.1"
150 if [ "${edns0}" = "no" ] ; then
156 # Generate resolvconf.conf so it updates forward.conf in addition to
157 # resolv.conf. Note "in addition to" rather than "instead of",
158 # because we still want it to update the domain name and search path
159 # if they change. Setting name_servers to "127.0.0.1" ensures that
160 # the libc resolver will try unbound first.
162 gen_resolvconf_conf() {
163 echo "# Generated by $self"
164 echo "resolv_conf=\"/dev/null\" # prevent updating ${resolv_conf}"
165 echo "unbound_conf=\"${forward_conf}\""
166 echo "unbound_pid=\"${pidfile}\""
167 echo "unbound_service=\"${service}\""
168 # resolvconf(8) likes to restart rather than reload
169 echo "unbound_restart=\"service ${service} reload\""
173 # Generate forward.conf
176 echo "# Generated by $self"
177 echo "# Do not edit this file."
181 if expr "${forwarder}" : "^[0-9A-Fa-f:.]\{1,\}$" >/dev/null ; then
182 echo " forward-addr: ${forwarder}"
184 echo " forward-host: ${forwarder}"
190 # Generate lan-zones.conf
192 gen_lanzones_conf() {
193 echo "# Generated by $self"
194 echo "# Do not edit this file."
196 echo " # Unblock reverse lookups for LAN addresses"
197 echo " unblock-lan-zones: yes"
198 echo " domain-insecure: 10.in-addr.arpa."
199 echo " domain-insecure: 127.in-addr.arpa."
200 echo " domain-insecure: 16.172.in-addr.arpa."
201 echo " domain-insecure: 17.172.in-addr.arpa."
202 echo " domain-insecure: 18.172.in-addr.arpa."
203 echo " domain-insecure: 19.172.in-addr.arpa."
204 echo " domain-insecure: 20.172.in-addr.arpa."
205 echo " domain-insecure: 21.172.in-addr.arpa."
206 echo " domain-insecure: 22.172.in-addr.arpa."
207 echo " domain-insecure: 23.172.in-addr.arpa."
208 echo " domain-insecure: 24.172.in-addr.arpa."
209 echo " domain-insecure: 25.172.in-addr.arpa."
210 echo " domain-insecure: 26.172.in-addr.arpa."
211 echo " domain-insecure: 27.172.in-addr.arpa."
212 echo " domain-insecure: 28.172.in-addr.arpa."
213 echo " domain-insecure: 29.172.in-addr.arpa."
214 echo " domain-insecure: 30.172.in-addr.arpa."
215 echo " domain-insecure: 31.172.in-addr.arpa."
216 echo " domain-insecure: 168.192.in-addr.arpa."
217 echo " domain-insecure: 254.169.in-addr.arpa."
218 echo " domain-insecure: d.f.ip6.arpa."
219 echo " domain-insecure: 8.e.ip6.arpa."
220 echo " domain-insecure: 9.e.ip6.arpa."
221 echo " domain-insecure: a.e.ip6.arpa."
222 echo " domain-insecure: b.e.ip6.arpa."
226 # Generate unbound.conf
229 echo "# Generated by $self"
231 echo " username: ${user}"
232 echo " directory: ${workdir}"
233 echo " chroot: ${chrootdir}"
234 echo " pidfile: ${pidfile}"
235 echo " auto-trust-anchor-file: ${anchor}"
237 if [ -f "${forward_conf}" ] ; then
238 echo "include: ${forward_conf}"
240 if [ -f "${lanzones_conf}" ] ; then
241 echo "include: ${lanzones_conf}"
243 if [ -d "${confdir}" ] ; then
244 echo "include: ${confdir}/*.conf"
249 # Replace one file with another, making a backup copy of the first,
250 # but only if the new file is different from the old.
255 if [ ! -f "${file}" ] ; then
256 echo "${file} created"
257 mv "${newfile}" "${file}"
258 elif ! cmp -s "${file}" "${newfile}" ; then
259 local oldfile="${file}.${bkext}"
260 echo "original ${file} saved as ${oldfile}"
261 mv "${file}" "${oldfile}"
262 mv "${newfile}" "${file}"
264 echo "${file} not modified"
270 # Print usage message and exit
274 echo "usage: $self [options] [forwarder ...]"
276 echo " -n do not start unbound"
277 echo " -a path full path to trust anchor file"
278 echo " -C path full path to additional configuration directory"
279 echo " -c path full path to unbound configuration file"
280 echo " -f path full path to forwarding configuration"
281 echo " -p path full path to pid file"
282 echo " -R path full path to resolvconf.conf"
283 echo " -r path full path to resolv.conf"
284 echo " -s service name of unbound service"
285 echo " -u user user to run unbound as"
286 echo " -w path full path to working directory"
297 # Parse and validate command-line options
299 while getopts "a:C:c:f:np:R:r:s:u:w:" option ; do
308 unbound_conf="$OPTARG"
311 forward_conf="$OPTARG"
320 resolvconf_conf="$OPTARG"
323 resolv_conf="$OPTARG"
343 # Get the list of forwarders, either from the command line or
347 if [ -z "$forwarders" ] ; then
348 echo "Extracting forwarders from ${resolv_conf}."
349 forwarders=$(get_nameservers <"${resolv_conf}")
353 # Generate forward.conf.
355 if [ -z "${forwarders}" ] ; then
356 echo -n "No forwarders found in ${resolv_conf##*/}, "
357 if [ -f "${forward_conf}" ] ; then
358 echo "using existing ${forward_conf##*/}."
360 echo "unbound will recurse."
363 local tmp_forward_conf=$(mktemp -u "${forward_conf}.XXXXX")
364 gen_forward_conf ${forwarders} >"${tmp_forward_conf}"
365 replace "${forward_conf}" "${tmp_forward_conf}"
369 # Generate lan-zones.conf.
371 local tmp_lanzones_conf=$(mktemp -u "${lanzones_conf}.XXXXX")
372 gen_lanzones_conf >"${tmp_lanzones_conf}"
373 replace "${lanzones_conf}" "${tmp_lanzones_conf}"
376 # Generate unbound.conf.
378 local tmp_unbound_conf=$(mktemp -u "${unbound_conf}.XXXXX")
380 gen_unbound_conf >"${tmp_unbound_conf}"
381 replace "${unbound_conf}" "${tmp_unbound_conf}"
384 # Start unbound, unless requested not to. Stop immediately if
385 # it is not enabled so we don't end up with a resolv.conf that
386 # points into nothingness. We could "onestart" it, but it
389 if [ "${start_unbound}" = "no" ] ; then
391 elif ! service "${service}" enabled ; then
392 echo "Please enable $service in rc.conf(5) and try again."
394 elif ! service "${service}" restart ; then
395 echo "Failed to start $service."
400 # Rewrite resolvconf.conf so resolvconf updates forward.conf
401 # instead of resolv.conf.
403 local tmp_resolvconf_conf=$(mktemp -u "${resolvconf_conf}.XXXXX")
404 gen_resolvconf_conf >"${tmp_resolvconf_conf}"
405 replace "${resolvconf_conf}" "${tmp_resolvconf_conf}"
408 # Finally, rewrite resolv.conf.
410 local tmp_resolv_conf=$(mktemp -u "${resolv_conf}.XXXXX")
411 gen_resolv_conf <"${resolv_conf}" >"${tmp_resolv_conf}"
412 replace "${resolv_conf}" "${tmp_resolv_conf}"