1 1.1 roy #!/bin/sh 2 1.7 roy # Copyright (c) 2007-2023 Roy Marples 3 1.1 roy # All rights reserved 4 1.1 roy 5 1.1 roy # dnsmasq subscriber for resolvconf 6 1.1 roy 7 1.1 roy # Redistribution and use in source and binary forms, with or without 8 1.1 roy # modification, are permitted provided that the following conditions 9 1.1 roy # are met: 10 1.1 roy # * Redistributions of source code must retain the above copyright 11 1.1 roy # notice, this list of conditions and the following disclaimer. 12 1.1 roy # * Redistributions in binary form must reproduce the above 13 1.1 roy # copyright notice, this list of conditions and the following 14 1.1 roy # disclaimer in the documentation and/or other materials provided 15 1.1 roy # with the distribution. 16 1.1 roy # 17 1.1 roy # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 1.1 roy # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 1.1 roy # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 1.1 roy # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 1.1 roy # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 1.1 roy # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 1.1 roy # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 1.1 roy # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 1.1 roy # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 1.1 roy # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 1.1 roy # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 roy 29 1.1 roy [ -f "@SYSCONFDIR@"/resolvconf.conf ] || exit 0 30 1.1 roy . "@SYSCONFDIR@/resolvconf.conf" || exit 1 31 1.2 kre [ -z "${dnsmasq_conf}${dnsmasq_resolv}" ] && exit 0 32 1.2 kre [ -z "$RESOLVCONF" ] && eval "$(@SBINDIR@/resolvconf -v)" 33 1.2 kre NL=" 34 1.2 kre " 35 1.1 roy 36 1.1 roy : ${dnsmasq_pid:=/var/run/dnsmasq.pid} 37 1.2 kre [ -s "$dnsmasq_pid" ] || dnsmasq_pid=/var/run/dnsmasq/dnsmasq.pid 38 1.2 kre [ -s "$dnsmasq_pid" ] || unset dnsmasq_pid 39 1.2 kre : ${dnsmasq_service:=dnsmasq} 40 1.2 kre newconf="# Generated by resolvconf$NL" 41 1.1 roy newresolv="$newconf" 42 1.1 roy 43 1.1 roy # Using dbus means that we never have to restart the daemon 44 1.1 roy # This is important as it means we should not drop DNS queries 45 1.1 roy # whilst changing DNS options around. However, dbus support is optional 46 1.1 roy # so we need to validate a few things first. 47 1.1 roy # Check for DBus support in the binary 48 1.1 roy dbus=false 49 1.2 kre dbus_ex=false 50 1.2 kre dbus_introspect=$(dbus-send --print-reply --system \ 51 1.2 kre --dest=uk.org.thekelleys.dnsmasq \ 52 1.2 kre /uk/org/thekelleys/dnsmasq \ 53 1.2 kre org.freedesktop.DBus.Introspectable.Introspect \ 54 1.2 kre 2>/dev/null) 55 1.2 kre if [ $? = 0 ]; then 56 1.2 kre dbus=true 57 1.2 kre if printf %s "$dbus_introspect" | \ 58 1.2 kre grep -q '<method name="SetDomainServers">' 59 1.1 roy then 60 1.2 kre dbus_ex=true 61 1.1 roy fi 62 1.1 roy fi 63 1.1 roy 64 1.1 roy for n in $NAMESERVERS; do 65 1.2 kre newresolv="${newresolv}nameserver $n$NL" 66 1.1 roy done 67 1.1 roy 68 1.1 roy dbusdest= 69 1.2 kre dbusdest_ex= 70 1.2 kre conf= 71 1.1 roy for d in $DOMAINS; do 72 1.1 roy dn="${d%%:*}" 73 1.1 roy ns="${d#*:}" 74 1.1 roy while [ -n "$ns" ]; do 75 1.2 kre n="${ns%%,*}" 76 1.2 kre if $dbus && ! $dbus_ex; then 77 1.2 kre case "$n" in 78 1.2 kre *.*.*.*) 79 1.2 kre SIFS=${IFS-y} OIFS=$IFS 80 1.2 kre IFS=. 81 1.2 kre set -- $n 82 1.2 kre num="0x$(printf %02x $1 $2 $3 $4)" 83 1.2 kre if [ "$SIFS" = y ]; then 84 1.2 kre unset IFS 85 1.2 kre else 86 1.2 kre IFS=$OIFS 87 1.2 kre fi 88 1.2 kre dbusdest="$dbusdest uint32:$(printf %u $num)" 89 1.2 kre dbusdest="$dbusdest string:$dn" 90 1.2 kre ;; 91 1.2 kre *:*%*) 92 1.2 kre # This version of dnsmasq won't accept 93 1.2 kre # scoped IPv6 addresses 94 1.2 kre dbus=false 95 1.2 kre ;; 96 1.2 kre *:*) 97 1.2 kre SIFS=${IFS-y} OIFS=$IFS bytes= front= back= 98 1.2 kre empty=false i=0 99 1.2 kre IFS=: 100 1.2 kre set -- $n 101 1.2 kre while [ -n "$1" ] || [ -n "$2" ]; do 102 1.2 kre addr="$1" 103 1.2 kre shift 104 1.2 kre if [ -z "$addr" ]; then 105 1.2 kre empty=true 106 1.2 kre continue 107 1.2 kre fi 108 1.7 roy i=$((i + 1)) 109 1.2 kre while [ ${#addr} -lt 4 ]; do 110 1.2 kre addr="0${addr}" 111 1.2 kre done 112 1.2 kre byte1="$(printf %d 0x${addr%??})" 113 1.2 kre byte2="$(printf %d 0x${addr#??})" 114 1.2 kre if $empty; then 115 1.2 kre back="$back byte:$byte1 byte:$byte2" 116 1.2 kre else 117 1.2 kre front="$front byte:$byte1 byte:$byte2" 118 1.2 kre fi 119 1.2 kre done 120 1.2 kre while [ $i != 8 ]; do 121 1.7 roy i=$((i + 1)) 122 1.2 kre front="$front byte:0 byte:0" 123 1.2 kre done 124 1.2 kre front="${front}$back" 125 1.2 kre if [ "$SIFS" = y ]; then 126 1.2 kre unset IFS 127 1.2 kre else 128 1.2 kre IFS=$OIFS 129 1.2 kre fi 130 1.2 kre dbusdest="${dbusdest}$front string:$dn" 131 1.2 kre ;; 132 1.2 kre *) 133 1.2 kre if ! $dbus_ex; then 134 1.2 kre dbus=false 135 1.2 kre fi 136 1.2 kre ;; 137 1.2 kre esac 138 1.1 roy fi 139 1.2 kre dbusdest_ex="$dbusdest_ex${dbusdest_ex:+,}/$dn/$n" 140 1.2 kre conf="${conf}server=/$dn/$n$NL" 141 1.1 roy [ "$ns" = "${ns#*,}" ] && break 142 1.1 roy ns="${ns#*,}" 143 1.1 roy done 144 1.1 roy done 145 1.1 roy 146 1.2 kre if $dbus; then 147 1.2 kre newconf="$newconf$NL# Domain specific servers will" 148 1.2 kre newconf="$newconf be sent over dbus${NL}" 149 1.2 kre else 150 1.2 kre newconf="$newconf$conf" 151 1.2 kre fi 152 1.2 kre 153 1.2 kre # Try to ensure that config dirs exist 154 1.7 roy if command -v config_mkdirs >/dev/null 2>&1; then 155 1.2 kre config_mkdirs "$dnsmasq_conf" "$dnsmasq_resolv" 156 1.2 kre else 157 1.2 kre @SBINDIR@/resolvconf -D "$dnsmasq_conf" "$dnsmasq_resolv" 158 1.2 kre fi 159 1.2 kre 160 1.1 roy changed=false 161 1.2 kre if [ -n "$dnsmasq_conf" ]; then 162 1.2 kre if [ ! -f "$dnsmasq_conf" ] || \ 163 1.2 kre [ "$(cat "$dnsmasq_conf")" != "$(printf %s "$newconf")" ] 164 1.2 kre then 165 1.1 roy changed=true 166 1.2 kre printf %s "$newconf" >"$dnsmasq_conf" 167 1.1 roy fi 168 1.2 kre fi 169 1.2 kre if [ -n "$dnsmasq_resolv" ]; then 170 1.1 roy # dnsmasq polls this file so no need to set changed=true 171 1.2 kre if [ -f "$dnsmasq_resolv" ]; then 172 1.2 kre if [ "$(cat "$dnsmasq_resolv")" != "$(printf %s "$newresolv")" ] 173 1.2 kre then 174 1.2 kre printf %s "$newresolv" >"$dnsmasq_resolv" 175 1.2 kre fi 176 1.2 kre else 177 1.2 kre printf %s "$newresolv" >"$dnsmasq_resolv" 178 1.2 kre fi 179 1.1 roy fi 180 1.1 roy 181 1.1 roy if $changed; then 182 1.2 kre # dnsmasq does not re-read the configuration file on SIGHUP 183 1.2 kre if [ -n "$dnsmasq_restart" ]; then 184 1.2 kre eval $dnsmasq_restart 185 1.2 kre elif [ -n "$RESTARTCMD" ]; then 186 1.2 kre set -- ${dnsmasq_service} 187 1.4 kre eval "$RESTARTCMD" 188 1.2 kre else 189 1.2 kre @SBINDIR@/resolvconf -r ${dnsmasq_service} 190 1.2 kre fi 191 1.1 roy fi 192 1.1 roy if $dbus; then 193 1.2 kre if [ -s "$dnsmasq_pid" ]; then 194 1.2 kre $changed || kill -HUP $(cat "$dnsmasq_pid") 195 1.2 kre fi 196 1.1 roy # Send even if empty so old servers are cleared 197 1.2 kre if $dbus_ex; then 198 1.2 kre method=SetDomainServers 199 1.2 kre if [ -n "$dbusdest_ex" ]; then 200 1.2 kre dbusdest_ex="array:string:$dbusdest_ex" 201 1.2 kre fi 202 1.2 kre dbusdest="$dbusdest_ex" 203 1.2 kre else 204 1.2 kre method=SetServers 205 1.2 kre fi 206 1.1 roy dbus-send --system --dest=uk.org.thekelleys.dnsmasq \ 207 1.2 kre /uk/org/thekelleys/dnsmasq uk.org.thekelleys.$method \ 208 1.1 roy $dbusdest 209 1.5 roy dbus-send --system --dest=uk.org.thekelleys.dnsmasq \ 210 1.5 roy /uk/org/thekelleys/dnsmasq uk.org.thekelleys.ClearCache 211 1.1 roy fi 212