1#!/bin/sh
2# Copyright 2007 Roy Marples
3# All rights reserved
4
5# libc subscriber for resolvconf
6
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10#     * Redistributions of source code must retain the above copyright
11#       notice, this list of conditions and the following disclaimer.
12#     * Redistributions in binary form must reproduce the above
13#       copyright notice, this list of conditions and the following
14#       disclaimer in the documentation and/or other materials provided
15#       with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29PREFIX=
30RESOLVCONF="${PREFIX}"/etc/resolvconf
31RESOLVCONFS="$(resolvconf -l)"
32BASE="${RESOLVCONF}/resolv.conf.d/base"
33
34uniqify() {
35    local result=
36    while [ -n "$1" ]; do
37		case " ${result} " in
38			*" $1 "*);;
39			*) result="${result} $1";;
40		esac
41		shift
42	done
43    echo "${result# *}"
44}
45
46OUR_NS=
47if [ -e "${BASE}" ]; then
48	OUR_NS="$(sed -n -e 's/^[[:space:]]*nameserver[[:space:]]*//p' "${BASE}")"
49fi
50OUR_NS="$(uniqify \
51	${OUR_NS} \
52	$(echo "${RESOLVCONFS}" \
53	| sed -n -e 's/^[[:space:]]*nameserver[[:space:]]*//p') \
54)"
55
56# libc only allows for 3 nameservers
57# truncate after 127 as well
58i=0
59NS=
60LOCALH=false
61for N in ${OUR_NS}; do
62	i=$((${i} + 1))
63	NS="${NS} ${N}"
64	[ "${i}" = "3" ] && break
65	case "${N}" in
66		127.*) LOCALH=true; break;;
67	esac
68done
69
70# This is nasty!
71# If we have a local nameserver then assume they are intelligent enough
72# to be forwarding domain requests to the correct nameserver and not search
73# ones. This means we prefer search then domain, otherwise, we use them in
74# the order given to us.
75OUR_SEARCH=
76if ${LOCALH}; then
77	if [ -e "${BASE}" ]; then
78		OUR_SEARCH="$(sed -n -e 's/^[[:space:]]*search[[:space:]]*//p' "${BASE}")"
79	fi
80	OUR_SEARCH="${OUR_SEARCH} $(echo "${RESOLVCONFS}" \
81		| sed -n 's/^[[:space:]]*search[[:space:]]*//p')"
82	if [ -e "${BASE}" ]; then
83		OUR_SEARCH="${OUR_SEARCH} $(sed -n -e 's/^[[:space:]]*domain[[:space:]]*//p' "${BASE}")"
84	fi
85	OUR_SEARCH="${OUR_SEARCH} $( echo "${RESOLVCONFS}" \
86		| sed -n -e 's/^[[:space:]]*domain[[:space:]]*//p')"
87else
88	if [ -e "${BASE}" ]; then
89		OUR_SEARCH="$(sed -n -e 's/^[[:space:]]*search[[:space:]]*//p' \
90			-e 's/^[[:space:]]*domain[[:space:]]*//p' "${BASE}")"
91	fi
92	OUR_SEARCH="${OUR_SEARCH} $(echo "${RESOLVCONFS}" \
93		| sed -n -e 's/^[[:space:]]*search[[:space:]]*//p' \
94			-e 's/^[[:space:]]*domain[[:space:]]*//p')"
95fi
96
97# libc only allows for 6 search domains
98i=0
99SEARCH=
100for S in $(uniqify ${OUR_SEARCH}); do
101	i=$((${i} + 1))
102	SEARCH="${SEARCH} ${S}"
103	[ "${i}" = "6" ] && break
104done
105[ -n "${SEARCH}" ] && SEARCH="search${SEARCH}"
106
107# Hold our new resolv.conf in a variable to save on temporary files
108NEWCONF="# Generated by resolvconf\n"
109[ -e "${RESOLVCONF}"/resolv.conf.d/head ] \
110	&& NEWCONF="${NEWCONF}$(cat "${RESOLVCONF}"/resolv.conf.d/head)\n"
111[ -n "${SEARCH}" ] && NEWCONF="${NEWCONF}${SEARCH}\n"
112for N in ${NS}; do
113	NEWCONF="${NEWCONF}nameserver ${N}\n"
114done
115
116# Now dump everything else from our resolvs
117if [ -e "${BASE}" ]; then
118	NEWCONF="${NEWCONF}$(sed -e '/^[[:space:]]*$/d' \
119		-e '/^[[:space:]]*nameserver[[:space:]]*.*/d' \
120		-e '/^[[:space:]]*search[[:space:]]*.*/d' \
121		-e '/^[[:space:]]*domain[[:space:]]*.*/d' \
122		"${BASE}")"
123fi
124
125# We don't know we're using GNU sed, so we do it like this
126NEWCONF="${NEWCONF}$(echo "${RESOLVCONFS}" | sed -e '/^[[:space:]]*$/d' \
127	-e '/^[[:space:]]*#/d' \
128	-e '/^[[:space:]]*nameserver[[:space:]]*.*/d' \
129	-e '/^[[:space:]]*search[[:space:]]*.*/d' \
130	-e '/^[[:space:]]*domain[[:space:]]*.*/d' \
131	)"
132[ -e "${RESOLVCONF}"/resolv.conf.d/tail ] \
133	&& NEWCONF="${NEWCONF}$(cat "${RESOLVCONF}"/resolv.conf.d/tail)"
134
135# Check if the file has actually changed or not
136if [ -e "${RESOLVCONF}"/run/resolv.conf ]; then
137	[ "$(cat "${RESOLVCONF}"/run/resolv.conf)" = "$(printf "${NEWCONF}")" ] && exit 0
138fi
139
140# Create our resolv.conf now
141(umask 022; printf "${NEWCONF}" > "${RESOLVCONF}"/run/resolv.conf)
142
143resolvconf -s nscd restart
144
145# Notify users of the resolver
146for x in "${REVOLVCONF}"/update-libc.d/*; do
147	[ -e "${x}" ] && "${x}" "$@"
148done
149
150# vim: ts=4 :
151