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 "$@"
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to