So the plan is for rebound to be the 'system' resolver, with libc talking to rbeound and rebound talking to the cloud. The main wrinkle is how does rebound find the cloud? rebound.conf, but dhclient doesn't know anything about rebound.conf, preferring to edit resolv.conf. But if rebound reads resolv.conf, what does libc read? This has been a bit of a tangle until now, especially in scenarios like upgrades where rebound may not even be running.
And so I present the following diff to enable a smooth transition. It's 'quantum' because it works whether or not rebound is running. No need to open the box. 1. rebound reads resolv.conf. This remains the config file for upstream DNS. 2. libc now prepends its nameserver list with localhost, thus always searching for rebound. If it's not running, we just continue down the list. This covers the basic use case, where enabling rebound now requires no additional work. No need to edit dhclient.conf, etc. It also works on ramdisks. It also works with a mix of old and new binaries. Once you flip resolv.conf back to upstream, old binaries will bypass rebound, but that's ok. The new rebound checks to make sure it's not stuck in a time loop, which is never good. I also note this improves the situation for people who have been using unbound as a local cache, too. Just enable unbound and libc will use it automatically. Particular edge case: if resolv.conf has no nameservers, then the localhost default is not prepended. So libc won't try talking to rebound if it's specifically configured not to (chroot). Index: lib/libc/asr/asr.c =================================================================== RCS file: /cvs/src/lib/libc/asr/asr.c,v retrieving revision 1.54 diff -u -p -r1.54 asr.c --- lib/libc/asr/asr.c 18 Jun 2016 15:25:28 -0000 1.54 +++ lib/libc/asr/asr.c 15 Sep 2016 00:42:30 -0000 @@ -549,6 +549,15 @@ pass0(char **tok, int n, struct asr_ctx return; if (n != 2) return; + /* prepend localhost to list */ + if (ac->ac_nscount == 0) { + if (asr_parse_nameserver((struct sockaddr *)&ss, "127.0.0.1")) + return; + if ((ac->ac_ns[ac->ac_nscount] = calloc(1, ss.ss_len)) == NULL) + return; + memmove(ac->ac_ns[ac->ac_nscount], &ss, ss.ss_len); + ac->ac_nscount += 1; + } if (asr_parse_nameserver((struct sockaddr *)&ss, tok[1])) return; if ((ac->ac_ns[ac->ac_nscount] = calloc(1, ss.ss_len)) == NULL) Index: usr.sbin/rebound/rebound.8 =================================================================== RCS file: /cvs/src/usr.sbin/rebound/rebound.8,v retrieving revision 1.4 diff -u -p -r1.4 rebound.8 --- usr.sbin/rebound/rebound.8 4 Dec 2015 04:50:43 -0000 1.4 +++ usr.sbin/rebound/rebound.8 15 Sep 2016 00:57:21 -0000 @@ -33,9 +33,7 @@ The options are as follows: .Bl -tag -width Ds .It Fl c Ar config Specify an alternative configuration file, instead of the default -.Pa /etc/rebound.conf . -At present, the config file consists of a single line containing the next -hop DNS server. +.Pa /etc/resolv.conf . .Nm will reload the configuration file when sent a SIGHUP signal. .It Fl d @@ -46,8 +44,8 @@ does not into the background. .El .Sh FILES -.Bl -tag -width "/etc/rebound.confXX" -compact -.It Pa /etc/rebound.conf +.Bl -tag -width "/etc/resolv.confXX" -compact +.It Pa /etc/resolv.conf Default .Nm configuration file. Index: usr.sbin/rebound/rebound.c =================================================================== RCS file: /cvs/src/usr.sbin/rebound/rebound.c,v retrieving revision 1.70 diff -u -p -r1.70 rebound.c --- usr.sbin/rebound/rebound.c 1 Sep 2016 10:57:24 -0000 1.70 +++ usr.sbin/rebound/rebound.c 15 Sep 2016 00:53:26 -0000 @@ -37,6 +37,7 @@ #include <errno.h> #include <getopt.h> #include <stdarg.h> +#include <ctype.h> #define MINIMUM(a,b) (((a)<(b))?(a):(b)) @@ -457,28 +458,41 @@ fail: static int readconfig(FILE *conf, union sockun *remoteaddr) { + const char ns[] = "nameserver"; char buf[1024]; + char *p; struct sockaddr_in *sin = &remoteaddr->i; struct sockaddr_in6 *sin6 = &remoteaddr->i6; - if (fgets(buf, sizeof(buf), conf) == NULL) - return -1; - buf[strcspn(buf, "\n")] = '\0'; + while (fgets(buf, sizeof(buf), conf) != NULL) { + buf[strcspn(buf, "\n")] = '\0'; - memset(remoteaddr, 0, sizeof(*remoteaddr)); - if (inet_pton(AF_INET, buf, &sin->sin_addr) == 1) { - sin->sin_len = sizeof(*sin); - sin->sin_family = AF_INET; - sin->sin_port = htons(53); - return AF_INET; - } else if (inet_pton(AF_INET6, buf, &sin6->sin6_addr) == 1) { - sin6->sin6_len = sizeof(*sin6); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = htons(53); - return AF_INET6; - } else { - return -1; + if (strncmp(buf, ns, strlen(ns)) != 0) + continue; + p = buf + strlen(ns) + 1; + while (isspace((unsigned char)*p)) + p++; + + /* this will not end well */ + if (strcmp(p, "127.0.0.1") == 0) + continue; + + memset(remoteaddr, 0, sizeof(*remoteaddr)); + if (inet_pton(AF_INET, p, &sin->sin_addr) == 1) { + sin->sin_len = sizeof(*sin); + sin->sin_family = AF_INET; + sin->sin_port = htons(53); + return AF_INET; + } else if (inet_pton(AF_INET6, p, &sin6->sin6_addr) == 1) { + sin6->sin6_len = sizeof(*sin6); + sin6->sin6_family = AF_INET6; + sin6->sin6_port = htons(53); + return AF_INET6; + } else { + return -1; + } } + return -1; } static int @@ -665,7 +679,7 @@ main(int argc, char **argv) struct kevent kev; struct rlimit rlim; struct timespec ts, *timeout = NULL; - const char *confname = "/etc/rebound.conf"; + const char *confname = "/etc/resolv.conf"; FILE *conf; while ((ch = getopt(argc, argv, "c:d")) != -1) {