svn commit: r255809 - in head: etc etc/defaults etc/rc.d share/man/man5 share/man/man8 tools/build/mk usr.sbin/unbound usr.sbin/unbound/local-setup

Dag-Erling Smørgrav des at FreeBSD.org
Mon Sep 23 04:36:53 UTC 2013


Author: des
Date: Mon Sep 23 04:36:51 2013
New Revision: 255809
URL: http://svnweb.freebsd.org/changeset/base/255809

Log:
  Add a setup script for unbound(8) called local-unbound-setup.  It
  generates a configuration suitable for running unbound as a caching
  forwarding resolver, and configures resolvconf(8) to update unbound's
  list of forwarders in addition to /etc/resolv.conf.  The initial list
  is taken from the existing resolv.conf, which is rewritten to point to
  localhost.  Alternatively, a list of forwarders can be provided on the
  command line.
  
  To assist this script, add an rc.subr command called "enabled" which
  does nothing except return 0 if the service is enabled and 1 if it is
  not, without going through the usual checks.  We should consider doing
  the same for "status", which is currently pointless.
  
  Add an rc script for unbound, called local_unbound.  If there is no
  configuration file, the rc script runs local-unbound-setup to generate
  one.
  
  Note that these scripts place the unbound configuration files in
  /var/unbound rather than /etc/unbound.  This is necessary so that
  unbound can reload its configuration while chrooted.  We should
  probably provide symlinks in /etc.
  
  Approved by:	re (blanket)

Added:
  head/etc/rc.d/local_unbound   (contents, props changed)
  head/usr.sbin/unbound/local-setup/
  head/usr.sbin/unbound/local-setup/Makefile   (contents, props changed)
  head/usr.sbin/unbound/local-setup/local-unbound-setup.sh   (contents, props changed)
Modified:
  head/etc/defaults/rc.conf
  head/etc/rc.d/Makefile
  head/etc/rc.subr
  head/share/man/man5/rc.conf.5
  head/share/man/man8/rc.8
  head/share/man/man8/rc.subr.8
  head/tools/build/mk/OptionalObsoleteFiles.inc
  head/usr.sbin/unbound/Makefile

Modified: head/etc/defaults/rc.conf
==============================================================================
--- head/etc/defaults/rc.conf	Mon Sep 23 00:16:19 2013	(r255808)
+++ head/etc/defaults/rc.conf	Mon Sep 23 04:36:51 2013	(r255809)
@@ -270,6 +270,7 @@ hastd_enable="NO"		# Run the HAST daemon
 hastd_program="/sbin/hastd"	# path to hastd, if you want a different one.
 hastd_flags=""			# Optional flags to hastd.
 ctld_enable="NO"		# CAM Target Layer / iSCSI target daemon.
+local_unbound_enable="NO"	# local caching resolver
 #
 # named.  It may be possible to run named in a sandbox, man security for
 # details.

Modified: head/etc/rc.d/Makefile
==============================================================================
--- head/etc/rc.d/Makefile	Mon Sep 23 00:16:19 2013	(r255808)
+++ head/etc/rc.d/Makefile	Mon Sep 23 04:36:51 2013	(r255809)
@@ -150,6 +150,7 @@ FILES=	DAEMON \
 	tmp \
 	${_ubthidhci} \
 	ugidfw \
+	${_unbound} \
 	${_utx} \
 	var \
 	virecover \
@@ -184,6 +185,10 @@ _nscd=		nscd
 _ubthidhci=	ubthidhci
 .endif
 
+.if ${MK_UNBOUND} != "no"
+_unbound=	local_unbound
+.endif
+
 .if ${MK_UTMPX} != "no"
 _utx=		utx
 .endif

Added: head/etc/rc.d/local_unbound
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/etc/rc.d/local_unbound	Mon Sep 23 04:36:51 2013	(r255809)
@@ -0,0 +1,91 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: local_unbound
+# REQUIRE: SERVERS cleanvar
+# KEYWORD: shutdown
+
+. /etc/rc.subr
+
+name="local_unbound"
+desc="local caching forwarding resolver"
+rcvar="local_unbound_enable"
+
+command="/usr/sbin/unbound"
+extra_commands="anchor configtest reload setup"
+start_precmd="local_unbound_prestart"
+reload_precmd="local_unbound_configtest"
+anchor_cmd="local_unbound_anchor"
+configtest_cmd="local_unbound_configtest"
+setup_cmd="local_unbound_setup"
+pidfile="/var/run/${name}.pid"
+
+: ${local_unbound_workdir:=/var/unbound}
+: ${local_unbound_config:=${local_unbound_workdir}/unbound.conf}
+: ${local_unbound_flags:=-c${local_unbound_config}}
+: ${local_unbound_forwardconf:=${local_unbound_workdir}/forward.conf}
+: ${local_unbound_anchor:=${local_unbound_workdir}/root.key}
+: ${local_unbound_forwarders:=}
+
+load_rc_config $name
+
+do_as_unbound()
+{
+	echo "$@" | su -m unbound
+}
+
+#
+# Retrieve or update the DNSSEC root anchor
+#
+local_unbound_anchor()
+{
+	do_as_unbound /usr/sbin/unbound-anchor -a ${local_unbound_anchor}
+	# we can't trust the exit code - check if the file exists
+	[ -f ${local_unbound_anchor} ]
+}
+
+#
+# Check the unbound configuration file
+#
+local_unbound_configtest()
+{
+	do_as_unbound /usr/sbin/unbound-checkconf ${local_unbound_config}
+}
+
+#
+# Create the unbound configuration file and update resolv.conf to
+# point to unbound.
+#
+local_unbound_setup()
+{
+	echo "Performing initial setup."
+	/usr/sbin/local-unbound-setup -n \
+	    -u unbound \
+	    -w ${local_unbound_workdir} \
+	    -c ${local_unbound_config} \
+	    -f ${local_unbound_forwardconf} \
+	    -a ${local_unbound_anchor} \
+	    ${local_unbound_forwarders}
+}
+
+#
+# Before starting, check that the configuration file and root anchor
+# exist.  If not, attempt to generate them.
+#
+local_unbound_prestart()
+{
+	# Create configuration file
+	if [ ! -f ${local_unbound_config} ] ; then
+		run_rc_command setup
+	fi
+
+	# Retrieve DNSSEC root key
+	if [ ! -f ${local_unbound_anchor} ] ; then
+		run_rc_command anchor
+	fi
+}
+
+load_rc_config $name
+run_rc_command "$1"

Modified: head/etc/rc.subr
==============================================================================
--- head/etc/rc.subr	Mon Sep 23 00:16:19 2013	(r255808)
+++ head/etc/rc.subr	Mon Sep 23 04:36:51 2013	(r255809)
@@ -546,6 +546,8 @@ check_startmsgs()
 #
 #	rcvar		Display what rc.conf variable is used (if any).
 #
+#	enabled		Return true if the service is enabled.
+#
 #	Variables available to methods, and after run_rc_command() has
 #	completed:
 #
@@ -614,7 +616,7 @@ run_rc_command()
 	eval _override_command=\$${name}_program
 	command=${_override_command:-$command}
 
-	_keywords="start stop restart rcvar $extra_commands"
+	_keywords="start stop restart rcvar enabled $extra_commands"
 	rc_pid=
 	_pidcmd=
 	_procname=${procname:-${command}}
@@ -635,6 +637,11 @@ run_rc_command()
 		rc_usage $_keywords
 	fi
 
+	if [ "$rc_arg" = "enabled" ] ; then
+		checkyesno ${rcvar}
+		return $?
+	fi
+
 	if [ -n "$flags" ]; then	# allow override from environment
 		rc_flags=$flags
 	else

Modified: head/share/man/man5/rc.conf.5
==============================================================================
--- head/share/man/man5/rc.conf.5	Mon Sep 23 00:16:19 2013	(r255808)
+++ head/share/man/man5/rc.conf.5	Mon Sep 23 04:36:51 2013	(r255809)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd September 10, 2013
+.Dd September 23, 2013
 .Dt RC.CONF 5
 .Os
 .Sh NAME
@@ -2041,6 +2041,13 @@ is set to
 .Dq Li YES ,
 these are the flags to pass to
 .Xr hastd 8 .
+.It Va local_unbound_enable
+.Pq Vt bool
+If set to
+.Dq Li YES ,
+run the
+.Xr unbound 8
+daemon as a local caching resolver.
 .It Va named_enable
 .Pq Vt bool
 If set to
@@ -4786,6 +4793,7 @@ The default is 30.
 .Xr sysctl 8 ,
 .Xr syslogd 8 ,
 .Xr timed 8 ,
+.Xr unbound 8 ,
 .Xr usbconfig 8 ,
 .Xr wlandebug 8 ,
 .Xr yp 8 ,

Modified: head/share/man/man8/rc.8
==============================================================================
--- head/share/man/man8/rc.8	Mon Sep 23 00:16:19 2013	(r255808)
+++ head/share/man/man8/rc.8	Mon Sep 23 04:36:51 2013	(r255809)
@@ -35,7 +35,7 @@
 .\"     @(#)rc.8	8.2 (Berkeley) 12/11/93
 .\" $FreeBSD$
 .\"
-.Dd January 14, 2012
+.Dd September 23, 2013
 .Dt RC 8
 .Os
 .Sh NAME
@@ -312,6 +312,9 @@ Defaults to displaying the process ID of
 If the script starts a process (rather than performing a one-off
 operation), wait for the command to exit.
 Otherwise it is not necessary to support this argument.
+.It Cm enabled
+Return 0 if the service is enabled and 1 if it is not.
+This command does not print anything.
 .It Cm rcvar
 Display which
 .Xr rc.conf 5

Modified: head/share/man/man8/rc.subr.8
==============================================================================
--- head/share/man/man8/rc.subr.8	Mon Sep 23 00:16:19 2013	(r255808)
+++ head/share/man/man8/rc.subr.8	Mon Sep 23 04:36:51 2013	(r255809)
@@ -29,7 +29,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd January 14, 2012
+.Dd September 23, 2012
 .Dt RC.SUBR 8
 .Os
 .Sh NAME
@@ -379,6 +379,9 @@ Perform a
 then a
 .Cm start .
 Defaults to displaying the process ID of the program (if running).
+.It Cm enabled
+Return 0 if the service is enabled and 1 if it is not.
+This command does not print anything.
 .It Cm rcvar
 Display which
 .Xr rc.conf 5

Modified: head/tools/build/mk/OptionalObsoleteFiles.inc
==============================================================================
--- head/tools/build/mk/OptionalObsoleteFiles.inc	Mon Sep 23 00:16:19 2013	(r255808)
+++ head/tools/build/mk/OptionalObsoleteFiles.inc	Mon Sep 23 04:36:51 2013	(r255809)
@@ -4375,6 +4375,7 @@ OLD_FILES+=usr/share/man/man8/telnetd.8.
 #.endif
 
 .if ${MK_UNBOUND} == no
+OLD_FILES+=etc/rc.d/local_unbound
 OLD_FILES+=usr/lib/private/libunbound.a
 OLD_FILES+=usr/lib/private/libunbound.so
 OLD_LIBS+=usr/lib/private/libunbound.so.5
@@ -4385,6 +4386,7 @@ OLD_FILES+=usr/lib32/private/libunbound.
 OLD_LIBS+=usr/lib32/private/libunbound.so.5
 OLD_FILES+=usr/lib32/private/libunbound_p.a
 .endif
+OLD_FILES+=usr/sbin/local-unbound-setup
 OLD_FILES+=usr/sbin/unbound
 OLD_FILES+=usr/sbin/unbound-anchor
 OLD_FILES+=usr/sbin/unbound-checkconf

Modified: head/usr.sbin/unbound/Makefile
==============================================================================
--- head/usr.sbin/unbound/Makefile	Mon Sep 23 00:16:19 2013	(r255808)
+++ head/usr.sbin/unbound/Makefile	Mon Sep 23 04:36:51 2013	(r255809)
@@ -1,5 +1,6 @@
 # $FreeBSD$
 
 SUBDIR=	daemon anchor checkconf control
+SUBDIR+= local-setup
 
 .include <bsd.subdir.mk>

Added: head/usr.sbin/unbound/local-setup/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/unbound/local-setup/Makefile	Mon Sep 23 04:36:51 2013	(r255809)
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+SCRIPTS= local-unbound-setup.sh
+MAN= #
+
+.include <bsd.prog.mk>

Added: head/usr.sbin/unbound/local-setup/local-unbound-setup.sh
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/unbound/local-setup/local-unbound-setup.sh	Mon Sep 23 04:36:51 2013	(r255809)
@@ -0,0 +1,357 @@
+#!/bin/sh
+#-
+# Copyright (c) 2013 Dag-Erling Smørgrav
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+#
+# Configuration variables
+#
+user=""
+unbound_conf=""
+forward_conf=""
+workdir=""
+chrootdir=""
+anchor=""
+pidfile=""
+resolv_conf=""
+resolvconf_conf=""
+service=""
+start_unbound=""
+forwarders=""
+
+#
+# Global variables
+#
+self=$(basename $(realpath "$0"))
+bkext=$(date "+%Y%m%d.%H%M%S")
+
+#
+# Set default values for unset configuration variables.
+#
+set_defaults() {
+	: ${user:=unbound}
+	: ${workdir:=/var/unbound}
+	: ${unbound_conf:=${workdir}/unbound.conf}
+	: ${forward_conf:=${workdir}/forward.conf}
+	: ${anchor:=${workdir}/root.key}
+	: ${pidfile:=/var/run/local_unbound.pid}
+	: ${resolv_conf:=/etc/resolv.conf}
+	: ${resolvconf_conf:=/etc/resolvconf.conf}
+	: ${service:=local_unbound}
+	: ${start_unbound:=yes}
+}
+
+#
+# Verify that the configuration files are inside the working
+# directory, and if so, set the chroot directory accordingly.
+#
+set_chrootdir() {
+	chrootdir="${workdir}"
+	for file in "${unbound_conf}" "${forward_conf}" "${anchor}" ; do
+		if [ "${file#${workdir%/}/}" = "${file}" ] ; then
+			echo "warning: ${file} is outside ${workdir}" >&2
+			chrootdir=""
+		fi
+	done
+	if [ -z "${chrootdir}" ] ; then
+		echo "warning: disabling chroot" >&2
+	fi
+}
+
+#
+# Scan through /etc/resolv.conf looking for uncommented nameserver
+# lines that don't point to localhost and return their values.
+#
+get_nameservers() {
+	while read line ; do
+		local bareline=${line%%\#*}
+		local key=${bareline%% *}
+		local value=${bareline#* }
+		case ${key} in
+		nameserver)
+			case ${value} in
+			127.0.0.1|::1|localhost|localhost.*)
+				;;
+			*)
+				echo "${value}"
+				;;
+			esac
+			;;
+		esac
+	done
+}
+
+#
+# Scan through /etc/resolv.conf looking for uncommented nameserver
+# lines.  Comment out any that don't point to localhost.  Finally,
+# append a nameserver line that points to localhost, if there wasn't
+# one already, and enable the edns0 option.
+#
+gen_resolv_conf() {
+	local localhost=no
+	local edns0=no
+	while read line ; do
+		local bareline=${line%%\#*}
+		local key=${bareline%% *}
+		local value=${bareline#* }
+		case ${key} in
+		nameserver)
+			case ${value} in
+			127.0.0.1|::1|localhost|localhost.*)
+				localhost=yes
+				;;
+			*)
+				echo -n "# "
+				;;
+			esac
+			;;
+		options)
+			case ${value} in
+			*edns0*)
+				edns0=yes
+				;;
+			esac
+			;;
+		esac
+		echo "${line}"
+	done
+	if [ "${localhost}" = "no" ] ; then
+		echo "nameserver 127.0.0.1"
+	fi
+	if [ "${edns0}" = "no" ] ; then
+		echo "options edns0"
+	fi
+}
+
+#
+# Generate resolvconf.conf so it updates forward.conf in addition to
+# resolv.conf.  Note "in addition to" rather than "instead of",
+# because we still want it to update the domain name and search path
+# if they change.  Setting name_servers to "127.0.0.1" ensures that
+# the libc resolver will try unbound first.
+#
+gen_resolvconf_conf() {
+	echo "# Generated by $self"
+	echo "name_servers=\"127.0.0.1\""
+	echo "unbound_conf=\"${forward_conf}\""
+	echo "unbound_pid=\"${pidfile}\""
+	echo "unbound_service=\"${service}\""
+	# resolvconf(8) likes to restart rather than reload - consider
+	# forcing its hand?
+	#echo "unbound_restart=\"service ${service} reload\""
+}
+
+#
+# Generate forward.conf
+#
+gen_forward_conf() {
+	echo "# Generated by $self"
+	echo "forward-zone:"
+	echo "        name: ."
+	for forwarder ; do
+		if expr "${forwarder}" : "^[0-9:.]\{1,\}$" >/dev/null ; then
+			echo "        forward-addr: ${forwarder}"
+		else
+			echo "        forward-host: ${forwarder}"
+		fi
+	done
+}
+
+#
+# Generate unbound.conf
+#
+gen_unbound_conf() {
+	echo "# Generated by $self"
+	echo "server:"
+	echo "        username: ${user}"
+	echo "        directory: ${workdir}"
+	echo "        chroot: ${chrootdir}"
+	echo "        pidfile: ${pidfile}"
+	echo "        auto-trust-anchor-file: ${anchor}"
+	echo ""
+	if [ -f "${forward_conf}" ] ; then
+		echo "include: ${forward_conf}"
+	fi
+}
+
+#
+# Replace one file with another, making a backup copy of the first,
+# but only if the new file is different from the old.
+#
+replace() {
+	local file="$1"
+	local newfile="$2"
+	if [ ! -f "${file}" ] ; then
+		echo "${file} created"
+		mv "${newfile}" "${file}"
+	elif ! cmp -s "${file}" "${newfile}" ; then
+		local oldfile="${file}.${bkext}"
+		echo "original ${file} saved as ${oldfile}"
+		mv "${file}" "${oldfile}"
+		mv "${newfile}" "${file}"
+	else
+		echo "${file} not modified"
+		rm "${newfile}"
+	fi
+}
+
+#
+# Print usage message and exit
+#
+usage() {
+	exec >&2
+	echo "usage: $self [options] [forwarder ...]"
+	echo "options:"
+	echo "    -n          do not start unbound"
+	echo "    -a path     full path to trust anchor file"
+	echo "    -c path     full path to unbound configuration"
+	echo "    -f path     full path to forwarding configuration"
+	echo "    -p path     full path to pid file"
+	echo "    -R path     full path to resolvconf.conf"
+	echo "    -r path     full path to resolv.conf"
+	echo "    -s service  name of unbound service"
+	echo "    -u user     user to run unbound as"
+	echo "    -w path     full path to working directory"
+	exit 1
+}
+
+#
+# Main
+#
+main() {
+	umask 022
+
+	#
+	# Parse and validate command-line options
+	#
+	while getopts "a:c:f:np:R:r:s:u:w:" option ; do
+		case $option in
+		a)
+			anchor="$OPTARG"
+			;;
+		c)
+			unbound_conf="$OPTARG"
+			;;
+		f)
+			forward_conf="$OPTARG"
+			;;
+		n)
+			start_unbound="no"
+			;;
+		p)
+			pidfile="$OPTARG"
+			;;
+		R)
+			resolvconf_conf="$OPTARG"
+			;;
+		r)
+			resolv_conf="$OPTARG"
+			;;
+		s)
+			service="$OPTARG"
+			;;
+		u)
+			user="$OPTARG"
+			;;
+		w)
+			workdir="$OPTARG"
+			;;
+		*)
+			usage
+			;;
+		esac
+	done
+	shift $((OPTIND-1))
+	set_defaults
+
+	#
+	# Get the list of forwarders, either from the command line or
+	# from resolv.conf.
+	#
+	forwarders="$@"
+	if [ -z "$forwarders" ] ; then
+		echo "Extracting forwarders from ${resolv_conf}."
+		forwarders=$(get_nameservers <"${resolv_conf}")
+	fi
+
+	#
+	# Generate forward.conf.
+	#
+	if [ -z "${forwarders}" ] ; then
+		echo -n "No forwarders found in ${resolv_conf##*/}, "
+		if [ -f "${forward_conf}" ] ; then
+			echo "using existing ${forward_conf##*/}."
+		else
+			echo "unbound will recurse."
+		fi
+	else
+		local tmp_forward_conf=$(mktemp -u "${forward_conf}.XXXXX")
+		gen_forward_conf ${forwarders} >"${tmp_forward_conf}"
+		replace "${forward_conf}" "${tmp_forward_conf}"
+	fi
+
+	#
+	# Generate unbound.conf.
+	#
+	local tmp_unbound_conf=$(mktemp -u "${unbound_conf}.XXXXX")
+	set_chrootdir
+	gen_unbound_conf >"${tmp_unbound_conf}"
+	replace "${unbound_conf}" "${tmp_unbound_conf}"
+
+	#
+	# Start unbound, unless requested not to.  Stop immediately if
+	# it is not enabled so we don't end up with a resolv.conf that
+	# points into nothingness.  We could "onestart" it, but it
+	# wouldn't stick.
+	#
+	if [ "${start_unbound}" = "no" ] ; then
+		# skip
+	elif ! service "${service}" enabled ; then
+		echo "Please enable $service in rc.conf(5) and try again."
+		return 1
+	elif ! service "${service}" restart ; then
+		echo "Failed to start $service."
+		return 1
+	fi
+
+	#
+	# Rewrite resolvconf.conf so resolvconf updates forward.conf
+	# instead of resolv.conf.
+	#
+	local tmp_resolvconf_conf=$(mktemp -u "${resolvconf_conf}.XXXXX")
+	gen_resolvconf_conf >"${tmp_resolvconf_conf}"
+	replace "${resolvconf_conf}" "${tmp_resolvconf_conf}"
+
+	#
+	# Finally, rewrite resolv.conf.
+	#
+	local tmp_resolv_conf=$(mktemp -u "${resolv_conf}.XXXXX")
+	gen_resolv_conf <"${resolv_conf}" >"${tmp_resolv_conf}"
+	replace "${resolv_conf}" "${tmp_resolv_conf}"
+}
+
+main "$@"


More information about the svn-src-head mailing list