Support multiple daemon instances with systemd in Debian.

This commit is contained in:
Simon Kelley
2019-04-08 16:50:13 +01:00
parent a2b8220f4e
commit 343b7b4ad0
7 changed files with 306 additions and 219 deletions

1
debian/changelog vendored
View File

@@ -3,6 +3,7 @@ dnsmasq (2.81-1) unstable; urgency=low
* New upstream.
* Fix nodocs/nodoc confusion in rules. (closes: #922758)
* Add Vcs-* fields to control. (closes: #922422)
* Add systemd support for multiple daemon instances. (closes: #914305)
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 1 Mar 2019 17:19:25 +0000

11
debian/default vendored
View File

@@ -1,5 +1,5 @@
# This file has five functions:
# 1) to completely disable starting dnsmasq,
# This file has six functions:
# 1) to completely disable starting this dnsmasq instance
# 2) to set DOMAIN_SUFFIX by running `dnsdomainname`
# 3) to select an alternative config file
# by setting DNSMASQ_OPTS to --conf-file=<file>
@@ -7,6 +7,8 @@
# more configuration variables.
# 5) to stop the resolvconf package from controlling dnsmasq's
# idea of which upstream nameservers to use.
# 6) to avoid using this dnsmasq instance as the system's default resolver
# by setting DNSMASQ_EXCEPT="lo"
# For upgraders from very old versions, all the shell variables set
# here in previous versions are still honored by the init script
# so if you just keep your old version of this file nothing will break.
@@ -31,3 +33,8 @@ CONFIG_DIR=/etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new
# /etc/dnsmasq.conf is not enough to override resolvconf if it is
# installed: the line below must be uncommented.
#IGNORE_RESOLVCONF=yes
# If the resolvconf package is installed, dnsmasq will tell resolvconf
# to use dnsmasq under 127.0.0.1 as the system's default resolver.
# Uncommenting this line inhibits this behaviour.
#DNSMASQ_EXCEPT="lo"

152
debian/init vendored
View File

@@ -15,12 +15,13 @@ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/dnsmasq
NAME=dnsmasq
DESC="DNS forwarder and DHCP server"
INSTANCE="${2}"
# Most configuration options in /etc/default/dnsmasq are deprecated
# but still honoured.
ENABLED=1
if [ -r /etc/default/$NAME ]; then
. /etc/default/$NAME
if [ -r /etc/default/${NAME}${INSTANCE:+.${INSTANCE}} ]; then
. /etc/default/${NAME}${INSTANCE:+.${INSTANCE}}
fi
# Get the system locale, so that messages are in the correct language, and the
@@ -35,7 +36,7 @@ fi
# package is still in place.
test -e /usr/share/dnsmasq/installed-marker || exit 0
test -x $DAEMON || exit 0
test -x ${DAEMON} || exit 0
# Provide skeleton LSB log functions for backports which don't have LSB functions.
if [ -f /lib/lsb/init-functions ]; then
@@ -50,13 +51,13 @@ else
}
log_daemon_msg () {
echo -n "${1}: $2"
echo -n "${1}: ${2}"
}
log_end_msg () {
if [ $1 -eq 0 ]; then
if [ "${1}" -eq 0 ]; then
echo "."
elif [ $1 -eq 255 ]; then
elif [ "${1}" -eq 255 ]; then
/bin/echo -e " (warning)."
else
/bin/echo -e " failed!"
@@ -77,22 +78,22 @@ fi
# override it just by configuration in /etc/dnsmasq.conf, it is necessary
# to set IGNORE_RESOLVCONF=yes in /etc/default/dnsmasq.
if [ ! "$RESOLV_CONF" ] &&
[ "$IGNORE_RESOLVCONF" != "yes" ] &&
if [ ! "${RESOLV_CONF}" ] &&
[ "${IGNORE_RESOLVCONF}" != "yes" ] &&
[ -x /sbin/resolvconf ]
then
RESOLV_CONF=/run/dnsmasq/resolv.conf
fi
for INTERFACE in $DNSMASQ_INTERFACE; do
DNSMASQ_INTERFACES="$DNSMASQ_INTERFACES -i $INTERFACE"
for INTERFACE in ${DNSMASQ_INTERFACE}; do
DNSMASQ_INTERFACES="${DNSMASQ_INTERFACES} -i ${INTERFACE}"
done
for INTERFACE in $DNSMASQ_EXCEPT; do
DNSMASQ_INTERFACES="$DNSMASQ_INTERFACES -I $INTERFACE"
for INTERFACE in ${DNSMASQ_EXCEPT}; do
DNSMASQ_INTERFACES="${DNSMASQ_INTERFACES} -I ${INTERFACE}"
done
if [ ! "$DNSMASQ_USER" ]; then
if [ ! "${DNSMASQ_USER}" ]; then
DNSMASQ_USER="dnsmasq"
fi
@@ -102,15 +103,15 @@ fi
# have no effect, but for otherwise-unconfigured installations, it stops dnsmasq
# from being vulnerable to DNS-reflection attacks.
DNSMASQ_OPTS="$DNSMASQ_OPTS --local-service"
DNSMASQ_OPTS="${DNSMASQ_OPTS} --local-service"
# If the dns-root-data package is installed, then the trust anchors will be
# available in $ROOT_DS, in BIND zone-file format. Reformat as dnsmasq
# available in ROOT_DS, in BIND zone-file format. Reformat as dnsmasq
# --trust-anchor options.
ROOT_DS="/usr/share/dns/root.ds"
if [ -f $ROOT_DS ]; then
if [ -f ${ROOT_DS} ]; then
DNSMASQ_OPTS="$DNSMASQ_OPTS `env LC_ALL=C sed -rne "s/^([.a-zA-Z0-9]+)([[:space:]]+[0-9]+)*([[:space:]]+IN)*[[:space:]]+DS[[:space:]]+/--trust-anchor=\1,/;s/[[:space:]]+/,/gp" $ROOT_DS | tr '\n' ' '`"
fi
@@ -124,24 +125,24 @@ start()
# /run may be volatile, so we need to ensure that
# /run/dnsmasq exists here as well as in postinst
if [ ! -d /run/dnsmasq ]; then
mkdir /run/dnsmasq || return 2
mkdir /run/dnsmasq || { [ -d /run/dnsmasq ] || return 2 ; }
chown dnsmasq:nogroup /run/dnsmasq || return 2
fi
[ -x /sbin/restorecon ] && /sbin/restorecon /run/dnsmasq
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null || return 1
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON -- \
-x /run/dnsmasq/$NAME.pid \
${MAILHOSTNAME:+ -m $MAILHOSTNAME} \
${MAILTARGET:+ -t $MAILTARGET} \
${DNSMASQ_USER:+ -u $DNSMASQ_USER} \
${DNSMASQ_INTERFACES:+ $DNSMASQ_INTERFACES} \
${DHCP_LEASE:+ -l $DHCP_LEASE} \
${DOMAIN_SUFFIX:+ -s $DOMAIN_SUFFIX} \
${RESOLV_CONF:+ -r $RESOLV_CONF} \
${CACHESIZE:+ -c $CACHESIZE} \
${CONFIG_DIR:+ -7 $CONFIG_DIR} \
${DNSMASQ_OPTS:+ $DNSMASQ_OPTS} \
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid --exec ${DAEMON} --test > /dev/null || return 1
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid --exec ${DAEMON} -- \
-x /run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid \
${MAILHOSTNAME:+ -m ${MAILHOSTNAME}} \
${MAILTARGET:+ -t ${MAILTARGET}} \
${DNSMASQ_USER:+ -u ${DNSMASQ_USER}} \
${DNSMASQ_INTERFACES:+ ${DNSMASQ_INTERFACES}} \
${DHCP_LEASE:+ -l ${DHCP_LEASE}} \
${DOMAIN_SUFFIX:+ -s ${DOMAIN_SUFFIX}} \
${RESOLV_CONF:+ -r ${RESOLV_CONF}} \
${CACHESIZE:+ -c ${CACHESIZE}} \
${CONFIG_DIR:+ -7 ${CONFIG_DIR}} \
${DNSMASQ_OPTS:+ ${DNSMASQ_OPTS}} \
|| return 2
}
@@ -150,9 +151,8 @@ start_resolvconf()
# If interface "lo" is explicitly disabled in /etc/default/dnsmasq
# Then dnsmasq won't be providing local DNS, so don't add it to
# the resolvconf server set.
for interface in $DNSMASQ_EXCEPT
do
[ $interface = lo ] && return
for interface in ${DNSMASQ_EXCEPT}; do
[ ${interface} = lo ] && return
done
# Also skip this if DNS functionality is disabled in /etc/dnsmasq.conf
@@ -161,7 +161,7 @@ start_resolvconf()
fi
if [ -x /sbin/resolvconf ] ; then
echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.$NAME
echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.${NAME}${INSTANCE:+.${INSTANCE}}
fi
return 0
}
@@ -173,13 +173,13 @@ stop()
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /run/dnsmasq/$NAME.pid --name $NAME
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid --name ${NAME}
}
stop_resolvconf()
{
if [ -x /sbin/resolvconf ] ; then
/sbin/resolvconf -d lo.$NAME
/sbin/resolvconf -d lo.${NAME}${INSTANCE:+.${INSTANCE}}
fi
return 0
}
@@ -191,20 +191,20 @@ status()
# 1 if daemon is dead and pid file exists
# 3 if daemon is not running
# 4 if daemon status is unknown
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null
case "$?" in
0) [ -e "/run/dnsmasq/$NAME.pid" ] && return 1 ; return 3 ;;
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid --exec ${DAEMON} --test > /dev/null
case "${?}" in
0) [ -e "/run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid" ] && return 1 ; return 3 ;;
1) return 0 ;;
*) return 4 ;;
esac
}
case "$1" in
case "${1}" in
start)
test "$ENABLED" != "0" || exit 0
log_daemon_msg "Starting $DESC" "$NAME"
test "${ENABLED}" != "0" || exit 0
log_daemon_msg "Starting ${DESC}" "${NAME}${INSTANCE:+.${INSTANCE}}"
start
case "$?" in
case "${?}" in
0)
log_end_msg 0
start_resolvconf
@@ -222,40 +222,45 @@ case "$1" in
;;
stop)
stop_resolvconf
if [ "$ENABLED" != "0" ]; then
log_daemon_msg "Stopping $DESC" "$NAME"
if [ "${ENABLED}" != "0" ]; then
log_daemon_msg "Stopping ${DESC}" "${NAME}${INSTANCE:+.${INSTANCE}}"
fi
stop
RETVAL="$?"
if [ "$ENABLED" = "0" ]; then
case "$RETVAL" in
0) log_daemon_msg "Stopping $DESC" "$NAME"; log_end_msg 0 ;;
RETVAL="${?}"
if [ "${ENABLED}" = "0" ]; then
case "${RETVAL}" in
0) log_daemon_msg "Stopping ${DESC}" "${NAME}${INSTANCE:+.${INSTANCE}}"; log_end_msg 0 ;;
esac
exit 0
fi
case "$RETVAL" in
case "${RETVAL}" in
0) log_end_msg 0 ; exit 0 ;;
1) log_warning_msg "(not running)" ; exit 0 ;;
*) log_end_msg 1; exit 1 ;;
esac
;;
checkconfig)
${DAEMON} --test ${CONFIG_DIR:+ -7 ${CONFIG_DIR}} ${DNSMASQ_OPTS:+ ${DNSMASQ_OPTS}} >/dev/null 2>&1
RETVAL="${?}"
exit ${RETVAL}
;;
restart|force-reload)
test "$ENABLED" != "0" || exit 1
$DAEMON --test ${CONFIG_DIR:+ -7 $CONFIG_DIR} ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS} >/dev/null 2>&1
if [ $? -ne 0 ]; then
test "${ENABLED}" != "0" || exit 1
${DAEMON} --test ${CONFIG_DIR:+ -7 ${CONFIG_DIR}} ${DNSMASQ_OPTS:+ ${DNSMASQ_OPTS}} >/dev/null 2>&1
if [ ${?} -ne 0 ]; then
NAME="configuration syntax check"
RETVAL="2"
else
stop_resolvconf
stop
RETVAL="$?"
RETVAL="${?}"
fi
log_daemon_msg "Restarting $DESC" "$NAME"
case "$RETVAL" in
log_daemon_msg "Restarting ${DESC}" "${NAME}${INSTANCE:+.${INSTANCE}}"
case "${RETVAL}" in
0|1)
sleep 2
start
case "$?" in
case "${?}" in
0)
log_end_msg 0
start_resolvconf
@@ -274,9 +279,9 @@ case "$1" in
esac
;;
status)
log_daemon_msg "Checking $DESC" "$NAME"
log_daemon_msg "Checking ${DESC}" "${NAME}${INSTANCE:+.${INSTANCE}}"
status
case "$?" in
case "${?}" in
0) log_success_msg "(running)" ; exit 0 ;;
1) log_success_msg "(dead, pid file exists)" ; exit 1 ;;
3) log_success_msg "(not running)" ; exit 3 ;;
@@ -284,7 +289,7 @@ case "$1" in
esac
;;
dump-stats)
kill -s USR1 `cat /run/dnsmasq/$NAME.pid`
kill -s USR1 `cat /run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid`
;;
systemd-start-resolvconf)
start_resolvconf
@@ -296,26 +301,25 @@ case "$1" in
# /run may be volatile, so we need to ensure that
# /run/dnsmasq exists here as well as in postinst
if [ ! -d /run/dnsmasq ]; then
mkdir /run/dnsmasq || return 2
mkdir /run/dnsmasq || { [ -d /run/dnsmasq ] || return 2 ; }
chown dnsmasq:nogroup /run/dnsmasq || return 2
fi
exec $DAEMON -x /run/dnsmasq/$NAME.pid \
${MAILHOSTNAME:+ -m $MAILHOSTNAME} \
${MAILTARGET:+ -t $MAILTARGET} \
${DNSMASQ_USER:+ -u $DNSMASQ_USER} \
${DNSMASQ_INTERFACES:+ $DNSMASQ_INTERFACES} \
${DHCP_LEASE:+ -l $DHCP_LEASE} \
${DOMAIN_SUFFIX:+ -s $DOMAIN_SUFFIX} \
${RESOLV_CONF:+ -r $RESOLV_CONF} \
${CACHESIZE:+ -c $CACHESIZE} \
${CONFIG_DIR:+ -7 $CONFIG_DIR} \
${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}
exec ${DAEMON} -x /run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid \
${MAILHOSTNAME:+ -m ${MAILHOSTNAME}} \
${MAILTARGET:+ -t ${MAILTARGET}} \
${DNSMASQ_USER:+ -u ${DNSMASQ_USER}} \
${DNSMASQ_INTERFACES:+ ${DNSMASQ_INTERFACES}} \
${DHCP_LEASE:+ -l ${DHCP_LEASE}} \
${DOMAIN_SUFFIX:+ -s ${DOMAIN_SUFFIX}} \
${RESOLV_CONF:+ -r ${RESOLV_CONF}} \
${CACHESIZE:+ -c ${CACHESIZE}} \
${CONFIG_DIR:+ -7 ${CONFIG_DIR}} \
${DNSMASQ_OPTS:+ ${DNSMASQ_OPTS}}
;;
*)
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload|dump-stats|status}" >&2
echo "Usage: /etc/init.d/${NAME} {start|stop|restart|force-reload|dump-stats|status}" >&2
exit 3
;;
esac
exit 0

5
debian/rules vendored
View File

@@ -129,6 +129,8 @@ define add_docs
gzip -9n $1/usr/share/doc/$(package)/changelog.archive
install -m 644 dbus/DBus-interface $1/usr/share/doc/$(package)/.
gzip -9n $1/usr/share/doc/$(package)/DBus-interface
install -m 644 debian/systemd_howto $1/usr/share/doc/$(package)/.
gzip -9n $1/usr/share/doc/$(package)/systemd_howto
gzip -9n $1/usr/share/man/man8/dnsmasq.8
for f in $1/usr/share/man/*; do \
if [ -f $$f/man8/dnsmasq.8 ]; then \
@@ -161,7 +163,7 @@ binary-indep: checkroot
rm -rf debian/trees/daemon
install -m 755 \
-d debian/trees/daemon/DEBIAN \
-d debian/trees/daemon/usr/share/doc \
-d debian/trees/daemon/usr/share/doc/dnsmasq \
-d debian/trees/daemon/etc/init.d \
-d debian/trees/daemon/etc/dnsmasq.d \
-d debian/trees/daemon/etc/resolvconf/update.d \
@@ -181,6 +183,7 @@ binary-indep: checkroot
install -m 644 dnsmasq.conf.example debian/trees/daemon/etc/dnsmasq.conf
install -m 644 debian/readme.dnsmasq.d debian/trees/daemon/etc/dnsmasq.d/README
install -m 644 debian/systemd.service debian/trees/daemon/lib/systemd/system/dnsmasq.service
install -m 644 debian/systemd@.service debian/trees/daemon/lib/systemd/system/dnsmasq@.service
install -m 644 debian/tmpfiles.conf debian/trees/daemon/usr/lib/tmpfiles.d/dnsmasq.conf
install -m 644 debian/insserv debian/trees/daemon/etc/insserv.conf.d/dnsmasq
ln -s $(package) debian/trees/daemon/usr/share/doc/dnsmasq

View File

@@ -10,7 +10,7 @@ Type=forking
PIDFile=/run/dnsmasq/dnsmasq.pid
# Test the config file and refuse starting if it is not valid.
ExecStartPre=/usr/sbin/dnsmasq --test
ExecStartPre=/etc/init.d/dnsmasq checkconfig
# We run dnsmasq via the /etc/init.d/dnsmasq script which acts as a
# wrapper picking up extra configuration files and then execs dnsmasq
@@ -20,7 +20,7 @@ ExecStart=/etc/init.d/dnsmasq systemd-exec
# The systemd-*-resolvconf functions configure (and deconfigure)
# resolvconf to work with the dnsmasq DNS server. They're called like
# this to get correct error handling (ie don't start-resolvconf if the
# dnsmasq daemon fails to start.
# dnsmasq daemon fails to start).
ExecStartPost=/etc/init.d/dnsmasq systemd-start-resolvconf
ExecStop=/etc/init.d/dnsmasq systemd-stop-resolvconf

31
debian/systemd@.service vendored Normal file
View File

@@ -0,0 +1,31 @@
[Unit]
Description=dnsmasq (%i) - A lightweight DHCP and caching DNS server
Requires=network.target
Wants=nss-lookup.target
Before=nss-lookup.target
After=network.target
[Service]
Type=forking
PIDFile=/run/dnsmasq/dnsmasq.%i.pid
# Test the config file and refuse starting if it is not valid.
ExecStartPre=/etc/init.d/dnsmasq checkconfig "%i"
# We run dnsmasq via the /etc/init.d/dnsmasq script which acts as a
# wrapper picking up extra configuration files and then execs dnsmasq
# itself, when called with the "systemd-exec" function.
ExecStart=/etc/init.d/dnsmasq systemd-exec "%i"
# The systemd-*-resolvconf functions configure (and deconfigure)
# resolvconf to work with the dnsmasq DNS server. They're called like
# this to get correct error handling (ie don't start-resolvconf if the
# dnsmasq daemon fails to start).
ExecStartPost=/etc/init.d/dnsmasq systemd-start-resolvconf "%i"
ExecStop=/etc/init.d/dnsmasq systemd-stop-resolvconf "%i"
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target

41
debian/systemd_howto vendored Normal file
View File

@@ -0,0 +1,41 @@
HOWTO
=====
dnsmasq comes with the possibility to run multiple systemd service instances on the same machine.
There is the main service which is enabled by default via `systemctl enable dnsmasq.service` and uses the configuration from `/etc/default/dnsmasq`.
Additional service instances can be enabled via `systemctl enable dnsmasq@<instance name>.service` that use the configuration from `/etc/default/dnsmasq.<instance name>`.
It is recommended to use a separate configuration file and directory for each instance.
Additionally make sure that all instances use either different ports and/or ip addresses to avoid binding collisions.
Example setup for an instance called "alt"
#1 File `/etc/dnsmasq.alt.conf` copied from `/etc/dnsmasq.conf`
#2 Directory `/etc/dnsmasq.alt.d`
#3 File `/etc/default/dnsmasq.alt` copied from `/etc/default/dnsmasq` with following adaptions:
* The options DNSMASQ_OPTS and CONFIG_DIR point to the correct configuration file and directory.
DNSMASQ_OPTS="... --conf-file=/etc/dnsmasq.alt.conf ..."
CONFIG_DIR=/etc/dnsmasq.alt.d,.dpkg-dist,.dpkg-old,.dpkg-new
* The option DNSMASQ_EXCEPT must contain "lo" to avoid that an instance becomes the machine's DNS resolver.
DNSMASQ_EXCEPT="lo"
* If the additional instance should bind to all IP addresses of a specific interface, e.g. "dnsalt01", then the following addition could be used:
DNSMASQ_OPTS="... --bind-dynamic --interface=dnsalt01 ..."
Additionally the main instance must be stopped from binding to interfaces that are used by other instances:
DNSMASQ_OPTS="... --bind-dynamic --except-interface=dnsalt* ..."
* If the additional instance should not use the machine's DNS resolver, normally that's the dnsmasq main instance, as upstream server, then the following addition could be used:
IGNORE_RESOLVCONF=yes
#4 Enable additional instance via `systemctl enable dnsmasq@alt.service`
#5 Start additional instance without reboot via `systemctl start dnsmasq@alt.service`
TODO
====
#1 - Found shortcoming on 2019-03-10
Only the option DNSMASQ_EXCEPT="lo" avoids that an DNS instance will be set as the machine's DNS resolver.
This may interfere with the wish to run an additional instance on a different port on the localhost addresses.
My suggestion in the initial Debian report [1] was to specify a explicit variable for this.
[1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=914305#5
#2 - Preferred configuration way
Should the variables DNSMASQ_INTERFACE and DNSMASQ_EXCEPT be used instead of --interface and --except-interface? (while "lo" still has to be in DNSMASQ_EXCEPT as of now)