#!/bin/sh # Copyright 2007 Roy Marples # All rights reserved # libc 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. PREFIX= RESOLVCONF="${PREFIX}"/etc/resolvconf RESOLVCONFS="$(resolvconf -l)" BASE="${RESOLVCONF}/resolv.conf.d/base" uniqify() { local result= while [ -n "$1" ]; do case " ${result} " in *" $1 "*);; *) result="${result} $1";; esac shift done echo "${result# *}" } OUR_NS= if [ -e "${BASE}" ]; then OUR_NS="$(sed -n -e 's/^[[:space:]]*nameserver[[:space:]]*//p' "${BASE}")" fi OUR_NS="$(uniqify \ ${OUR_NS} \ $(echo "${RESOLVCONFS}" \ | sed -n -e 's/^[[:space:]]*nameserver[[:space:]]*//p') \ )" # libc only allows for 3 nameservers # truncate after 127 as well i=0 NS= LOCALH=false for N in ${OUR_NS}; do i=$((${i} + 1)) NS="${NS} ${N}" [ "${i}" = "3" ] && break case "${N}" in 127.*) LOCALH=true; break;; esac done # This is nasty! # If we have a local nameserver then assume they are intelligent enough # to be forwarding domain requests to the correct nameserver and not search # ones. This means we prefer search then domain, otherwise, we use them in # the order given to us. OUR_SEARCH= if ${LOCALH}; then if [ -e "${BASE}" ]; then OUR_SEARCH="$(sed -n -e 's/^[[:space:]]*search[[:space:]]*//p' "${BASE}")" fi OUR_SEARCH="${OUR_SEARCH} $(echo "${RESOLVCONFS}" \ | sed -n 's/^[[:space:]]*search[[:space:]]*//p')" if [ -e "${BASE}" ]; then OUR_SEARCH="${OUR_SEARCH} $(sed -n -e 's/^[[:space:]]*domain[[:space:]]*//p' "${BASE}")" fi OUR_SEARCH="${OUR_SEARCH} $( echo "${RESOLVCONFS}" \ | sed -n -e 's/^[[:space:]]*domain[[:space:]]*//p')" else if [ -e "${BASE}" ]; then OUR_SEARCH="$(sed -n -e 's/^[[:space:]]*search[[:space:]]*//p' \ -e 's/^[[:space:]]*domain[[:space:]]*//p' "${BASE}")" fi OUR_SEARCH="${OUR_SEARCH} $(echo "${RESOLVCONFS}" \ | sed -n -e 's/^[[:space:]]*search[[:space:]]*//p' \ -e 's/^[[:space:]]*domain[[:space:]]*//p')" fi # libc only allows for 6 search domains i=0 SEARCH= for S in $(uniqify ${OUR_SEARCH}); do i=$((${i} + 1)) SEARCH="${SEARCH} ${S}" [ "${i}" = "6" ] && break done [ -n "${SEARCH}" ] && SEARCH="search${SEARCH}" # Hold our new resolv.conf in a variable to save on temporary files NEWCONF="# Generated by resolvconf\n" [ -e "${RESOLVCONF}"/resolv.conf.d/head ] \ && NEWCONF="${NEWCONF}$(cat "${RESOLVCONF}"/resolv.conf.d/head)\n" [ -n "${SEARCH}" ] && NEWCONF="${NEWCONF}${SEARCH}\n" for N in ${NS}; do NEWCONF="${NEWCONF}nameserver ${N}\n" done # Now dump everything else from our resolvs if [ -e "${BASE}" ]; then NEWCONF="${NEWCONF}$(sed -e '/^[[:space:]]*$/d' \ -e '/^[[:space:]]*nameserver[[:space:]]*.*/d' \ -e '/^[[:space:]]*search[[:space:]]*.*/d' \ -e '/^[[:space:]]*domain[[:space:]]*.*/d' \ "${BASE}")" fi # We don't know we're using GNU sed, so we do it like this NEWCONF="${NEWCONF}$(echo "${RESOLVCONFS}" | sed -e '/^[[:space:]]*$/d' \ -e '/^[[:space:]]*#/d' \ -e '/^[[:space:]]*nameserver[[:space:]]*.*/d' \ -e '/^[[:space:]]*search[[:space:]]*.*/d' \ -e '/^[[:space:]]*domain[[:space:]]*.*/d' \ )" [ -e "${RESOLVCONF}"/resolv.conf.d/tail ] \ && NEWCONF="${NEWCONF}$(cat "${RESOLVCONF}"/resolv.conf.d/tail)" # Check if the file has actually changed or not if [ -e "${RESOLVCONF}"/run/resolv.conf ]; then [ "$(cat "${RESOLVCONF}"/run/resolv.conf)" = "$(printf "${NEWCONF}")" ] && exit 0 fi # Create our resolv.conf now (umask 022; printf "${NEWCONF}" > "${RESOLVCONF}"/run/resolv.conf) resolvconf -s nscd restart # Notify users of the resolver for x in "${REVOLVCONF}"/update-libc.d/*; do [ -e "${x}" ] && "${x}" "$@" done # vim: ts=4 :