3 # SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5 # Copyright (c) 2013 Dag-Erling Smørgrav
8 # Redistribution and use in source and binary forms, with or without
9 # modification, are permitted provided that the following conditions
11 # 1. Redistributions of source code must retain the above copyright
12 # notice, this list of conditions and the following disclaimer.
13 # 2. Redistributions in binary form must reproduce the above copyright
14 # notice, this list of conditions and the following disclaimer in the
15 # documentation and/or other materials provided with the distribution.
17 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 # Configuration variables
55 self=$(basename $(realpath "$0"))
56 bkext=$(date "+%Y%m%d.%H%M%S")
59 # Set default values for unset configuration variables.
63 : ${workdir:=/var/unbound}
64 : ${confdir:=${workdir}/conf.d}
65 : ${unbound_conf:=${workdir}/unbound.conf}
66 : ${forward_conf:=${workdir}/forward.conf}
67 : ${lanzones_conf:=${workdir}/lan-zones.conf}
68 : ${control_conf:=${workdir}/control.conf}
69 : ${control_socket:=/var/run/local_unbound.ctl}
70 : ${anchor:=${workdir}/root.key}
71 : ${pidfile:=/var/run/local_unbound.pid}
72 : ${resolv_conf:=/etc/resolv.conf}
73 : ${resolvconf_conf:=/etc/resolvconf.conf}
74 : ${service:=local_unbound}
75 : ${start_unbound:=yes}
79 # Verify that the configuration files are inside the working
80 # directory, and if so, set the chroot directory accordingly.
83 chrootdir="${workdir}"
84 for file in "${unbound_conf}" "${forward_conf}" \
85 "${lanzones_conf}" "${control_conf}" "${anchor}" ; do
86 if [ "${file#${workdir%/}/}" = "${file}" ] ; then
87 echo "warning: ${file} is outside ${workdir}" >&2
91 if [ -z "${chrootdir}" ] ; then
92 echo "warning: disabling chroot" >&2
97 # Scan through /etc/resolv.conf looking for uncommented nameserver
98 # lines that don't point to localhost and return their values.
102 local bareline=${line%%\#*}
103 local key=${bareline%% *}
104 local value=${bareline#* }
108 127.0.0.1|::1|localhost|localhost.*)
120 # Scan through /etc/resolv.conf looking for uncommented nameserver
121 # lines. Comment out any that don't point to localhost. Finally,
122 # append a nameserver line that points to localhost, if there wasn't
123 # one already, and enable the edns0 option.
129 local bareline=${line%%\#*}
130 local key=${bareline%% *}
131 local value=${bareline#* }
135 127.0.0.1|::1|localhost|localhost.*)
153 if [ "${localhost}" = "no" ] ; then
154 echo "nameserver 127.0.0.1"
156 if [ "${edns0}" = "no" ] ; then
165 echo "# This file was generated by $self."
166 echo "# Modifications will be overwritten."
170 # Generate resolvconf.conf so it updates forward.conf in addition to
171 # resolv.conf. Note "in addition to" rather than "instead of",
172 # because we still want it to update the domain name and search path
173 # if they change. Setting name_servers to "127.0.0.1" ensures that
174 # the libc resolver will try unbound first.
176 gen_resolvconf_conf() {
179 echo "resolv_conf=\"/dev/null\" # prevent updating ${resolv_conf}"
180 if [ "${style}" = "dynamic" ] ; then
181 echo "unbound_conf=\"${forward_conf}\""
182 echo "unbound_pid=\"${pidfile}\""
183 echo "unbound_service=\"${service}\""
184 # resolvconf(8) likes to restart rather than reload
185 echo "unbound_restart=\"service ${service} reload\""
187 echo "# Static DNS configuration"
192 # Generate forward.conf
199 if expr "${forwarder}" : "^[0-9A-Fa-f:.]\{1,\}$" >/dev/null ; then
200 echo " forward-addr: ${forwarder}"
202 echo " forward-host: ${forwarder}"
208 # Generate lan-zones.conf
210 gen_lanzones_conf() {
213 echo " # Unblock reverse lookups for LAN addresses"
214 echo " unblock-lan-zones: yes"
215 echo " insecure-lan-zones: yes"
219 # Generate control.conf
223 echo "remote-control:"
224 echo " control-enable: yes"
225 echo " control-interface: ${control_socket}"
226 echo " control-use-cert: no"
230 # Generate unbound.conf
235 echo " username: ${user}"
236 echo " directory: ${workdir}"
237 echo " chroot: ${chrootdir}"
238 echo " pidfile: ${pidfile}"
239 echo " auto-trust-anchor-file: ${anchor}"
241 if [ -f "${forward_conf}" ] ; then
242 echo "include: ${forward_conf}"
244 if [ -f "${lanzones_conf}" ] ; then
245 echo "include: ${lanzones_conf}"
247 if [ -f "${control_conf}" ] ; then
248 echo "include: ${control_conf}"
250 if [ -d "${confdir}" ] ; then
251 echo "include: ${confdir}/*.conf"
256 # Rename a file we are about to replace.
260 if [ -f "${file}" ] ; then
261 local bkfile="${file}.${bkext}"
262 echo "Original ${file} saved as ${bkfile}"
263 mv "${file}" "${bkfile}"
268 # Replace one file with another, making a backup copy of the first,
269 # but only if the new file is different from the old.
274 if [ ! -f "${file}" ] ; then
275 echo "${file} created"
276 mv "${newfile}" "${file}"
277 elif ! cmp -s "${file}" "${newfile}" ; then
279 mv "${newfile}" "${file}"
281 echo "${file} not modified"
287 # Print usage message and exit
291 echo "usage: $self [options] [forwarder ...]"
293 echo " -n do not start unbound"
294 echo " -a path full path to trust anchor file"
295 echo " -C path full path to additional configuration directory"
296 echo " -c path full path to unbound configuration file"
297 echo " -f path full path to forwarding configuration"
298 echo " -O path full path to remote control socket"
299 echo " -o path full path to remote control configuration"
300 echo " -p path full path to pid file"
301 echo " -R path full path to resolvconf.conf"
302 echo " -r path full path to resolv.conf"
303 echo " -s service name of unbound service"
304 echo " -u user user to run unbound as"
305 echo " -w path full path to working directory"
316 # Parse and validate command-line options
318 while getopts "a:C:c:f:no:p:R:r:s:u:w:" option ; do
327 unbound_conf="$OPTARG"
330 forward_conf="$OPTARG"
336 control_socket="$OPTARG"
339 control_conf="$OPTARG"
345 resolvconf_conf="$OPTARG"
348 resolv_conf="$OPTARG"
368 # Get the list of forwarders, either from the command line or
372 case "${forwarders}" in
378 echo "Extracting forwarders from ${resolv_conf}."
379 forwarders=$(get_nameservers <"${resolv_conf}")
388 # Generate forward.conf.
390 if [ -z "${forwarders}" ] ; then
391 echo -n "No forwarders found in ${resolv_conf##*/}, "
392 if [ -f "${forward_conf}" ] ; then
393 echo "using existing ${forward_conf##*/}."
395 echo "unbound will recurse."
397 elif [ "${forwarders}" = "none" ] ; then
398 echo "Forwarding disabled, unbound will recurse."
399 backup "${forward_conf}"
401 local tmp_forward_conf=$(mktemp -u "${forward_conf}.XXXXX")
402 gen_forward_conf ${forwarders} | unexpand >"${tmp_forward_conf}"
403 replace "${forward_conf}" "${tmp_forward_conf}"
407 # Generate lan-zones.conf.
409 local tmp_lanzones_conf=$(mktemp -u "${lanzones_conf}.XXXXX")
410 gen_lanzones_conf | unexpand >"${tmp_lanzones_conf}"
411 replace "${lanzones_conf}" "${tmp_lanzones_conf}"
414 # Generate control.conf.
416 local tmp_control_conf=$(mktemp -u "${control_conf}.XXXXX")
417 gen_control_conf | unexpand >"${tmp_control_conf}"
418 replace "${control_conf}" "${tmp_control_conf}"
421 # Generate unbound.conf.
423 local tmp_unbound_conf=$(mktemp -u "${unbound_conf}.XXXXX")
425 gen_unbound_conf | unexpand >"${tmp_unbound_conf}"
426 replace "${unbound_conf}" "${tmp_unbound_conf}"
429 # Start unbound, unless requested not to. Stop immediately if
430 # it is not enabled so we don't end up with a resolv.conf that
431 # points into nothingness. We could "onestart" it, but it
434 if [ "${start_unbound}" = "no" ] ; then
436 elif ! service "${service}" enabled ; then
437 echo "Please enable $service in rc.conf(5) and try again."
439 elif ! service "${service}" restart ; then
440 echo "Failed to start $service."
445 # Rewrite resolvconf.conf so resolvconf updates forward.conf
446 # instead of resolv.conf.
448 local tmp_resolvconf_conf=$(mktemp -u "${resolvconf_conf}.XXXXX")
449 gen_resolvconf_conf "${style}" | unexpand >"${tmp_resolvconf_conf}"
450 replace "${resolvconf_conf}" "${tmp_resolvconf_conf}"
453 # Finally, rewrite resolv.conf.
455 local tmp_resolv_conf=$(mktemp -u "${resolv_conf}.XXXXX")
456 gen_resolv_conf <"${resolv_conf}" | unexpand >"${tmp_resolv_conf}"
457 replace "${resolv_conf}" "${tmp_resolv_conf}"