#!/bin/sh # Copyright 2007 Roy Marples # All rights reserved # dnsmasq subscriber for resolvconf # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * 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 COPYRIGHT HOLDERS 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 COPYRIGHT # OWNER 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. # This is very important! # We assume that we are a local dns cache - after all, why would a server # use resolvconf? # Now that we have assumed this, we also assume that generic DHCP clients # will enter their domains and search domains ONLY in the "search" field # in their resolv.confs and VPN clients will put the domain they are for # into the domain field only. # This allows dnsmasq to forward domains for a specific VPN domain to the # VPN nameserver and everything else to the standard name servers. # A sample dnsmasq config that works as above is like so. # NOTE: The loopback interface on some systems maybe lo0. #domain-needed #interface=lo #resolv-file=/etc/dnsmasq-resolv.conf #conf-file=/etc/dnsmasq-resolvconf.conf # The last step is to configure dns configuration for /etc/resolv.conf # for the lo interface. You can do this in resolvconf as well by adding #nameserver 127.0.0.1 # to resolv.conf.d/base # Load our variables from resolvconf VARS="$(resolvconf -v)" eval "${VARS}" PREFIX= DNSMASQRESOLV="${PREFIX}/etc/dnsmasq-resolv.conf" DNSMASQCONF="${PREFIX}/etc/dnsmasq-resolvconf.conf" NEWCONF="# Generated by resolvconf\n" NEWRESOLV="${NEWCONF}" # Using DBUS means that we never have to restart the daemon # This is important as it means we should not drop DNS queries # whilst changing DNS options around. However, DBUS support is optional # so we need to validate a few things first. # Check for DBus support in the binary DBUS=no dbuspid=/var/run/dbus/dbus.pid [ -s "${dbuspid}" ] || dbuspid=/var/run/dbus.pid if [ -s "${dbuspid}" -a -s /var/run/dnsmasq.pid ]; then if dnsmasq --version 2>/dev/null | \ grep -q "^Compile time options.*[[:space:]]DBus[[:space:]]" \ ; then # Sanity - check that dnsmasq and dbus are running if kill -0 $(cat "${dbuspid}") \ && kill -0 $(cat /var/run/dnsmasq.pid); then DBUS=yes NEWCONF="${NEWCONF}\n# Domain specific servers will be sent over dbus\nenable-dbus\n" fi fi fi uniqify() { local result= while [ -n "$1" ]; do case " ${result} " in *" $1 "*);; *) result="${result} $1";; esac shift done echo "${result# *}" } # If we only have domain information then put it in search too [ -z "${NEWSEARCH}" -a -z "${NEWNS}" ] && NEWSEARCH="${NEWDOMAIN}" for N in ${NEWSEARCH}; do case " ${NEWSL} " in *" ${N%,*} "*);; *) NEWSL="${NEWSL} ${N%,*}";; esac case "\n${NEWRESOLV}\n" in *"\nnameserver ${N#*,}\n"*);; *) NEWRESOLV="${NEWRESOLV}nameserver ${N#*,}\n";; esac done for N in ${NEWNS}; do case "\n${NEWRESOLV}\n" in *"\nnameserver ${N}\n");; *) NEWRESOLV="${NEWRESOLV}nameserver ${N}\n";; esac done [ -n "${NEWSL}" ] && NEWRESOLV="${NEWRESOLV}search${NEWSL}\n" DBUSDEST= for DN in $(uniqify ${NEWDOMAIN}); do if [ "${DBUS}" = "yes" ]; then IP=${DN#*,} SIFS=${IFS-y} OIFS=$IFS IFS=. set -- ${IP} NUM="0x$(printf "%02x" $1 $2 $3 $4)" if [ "${SIFS}" = "y" ]; then unset IFS else IFS=$OIFS fi DBUSDEST="${DBUSDEST} uint32:$(printf "%d" ${NUM}) string:${DN%,*}" else NEWCONF="${NEWCONF}server=/${DN%,*}/${DN#*,}\n" fi done RELOAD="no" if [ -e "${DNSMASQCONF}" ]; then if [ "$(cat "${DNSMASQCONF}")" != "$(printf "${NEWCONF}")" ]; then RELOAD="yes" printf "${NEWCONF}" > "${DNSMASQCONF}" fi else RELOAD="yes" printf "${NEWCONF}" > "${DNSMASQCONF}" fi if [ -e "${DNSMASQRESOLV}" ]; then if [ "$(cat "${DNSMASQRESOLV}")" != "$(printf "${NEWRESOLV}")" ]; then RELOAD="yes" printf "${NEWRESOLV}" > "${DNSMASQRESOLV}" fi else # dnsmasq polls this file so no need to set RELOAD="yes" printf "${NEWRESOLV}" > "${DNSMASQRESOLV}" fi [ "${RELOAD}" = "yes" ] && resolvconf -s dnsmasq restart if [ "${DBUS}" = "yes" ]; then [ "${RELOAD}" != "yes" ] && resolvconf -s dnsmasq reload # Send even if emtpy so old servers are cleared dbus-send --system --dest=uk.org.thekelleys.dnsmasq \ /uk/org/thekelleys/dnsmasq uk.org.thekelleys.SetServers \ ${DBUSDEST} fi # vim: ts=4 :