From owner-svn-src-head@FreeBSD.ORG Mon Sep 23 04:36:53 2013 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id C31E286F; Mon, 23 Sep 2013 04:36:53 +0000 (UTC) (envelope-from des@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id ACDA22AFF; Mon, 23 Sep 2013 04:36:53 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r8N4arlo019719; Mon, 23 Sep 2013 04:36:53 GMT (envelope-from des@svn.freebsd.org) Received: (from des@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r8N4apZZ019707; Mon, 23 Sep 2013 04:36:51 GMT (envelope-from des@svn.freebsd.org) Message-Id: <201309230436.r8N4apZZ019707@svn.freebsd.org> From: Dag-Erling Smørgrav Date: Mon, 23 Sep 2013 04:36:51 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: 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 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Sep 2013 04:36:53 -0000 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 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 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 "$@"