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) {

Reply via email to