Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F152018469
D56268.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
78 KB
Referenced Files
None
Subscribers
None
D56268.diff
View Options
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2007-2019 Roy Marples <roy@marples.name>
+Copyright (c) 2007-2020 Roy Marples <roy@marples.name>
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,9 @@
CONFIG_MK?= ${_CONFIG_MK}
include ${CONFIG_MK}
+DIST!= if test -d .git; then echo "dist-git"; \
+ else echo "dist-inst"; fi
+
SBINDIR?= /sbin
SYSCONFDIR?= /etc
LIBEXECDIR?= /libexec/resolvconf
@@ -20,9 +23,11 @@
DOCMODE?= 0644
MANMODE?= 0444
-RESOLVCONF= resolvconf resolvconf.8 resolvconf.conf.5
-SUBSCRIBERS= libc dnsmasq named pdnsd pdns_recursor unbound
-TARGET= ${RESOLVCONF} ${SUBSCRIBERS}
+RESOLVCONF= resolvconf resolvconf.8 resolvconf.conf.5
+SUBSCRIBERS= libc dnsmasq named pdnsd pdns_recursor unbound
+SUBSCRIBERS+= systemd-resolved resolvectl
+LIBC_SUBSCRIBERS= avahi-daemon mdnsd
+TARGET= ${RESOLVCONF} ${SUBSCRIBERS} ${LIBC_SUBSCRIBERS}
SRCS= ${TARGET:C,$,.in,} # pmake
SRCS:= ${TARGET:=.in} # gmake
@@ -36,12 +41,12 @@
SED_STATUSARG= -e 's:@STATUSARG@:${STATUSARG}:g'
DISTPREFIX?= ${PKG}-${VERSION}
-DISTFILEGZ?= ${DISTPREFIX}.tar.gz
DISTFILE?= ${DISTPREFIX}.tar.xz
DISTINFO= ${DISTFILE}.distinfo
-DISTINFOSIGN= ${DISTINFO}.asc
-CKSUM?= cksum -a SHA256
-PGP?= netpgp
+DISTINFOMD= ${DISTINFO}.md
+DISTSIGN= ${DISTFILE}.asc
+SHA256?= sha256
+PGP?= gpg2
GITREF?= HEAD
@@ -59,7 +64,7 @@
rm -f ${TARGET}
distclean: clean
- rm -f config.mk ${DISTFILE} ${DISTINFO} ${DISTINFOSIGN}
+ rm -f config.mk ${DISTFILE} ${DISTINFO} ${DISTINFOMD} ${DISTSIGN}
installdirs:
@@ -71,6 +76,9 @@
${INSTALL} -m ${DOCMODE} resolvconf.conf ${DESTDIR}${SYSCONFDIR}
${INSTALL} -d ${DESTDIR}${LIBEXECDIR}
${INSTALL} -m ${DOCMODE} ${SUBSCRIBERS} ${DESTDIR}${LIBEXECDIR}
+ ${INSTALL} -d ${DESTDIR}${LIBEXECDIR}/libc.d
+ ${INSTALL} -m ${DOCMODE} ${LIBC_SUBSCRIBERS} \
+ ${DESTDIR}${LIBEXECDIR}/libc.d
maninstall:
${INSTALL} -d ${DESTDIR}${MANDIR}/man8
@@ -87,18 +95,30 @@
mkdir /tmp/${DISTPREFIX}
cp -RPp * /tmp/${DISTPREFIX}
(cd /tmp/${DISTPREFIX}; make clean)
- tar -cvjpf ${DISTFILE} -C /tmp ${DISTPREFIX}
+ tar -cvJpf ${DISTFILE} -C /tmp ${DISTPREFIX}
rm -rf /tmp/${DISTPREFIX}
-dist: dist-git
+dist: ${DIST}
distinfo: dist
- rm -f ${DISTINFO} ${DISTINFOSIGN}
- ${CKSUM} ${DISTFILE} >${DISTINFO}
- #printf "SIZE (${DISTFILE}) = %s\n" $$(wc -c <${DISTFILE}) >>${DISTINFO}
- ${PGP} --clearsign --output=${DISTINFOSIGN} ${DISTINFO}
- chmod 644 ${DISTINFOSIGN}
- ls -l ${DISTFILE} ${DISTINFO} ${DISTINFOSIGN}
+ rm -f ${DISTINFO} ${DISTSIGN}
+ ${SHA256} ${DISTFILE} >${DISTINFO}
+ wc -c <${DISTFILE} \
+ | xargs printf 'Size (${DISTFILE}) = %s\n' >>${DISTINFO}
+ ${PGP} --sign --armour --detach ${DISTFILE}
+ chmod 644 ${DISTSIGN}
+ ls -l ${DISTFILE} ${DISTINFO} ${DISTSIGN}
+
+${DISTINFOMD}: ${DISTINFO}
+ echo '```' >${DISTINFOMD}
+ cat ${DISTINFO} >>${DISTINFOMD}
+ echo '```' >>${DISTINFOMD}
+
+release: distinfo ${DISTINFOMD}
+ gh release create v${VERSION} \
+ --title "openresolv ${VERSION}" --draft --generate-notes \
+ --notes-file ${DISTINFOMD} \
+ ${DISTFILE} ${DISTSIGN}
import: dist
rm -rf /tmp/${DISTPREFIX}
@@ -115,4 +135,4 @@
@${ECHO} "openresolv-${VERSION} imported to ${DESTDIR}"
import-src:
- ${MAKE} _import-src DESTDIR=`if [ -n "${DESTDIR}" ]; then echo "${DESTDIR}"; else echo /tmp/${DISTPREFIX}; fi`
+ ${MAKE} _import-src DESTDIR=`if [ -n "${DESTDIR}" ]; then echo "${DESTDIR}"; else echo /tmp/${DISTPREFIX}; fi`
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@
The last point is quite important, especially when running VPN systems.
Take the following resolv.conf files which have been generated by a
-[DHCP client](../dhcpcd) and sent to resolvconf:
+[DHCP client](https://github.com/NetworkConfiguration/dhcpcd) and sent to resolvconf:
```
# resolv.conf from bge0
@@ -58,7 +58,12 @@
* [dnsmasq](http://www.thekelleys.org.uk/dnsmasq/doc.html)
* [ISC BIND](http://www.isc.org/software/bind)
* [PowerDNS Recursor](http://wiki.powerdns.com/trac)
+ * [systemd-resolved](https://www.freedesktop.org/software/systemd/man/latest/systemd-resolved.service.html)
See the
-[configuration section](https://roy.marples.name/projects/openresolv/config)
+[configuration section](https://roy.marples.name/projects/openresolv/configuration)
for more details.
+
+If openresolv updates `/etc/resolv.conf` it can notify the following of this:
+ * [Bonjour (mdnsd)](https://developer.apple.com/bonjour/)
+ * [avahi](http://www.avahi.org/)
diff --git a/pdns_recursor.in b/avahi-daemon.in
copy from pdns_recursor.in
copy to avahi-daemon.in
--- a/pdns_recursor.in
+++ b/avahi-daemon.in
@@ -1,8 +1,8 @@
#!/bin/sh
-# Copyright (c) 2009-2019 Roy Marples
+# Copyright (c) 2007-2023 Roy Marples
# All rights reserved
-# PowerDNS Recursor subscriber for resolvconf
+# avahi-daemon notifier for resolvconf libc subscriber
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -26,50 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-[ -f "@SYSCONFDIR@"/resolvconf.conf ] || exit 0
-. "@SYSCONFDIR@/resolvconf.conf" || exit 1
-[ -z "$pdns_zones" ] && exit 0
-[ -z "$RESOLVCONF" ] && eval "$(@SBINDIR@/resolvconf -v)"
-NL="
-"
-
-: ${pdns_service:=pdns-recursor}
-
-newzones=
-
-for n in $NAMESERVERS; do
- newzones="$newzones${newzones:+,}$n"
-done
-[ -n "$newzones" ] && newzones="+.=$newzones$NL"
-
-for d in $DOMAINS; do
- newns=
- ns="${d#*:}"
- while [ -n "$ns" ]; do
- newns="$newns${newns:+,}${ns%%,*}"
- [ "$ns" = "${ns#*,}" ] && break
- ns="${ns#*,}"
- done
- [ -n "$newns" ] && newzones="$newzones${d%%:*}=$newns$NL"
-done
-
-# Try to ensure that config dirs exist
-if type config_mkdirs >/dev/null 2>&1; then
- config_mkdirs "$pdnsd_zones"
-else
- @SBINDIR@/resolvconf -D "$pdnsd_zones"
-fi
-
-if [ ! -f "$pdns_zones" ] || \
- [ "$(cat "$pdns_zones")" != "$(printf %s "$newzones")" ]
-then
- printf %s "$newzones" >"$pdns_zones"
- if [ -n "$pdns_restart" ]; then
- eval $pdns_restart
- elif [ -n "$RESTARTCMD" ]; then
- set -- ${pdns_service}
- eval "$RESTARTCMD"
- else
- @SBINDIR@/resolvconf -r ${pdns_service}
- fi
+: ${avahi_daemon_pidfile:=/var/run/avahi-daemon/pid}
+if [ -s "$avahi_daemon_pidfile" ]; then
+ kill -HUP $(cat "$avahi_daemon_pidfile")
fi
diff --git a/configure b/configure
old mode 100644
new mode 100755
--- a/configure
+++ b/configure
@@ -39,7 +39,7 @@
--includedir) eval INCLUDEDIR="$INCLUDEDIR${INCLUDEDIR:+ }$var";;
--datadir|--infodir) ;; # ignore autotools
--disable-maintainer-mode|--disable-dependency-tracking) ;;
- --help) echo "See the README file for available options"; exit 0;;
+ --help) echo "See the source for available options"; exit 0;;
*) echo "$0: WARNING: unknown option $opt" >&2;;
esac
done
@@ -92,7 +92,7 @@
: ${LIBEXECDIR:=${PREFIX:-/usr}/libexec/resolvconf}
;;
linux*)
- # cksum does't support -a and netpgp is rare
+ # cksum doesn't support -a and netpgp is rare
echo "CKSUM= sha256sum --tag" >>$CONFIG_MK
echo "PGP= gpg2" >>$CONFIG_MK
;;
diff --git a/dnsmasq.in b/dnsmasq.in
--- a/dnsmasq.in
+++ b/dnsmasq.in
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (c) 2007-2019 Roy Marples
+# Copyright (c) 2007-2023 Roy Marples
# All rights reserved
# dnsmasq subscriber for resolvconf
@@ -105,7 +105,7 @@
empty=true
continue
fi
- i=$(($i + 1))
+ i=$((i + 1))
while [ ${#addr} -lt 4 ]; do
addr="0${addr}"
done
@@ -118,7 +118,7 @@
fi
done
while [ $i != 8 ]; do
- i=$(($i + 1))
+ i=$((i + 1))
front="$front byte:0 byte:0"
done
front="${front}$back"
@@ -151,7 +151,7 @@
fi
# Try to ensure that config dirs exist
-if type config_mkdirs >/dev/null 2>&1; then
+if command -v config_mkdirs >/dev/null 2>&1; then
config_mkdirs "$dnsmasq_conf" "$dnsmasq_resolv"
else
@SBINDIR@/resolvconf -D "$dnsmasq_conf" "$dnsmasq_resolv"
diff --git a/libc.in b/libc.in
--- a/libc.in
+++ b/libc.in
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (c) 2007-2019 Roy Marples
+# Copyright (c) 2007-2025 Roy Marples
# All rights reserved
# libc subscriber for resolvconf
@@ -29,10 +29,23 @@
SYSCONFDIR=@SYSCONFDIR@
LIBEXECDIR=@LIBEXECDIR@
VARDIR=@VARDIR@
-IFACEDIR="$VARDIR/interfaces"
+KEYDIR="$VARDIR/keys"
+# Compat
+if [ ! -d "$KEYDIR" ] && [ -d "$VARDIR/interfaces" ]; then
+ KEYDIR="$VARDIR/interfaces"
+fi
+
+CMD="$1"
+KEY="$2"
+
NL="
"
+warn()
+{
+ echo "${0##*/}: $*" >&2
+}
+
# sed may not be available, and this is faster on small files
key_get_value()
{
@@ -94,8 +107,12 @@
fi
fi
: ${resolv_conf:=/etc/resolv.conf}
+if [ "$resolv_conf" = "/dev/null" ]; then
+ exit 0
+fi
+: ${resolv_conf_tmp:="$resolv_conf.$$.openresolv"}
: ${libc_service:=nscd}
-: ${list_resolv:=@SBINDIR@/resolvconf -l}
+: ${list_resolv:=@SBINDIR@/resolvconf -L}
if [ "${resolv_conf_head-x}" = x ] && [ -f "$SYSCONFDIR"/resolv.conf.head ]
then
resolv_conf_head="$(cat "${SYSCONFDIR}"/resolv.conf.head)"
@@ -105,9 +122,8 @@
resolv_conf_tail="$(cat "$SYSCONFDIR"/resolv.conf.tail)"
fi
-backup=true
signature="# Generated by resolvconf"
-
+
uniqify()
{
result=
@@ -123,15 +139,14 @@
case "${resolv_conf_passthrough:-NO}" in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
- backup=false
newest=
- for conf in "$IFACEDIR"/*; do
+ for conf in "$KEYDIR"/*; do
if [ -z "$newest" ] || [ "$conf" -nt "$newest" ]; then
newest="$conf"
fi
done
[ -z "$newest" ] && exit 0
- newconf="$(cat "$newest")$NL"
+ newconf="$signature$NL$(cat "$newest")$NL"
;;
/dev/null|[Nn][Uu][Ll][Ll])
: ${resolv_conf_local_only:=NO}
@@ -207,27 +222,44 @@
# Check if the file has actually changed or not
if [ -e "$resolv_conf" ]; then
- [ "$(cat "$resolv_conf")" = "$(printf %s "$newconf")" ] && exit 0
-fi
-
-# Change is good.
-# If the old file does not have our signature, back it up.
-# If the new file just has our signature, restore the backup.
-if $backup; then
- if [ "$newconf" = "$signature$NL" ]; then
- if [ -e "$resolv_conf.bak" ]; then
- newconf="$(cat "$resolv_conf.bak")$NL"
- fi
- elif [ -e "$resolv_conf" ]; then
- read line <"$resolv_conf"
- if [ "$line" != "$signature" ]; then
- cp "$resolv_conf" "$resolv_conf.bak"
+ if [ "$CMD" != u ] && \
+ [ "$(cat "$resolv_conf")" = "$(printf %s "$newconf")" ]
+ then
+ exit 0
+ fi
+ read line <"$resolv_conf"
+ if [ "$line" != "$signature" ]; then
+ if [ "$CMD" != u ]; then
+ warn "signature mismatch: $resolv_conf"
+ warn "run \`resolvconf -u\` to update"
+ exit 1
fi
+ cp "$resolv_conf" "$resolv_conf.bak"
fi
fi
-# Create our resolv.conf now
-(umask 022; printf %s "$newconf" >"$resolv_conf")
+# There are pros and cons for writing directly to resolv.conf
+# instead of a temporary file and then moving it over.
+# The default is to write to resolv.conf as it has the least
+# issues and has been the long standing default behaviour.
+# resolv.conf could also be bind mounted for network namespaces
+# so we cannot move in this instance.
+case "${resolv_conf_mv:-NO}" in
+[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
+ # Protect against symlink attack, ensure new file does not exist
+ rm -f "$resolv_conf_tmp"
+ # Keep original file owner, group and mode
+ [ -r "$resolv_conf" ] && cp -p "$resolv_conf" "$resolv_conf_tmp"
+ # Create our resolv.conf now
+ if (umask 022; printf %s "$newconf" >"$resolv_conf_tmp"); then
+ mv "$resolv_conf_tmp" "$resolv_conf"
+ fi
+ ;;
+*)
+ (umask 022; printf %s "$newconf" >"$resolv_conf")
+ ;;
+esac
+
if [ -n "$libc_restart" ]; then
eval $libc_restart
elif [ -n "$RESTARTCMD" ]; then
diff --git a/pdns_recursor.in b/mdnsd.in
copy from pdns_recursor.in
copy to mdnsd.in
--- a/pdns_recursor.in
+++ b/mdnsd.in
@@ -1,8 +1,8 @@
#!/bin/sh
-# Copyright (c) 2009-2019 Roy Marples
+# Copyright (c) 2007-2023 Roy Marples
# All rights reserved
-# PowerDNS Recursor subscriber for resolvconf
+# mdnsd notifier for resolvconf libc subscriber
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -26,50 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-[ -f "@SYSCONFDIR@"/resolvconf.conf ] || exit 0
-. "@SYSCONFDIR@/resolvconf.conf" || exit 1
-[ -z "$pdns_zones" ] && exit 0
-[ -z "$RESOLVCONF" ] && eval "$(@SBINDIR@/resolvconf -v)"
-NL="
-"
-
-: ${pdns_service:=pdns-recursor}
-
-newzones=
-
-for n in $NAMESERVERS; do
- newzones="$newzones${newzones:+,}$n"
-done
-[ -n "$newzones" ] && newzones="+.=$newzones$NL"
-
-for d in $DOMAINS; do
- newns=
- ns="${d#*:}"
- while [ -n "$ns" ]; do
- newns="$newns${newns:+,}${ns%%,*}"
- [ "$ns" = "${ns#*,}" ] && break
- ns="${ns#*,}"
- done
- [ -n "$newns" ] && newzones="$newzones${d%%:*}=$newns$NL"
-done
-
-# Try to ensure that config dirs exist
-if type config_mkdirs >/dev/null 2>&1; then
- config_mkdirs "$pdnsd_zones"
-else
- @SBINDIR@/resolvconf -D "$pdnsd_zones"
-fi
-
-if [ ! -f "$pdns_zones" ] || \
- [ "$(cat "$pdns_zones")" != "$(printf %s "$newzones")" ]
-then
- printf %s "$newzones" >"$pdns_zones"
- if [ -n "$pdns_restart" ]; then
- eval $pdns_restart
- elif [ -n "$RESTARTCMD" ]; then
- set -- ${pdns_service}
- eval "$RESTARTCMD"
- else
- @SBINDIR@/resolvconf -r ${pdns_service}
- fi
+: ${mdnsd_pidfile:=/var/run/mdnsd/mdnsd.pid}
+if [ -s "$mdnsd_pidfile" ]; then
+ kill -HUP $(cat "$mdnsd_pidfile")
fi
diff --git a/named.in b/named.in
--- a/named.in
+++ b/named.in
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (c) 2007-2016 Roy Marples
+# Copyright (c) 2007-2023 Roy Marples
# All rights reserved
# named subscriber for resolvconf
@@ -79,7 +79,7 @@
done
# Try to ensure that config dirs exist
-if type config_mkdirs >/dev/null 2>&1; then
+if command -v config_mkdirs >/dev/null 2>&1; then
config_mkdirs "$named_options" "$named_zones"
else
@SBINDIR@/resolvconf -D "$named_options" "$named_zones"
diff --git a/pdns_recursor.in b/pdns_recursor.in
--- a/pdns_recursor.in
+++ b/pdns_recursor.in
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (c) 2009-2019 Roy Marples
+# Copyright (c) 2009-2023 Roy Marples
# All rights reserved
# PowerDNS Recursor subscriber for resolvconf
@@ -54,7 +54,7 @@
done
# Try to ensure that config dirs exist
-if type config_mkdirs >/dev/null 2>&1; then
+if command -v config_mkdirs >/dev/null 2>&1; then
config_mkdirs "$pdnsd_zones"
else
@SBINDIR@/resolvconf -D "$pdnsd_zones"
diff --git a/pdnsd.in b/pdnsd.in
--- a/pdnsd.in
+++ b/pdnsd.in
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (c) 2010-2018 Roy Marples
+# Copyright (c) 2010-2023 Roy Marples
# All rights reserved
# pdnsd subscriber for resolvconf
@@ -46,7 +46,7 @@
in_marker=0
shift; shift
- if type sed >/dev/null 2>&1; then
+ if command -v sed >/dev/null 2>&1; then
sed "/^$m1/,/^$m2/d" $@
else
for x do
@@ -66,9 +66,9 @@
change_file()
{
if [ -e "$1" ]; then
- if type cmp >/dev/null 2>&1; then
+ if command -v cmp >/dev/null 2>&1; then
cmp -s "$1" "$2"
- elif type diff >/dev/null 2>&1; then
+ elif command -v diff >/dev/null 2>&1; then
diff -q "$1" "$2" >/dev/null
else
# Hopefully we're only working on small text files ...
@@ -88,7 +88,7 @@
changed=false
# Try to ensure that config dirs exist
-if type config_mkdirs >/dev/null 2>&1; then
+if command -v config_mkdirs >/dev/null 2>&1; then
config_mkdirs "$pdnsd_resolv" "$pdnsd_conf"
else
@SBINDIR@/resolvconf -D "$pdnsd_resolv" "$pdnsd_conf"
diff --git a/resolvconf.8.in b/resolvconf.8.in
--- a/resolvconf.8.in
+++ b/resolvconf.8.in
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2007-2016 Roy Marples
+.\" Copyright (c) 2007-2025 Roy Marples
.\" All rights reserved
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd November 29, 2016
+.Dd June 26, 2025
.Dt RESOLVCONF 8
.Os
.Sh NAME
@@ -35,14 +35,18 @@
.Op Fl m Ar metric
.Op Fl p
.Op Fl x
-.Fl a Ar interface Ns Op Ar .protocol
+.Fl a Ar key
.No < Ns Pa file
.Nm
+.Fl C Ar pattern
+.Nm
+.Fl c Ar pattern
+.Nm
.Op Fl f
-.Fl d Ar interface Ns Op Ar .protocol
+.Fl d Ar key
.Nm
.Op Fl x
-.Fl il Ar pattern
+.Fl iLlp Ar pattern
.Nm
.Fl u
.Nm
@@ -68,12 +72,20 @@
via
.Xr stdin 4
with the argument
-.Fl a Ar interface Ns Op Ar .protocol
+.Fl a Ar key
instead of the filesystem.
.Nm
then updates
.Pa /etc/resolv.conf
as it thinks best.
+If
+.Pa /etc/resolv.conf
+already exists and the top line does not match the expected signature,
+then
+.Nm
+will refuse to update it unless the
+.Fl u
+update command is given.
When a local resolver other than libc is installed, such as
.Xr dnsmasq 8
or
@@ -82,27 +94,40 @@
.Nm
will supply files that the resolver should be configured to include.
.Pp
+At it's heart,
.Nm
-assumes it has a job to do.
-In some situations
+is a key/value store for
+.Pa resolv.conf
+files.
+Each entry must have a unique
+.Ar key
+and should be expressed as
+.Sy interface.protocol
+so that it's easy to tell from where the
+.Pa resolv.conf
+file came from.
+This also allows using pattern matching such as
+.Sy interface.*
+to match all protocols running on the interface.
+For example, a modern system will likely run DHCP, RA and DHCPv6
+which could be from separate programs or one program running
+many protocols.
+However, this is not a fixed requirement,
.Nm
-needs to act as a deterrent to writing to
-.Pa /etc/resolv.conf .
-Where this file cannot be made immutable or you just need to toggle this
-behaviour,
-.Nm
-can be disabled by adding
-.Sy resolvconf Ns = Ns NO
-to
-.Xr resolvconf.conf 5 .
+will work with any key name and it should be treated as an opaque value
+outside of
+.Nm .
.Pp
.Nm
-can mark an interfaces
+can mark a
.Pa resolv.conf
-as private.
+as private and optionally non-searchable.
This means that the name servers listed in that
.Pa resolv.conf
-are only used for queries against the domain/search listed in the same file.
+are only used for queries against the domain/search listed in the same file
+and if non-searchable then the domain/search listed are
+excluded from the global search list defined in
+.Pa /etc/resolv.conf .
This only works when a local resolver other than libc is installed.
See
.Xr resolvconf.conf 5
@@ -111,57 +136,97 @@
to use a local name server and how to remove the private marking.
.Pp
.Nm
-can mark an interfaces
+can mark a
.Pa resolv.conf
as exclusive.
-Only the latest exclusive interface is used for processing, otherwise all are.
+Only the latest exclusive key is used for processing, otherwise all are.
.Pp
-When an interface goes down, it should then call
+When a configuration source goes away,
+such as an interface going down or a VPN stopping,
+it should then call
.Nm
with
-.Fl d Ar interface.*
-arguments to delete the
+.Fl d Ar key
+arguments to clean up the
.Pa resolv.conf
-file(s) for all the
-.Ar protocols
-on the
-.Ar interface .
+it added previously.
+For systems that support the concept of persisting configuration when
+the source is suspended,
+such as the carrier going down,
+then it should instead call
+.Nm
+with
+.Fl C Ar key
+arguments to deprecate the entry
+.Fl c Ar key
+to activate the entry when it comes back again.
+This only affects the order in which the
+.Pa resolv.conf
+entries are processed.
.Pp
-Here are some options for the above commands:-
+Here are some options for the above commands:
.Bl -tag -width pattern_opt
.It Fl f
-Ignore non existent interfaces.
-Only really useful for deleting interfaces.
+Ignore non existent
+.Pa resolv.conf
+entries.
+Only really useful for deleting.
.It Fl m Ar metric
-Set the metric of the interface when adding it, default of 0.
+Set the metric of the
+.Pa resolv.conf
+entry when adding it, default of 0.
Lower metrics take precedence.
-This affects the default order of interfaces when listed.
-.It Fl p
-Marks the interface
+This affects the default order of entires when listed.
+.It Fl p Op Ar pattern
+Marks the
.Pa resolv.conf
-as private.
+as private if the
+.Fl a
+command is given, otherwise
+.Pa resolv.conf
+entries having their key matching
+.Ar pattern
+are listed.
+If an extra
+.Fl p
+is given then the
+.Pa resolv.conf
+is marked as non-searchable as well.
.It Fl x
-Mark the interface
+Mark the
.Pa resolv.conf
-as exclusive when adding, otherwise only use the latest exclusive interface.
+as exclusive when adding, otherwise only use the latest exclusive key.
.El
.Pp
.Nm
-has some more commands for general usage:-
+has some more commands for general usage:
.Bl -tag -width pattern_opt
-.It Fl i Ar pattern
-List the interfaces and protocols, optionally matching
+.It Fl i Op Ar pattern
+List the keys stored, optionally matching
.Ar pattern ,
we have
.Pa resolv.conf
files for.
-.It Fl l Ar pattern
+If the
+.Fl L
+option is given first, then the keys will be list post-processed.
+.It Fl L Op Ar pattern
+List the
+.Pa resolv.conf
+files we have,
+post-processed by the
+.Xr resolvconf.conf 5
+configuration.
+If
+.Ar pattern
+is specified then we list the files for the keys which match it.
+.It Fl l Op Ar pattern
List the
.Pa resolv.conf
files we have.
If
.Ar pattern
-is specified then we list the files for the interfaces and protocols
+is specified then we list the files for the keys which match it.
that match it.
.It Fl u
Force
@@ -169,27 +234,23 @@
to update all its subscribers.
.Nm
does not update the subscribers when adding a resolv.conf that matches
-what it already has for that interface.
+what it already has for that key.
.It Fl Fl version
Echo the resolvconf version to
.Em stdout .
.El
.Pp
.Nm
-also has some commands designed to be used by it's subscribers and
-system startup:-
+also has some commands designed to be used by its subscribers and
+system startup:
.Bl -tag -width pattern_opt
.It Fl I
Initialise the state directory
.Pa @VARDIR@ .
-This only needs to be called if the initial system boot sequence does not
-automatically clean it out; for example the state directory is moved
-somewhere other than
-.Pa /var/run .
-If used, it should only be called once as early in the system boot sequence
-as possible and before
-.Nm
-is used to add interfaces.
+This should be called after the base state directory has either been
+cleaned out or mounted as a memory backed filesystem during the
+initial boot sequence before any daemon has the chance to call
+.Nm .
.It Fl R
Echo the command used to restart a service.
.It Fl r Ar service
@@ -208,17 +269,18 @@
.Xr resolvconf.conf 5
is set.
.El
-.Sh INTERFACE ORDERING
+.Sh RESOLV.CONF ORDERING
For
.Nm
-to work effectively, it has to process the resolv.confs for the interfaces
-in the correct order.
+to work effectively, it has to process the
+.Pa resolv.conf
+entries in the correct order.
.Nm
-first processes interfaces from the
-.Sy interface_order
-list, then interfaces without a metic and that match the
+first processes keys from the
+.Sy key_order
+list, then entries without a metric and that match the
.Sy dynamic_order
-list, then interfaces with a metric in order and finally the rest in
+list, then entries with a metric in order and finally the rest in
the operating systems lexical order.
See
.Xr resolvconf.conf 5
@@ -226,19 +288,9 @@
.Sh PROTOCOLS
Here are some suggested protocol tags to use for each
.Pa resolv.conf
-file registered on an
-.Ar interface Ns No :-
.Bl -tag -width pattern_opt
.It dhcp
Dynamic Host Configuration Protocol.
-Initial versions of
-.Nm
-did not recommend a
-.Ar protocol
-tag be appended to the
-.Ar interface
-name.
-When the protocol is absent, it is assumed to be the DHCP protocol.
.It ppp
Point-to-Point Protocol.
.It ra
@@ -270,11 +322,15 @@
.Va IF_METRIC
for the metric.
.It Va IF_PRIVATE
-Marks the interface
+Marks the
.Pa resolv.conf
as private.
+.It Va IF_NOSEARCH
+Marks the
+.Pa resolv.conf
+as non-searchable.
.It Va IF_EXCLUSIVE
-Marks the interface
+Marks the
.Pa resolv.conf
as exclusive.
.El
@@ -295,6 +351,17 @@
State directory for
.Nm .
.El
+.Sh NOTES
+Domain labels are assumed to be in ASCII and are converted to lower case
+to avoid duplicate zones when given differing case from different sources.
+.Pp
+When running a local resolver other than libc, you will need to configure it
+to include files that
+.Nm
+will generate.
+You should consult
+.Xr resolvconf.conf 5
+for instructions on how to configure your resolver.
.Sh SEE ALSO
.Xr resolver 3 ,
.Xr stdin 4 ,
@@ -310,14 +377,3 @@
.Sh BUGS
Please report them to
.Lk http://roy.marples.name/projects/openresolv
-.Pp
-.Nm
-does not validate any of the files given to it.
-.Pp
-When running a local resolver other than libc, you will need to configure it
-to include files that
-.Nm
-will generate.
-You should consult
-.Xr resolvconf.conf 5
-for instructions on how to configure your resolver.
diff --git a/resolvconf.conf.5.in b/resolvconf.conf.5.in
--- a/resolvconf.conf.5.in
+++ b/resolvconf.conf.5.in
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2009-2016 Roy Marples
+.\" Copyright (c) 2009-2025 Roy Marples
.\" All rights reserved
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd September 8, 2019
+.Dd May 15, 2025
.Dt RESOLVCONF.CONF 5
.Os
.Sh NAME
@@ -61,26 +61,44 @@
.Nm resolvconf
from running any subscribers.
Defaults to YES.
-.It Sy interface_order
-These interfaces will always be processed first.
-If unset, defaults to the following:-
-.Bd -compact -literal -offset indent
+.It Sy allow_keys
+If set, only these keys will be processed.
+.It Sy deny_keys
+If set, these keys will not be processed.
+.It Sy exclude
+Is a space separated list of key/value pairs to match.
+If all key/value pairs in one element can be found in the file,
+then the whole file will be excluded from processing.
+The syntax is this:
+.Va $keyword Ns / Ns Va $match Ns Op / Ns Va $keyword Ns / Ns Va $match
+.Pp
+For example given this configuration:
+.Bd -literal -compact -offset indent
+exclude="search/foo*/nameserver/1.2.3.4 search/bar.org"
+.Ed
+.Pp
+Then any resolv.conf with both a search option starting with foo with a nameserver of 1.2.3.4
+OR a search option of bar.org would be excluded.
+.It Sy key_order
+These keys will always be processed first.
+If unset, defaults to the following:
+.Bd -literal -compact -offset indent
lo lo[0-9]*
.Ed
.It Sy dynamic_order
-These interfaces will be processed next, unless they have a metric.
-If unset, defaults to the following:-
-.Bd -compact -literal -offset indent
-tap[0-9]* tun[0-9]* vpn vpn[0-9]* ppp[0-9]* ippp[0-9]*
+These keys will be processed next, unless they have a metric.
+If unset, defaults to the following:
+.Bd -literal -compact -offset indent
+tap[0-9]* tun[0-9]* vpn vpn[0-9]* wg[0-9]* ppp[0-9]* ippp[0-9]*
.Ed
-.It Sy inclusive_interfaces
-Ignore any exclusive marking for these interfaces.
+.It Sy inclusive_keys
+Ignore any exclusive marking for these keys.
This is handy when 3rd party integrations force the
.Nm resolvconf -x
option and you want to disable it easily.
.It Sy local_nameservers
-If unset, defaults to the following:-
-.Bd -compact -literal -offset indent
+If unset, defaults to the following:
+.Bd -literal -compact -offset indent
127.* 0.0.0.0 255.255.255.255 ::1
.Ed
.It Sy search_domains
@@ -101,20 +119,25 @@
A list of name servers to be removed from consideration.
The default is 0.0.0.0 as some faulty routers send it via DHCP.
To remove a block, you can use 192.168.*
-.It Sy private_interfaces
-These interfaces name servers will only be queried for the domains listed
+.It Sy private_keys
+These keys name servers will only be queried for the domains listed
in their resolv.conf.
Useful for VPN domains.
Setting
-.Sy private_interfaces Ns ="*"
+.Sy private_keys Ns ="*"
will stop the forwarding of the root zone and allows the local resolver to
recursively query the root servers directly.
Requires a local nameserver other than libc.
This is equivalent to the
.Nm resolvconf -p
option.
-.It Sy public_interfaces
-Force these interface to be public, overriding the private marking.
+.It Sy nosearch_keys
+These keys domains/search won't be added to the global search list
+in
+.Pa /etc/resolv.conf .
+.It Sy public_keys
+Force these keys to be public, overriding the private and nosearch
+markings.
This is handy when 3rd party integrations force the
.Nm resolvconf -p
option and you want to disable it easily.
@@ -124,24 +147,27 @@
.Va $keyword Ns / Ns Va $match Ns / Ns Va $replacement
.Pp
Example, given this resolv.conf:
-.Bd -compact -literal -offset indent
+.Bd -literal -compact -offset indent
domain foo.org
search foo.org dead.beef
nameserver 1.2.3.4
nameserver 2.3.4.5
.Ed
-and this configuaration:
-.Bd -compact -literal -offset indent
+.Pp
+and this configuration:
+.Bd -literal -compact -offset indent
replace="search/foo*/bar.com"
replace="$replace nameserver/1.2.3.4/5.6.7.8"
replace="$replace nameserver/2.3.4.5/"
.Ed
+.Pp
you would get this resolv.conf instead:
-.Bd -compact -literal -offset indent
+.Bd -literal -compact -offset indent
domain foo.org
search bar.com
nameserver 5.6.7.8
.Ed
+.Pp
.It Sy replace_sub
Works the same way as
.Sy replace
@@ -152,11 +178,12 @@
to
.Sy replace_sub ,
you would get this resolv.conf instead:
-.Bd -compact -literal -offset indent
+.Bd -literal -compact -offset indent
domain foo.org
search bar.com dead.beef
nameserver 5.6.7.8
.Ed
+.Pp
.It Sy state_dir
Override the default state directory of
.Pa @VARDIR@ .
@@ -167,12 +194,17 @@
.Sh LIBC OPTIONS
The following variables affect
.Xr resolv.conf 5
-directly:-
+directly:
.Bl -tag -width indent
.It Sy resolv_conf
Defaults to
.Pa /etc/resolv.conf
if not set.
+Set to
+.Pa /dev/null
+to stop
+.Xr resolvconf 8
+from changing it.
.It Sy resolv_conf_options
A list of libc resolver options, as specified in
.Xr resolv.conf 5 .
@@ -188,6 +220,14 @@
.Nm
is written to
.Sy resolv_conf .
+.It Sy resolv_conf_restore
+When set to YES and
+and an empty
+.Pa resolv.conf
+would be written, restore
+.Pa resolv.conf.bak
+instead if it exists.
+Defaults to YES if not set.
.It Sy resolv_conf_sortlist
A libc resolver sortlist, as specified in
.Xr resolv.conf 5 .
@@ -206,21 +246,28 @@
Append search domains to the dynamically generated list.
.It Sy prepend_search
Prepend search domains to the dynamically generated list.
+.It Sy resolv_conf_mv
+Defaults to NO.
+Defines if
+.Pa /etc/resolv.conf
+is updated by writing to a temporary file and then moving it
+vs writing directly to it.
.El
.Sh SUBSCRIBER OPTIONS
openresolv ships with subscribers for the name servers
.Xr dnsmasq 8 ,
.Xr named 8 ,
.Xr pdnsd 8 ,
-.Xr pdns_recursor 8 ,
+.Xr pdns_recursor 1 ,
and
.Xr unbound 8 .
Each subscriber can create configuration files which should be included in
-in the subscribers main configuration file.
+the subscribers main configuration file.
.Pp
-To disable a subscriber, simply set it's name to NO.
+To disable a subscriber, simply set its name to NO.
+If the subscriber name has a dash in it, then replace it with an underscore.
For example, to disable the libc subscriber you would set:
-.Bd -compact -literal -offset indent
+.Bd -literal -compact -offset indent
libc=NO
.Ed
.Bl -tag -width indent
@@ -230,14 +277,14 @@
This file tells dnsmasq which name servers to use for global lookups.
.Pp
Example resolvconf.conf for dnsmasq:
-.Bd -compact -literal -offset indent
+.Bd -literal -compact -offset indent
name_servers=127.0.0.1
dnsmasq_conf=/etc/dnsmasq-conf.conf
dnsmasq_resolv=/etc/dnsmasq-resolv.conf
.Ed
.Pp
Example dnsmasq.conf:
-.Bd -compact -literal -offset indent
+.Bd -literal -compact -offset indent
listen-address=127.0.0.1
# If dnsmasq is compiled for DBus then we can take
# advantage of not having to restart dnsmasq.
@@ -253,14 +300,14 @@
This file tells named which name servers to use for specific domains.
.Pp
Example resolvconf.conf for named:
-.Bd -compact -literal -offset indent
+.Bd -literal -compact -offset indent
name_servers=127.0.0.1
named_options=/etc/named-options.conf
named_zones=/etc/named-zones.conf
.Ed
.Pp
Example named.conf:
-.Bd -compact -literal -offset indent
+.Bd -literal -compact -offset indent
options {
listen-on { 127.0.0.1; };
include "/etc/named-options.conf";
@@ -281,14 +328,14 @@
.Pa pdnsd_conf .
.Pp
Example resolvconf.conf for pdnsd:
-.Bd -compact -literal -offset indent
+.Bd -literal -compact -offset indent
name_servers=127.0.0.1
pdnsd_conf=/etc/pdnsd.conf
# pdnsd_resolv=/etc/pdnsd-resolv.conf
.Ed
.Pp
Example pdnsd.conf:
-.Bd -compact -literal -offset indent
+.Bd -literal -compact -offset indent
global {
server_ip = 127.0.0.1;
status_ctl = on;
@@ -304,29 +351,76 @@
This file tells pdns_recursor about specific and global name servers.
.Pp
Example resolvconf.conf for pdns_recursor:
-.Bd -compact -literal -offset indent
+.Bd -literal -compact -offset indent
name_servers=127.0.0.1
pdns_zones=/etc/pdns/recursor-zones.conf
.Ed
.Pp
Example recursor.conf:
-.Bd -compact -literal -offset indent
+.Bd -literal -compact -offset indent
allow-from=127.0.0.0/8, ::1/128
forward-zones-file=/etc/pdns/recursor-zones.conf
.Ed
+.It Sy resolvectl
+When set to YES,
+.Xr resolvectl 1
+will be used to write per interface entries from
+.Xr resolvconf 8
+to
+.Xr systemd-resolved 8 .
+A warning is emitted for any entry that cannot be matched to an
+interface.
+.Pp
+This subscriber should only be used if your systemd-resolved does
+not support DNS delegates and you need private or non searchable
+.Xr resolvconf 8
+entries, or you're really beholden to seeing DNS setup per interface via
+.Xr resolvectl 1 .
+The systemd-resolved subscriber documented below is the better option.
+.Pp
+Example resolvconf.conf for resolvectl:
+.Bd -literal -compact -offset indent
+# Keep /etc/resolv.conf as systemd-resolved wants it
+libc=NO
+resolvectl=YES
+.Ed
+.It Sy systemd_resolved
+When set to YES, global DNS will be written to the
+.Sy systemd_resolved_conf
+configuration file and DNS delegates will be written to the
+.Sy systemd_delegate_dir
+directory.
+.It Sy systemd_resolved_conf
+Defaults to
+.Pa /run/systemd/resolved.conf.d/60-resolvconf.conf .
+.It Sy systemd_delegate_dir
+Defaults to
+.Pa /run/systemd/dns-delegate.d .
+.Pp
+Example resolvconf.conf for systemd-resolved:
+.Bd -literal -compact -offset indent
+# Keep /etc/resolv.conf as systemd-resolved wants it
+libc=NO
+systemd_resolved=YES
+.Ed
.It Sy unbound_conf
This file tells unbound about specific and global name servers.
.It Sy unbound_insecure
When set to YES, unbound marks the domains as insecure, thus ignoring DNSSEC.
+.It Sy unbound_private
+When set to YES, unbound marks the domains as private, allowing it and its subdomains to contain private addresses.
+.It Sy unbound_forward_zone_options
+Options appended to each forward zone.
+Each option should be separated by an embedded new line.
.Pp
Example resolvconf.conf for unbound:
-.Bd -compact -literal -offset indent
+.Bd -literal -compact -offset indent
name_servers=127.0.0.1
unbound_conf=/etc/unbound-resolvconf.conf
.Ed
.Pp
Example unbound.conf:
-.Bd -compact -literal -offset indent
+.Bd -literal -compact -offset indent
include: /etc/unbound-resolvconf.conf
.Ed
.El
@@ -380,5 +474,13 @@
Each distribution is a special snowflake and likes to name the same thing
differently, namely the named service script.
.Pp
+Swapping between resolvectl and systemd-resolved subscribers at runtime
+is not supported.
+Files referenced by systemd_resolved_conf and systemd_delegate_dir
+need to be removed by hand.
+A reboot is recommended so that stale data is removed.
+While you could run them both at the same time, only using one is the
+recommended approach.
+.Pp
Please report them to
-.Lk http://roy.marples.name/projects/openresolv
+.Lk https://roy.marples.name/projects/openresolv
diff --git a/resolvconf.in b/resolvconf.in
--- a/resolvconf.in
+++ b/resolvconf.in
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (c) 2007-2019 Roy Marples
+# Copyright (c) 2007-2025 Roy Marples
# All rights reserved
# Redistribution and use in source and binary forms, with or without
@@ -25,7 +25,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
RESOLVCONF="$0"
-OPENRESOLV_VERSION="3.9.2"
+OPENRESOLV_VERSION="3.17.4"
SYSCONFDIR=@SYSCONFDIR@
LIBEXECDIR=@LIBEXECDIR@
VARDIR=@VARDIR@
@@ -34,7 +34,7 @@
if [ "$1" = "--version" ]; then
echo "openresolv $OPENRESOLV_VERSION"
- echo "Copyright (c) 2007-2016 Roy Marples"
+ echo "Copyright (c) 2007-2025 Roy Marples"
exit 0
fi
@@ -44,10 +44,31 @@
# If you change this, change the test in VFLAG and libc.in as well
local_nameservers="127.* 0.0.0.0 255.255.255.255 ::1"
-dynamic_order="tap[0-9]* tun[0-9]* vpn vpn[0-9]* ppp[0-9]* ippp[0-9]*"
+dynamic_order="tap[0-9]* tun[0-9]* vpn vpn[0-9]* wg[0-9]* ppp[0-9]* ippp[0-9]*"
interface_order="lo lo[0-9]*"
name_server_blacklist="0.0.0.0"
+# Poor mans cat
+# /usr might not be available
+cat()
+{
+ OIFS="$IFS"
+ IFS=''
+ if [ -n "$1" ]; then
+ while read -r line; do
+ printf "%s\n" "$line"
+ done < "$1"
+ else
+ while read -r line; do
+ printf "%s\n" "$line"
+ done
+ fi
+ retval=$?
+ IFS="$OIFS"
+ return $retval
+}
+
+
# Support original resolvconf configuration layout
# as well as the openresolv config file
if [ -f "$SYSCONFDIR"/resolvconf.conf ]; then
@@ -59,21 +80,36 @@
interface_order="$(cat "$SYSCONFDIR"/interface-order)"
fi
fi
-IFACEDIR="$VARDIR/interfaces"
+
+KEYDIR="$VARDIR/keys"
METRICDIR="$VARDIR/metrics"
PRIVATEDIR="$VARDIR/private"
+NOSEARCHDIR="$VARDIR/nosearch"
EXCLUSIVEDIR="$VARDIR/exclusive"
+DEPRECATEDDIR="$VARDIR/deprecated"
LOCKDIR="$VARDIR/lock"
_PWD="$PWD"
+# Compat
+if [ ! -d "$KEYDIR" ] && [ -d "$VARDIR/interfaces" ]; then
+ KEYDIR="$VARDIR/interfaces"
+fi
+: ${allow_keys:="$allow_interfaces"}
+: ${deny_keys:="$deny_interfaces"}
+: ${key_order:="$interface_order"}
+: ${inclusive_keys:="$inclusive_interfaces"}
+: ${exclusive_keys:="$exclusive_interfaces"}
+: ${private_keys:="$private_interfaces"}
+: ${public_keys:="$public_interfaces"}
+
warn()
{
- echo "$*" >&2
+ echo "${RESOLVCONF##*/}: $*" >&2
}
error_exit()
{
- echo "$*" >&2
+ warn "$*"
exit 1
}
@@ -85,24 +121,27 @@
Inform the system about any DNS updates.
Commands:
- -a \$INTERFACE Add DNS information to the specified interface
+ -a \$KEY Add DNS information to the specified key
(DNS supplied via stdin in resolv.conf format)
- -d \$INTERFACE Delete DNS information from the specified interface
+ -C \$PATTERN Deprecate DNS information for matched key
+ -c \$PATTERN Configure DNS information for matched key
+ -d \$PATTERN Delete DNS information from the matched key
-h Show this help cruft
- -i [\$PATTERN] Show interfaces that have supplied DNS information
- optionally from interfaces that match the specified
+ -i [\$PATTERN] Show keys that have supplied DNS information
+ optionally from keys that match the specified
pattern
- -l [\$PATTERN] Show DNS information, optionally from interfaces
+ -l [\$PATTERN] Show DNS information, optionally from keys
that match the specified pattern
+ -L [\$PATTERN] Same as -l, but adjusted by our config
-u Run updates from our current DNS information
--version Echo the ${RESOLVCONF##*/} version
Options:
- -f Ignore non existent interfaces
+ -f Ignore non existent keys
-m metric Give the added DNS information a metric
- -p Mark the interface as private
- -x Mark the interface as exclusive
+ -p Mark the resolv.conf as private
+ -x Mark the resolv.conf as exclusive
Subscriber and System Init Commands:
-I Init the state dir
@@ -117,56 +156,111 @@
EOF
[ -z "$1" ] && exit 0
echo
- error_exit "$*"
+ error_exit "$@"
}
-# Strip any trailing dot from each name as a FQDN does not belong
-# in resolv.conf(5)
-# If you think otherwise, capture a DNS trace and you'll see libc
-# will strip it regardless.
-# This also solves setting up duplicate zones in our subscribers.
-# Also strip any comments denoted by #.
-resolv_strip()
-{
- space=
- for word; do
- case "$word" in
- \#*) break;;
- esac
- printf "%s%s" "$space${word%.}"
- space=" "
- done
- printf "\n"
-}
+public_key() {
+ key="$1"
-private_iface()
-{
# Allow expansion
- cd "$IFACEDIR"
+ cd "$KEYDIR"
- # Public interfaces override private ones.
- for p in $public_interfaces; do
- case "$iface" in
- "$p"|"$p":*) return 1;;
- esac
- done
-
- if [ -e "$PRIVATEDIR/$iface" ]; then
- return 0
- fi
-
- for p in $private_interfaces; do
- case "$iface" in
+ # Public keys override private ones.
+ for p in $public_keys; do
+ case "$key" in
"$p"|"$p":*) return 0;;
esac
done
- # Not a private interface
return 1
}
+private_key()
+{
+ key="$1"
+
+ if public_key "$key"; then
+ return 1
+ fi
+
+ if [ -e "$PRIVATEDIR/$key" ]; then
+ return 0
+ fi
+
+ for p in $private_keys; do
+ case "$key" in
+ "$p"|"$p":*) return 0;;
+ esac
+ done
+
+ # Not a private key
+ return 1
+}
+
+nosearch_key()
+{
+ key="$1"
+
+ if public_key "$key"; then
+ return 1
+ fi
+
+ if [ -e "$NOSEARCHDIR/$key" ]; then
+ return 0
+ fi
+
+ for p in $nosearch_keys; do
+ case "$key" in
+ "$p"|"$p":*) return 0;;
+ esac
+ done
+
+ # Not a non searchable key
+ return 1
+}
+
+exclusive_key()
+{
+ key="$1"
+
+ for x in "$EXCLUSIVEDIR/"*" $key"; do
+ if [ -f "$x" ]; then
+ return 0
+ fi
+ done
+
+ # Not an exclusive key
+ return 1
+}
+
+# Quote input so it can be safely used for variable assignment via eval
+quote()
+{
+ if [ -z "$1" ]; then
+ R="''"
+ else
+ R=
+ for W; do
+ while [ -n "$W" ]; do
+ case "$W" in
+ \'*) R="$R\\'"; W=${W#?};;
+ ?\'*) R="$R\\${W%%\'*}"; W="${W#?}";;
+ *\'*) R="$R'${W%%\'*}'"; W="'${W#*\'}";;
+ ?) R="$R\\$W"; W=;;
+ *) R="$R'$W'"; W=;;
+ esac
+ done
+ done
+ fi
+
+ printf '%s\n' "$R"
+ return 0
+}
+
# Parse resolv.conf's and make variables
# for domain name servers, search name servers and global nameservers
+# Important! Each printf here should use the above quote function
+# to ensure that user input is quoted for eval.
parse_resolv()
{
domain=
@@ -174,26 +268,32 @@
newns=
ns=
private=false
+ nosearch=false
search=
while read -r line; do
- stripped_line="$(resolv_strip ${line#* })"
+ value="${line#* }"
case "$line" in
"# resolv.conf from "*)
if ${new}; then
- iface="${line#\# resolv.conf from *}"
+ key="${line#\# resolv.conf from *}"
new=false
- if private_iface "$iface"; then
+ if nosearch_key "$key"; then
private=true
+ nosearch=true
+ elif private_key "$key"; then
+ private=true
+ nosearch=false
else
private=false
+ nosearch=false
fi
fi
;;
"nameserver "*)
islocal=false
for l in $local_nameservers; do
- case "$stripped_line" in
+ case "$value" in
$l)
islocal=true
break
@@ -201,20 +301,22 @@
esac
done
if $islocal; then
- echo "LOCALNAMESERVERS=\"\$LOCALNAMESERVERS $stripped_line\""
+ printf 'LOCALNAMESERVERS="$LOCALNAMESERVERS "%s\n' "$(quote "$value")"
else
- ns="$ns$stripped_line "
+ ns="$ns${ns:+ }$value"
fi
;;
"domain "*)
- search="$stripped_line"
+ search="$value"
if [ -z "$domain" ]; then
domain="$search"
- echo "DOMAIN=\"$domain\""
+ if ! $nosearch; then
+ printf 'DOMAIN=%s\n' "$(quote "$domain")"
+ fi
fi
;;
"search "*)
- search="$stripped_line"
+ search="$value"
;;
*)
[ -n "$line" ] && continue
@@ -227,11 +329,13 @@
for d in $search; do
ds="$ds${ds:+ }$d:$newns"
done
- echo "DOMAINS=\"\$DOMAINS $ds\""
+ printf 'DOMAINS="$DOMAINS "%s\n' "$(quote "$ds")"
+ fi
+ if ! $nosearch; then
+ printf 'SEARCH="$SEARCH "%s\n' "$(quote "$search")"
fi
- echo "SEARCH=\"\$SEARCH $search\""
if ! $private; then
- echo "NAMESERVERS=\"\$NAMESERVERS $ns\""
+ printf 'NAMESERVERS="$NAMESERVERS "%s\n' "$(quote "$ns")"
fi
ns=
search=
@@ -274,26 +378,21 @@
config_mkdirs()
{
- e=0
for f; do
[ -n "$f" ] || continue
d="$(dirname "$f")"
if [ ! -d "$d" ]; then
- if type install >/dev/null 2>&1; then
- install -d "$d" || e=$?
- else
- mkdir "$d" || e=$?
- fi
+ mkdir -p "$d" || return $?
fi
done
- return $e
+ return 0
}
# With the advent of alternative init systems, it's possible to have
# more than one installed. So we need to try and guess what one we're
-# using unless overriden by configure.
+# using unless overridden by configure.
# Note that restarting a service is a last resort - the subscribers
-# should make a reasonable attempt to reconfigre the service via some
+# should make a reasonable attempt to reconfigure the service via some
# method, normally SIGHUP.
detect_init()
{
@@ -328,6 +427,12 @@
then
/usr/sbin/invoke-rc.d $1 restart
fi'
+ elif [ -x /usr/bin/s6-rc ] && [ -x /usr/bin/s6-svc ]; then
+ RESTARTCMD='
+ if s6-rc -a list 2>/dev/null | grep -qFx $1-srv
+ then
+ s6-svc -r /run/service/$1-srv
+ fi'
elif [ -x /sbin/service ]; then
# Old RedHat
RCDIR=/etc/init.d
@@ -368,6 +473,8 @@
then
/etc/rc.d/$1 restart
fi'
+ elif [ -d /etc/dinit.d ] && command -v dinitctl >/dev/null 2>&1; then
+ RESTARTCMD='dinitctl --quiet restart --ignore-unstarted $1'
else
for x in /etc/init.d/rc.d /etc/rc.d /etc/init.d; do
[ -d $x ] || continue
@@ -395,9 +502,9 @@
{
OIFS="$IFS"
- [ -n "$1" ] && [ -f "$IFACEDIR/$1" ] || return 1
+ [ -n "$1" ] && [ -f "$KEYDIR/$1" ] || return 1
echo "# resolv.conf from $1"
- # Our variable maker works of the fact each resolv.conf per interface
+ # Our variable maker works of the fact each resolv.conf per key
# is separated by blank lines.
# So we remove them when echoing them.
while read -r line; do
@@ -407,103 +514,296 @@
IFS=''
printf "%s\n" "$line"
fi
- done < "$IFACEDIR/$1"
+ done < "$KEYDIR/$1"
IFS="$OIFS"
}
+deprecated_key()
+{
+ [ -d "$DEPRECATEDDIR" ] || return 1
+
+ cd "$DEPRECATEDDIR"
+ for da; do
+ for daf in *; do
+ [ -f "$daf" ] || continue
+ case "$da" in
+ $daf) return 0;;
+ esac
+ done
+ done
+ return 1
+}
+
+match()
+{
+ match="$1"
+ file="$2"
+ retval=1
+ count=0
+
+ while read -r keyword value; do
+ new_match=
+ for om in $match; do
+ m="$om"
+ keep=
+ while [ -n "$m" ]; do
+ k="${m%%/*}"
+ r="${m#*/}"
+ f="${r%%/*}"
+ r="${r#*/}"
+ # If the length of m is the same as k/f then
+ # we know that we are done
+ if [ ${#m} = $((${#k} + 1 + ${#f})) ]; then
+ r=
+ fi
+ m="$r"
+ matched=false
+ case "$keyword" in
+ $k)
+ case "$value" in
+ $f)
+ matched=true
+ ;;
+ esac
+ ;;
+ esac
+ if ! $matched; then
+ keep="$keep${keep:+/}$k/$f"
+ fi
+ done
+ if [ -n "$om" ] && [ -z "$keep" ]; then
+ retval=0
+ break 2
+ fi
+ new_match="${new_match}${new_match:+ }${keep}"
+ done
+ match="${new_match}"
+ done < "$file"
+ return $retval
+}
+
+list_keys() {
+ list_cmd="$1"
+ shift
+
+ [ -d "$KEYDIR" ] || return 0
+ cd "$KEYDIR"
+
+ [ -n "$1" ] || set -- "*"
+ list=
+ retval=0
+ if [ "$list_cmd" = -i ] || [ "$list_cmd" = -l ]; then
+ for i in $@; do
+ if [ ! -f "$i" ]; then
+ if ! $force && [ "$i" != "*" ]; then
+ echo "No resolv.conf for key $i" >&2
+ fi
+ retval=2
+ continue
+ fi
+ list="$list $i"
+ done
+ [ -z "$list" ] || uniqify $list
+ return $retval
+ fi
+
+ if [ "$list_cmd" != -I ] && [ "$list_cmd" != -L ]; then
+ echo "list_keys: unknown command $list_cmd" >&2
+ return 1
+ fi
+
+ if [ -d "$EXCLUSIVEDIR" ]; then
+ cd "$EXCLUSIVEDIR"
+ for i in $EXCLUSIVEDIR/*; do
+ if [ -f "$i" ]; then
+ cd "$KEYDIR"
+ for ii in $inclusive_keys; do
+ if [ -f "$ii" ] && [ "${i#* }" = "$ii" ]; then
+ continue 2
+ fi
+ done
+ list="${i#* }"
+ break
+ fi
+ done
+ cd "$KEYDIR"
+ if [ -n "$list" ]; then
+ for i in $@; do
+ # list will be one item due to the above
+ if [ -f "$i" ] && [ "$i" = "$list" ]; then
+ echo "$i"
+ return 0
+ fi
+ done
+ return 0
+ fi
+ fi
+
+ for i in $key_order; do
+ for ii in "$i" "$i":* "$i".*; do
+ [ -f "$ii" ] && list="$list $ii"
+ done
+ done
+
+ for i in $dynamic_order; do
+ for ii in "$i" "$i":* "$i".*; do
+ if [ -f "$ii" ] && ! [ -e "$METRICDIR/"*" $ii" ]
+ then
+ list="$list $ii"
+ fi
+ done
+ done
+
+ # Interfaces have an implicit metric of 0 if not specified.
+ for i in *; do
+ if [ -f "$i" ] && ! [ -e "$METRICDIR/"*" $i" ]; then
+ list="$list $i"
+ fi
+ done
+
+ if [ -d "$METRICDIR" ]; then
+ cd "$METRICDIR"
+ for i in *; do
+ [ -f "$i" ] && list="$list ${i#* }"
+ done
+ cd "$KEYDIR"
+ fi
+
+ # Move deprecated keys to the back
+ active=
+ deprecated=
+ for i in $list; do
+ if deprecated_key "$i"; then
+ deprecated="$deprecated $i"
+ else
+ active="$active $i"
+ fi
+ done
+ list="$active $deprecated"
+
+ retval=0
+ if [ "$1" != "*" ]; then
+ cd "$KEYDIR"
+ matched=
+ for i in $@; do
+ if ! [ -f "$i" ]; then
+ if ! $force; then
+ echo "No resolv.conf for key $i" >&2
+ fi
+ retval=2
+ continue
+ fi
+ for ii in $list; do
+ if [ "$i" = "$ii" ]; then
+ matched="$matched${matched:+ }$i"
+ break
+ fi
+ done
+ done
+ if [ -z "$matched" ]; then
+ return $retval
+ fi
+ list="$matched"
+ fi
+
+ allowed=
+ for i in $(uniqify $list); do
+ if [ -n "$allow_keys" ]; then
+ x=false
+ for ii in $allow_keys; do
+ if [ "$i" = "$ii" ]; then
+ x=true
+ break
+ fi
+ done
+ $x || continue
+ fi
+ for ii in $deny_keys; do
+ if [ "$i" = "$ii" ]; then
+ continue 2
+ fi
+ done
+
+ if [ -n "$exclude" ] && match "$exclude" "$i"; then
+ continue
+ fi
+ allowed="$allowed${allowed:+ }$i"
+ done
+
+ cd "$KEYDIR"
+ for i in $exclusive_keys; do
+ for ii in $allowed; do
+ if [ "$i" = "$ii" ]; then
+ echo "$i"
+ return
+ fi
+ done
+ done
+ [ -z "$allowed" ] || echo "$allowed"
+}
+
list_resolv()
{
- [ -d "$IFACEDIR" ] || return 0
-
- cmd="$1"
- shift
- excl=false
- list=
- report=false
- retval=0
-
- case "$IF_EXCLUSIVE" in
- [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
- excl=true
- if [ -d "$EXCLUSIVEDIR" ]; then
- cd "$EXCLUSIVEDIR"
- for i in *; do
- if [ -f "$i" ]; then
- list="${i#* }"
- break
- fi
- done
- fi
- cd "$IFACEDIR"
- for i in $inclusive_interfaces; do
- if [ -f "$i" ] && [ "$list" = "$i" ]; then
- list=
- excl=false
- break
- fi
- done
- ;;
- esac
-
- # If we have an interface ordering list, then use that.
- # It works by just using pathname expansion in the interface directory.
- if [ -n "$1" ]; then
- list="$*"
- $force || report=true
- elif ! $excl; then
- cd "$IFACEDIR"
- for i in $interface_order; do
- [ -f "$i" ] && list="$list $i"
- for ii in "$i":* "$i".*; do
- [ -f "$ii" ] && list="$list $ii"
- done
- done
- for i in $dynamic_order; do
- if [ -e "$i" ] && ! [ -e "$METRICDIR/"*" $i" ]; then
- list="$list $i"
- fi
- for ii in "$i":* "$i".*; do
- if [ -f "$ii" ] && ! [ -e "$METRICDIR/"*" $ii" ]
- then
- list="$list $ii"
- fi
- done
- done
- # Interfaces have an implicit metric of 0 if not specified.
- for i in *; do
- if [ -f "$i" ] && ! [ -e "$METRICDIR/"*" $i" ]; then
- list="$list $i"
- fi
- done
- if [ -d "$METRICDIR" ]; then
- cd "$METRICDIR"
- for i in *; do
- [ -f "$i" ] && list="$list ${i#* }"
- done
- fi
+ keys="$(list_keys "$@")"
+ retval=$?
+ if [ "$retval" != 0 ]; then
+ return $retval
fi
-
- cd "$IFACEDIR"
- retval=1
- for i in $(uniqify $list); do
- # Only list interfaces which we really have
- if ! [ -f "$i" ]; then
- if $report; then
- echo "No resolv.conf for interface $i" >&2
- retval=2
- fi
- continue
- fi
-
- if [ "$cmd" = i ] || [ "$cmd" = "-i" ]; then
- printf %s "$i "
- else
- echo_resolv "$i" && echo
- fi
- [ $? = 0 ] && [ "$retval" = 1 ] && retval=0
+ for i in $keys; do
+ echo_resolv "$i" && echo
done
- [ "$cmd" = i ] || [ "$cmd" = "-i" ] && echo
- return $retval
+}
+
+list_private()
+{
+ KEYS=
+ cd "$KEYDIR"
+ if [ -z "$1" ]; then
+ set -- "*"
+ fi
+ for i in $@; do
+ if private_key "$i"; then
+ KEYS="${KEYS}${KEYS:+ }$i"
+ fi
+ done
+ if [ -n "$KEYS" ]; then
+ echo "$KEYS"
+ fi
+}
+
+list_nosearch()
+{
+
+ KEYS=
+ cd "$KEYDIR"
+ if [ -z "$1" ]; then
+ set -- "*"
+ fi
+ for i in $@; do
+ if nosearch_key "$i"; then
+ KEYS="${KEYS}${KEYS:+ }$i"
+ fi
+ done
+ if [ -n "$KEYS" ]; then
+ echo "$KEYS"
+ fi
+}
+
+list_exclusive()
+{
+ KEYS=
+ cd "$KEYDIR"
+ if [ -z "$1" ]; then
+ set -- "*"
+ fi
+ for i in $@; do
+ if exclusive_key "$i"; then
+ KEYS="${KEYS}${KEYS:+ }$i"
+ fi
+ done
+ if [ -n "$KEYS" ]; then
+ echo "$KEYS"
+ fi
}
list_remove()
@@ -558,7 +858,81 @@
echo
}
-replace()
+tolower() {
+ # There is no good way of doing this portably in shell :(
+ # Luckily we are only doing this for domain names which we
+ # know have to be ASCII.
+ # Non ASCII domains *should* be translated to ASCII *before*
+ # we get to this stage.
+ # We could use echo "$@" | tr '[:upper:]' '[:lower:]' but
+ # tr is in /usr/bin and may not be available when data is fed
+ # to resolvconf.
+ # So it's the cost of a pipe + fork vs this slow loop
+ #
+ for word; do
+ # Check if we have any upper to avoid looping per char
+ case "$word" in
+ *[A-Z]*) ;;
+ *) printf "%s " "$word"; continue;;
+ esac
+
+ while [ -n "$word" ]; do
+ # Remove everything except the first character
+ afterchar="${word#?}"
+ # Remove the afterchar to get the first character
+ char="${word%%$afterchar}"
+ # Assign afterchar back to word for looping
+ word="$afterchar"
+
+ # Now enforce lowercase a-z
+ case "$char" in
+ A) char=a;;
+ B) char=b;;
+ C) char=c;;
+ D) char=d;;
+ E) char=e;;
+ F) char=f;;
+ G) char=g;;
+ H) char=h;;
+ I) char=i;;
+ J) char=j;;
+ K) char=k;;
+ L) char=l;;
+ M) char=m;;
+ N) char=n;;
+ O) char=o;;
+ P) char=p;;
+ Q) char=q;;
+ R) char=r;;
+ S) char=s;;
+ T) char=t;;
+ U) char=u;;
+ V) char=v;;
+ W) char=w;;
+ X) char=x;;
+ Y) char=y;;
+ Z) char=z;;
+ esac
+ printf %s "$char"
+ done
+ printf " "
+ done
+ printf "\n"
+}
+
+# Strip any trailing dot from each name as a FQDN does not belong
+# in resolv.conf(5).
+# While DNS is not case sensitive, our labels for building the zones
+# are, so ensure it's lower case.
+process_domain()
+{
+ for word in $(tolower "$@"); do
+ printf "%s " "${word%.}"
+ done
+ printf "\n"
+}
+
+process_resolv()
{
while read -r keyword value; do
for r in $replace; do
@@ -593,6 +967,18 @@
done
val="$val${val:+ }$sub"
done
+ case "$keyword" in
+ \#)
+ case "$val" in
+ "resolv.conf from "*) ;;
+ *) continue;;
+ esac
+ ;;
+ \#*) continue;;
+ esac
+ case "$keyword" in
+ domain|search) val="$(process_domain $val)";;
+ esac
printf "%s %s\n" "$keyword" "$val"
done
}
@@ -605,14 +991,12 @@
SEARCH=
NAMESERVERS=
LOCALNAMESERVERS=
-
+
if [ -n "${name_servers}${search_domains}" ]; then
eval "$(echo_prepend | parse_resolv)"
fi
if [ -z "$VFLAG" ]; then
- IF_EXCLUSIVE=1
- list_resolv -i "$@" >/dev/null || IF_EXCLUSIVE=0
- eval "$(list_resolv -l "$@" | replace | parse_resolv)"
+ eval "$(list_resolv -L "$@" | process_resolv | parse_resolv)"
fi
if [ -n "${name_servers_append}${search_domains_append}" ]; then
eval "$(echo_append | parse_resolv)"
@@ -646,6 +1030,7 @@
newdomains="$newdomains${newdomains:+ }$dn:$newns"
fi
done
+
DOMAIN="$(list_remove domain_blacklist $DOMAIN)"
SEARCH="$(uniqify $SEARCH)"
SEARCH="$(list_remove domain_blacklist $SEARCH)"
@@ -653,21 +1038,30 @@
NAMESERVERS="$(list_remove name_server_blacklist $NAMESERVERS)"
LOCALNAMESERVERS="$(uniqify $LOCALNAMESERVERS)"
LOCALNAMESERVERS="$(list_remove name_server_blacklist $LOCALNAMESERVERS)"
- echo "DOMAIN='$DOMAIN'"
- echo "SEARCH='$SEARCH'"
- echo "NAMESERVERS='$NAMESERVERS'"
- echo "LOCALNAMESERVERS='$LOCALNAMESERVERS'"
- echo "DOMAINS='$newdomains'"
+
+ # Ensure output is quoted for eval
+ printf 'DOMAIN=%s\n' "$(quote "$DOMAIN")"
+ printf 'SEARCH=%s\n' "$(quote "$SEARCH")"
+ printf 'NAMESERVERS=%s\n' "$(quote "$NAMESERVERS")"
+ printf 'LOCALNAMESERVERS=%s\n' "$(quote "$LOCALNAMESERVERS")"
+ printf 'DOMAINS=%s\n' "$(quote "$newdomains")"
}
force=false
+LFLAG=
VFLAG=
-while getopts a:Dd:fhIilm:pRruvVx OPT; do
+while getopts a:C:c:Dd:fhIiLlm:pRruvVx OPT; do
case "$OPT" in
f) force=true;;
h) usage;;
m) IF_METRIC="$OPTARG";;
- p) IF_PRIVATE=1;;
+ p)
+ if [ "$IF_PRIVATE" = 1 ]; then
+ IF_NOSEARCH=1
+ else
+ IF_PRIVATE=1
+ fi
+ ;;
V)
VFLAG=1
if [ "$local_nameservers" = \
@@ -677,19 +1071,23 @@
fi
;;
x) IF_EXCLUSIVE=1;;
- '?') ;;
- *) cmd="$OPT"; iface="$OPTARG";;
+ '?') exit 1;;
+ *)
+ [ "$OPT" != L ] || LFLAG=1
+ cmd="$OPT"; key="$OPTARG";;
esac
done
shift $(($OPTIND - 1))
-args="$iface${iface:+ }$*"
+if [ -n "$key" ]; then
+ set -- "$key" "$@"
+fi
-# -I inits the state dir
-if [ "$cmd" = I ]; then
- if [ -d "$VARDIR" ]; then
- rm -rf "$VARDIR"/*
+if [ -z "$cmd" ]; then
+ if [ "$IF_PRIVATE" = 1 ]; then
+ cmd=p
+ elif [ "$IF_EXCLUSIVE" = 1 ]; then
+ cmd=x
fi
- exit $?
fi
# -D ensures that the listed config file base dirs exist
@@ -698,9 +1096,38 @@
exit $?
fi
-# -l lists our resolv files, optionally for a specific interface
-if [ "$cmd" = l ] || [ "$cmd" = i ]; then
- list_resolv "$cmd" "$args"
+# -i lists which keys have a resolv file
+if [ "$cmd" = i ]; then
+ # If the -L modifier is given, the list is post-processed
+ if [ "$LFLAG" = 1 ]; then
+ cmd="L"
+ fi
+ list_keys "-$cmd" "$@"
+ exit $?
+fi
+
+# -l lists our resolv files, optionally for a specific key
+if [ "$cmd" = l ]; then
+ list_resolv "-$cmd" "$@"
+ exit $?
+fi
+# -L is the same as -l, but post-processed from our config
+if [ "$cmd" = L ]; then
+ list_resolv "-$cmd" "$@" | process_resolv
+ exit $?
+fi
+
+if [ "$cmd" = p ]; then
+ if [ "$IF_NOSEARCH" = 1 ]; then
+ list_nosearch "$@"
+ else
+ list_private "$@"
+ fi
+ exit $?
+fi
+
+if [ "$cmd" = x ]; then
+ list_exclusive "$@"
exit $?
fi
@@ -708,7 +1135,6 @@
if [ "$cmd" = r ] || [ "$cmd" = R ]; then
detect_init || exit 1
if [ "$cmd" = r ]; then
- set -- $args
eval "$RESTARTCMD"
else
echo "$RESTARTCMD" |
@@ -719,30 +1145,36 @@
# Not normally needed, but subscribers should be able to run independently
if [ "$cmd" = v ] || [ -n "$VFLAG" ]; then
- make_vars "$iface"
+ make_vars "$@"
exit $?
fi
# Test that we have valid options
-if [ "$cmd" = a ] || [ "$cmd" = d ]; then
- if [ -z "$iface" ]; then
- usage "Interface not specified"
+case "$cmd" in
+a|d|C|c)
+ if [ -z "$key" ]; then
+ error_exit "Key not specified"
+ fi
+ ;;
+I|u) ;;
+*)
+ if [ -n "$cmd" ] && [ "$cmd" != h ]; then
+ error_exit "Unknown option $cmd"
fi
-elif [ "$cmd" != u ]; then
- [ -n "$cmd" ] && [ "$cmd" != h ] && usage "Unknown option $cmd"
usage
-fi
+ ;;
+esac
if [ "$cmd" = a ]; then
- for x in '/' \\ ' ' '*'; do
- case "$iface" in
- *[$x]*) error_exit "$x not allowed in interface name";;
+ for x in '/' '\' ' ' '*'; do
+ case "$key" in
+ "$x"|"$x"*|*"$x"|*"$x"*) error_exit "$x not allowed in key name";;
esac
done
for x in '.' '-' '~'; do
- case "$iface" in
- [$x]*) error_exit \
- "$x not allowed at start of interface name";;
+ case "$key" in
+ "$x"*) error_exit \
+ "$x not allowed at start of key name";;
esac
done
[ "$cmd" = a ] && [ -t 0 ] && error_exit "No file given via stdin"
@@ -765,15 +1197,15 @@
fi
fi
-if [ ! -d "$IFACEDIR" ]; then
- mkdir -m 0755 -p "$IFACEDIR" || \
- error_exit "Failed to create needed directory $IFACEDIR"
+if [ ! -d "$KEYDIR" ]; then
+ mkdir -m 0755 -p "$KEYDIR" || \
+ error_exit "Failed to create needed directory $KEYDIR"
if [ "$cmd" = d ]; then
# Provide the same error messages as below
if ! ${force}; then
- cd "$IFACEDIR"
- for i in $args; do
- warn "No resolv.conf for interface $i"
+ cd "$KEYDIR"
+ for i in $@; do
+ warn "No resolv.conf for key $i"
done
fi
${force}
@@ -781,7 +1213,7 @@
fi
fi
-# An interface was added, changed, deleted or a general update was called.
+# A key was added, changed, deleted or a general update was called.
# Due to exclusivity we need to ensure that this is an atomic operation.
# Our subscribers *may* need this as well if the init system is sub par.
# As such we spinlock at this point as best we can.
@@ -789,6 +1221,9 @@
# in /usr which we do our very best to operate without.
[ -w "$VARDIR" ] || error_exit "Cannot write to $LOCKDIR"
: ${lock_timeout:=10}
+: ${clear_nopids:=5}
+have_pid=false
+had_pid=false
while true; do
if mkdir "$LOCKDIR" 2>/dev/null; then
trap 'rm -rf "$LOCKDIR";' EXIT
@@ -796,18 +1231,43 @@
echo $$ >"$LOCKDIR/pid"
break
fi
- pid=$(cat "$LOCKDIR/pid")
- if ! kill -0 "$pid"; then
+ pid=$(cat "$LOCKDIR/pid" 2>/dev/null)
+ if [ "$pid" -gt 0 ] 2>/dev/null; then
+ have_pid=true
+ had_pid=true
+ else
+ have_pid=false
+ clear_nopids=$(($clear_nopids - 1))
+ if [ "$clear_nopids" -le 0 ]; then
+ warn "not seen a pid, clearing lock directory"
+ rm -rf "$LOCKDIR"
+ else
+ lock_timeout=$(($lock_timeout - 1))
+ sleep 1
+ fi
+ continue
+ fi
+ if $have_pid && ! kill -0 "$pid"; then
warn "clearing stale lock pid $pid"
rm -rf "$LOCKDIR"
continue
fi
lock_timeout=$(($lock_timeout - 1))
if [ "$lock_timeout" -le 0 ]; then
- error_exit "timed out waiting for lock from pid $pid"
+ if $have_pid; then
+ error_exit "timed out waiting for lock from pid $pid"
+ else
+ if $had_pid; then
+ error_exit "timed out waiting for lock" \
+ "from some pids"
+ else
+ error_exit "timed out waiting for lock"
+ fi
+ fi
fi
sleep 1
done
+unset have_pid had_pid clear_nopids
case "$cmd" in
a)
@@ -816,9 +1276,9 @@
changed=false
changedfile=false
# If what we are given matches what we have, then do nothing
- if [ -e "$IFACEDIR/$iface" ]; then
+ if [ -e "$KEYDIR/$key" ]; then
if [ "$(echo "$resolv")" != \
- "$(cat "$IFACEDIR/$iface")" ]
+ "$(cat "$KEYDIR/$key")" ]
then
changed=true
changedfile=true
@@ -828,21 +1288,21 @@
changedfile=true
fi
- # Set metric and private before creating the interface resolv.conf file
+ # Set metric and private before creating the resolv.conf file
# to ensure that it will have the correct flags
[ ! -d "$METRICDIR" ] && mkdir "$METRICDIR"
- oldmetric="$METRICDIR/"*" $iface"
+ oldmetric="$METRICDIR/"*" $key"
newmetric=
if [ -n "$IF_METRIC" ]; then
# Pad metric to 6 characters, so 5 is less than 10
while [ ${#IF_METRIC} -le 6 ]; do
IF_METRIC="0$IF_METRIC"
done
- newmetric="$METRICDIR/$IF_METRIC $iface"
+ newmetric="$METRICDIR/$IF_METRIC $key"
fi
- rm -f "$METRICDIR/"*" $iface"
+ rm -f "$METRICDIR/"*" $key"
[ "$oldmetric" != "$newmetric" ] &&
- [ "$oldmetric" != "$METRICDIR/* $iface" ] &&
+ [ "$oldmetric" != "$METRICDIR/* $key" ] &&
changed=true
[ -n "$newmetric" ] && echo " " >"$newmetric"
@@ -852,19 +1312,37 @@
[ -e "$PRIVATEDIR" ] && rm "$PRIVATEDIR"
mkdir "$PRIVATEDIR"
fi
- [ -e "$PRIVATEDIR/$iface" ] || changed=true
- [ -d "$PRIVATEDIR" ] && echo " " >"$PRIVATEDIR/$iface"
+ [ -e "$PRIVATEDIR/$key" ] || changed=true
+ [ -d "$PRIVATEDIR" ] && echo " " >"$PRIVATEDIR/$key"
;;
*)
- if [ -e "$PRIVATEDIR/$iface" ]; then
- rm -f "$PRIVATEDIR/$iface"
+ if [ -e "$PRIVATEDIR/$key" ]; then
+ rm -f "$PRIVATEDIR/$key"
changed=true
fi
;;
esac
+ case "$IF_NOSEARCH" in
+ [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
+ if [ ! -d "$NOSEARCHDIR" ]; then
+ [ -e "$NOSEARCHDIR" ] && rm "$NOSEARCHDIR"
+ mkdir "$NOSEARCHDIR"
+ fi
+ [ -e "$NOSEARCHDIR/$key" ] || changed=true
+ [ -d "$NOSEARCHDIR" ] && echo " " >"$NOSEARCHDIR/$key"
+ ;;
+ *)
+ if [ -e "$NOSEARCHDIR/$key" ]; then
+ rm -f "$NOSEARCHDIR/$key"
+ changed=true
+ fi
+ ;;
+ esac
+ set +x
+
oldexcl=
- for x in "$EXCLUSIVEDIR/"*" $iface"; do
+ for x in "$EXCLUSIVEDIR/"*" $key"; do
if [ -f "$x" ]; then
oldexcl="$x"
break
@@ -880,7 +1358,7 @@
for x in *; do
[ -f "$x" ] && break
done
- if [ "${x#* }" != "$iface" ]; then
+ if [ "${x#* }" != "$key" ]; then
if [ "$x" = "${x% *}" ]; then
x=10000000
else
@@ -892,7 +1370,7 @@
x=$(($x - 1))
fi
if [ -d "$EXCLUSIVEDIR" ]; then
- echo " " >"$EXCLUSIVEDIR/$x $iface"
+ echo " " >"$EXCLUSIVEDIR/$x $key"
fi
changed=true
fi
@@ -906,34 +1384,80 @@
esac
if $changedfile; then
- printf "%s\n" "$resolv" >"$IFACEDIR/$iface" || exit $?
- elif ! $changed; then
+ printf "%s\n" "$resolv" >"$KEYDIR/$key" || exit $?
+ elif ! $changed && [ ! -e "$VARDIR"/error ]; then
exit 0
fi
unset changed changedfile oldmetric newmetric x oldexcl
;;
d)
- # Delete any existing information about the interface
- cd "$IFACEDIR"
+ # Delete any existing information about the key
+ cd "$KEYDIR"
changed=false
- for i in $args; do
+ for i in $@; do
if [ -e "$i" ]; then
changed=true
elif ! ${force}; then
- warn "No resolv.conf for interface $i"
+ warn "No resolv.conf for key $i"
fi
rm -f "$i" "$METRICDIR/"*" $i" \
"$PRIVATEDIR/$i" \
"$EXCLUSIVEDIR/"*" $i" || exit $?
done
- if ! ${changed}; then
+
+ if ! $changed && [ ! -e "$VARDIR"/error ]; then
# Set the return code based on the forced flag
- ${force}
+ $force
exit $?
fi
unset changed i
;;
+
+C)
+ # Mark key as deprecated
+ [ ! -d "$DEPRECATEDDIR" ] && mkdir "$DEPRECATEDDIR"
+ cd "$DEPRECATEDDIR"
+ changed=false
+ for i in $@; do
+ if [ ! -e "$i" ]; then
+ changed=true
+ echo " " >"$i" || exit $?
+ fi
+ done
+ if ! $changed && [ ! -e "$VARDIR"/error ]; then
+ exit 0
+ fi
+ unset changed i
+ ;;
+
+c)
+ # Mark key as active
+ if [ -d "$DEPRECATEDDIR" ]; then
+ cd "$DEPRECATEDDIR"
+ changed=false
+ for i in $@; do
+ if [ -e "$i" ]; then
+ changed=true
+ rm "$i" || exit $?
+ fi
+ done
+ if ! $changed && [ ! -e "$VARDIR"/error ]; then
+ exit 0
+ fi
+ unset changed i
+ fi
+ ;;
+I)
+ # Init the state dir, keeping our lock and key directories only
+ for i in "$VARDIR"/*; do
+ case "$i" in
+ "$LOCKDIR") ;;
+ "$KEYDIR") rm -rf "$KEYDIR"/*;;
+ *) rm -rf "$i";;
+ esac
+ done
+ ;;
esac
case "${resolvconf:-YES}" in
@@ -947,7 +1471,7 @@
eval "$(make_vars)"
export RESOLVCONF DOMAINS SEARCH NAMESERVERS LOCALNAMESERVERS
-: ${list_resolv:=list_resolv -l}
+: ${list_resolv:=list_resolv -L}
retval=0
# Run scripts in the same directory resolvconf is run from
@@ -955,17 +1479,26 @@
cd "$_PWD"
for script in "$LIBEXECDIR"/*; do
if [ -f "$script" ]; then
- eval script_enabled="\$${script##*/}"
+ script_var="${script##*/}"
+ while [ "${script_var%%-*}" != "$script_var" ]; do
+ script_var="${script_var%%-*}_${script_var#*-}"
+ done
+ eval script_enabled="\$$script_var"
case "${script_enabled:-YES}" in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;;
*) continue;;
esac
if [ -x "$script" ]; then
- "$script" "$cmd" "$iface"
+ "$script" "$cmd" "$key"
else
- (set -- "$cmd" "$iface"; . "$script")
+ (set -- "$cmd" "$key"; . "$script")
fi
retval=$(($retval + $?))
fi
done
+if [ "$retval" = 0 ]; then
+ rm -f "$VARDIR"/error
+else
+ echo "$retval" >"$VARDIR"/error
+fi
exit $retval
diff --git a/resolvectl.in b/resolvectl.in
new file mode 100644
--- /dev/null
+++ b/resolvectl.in
@@ -0,0 +1,159 @@
+#!/bin/sh
+# Copyright (c) 2025 Roy Marples
+# All rights reserved
+
+# resolvectl 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.
+
+[ -f "@SYSCONFDIR@"/resolvconf.conf ] || exit 0
+. "@SYSCONFDIR@/resolvconf.conf" || exit 1
+
+case "${resolvectl:-NO}" in
+[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;;
+*) exit 0;;
+esac
+
+# If we don't have resolvectl or systemd-resolved isn't running then
+# we can't do much.
+# We can't persist our data in /run/systemd/resolve/netif/$ifindex
+# because systemd-resolved keeps it somehow, ie we can't change it
+# once we have inserted it
+if ! [ -d /sys/class/net ] || \
+ ! type resolvectl >/dev/null 2>&1 || \
+ ! pidof systemd-resolved >/dev/null
+then
+ exit 1
+fi
+
+# resolvectl only accepts resolv.conf setup per physical interface
+# although resolvconf has always hinted that the named configuration
+# should be $interface.$protocol, this has never been a fixed requirement.
+# Because resolvectl only accepts one configuration per interface we need
+# to try and merge the resolv.conf's together.
+# Luckily resolvconf makes this easy for us.
+
+# Returns a list of resolvconf entries for a real interface
+get_resolvconf_interfaces() {
+ IFACE="$1"
+ [ -d /sys/class/net/"$IFACE" ] || return 1
+
+ IFACES=
+ for IFACE_PROTO in $(@SBINDIR@/resolvconf -Li "$IFACE" "$IFACE.*" 2>/dev/null); do
+ # ens5 will work with ens5.dhcp and ens5.ra,
+ # but not ens5.5 or ens5.5.dhcp
+ if [ "$IFACE_PROTO" != "$IFACE" ]; then
+ # Ensure that ens5.5.dhcp doesn't work for ens5
+ if [ "${IFACE_PROTO%.*}" != "$IFACE" ]; then
+ continue
+ fi
+ # Ensure that ens5.dhcp isn't a real interface
+ # as ens5.5 likely is and the .5 matches the .dhcp
+ if [ -d /sys/class/net/"$IFACE_PROTO" ]; then
+ continue
+ fi
+ fi
+ IFACES="$IFACES${IFACES:+ }$IFACE_PROTO"
+ done
+ echo "$IFACES"
+}
+
+# For the given interface, apply a list of resolvconf entries
+apply_resolvconf() {
+ IFACE="$1"
+ shift
+
+ if [ -z "$1" ]; then
+ resolvectl revert "$IFACE"
+ return
+ fi
+
+ # Set the default-route property first to avoid leakage.
+ # If any entry is private, the whole interface has to be private.
+ # If a more granular approach is needed, consider using the
+ # systemd-resolved subscriber instead which supports DNS delegates.
+ if [ -n "$(@SBINDIR@/resolvconf -p $@)" ]; then
+ resolvectl default-route "$IFACE" false
+ else
+ resolvectl default-route "$IFACE" true
+ fi
+
+ # Now set domain and dns
+ DOMAIN=$(@SBINDIR@/resolvconf -L $@ 2>/dev/null | sed -n -e "s/domain //p" -e "s/search //p")
+ NS=$(@SBINDIR@/resolvconf -L $@ 2>/dev/null | sed -n -e "s/nameserver //p")
+ if [ -n "$DOMAIN" ]; then
+ # If any entry is marked as not searchable, we mark all the
+ # domains as non searchable.
+ # If a more granular approach is needed, consider using the
+ # systemd-resolved subscriber instead which supports DNS delegates.
+ if [ -n "$(@SBINDIR@/resolvconf -pp $@)" ]; then
+ ND=
+ for d in $DOMAIN; do
+ ND="$ND${ND:+ }~$d"
+ done
+ DOMAIN="$ND"
+ fi
+ resolvectl domain "$IFACE" $DOMAIN
+ else
+ resolvectl domain "$IFACE" ""
+ fi
+ if [ -n "$NS" ]; then
+ resolvectl dns "$IFACE" $NS
+ else
+ resolvectl dns "$IFACE" ""
+ fi
+}
+
+# To get the full features of resolvconf, we need to work out each interface
+# for every resolvconf addition and deletion
+# This is because resolvconf.conf might have changed OR an exclusive
+# interface deleted which makes other interfaces visible.
+cd /sys/class/net
+for IFACE in *; do
+ if [ "$IFACE" = lo ]; then
+ # systemd-resolved doesn't work with lo
+ continue
+ fi
+
+ IFACES=$(get_resolvconf_interfaces "$IFACE")
+ apply_resolvconf "$IFACE" $IFACES
+done
+
+# warn about resolv.conf with no matching interface
+FAILED=
+for IFACE_PROTO in $(@SBINDIR@/resolvconf -Li); do
+ IFACE="${IFACE_PROTO%.*}"
+ if [ "$IFACE" = lo ]; then
+ # Don't warn about loopback interface as that is typically
+ # used to configure libc for a nameserver on it and the libc
+ # subscriber will process that just fine.
+ continue
+ fi
+
+ if ! [ -d "/sys/class/net/$IFACE" ]; then
+ FAILED="$FAILED${FAILED:+ }$IFACE_PROTO"
+ fi
+done
+if [ -n "$FAILED" ]; then
+ echo "Could not apply resolv.conf to resolvectl: $FAILED" >&2
+fi
diff --git a/unbound.in b/systemd-resolved.in
copy from unbound.in
copy to systemd-resolved.in
--- a/unbound.in
+++ b/systemd-resolved.in
@@ -1,8 +1,8 @@
#!/bin/sh
-# Copyright (c) 2009-2016 Roy Marples
+# Copyright (c) 2025 Roy Marples
# All rights reserved
-# unbound subscriber for resolvconf
+# systemd-resolved subscriber for resolvconf
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -26,72 +26,71 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-unbound_insecure=
-
[ -f "@SYSCONFDIR@"/resolvconf.conf ] || exit 0
. "@SYSCONFDIR@/resolvconf.conf" || exit 1
-[ -z "$unbound_conf" ] && exit 0
-[ -z "$RESOLVCONF" ] && eval "$(@SBINDIR@/resolvconf -v)"
+
+case "${systemd_resolved:-NO}" in
+[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;;
+*) exit 0;;
+esac
+
+[ -n "$RESOLVCONF" ] || eval "$(@SBINDIR@/resolvconf -v)"
NL="
"
-: ${unbound_pid:=/var/run/unbound.pid}
-: ${unbound_service:=unbound}
-newconf="# Generated by resolvconf$NL"
+: ${systemd_resolved_conf:=/run/systemd/resolved.conf.d/60-resolvconf.conf}
+: ${systemd_delegate_dir:=/run/systemd/dns-delegate.d}
+# Try to ensure that config dirs exist
+if command -v config_mkdirs >/dev/null 2>&1; then
+ config_mkdirs "$systemd_resolved_conf" "$systemd_delegate_dir/x"
+else
+ @SBINDIR@/resolvconf -D "$systemd_resolved_conf" "$systemd_delegate_dir/x"
+fi
+
+header="# Generated by resolvconf$NL"
+header="${header}$NL"
+header="${header}[Resolve]$NL"
+
+conf="$header"
+# We emit blank values to force them to reset on SIGHUP
+conf="${conf}DNS=$NAMESERVERS$NL"
+# Indicate these nameservers are for all domain lookups by using ~.
+conf="${conf}Domains=$SEARCH${NAMESERVERS:+ ~.}$NL"
+
+printf %s "$conf" >"$systemd_resolved_conf"
+
+# DNS Delegates requires https://github.com/systemd/systemd/pull/34368
+rm -f "$systemd_delegate_dir/resolvconf-"*".dns-delegate"
+header="# Generated by resolvconf$NL"
+header="${header}$NL"
+header="${header}[Delegate]$NL"
for d in $DOMAINS; do
dn="${d%%:*}"
ns="${d#*:}"
- case "$unbound_insecure" in
- [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
- newconf="$newconf${NL}server:$NL"
- newconf="$newconf domain-insecure: \"$dn\"$NL"
- ;;
- esac
- newconf="$newconf${NL}forward-zone:$NL name: \"$dn\"$NL"
+ dconf="${header}Domains="
+ search=false
+ for sd in $SEARCH; do
+ if [ "$sd" = "$dn" ]; then
+ search=true
+ break
+ fi
+ done
+ if ! $search; then
+ dconf="${dconf}~"
+ fi
+ dconf="${dconf}$dn$NL"
+ dconf="${dconf}DNS="
while [ -n "$ns" ]; do
- newconf="$newconf forward-addr: ${ns%%,*}$NL"
+ dconf="$dconf${ns%%,*} "
[ "$ns" = "${ns#*,}" ] && break
ns="${ns#*,}"
done
+ dconf="$dconf$NL"
+ printf %s "$dconf" >"$systemd_delegate_dir/resolvconf-$dn.dns-delegate"
done
-if [ -n "$NAMESERVERS" ]; then
- newconf="$newconf${NL}forward-zone:$NL name: \".\"$NL"
- for n in $NAMESERVERS; do
- newconf="$newconf forward-addr: $n$NL"
- done
-fi
-
-# Try to ensure that config dirs exist
-if type config_mkdirs >/dev/null 2>&1; then
- config_mkdirs "$unbound_conf"
-else
- @SBINDIR@/resolvconf -D "$unbound_conf"
-fi
-
-restart_unbound()
-{
- if [ -n "$unbound_restart" ]; then
- eval $unbound_restart
- elif [ -n "$RESTARTCMD" ]; then
- set -- ${unbound_service}
- eval "$RESTARTCMD"
- else
- @SBINDIR@/resolvconf -r ${unbound_service}
- fi
-}
-
-if [ ! -f "$unbound_conf" ] || \
- [ "$(cat "$unbound_conf")" != "$(printf %s "$newconf")" ]
-then
- printf %s "$newconf" >"$unbound_conf"
- # If we can't sent a HUP then force a restart
- if [ -s "$unbound_pid" ]; then
- if ! kill -HUP $(cat "$unbound_pid") 2>/dev/null; then
- restart_unbound
- fi
- else
- restart_unbound
- fi
+pid=$(pidof systemd-resolved)
+if [ -n "$pid" ]; then
+ kill -HUP $pid
fi
diff --git a/unbound.in b/unbound.in
--- a/unbound.in
+++ b/unbound.in
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (c) 2009-2016 Roy Marples
+# Copyright (c) 2009-2023 Roy Marples
# All rights reserved
# unbound subscriber for resolvconf
@@ -27,6 +27,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
unbound_insecure=
+unbound_private=
[ -f "@SYSCONFDIR@"/resolvconf.conf ] || exit 0
. "@SYSCONFDIR@/resolvconf.conf" || exit 1
@@ -42,13 +43,29 @@
for d in $DOMAINS; do
dn="${d%%:*}"
ns="${d#*:}"
+ create_unbound_insecure=false
+ create_unbound_private=false
case "$unbound_insecure" in
[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
- newconf="$newconf${NL}server:$NL"
- newconf="$newconf domain-insecure: \"$dn\"$NL"
- ;;
+ create_unbound_insecure=true ;;
esac
+ case "$unbound_private" in
+ [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
+ create_unbound_private=true ;;
+ esac
+ if $create_unbound_insecure || $create_unbound_private; then
+ newconf="$newconf${NL}server:$NL"
+ if $create_unbound_insecure; then
+ newconf="$newconf domain-insecure: \"$dn\"$NL"
+ fi
+ if $create_unbound_private; then
+ newconf="$newconf private-domain: \"$dn\"$NL"
+ fi
+ fi
newconf="$newconf${NL}forward-zone:$NL name: \"$dn\"$NL"
+ if [ -n "$unbound_forward_zone_options" ]; then
+ newconf="$newconf $unbound_forward_zone_options${NL}"
+ fi
while [ -n "$ns" ]; do
newconf="$newconf forward-addr: ${ns%%,*}$NL"
[ "$ns" = "${ns#*,}" ] && break
@@ -58,13 +75,16 @@
if [ -n "$NAMESERVERS" ]; then
newconf="$newconf${NL}forward-zone:$NL name: \".\"$NL"
+ if [ -n "$unbound_forward_zone_options" ]; then
+ newconf="$newconf $unbound_forward_zone_options${NL}"
+ fi
for n in $NAMESERVERS; do
newconf="$newconf forward-addr: $n$NL"
done
fi
# Try to ensure that config dirs exist
-if type config_mkdirs >/dev/null 2>&1; then
+if command -v config_mkdirs >/dev/null 2>&1; then
config_mkdirs "$unbound_conf"
else
@SBINDIR@/resolvconf -D "$unbound_conf"
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Apr 13, 3:15 AM (14 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31391481
Default Alt Text
D56268.diff (78 KB)
Attached To
Mode
D56268: Import openresolv 3.17.4
Attached
Detach File
Event Timeline
Log In to Comment