rebound quantum entanglement

classic Classic list List threaded Threaded
28 messages Options
12
Reply | Threaded
Open this post in threaded view
|

rebound quantum entanglement

Ted Unangst-6
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 | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Bob Beck-2
how is rebound going to handle a change in resolv.conf? thats still a
problem here

On Wednesday, 14 September 2016, Ted Unangst <[hidden email]> wrote:

> 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 | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Ted Unangst-6
Bob Beck wrote:
> how is rebound going to handle a change in resolv.conf? thats still a
> problem here

oh, that's easy. it watches the file for changes. i never quite got around to
that, but it's another five lines.

Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Bob Beck-2
wont this also mean if it is not running i have to wait for the localhost
attempt to fail before the resolver moves on? (ASR_STATE_NEXT_NS, etc) so i
slow everything down for a timeout?

dont get me wrong, it is an interesting direction, but I think maybe get
the rest of the five line changes into rebound to make it useful and then
look at libc which might need slightly more cleverness than just adding
localhost unconditionally.

On Wednesday, 14 September 2016, Ted Unangst <[hidden email]> wrote:

> Bob Beck wrote:
> > how is rebound going to handle a change in resolv.conf? thats still a
> > problem here
>
> oh, that's easy. it watches the file for changes. i never quite got around
> to
> that, but it's another five lines.
>
Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Theo de Raadt-2
> wont this also mean if it is not running i have to wait for the localhost
> attempt to fail before the resolver moves on? (ASR_STATE_NEXT_NS, etc) so i
> slow everything down for a timeout?

i think that is right.

ktrace would show what is going on.

if it stalls, this is not enough.


Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Todd C. Miller
In reply to this post by Bob Beck-2
On Wed, 14 Sep 2016 20:00:32 -0600, Bob Beck wrote:

> wont this also mean if it is not running i have to wait for the localhost
> attempt to fail before the resolver moves on? (ASR_STATE_NEXT_NS, etc) so i
> slow everything down for a timeout?

Not if he connects to the TCP port 53 instead of the UDP; it looks like
rebound binds to both.

 - todd

Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Theo de Raadt-2
> > wont this also mean if it is not running i have to wait for the localhost
> > attempt to fail before the resolver moves on? (ASR_STATE_NEXT_NS, etc) so i
> > slow everything down for a timeout?
>
> Not if he connects to the TCP port 53 instead of the UDP; it looks like
> rebound binds to both.

OK.  But I suspect this is multiple system-call roundtrip for everyone
not running rebound.

Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Ted Unangst-6
In reply to this post by Bob Beck-2
Bob Beck wrote:
> wont this also mean if it is not running i have to wait for the localhost
> attempt to fail before the resolver moves on? (ASR_STATE_NEXT_NS, etc) so i
> slow everything down for a timeout?

you get back unreachable and move on. it's fast. you can try it. :)

Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Ted Unangst-6
In reply to this post by Ted Unangst-6
Ted Unangst wrote:
> Bob Beck wrote:
> > how is rebound going to handle a change in resolv.conf? thats still a
> > problem here
>
> oh, that's easy. it watches the file for changes. i never quite got around to
> that, but it's another five lines.

ok, so it's a net +15 lines, including blanks.

Index: rebound.8
===================================================================
RCS file: /cvs/src/usr.sbin/rebound/rebound.8,v
retrieving revision 1.4
diff -u -p -r1.4 rebound.8
--- rebound.8 4 Dec 2015 04:50:43 -0000 1.4
+++ 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: rebound.c
===================================================================
RCS file: /cvs/src/usr.sbin/rebound/rebound.c,v
retrieving revision 1.70
diff -u -p -r1.70 rebound.c
--- rebound.c 1 Sep 2016 10:57:24 -0000 1.70
+++ rebound.c 15 Sep 2016 02:30:46 -0000
@@ -33,10 +33,12 @@
 #include <string.h>
 #include <err.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <pwd.h>
 #include <errno.h>
 #include <getopt.h>
 #include <stdarg.h>
+#include <ctype.h>
 
 #define MINIMUM(a,b) (((a)<(b))?(a):(b))
 
@@ -455,34 +457,51 @@ fail:
 }
 
 static int
-readconfig(FILE *conf, union sockun *remoteaddr)
+readconfig(int conffd, union sockun *remoteaddr)
 {
+ const char ns[] = "nameserver";
  char buf[1024];
+ char *p;
  struct sockaddr_in *sin = &remoteaddr->i;
  struct sockaddr_in6 *sin6 = &remoteaddr->i6;
+ FILE *conf;
+ int rv = -1;
 
- if (fgets(buf, sizeof(buf), conf) == NULL)
- return -1;
- buf[strcspn(buf, "\n")] = '\0';
+ conf = fdopen(conffd, "r");
 
- 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;
+ while (fgets(buf, sizeof(buf), conf) != NULL) {
+ buf[strcspn(buf, "\n")] = '\0';
+
+ 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);
+ rv = 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);
+ rv = AF_INET6;
+ }
+ break;
  }
+ fclose(conf);
+ return rv;
 }
 
 static int
-launch(FILE *conf, int ud, int ld, int kq)
+launch(int conffd, int ud, int ld)
 {
  union sockun remoteaddr;
  struct kevent ch[2], kev[4];
@@ -490,16 +509,13 @@ launch(FILE *conf, int ud, int ld, int k
  struct request *req;
  struct dnscache *ent;
  struct passwd *pwd;
- int i, r, af;
+ int i, r, af, kq;
  pid_t parent, child;
 
  parent = getpid();
  if (!debug) {
- if ((child = fork())) {
- fclose(conf);
+ if ((child = fork()))
  return child;
- }
- close(kq);
  }
 
  kq = kqueue();
@@ -526,8 +542,7 @@ launch(FILE *conf, int ud, int ld, int k
  if (pledge("stdio inet", NULL) == -1)
  logerr("pledge failed");
 
- af = readconfig(conf, &remoteaddr);
- fclose(conf);
+ af = readconfig(conffd, &remoteaddr);
  if (af == -1)
  logerr("parse error in config file");
 
@@ -647,6 +662,23 @@ launch(FILE *conf, int ud, int ld, int k
  exit(1);
 }
 
+static int
+openconfig(const char *confname, int kq)
+{
+ struct kevent kev;
+ int conffd;
+
+ conffd = open(confname, O_RDONLY);
+ if (conffd == -1)
+ logerr("failed to open config %s", confname);
+ if (kq != -1) {
+ EV_SET(&kev, conffd, EVFILT_VNODE, EV_ADD,
+    NOTE_DELETE | NOTE_WRITE | NOTE_ATTRIB, 0, NULL);
+ kevent(kq, &kev, 1, NULL, 0, NULL);
+ }
+ return conffd;
+}
+
 static void __dead
 usage(void)
 {
@@ -658,15 +690,14 @@ int
 main(int argc, char **argv)
 {
  union sockun bindaddr;
- int r, kq, ld, ud, ch;
+ int r, kq, ld, ud, ch, conffd;
  int one;
  int childdead, hupped;
  pid_t child;
  struct kevent kev;
  struct rlimit rlim;
  struct timespec ts, *timeout = NULL;
- const char *confname = "/etc/rebound.conf";
- FILE *conf;
+ const char *confname = "/etc/resolv.conf";
 
  while ((ch = getopt(argc, argv, "c:d")) != -1) {
  switch (ch) {
@@ -726,17 +757,15 @@ main(int argc, char **argv)
  logerr("bind: %s", strerror(errno));
  if (listen(ld, 10) == -1)
  logerr("listen: %s", strerror(errno));
-
- conf = fopen(confname, "r");
- if (!conf)
- logerr("failed to open config %s", confname);
-
+
  signal(SIGPIPE, SIG_IGN);
  signal(SIGUSR1, SIG_IGN);
  signal(SIGHUP, SIG_IGN);
 
- if (debug)
- return launch(conf, ud, ld, -1);
+ if (debug) {
+ conffd = openconfig(confname, -1);
+ return launch(conffd, ud, ld);
+ }
 
  if (daemon(0, 0) == -1)
  logerr("daemon: %s", strerror(errno));
@@ -744,12 +773,14 @@ main(int argc, char **argv)
 
  kq = kqueue();
 
+ conffd = openconfig(confname, kq);
+
  EV_SET(&kev, SIGHUP, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
  kevent(kq, &kev, 1, NULL, 0, NULL);
  while (1) {
  hupped = 0;
  childdead = 0;
- child = launch(conf, ud, ld, kq);
+ child = launch(conffd, ud, ld);
  if (child == -1)
  logerr("failed to launch");
 
@@ -767,6 +798,12 @@ main(int argc, char **argv)
  if (r == 0) {
  /* timeout expired */
  logerr("child died without HUP");
+ } else if (kev.filter == EVFILT_VNODE) {
+ /* config file changed */
+ logmsg(LOG_INFO, "config changed, reloading");
+ close(conffd);
+ sleep(1);
+ raise(SIGHUP);
  } else if (kev.filter == EVFILT_SIGNAL) {
  /* signaled. kill child. */
  logmsg(LOG_INFO, "received HUP, restarting");
@@ -774,10 +811,7 @@ main(int argc, char **argv)
  if (childdead)
  break;
  kill(child, SIGHUP);
- conf = fopen(confname, "r");
- if (!conf)
- logerr("failed to open config %s",
-    confname);
+ conffd = openconfig(confname, kq);
  } else if (kev.filter == EVFILT_PROC) {
  /* child died. wait for our own HUP. */
  logmsg(LOG_INFO, "observed child exit");

Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Bob Beck-2
Yep.  and now you need to solve the problem that when prepending 127.0.0.1,
and hitting rebound, which in turn is going to only grab the first dns
server from my resolv.conf instead of all of them, that it now doubles my
failure time when the first dns server doesn't respond (once for libc
asking rebound, which asks only the first server it found, which fails)
then falls back to libc asking resolv.conf which again... asks the first
server, and fails again.

So the problem here is that it's going to be great when things are working
but become a failure multiplier when something breaks.

Of course - perhaps you could query them all in parallel to mitigate this?
  Rebound might need to become a real boy if we're going to do something
like this.  If rebound were a "real boy" it would be it easier to say "just
use rebound or if it's not there just use resolv.conf normally

then nothing changes at *all* when it's not there.


On Wed, Sep 14, 2016 at 8:39 PM, Ted Unangst <[hidden email]> wrote:

> Ted Unangst wrote:
> > Bob Beck wrote:
> > > how is rebound going to handle a change in resolv.conf? thats still a
> > > problem here
> >
> > oh, that's easy. it watches the file for changes. i never quite got
> around to
> > that, but it's another five lines.
>
> ok, so it's a net +15 lines, including blanks.
>
> Index: rebound.8
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rebound/rebound.8,v
> retrieving revision 1.4
> diff -u -p -r1.4 rebound.8
> --- rebound.8   4 Dec 2015 04:50:43 -0000       1.4
> +++ 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: rebound.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/rebound/rebound.c,v
> retrieving revision 1.70
> diff -u -p -r1.70 rebound.c
> --- rebound.c   1 Sep 2016 10:57:24 -0000       1.70
> +++ rebound.c   15 Sep 2016 02:30:46 -0000
> @@ -33,10 +33,12 @@
>  #include <string.h>
>  #include <err.h>
>  #include <unistd.h>
> +#include <fcntl.h>
>  #include <pwd.h>
>  #include <errno.h>
>  #include <getopt.h>
>  #include <stdarg.h>
> +#include <ctype.h>
>
>  #define MINIMUM(a,b) (((a)<(b))?(a):(b))
>
> @@ -455,34 +457,51 @@ fail:
>  }
>
>  static int
> -readconfig(FILE *conf, union sockun *remoteaddr)
> +readconfig(int conffd, union sockun *remoteaddr)
>  {
> +       const char ns[] = "nameserver";
>         char buf[1024];
> +       char *p;
>         struct sockaddr_in *sin = &remoteaddr->i;
>         struct sockaddr_in6 *sin6 = &remoteaddr->i6;
> +       FILE *conf;
> +       int rv = -1;
>
> -       if (fgets(buf, sizeof(buf), conf) == NULL)
> -               return -1;
> -       buf[strcspn(buf, "\n")] = '\0';
> +       conf = fdopen(conffd, "r");
>
> -       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;
> +       while (fgets(buf, sizeof(buf), conf) != NULL) {
> +               buf[strcspn(buf, "\n")] = '\0';
> +
> +               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);
> +                       rv = 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);
> +                       rv = AF_INET6;
> +               }
> +               break;
>         }
> +       fclose(conf);
> +       return rv;
>  }
>
>  static int
> -launch(FILE *conf, int ud, int ld, int kq)
> +launch(int conffd, int ud, int ld)
>  {
>         union sockun remoteaddr;
>         struct kevent ch[2], kev[4];
> @@ -490,16 +509,13 @@ launch(FILE *conf, int ud, int ld, int k
>         struct request *req;
>         struct dnscache *ent;
>         struct passwd *pwd;
> -       int i, r, af;
> +       int i, r, af, kq;
>         pid_t parent, child;
>
>         parent = getpid();
>         if (!debug) {
> -               if ((child = fork())) {
> -                       fclose(conf);
> +               if ((child = fork()))
>                         return child;
> -               }
> -               close(kq);
>         }
>
>         kq = kqueue();
> @@ -526,8 +542,7 @@ launch(FILE *conf, int ud, int ld, int k
>         if (pledge("stdio inet", NULL) == -1)
>                 logerr("pledge failed");
>
> -       af = readconfig(conf, &remoteaddr);
> -       fclose(conf);
> +       af = readconfig(conffd, &remoteaddr);
>         if (af == -1)
>                 logerr("parse error in config file");
>
> @@ -647,6 +662,23 @@ launch(FILE *conf, int ud, int ld, int k
>         exit(1);
>  }
>
> +static int
> +openconfig(const char *confname, int kq)
> +{
> +       struct kevent kev;
> +       int conffd;
> +
> +       conffd = open(confname, O_RDONLY);
> +       if (conffd == -1)
> +               logerr("failed to open config %s", confname);
> +       if (kq != -1) {
> +               EV_SET(&kev, conffd, EVFILT_VNODE, EV_ADD,
> +                   NOTE_DELETE | NOTE_WRITE | NOTE_ATTRIB, 0, NULL);
> +               kevent(kq, &kev, 1, NULL, 0, NULL);
> +       }
> +       return conffd;
> +}
> +
>  static void __dead
>  usage(void)
>  {
> @@ -658,15 +690,14 @@ int
>  main(int argc, char **argv)
>  {
>         union sockun bindaddr;
> -       int r, kq, ld, ud, ch;
> +       int r, kq, ld, ud, ch, conffd;
>         int one;
>         int childdead, hupped;
>         pid_t child;
>         struct kevent kev;
>         struct rlimit rlim;
>         struct timespec ts, *timeout = NULL;
> -       const char *confname = "/etc/rebound.conf";
> -       FILE *conf;
> +       const char *confname = "/etc/resolv.conf";
>
>         while ((ch = getopt(argc, argv, "c:d")) != -1) {
>                 switch (ch) {
> @@ -726,17 +757,15 @@ main(int argc, char **argv)
>                 logerr("bind: %s", strerror(errno));
>         if (listen(ld, 10) == -1)
>                 logerr("listen: %s", strerror(errno));
> -
> -       conf = fopen(confname, "r");
> -       if (!conf)
> -               logerr("failed to open config %s", confname);
> -
> +
>         signal(SIGPIPE, SIG_IGN);
>         signal(SIGUSR1, SIG_IGN);
>         signal(SIGHUP, SIG_IGN);
>
> -       if (debug)
> -               return launch(conf, ud, ld, -1);
> +       if (debug) {
> +               conffd = openconfig(confname, -1);
> +               return launch(conffd, ud, ld);
> +       }
>
>         if (daemon(0, 0) == -1)
>                 logerr("daemon: %s", strerror(errno));
> @@ -744,12 +773,14 @@ main(int argc, char **argv)
>
>         kq = kqueue();
>
> +       conffd = openconfig(confname, kq);
> +
>         EV_SET(&kev, SIGHUP, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
>         kevent(kq, &kev, 1, NULL, 0, NULL);
>         while (1) {
>                 hupped = 0;
>                 childdead = 0;
> -               child = launch(conf, ud, ld, kq);
> +               child = launch(conffd, ud, ld);
>                 if (child == -1)
>                         logerr("failed to launch");
>
> @@ -767,6 +798,12 @@ main(int argc, char **argv)
>                         if (r == 0) {
>                                 /* timeout expired */
>                                 logerr("child died without HUP");
> +                       } else if (kev.filter == EVFILT_VNODE) {
> +                               /* config file changed */
> +                               logmsg(LOG_INFO, "config changed,
> reloading");
> +                               close(conffd);
> +                               sleep(1);
> +                               raise(SIGHUP);
>                         } else if (kev.filter == EVFILT_SIGNAL) {
>                                 /* signaled. kill child. */
>                                 logmsg(LOG_INFO, "received HUP,
> restarting");
> @@ -774,10 +811,7 @@ main(int argc, char **argv)
>                                 if (childdead)
>                                         break;
>                                 kill(child, SIGHUP);
> -                               conf = fopen(confname, "r");
> -                               if (!conf)
> -                                       logerr("failed to open config %s",
> -                                           confname);
> +                               conffd = openconfig(confname, kq);
>                         } else if (kev.filter == EVFILT_PROC) {
>                                 /* child died. wait for our own HUP. */
>                                 logmsg(LOG_INFO, "observed child exit");
>
Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Bob Beck-2
BTW I'm not picking on you.. my DNS setup blew up this week for local
resolution and I've been dealing with the fallout - so the topic
is relatively near and dear to my heart.

On Wed, Sep 14, 2016 at 10:07 PM, Bob Beck <[hidden email]> wrote:

>
> Yep.  and now you need to solve the problem that when prepending
> 127.0.0.1, and hitting rebound, which in turn is going to only grab the
> first dns server from my resolv.conf instead of all of them, that it now
> doubles my failure time when the first dns server doesn't respond (once for
> libc asking rebound, which asks only the first server it found, which
> fails) then falls back to libc asking resolv.conf which again... asks the
> first server, and fails again.
>
> So the problem here is that it's going to be great when things are working
> but become a failure multiplier when something breaks.
>
> Of course - perhaps you could query them all in parallel to mitigate this?
>   Rebound might need to become a real boy if we're going to do something
> like this.  If rebound were a "real boy" it would be it easier to say "just
> use rebound or if it's not there just use resolv.conf normally
>
> then nothing changes at *all* when it's not there.
>
>
> On Wed, Sep 14, 2016 at 8:39 PM, Ted Unangst <[hidden email]> wrote:
>
>> Ted Unangst wrote:
>> > Bob Beck wrote:
>> > > how is rebound going to handle a change in resolv.conf? thats still a
>> > > problem here
>> >
>> > oh, that's easy. it watches the file for changes. i never quite got
>> around to
>> > that, but it's another five lines.
>>
>> ok, so it's a net +15 lines, including blanks.
>>
>> Index: rebound.8
>> ===================================================================
>> RCS file: /cvs/src/usr.sbin/rebound/rebound.8,v
>> retrieving revision 1.4
>> diff -u -p -r1.4 rebound.8
>> --- rebound.8   4 Dec 2015 04:50:43 -0000       1.4
>> +++ 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: rebound.c
>> ===================================================================
>> RCS file: /cvs/src/usr.sbin/rebound/rebound.c,v
>> retrieving revision 1.70
>> diff -u -p -r1.70 rebound.c
>> --- rebound.c   1 Sep 2016 10:57:24 -0000       1.70
>> +++ rebound.c   15 Sep 2016 02:30:46 -0000
>> @@ -33,10 +33,12 @@
>>  #include <string.h>
>>  #include <err.h>
>>  #include <unistd.h>
>> +#include <fcntl.h>
>>  #include <pwd.h>
>>  #include <errno.h>
>>  #include <getopt.h>
>>  #include <stdarg.h>
>> +#include <ctype.h>
>>
>>  #define MINIMUM(a,b) (((a)<(b))?(a):(b))
>>
>> @@ -455,34 +457,51 @@ fail:
>>  }
>>
>>  static int
>> -readconfig(FILE *conf, union sockun *remoteaddr)
>> +readconfig(int conffd, union sockun *remoteaddr)
>>  {
>> +       const char ns[] = "nameserver";
>>         char buf[1024];
>> +       char *p;
>>         struct sockaddr_in *sin = &remoteaddr->i;
>>         struct sockaddr_in6 *sin6 = &remoteaddr->i6;
>> +       FILE *conf;
>> +       int rv = -1;
>>
>> -       if (fgets(buf, sizeof(buf), conf) == NULL)
>> -               return -1;
>> -       buf[strcspn(buf, "\n")] = '\0';
>> +       conf = fdopen(conffd, "r");
>>
>> -       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;
>> +       while (fgets(buf, sizeof(buf), conf) != NULL) {
>> +               buf[strcspn(buf, "\n")] = '\0';
>> +
>> +               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);
>> +                       rv = 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);
>> +                       rv = AF_INET6;
>> +               }
>> +               break;
>>         }
>> +       fclose(conf);
>> +       return rv;
>>  }
>>
>>  static int
>> -launch(FILE *conf, int ud, int ld, int kq)
>> +launch(int conffd, int ud, int ld)
>>  {
>>         union sockun remoteaddr;
>>         struct kevent ch[2], kev[4];
>> @@ -490,16 +509,13 @@ launch(FILE *conf, int ud, int ld, int k
>>         struct request *req;
>>         struct dnscache *ent;
>>         struct passwd *pwd;
>> -       int i, r, af;
>> +       int i, r, af, kq;
>>         pid_t parent, child;
>>
>>         parent = getpid();
>>         if (!debug) {
>> -               if ((child = fork())) {
>> -                       fclose(conf);
>> +               if ((child = fork()))
>>                         return child;
>> -               }
>> -               close(kq);
>>         }
>>
>>         kq = kqueue();
>> @@ -526,8 +542,7 @@ launch(FILE *conf, int ud, int ld, int k
>>         if (pledge("stdio inet", NULL) == -1)
>>                 logerr("pledge failed");
>>
>> -       af = readconfig(conf, &remoteaddr);
>> -       fclose(conf);
>> +       af = readconfig(conffd, &remoteaddr);
>>         if (af == -1)
>>                 logerr("parse error in config file");
>>
>> @@ -647,6 +662,23 @@ launch(FILE *conf, int ud, int ld, int k
>>         exit(1);
>>  }
>>
>> +static int
>> +openconfig(const char *confname, int kq)
>> +{
>> +       struct kevent kev;
>> +       int conffd;
>> +
>> +       conffd = open(confname, O_RDONLY);
>> +       if (conffd == -1)
>> +               logerr("failed to open config %s", confname);
>> +       if (kq != -1) {
>> +               EV_SET(&kev, conffd, EVFILT_VNODE, EV_ADD,
>> +                   NOTE_DELETE | NOTE_WRITE | NOTE_ATTRIB, 0, NULL);
>> +               kevent(kq, &kev, 1, NULL, 0, NULL);
>> +       }
>> +       return conffd;
>> +}
>> +
>>  static void __dead
>>  usage(void)
>>  {
>> @@ -658,15 +690,14 @@ int
>>  main(int argc, char **argv)
>>  {
>>         union sockun bindaddr;
>> -       int r, kq, ld, ud, ch;
>> +       int r, kq, ld, ud, ch, conffd;
>>         int one;
>>         int childdead, hupped;
>>         pid_t child;
>>         struct kevent kev;
>>         struct rlimit rlim;
>>         struct timespec ts, *timeout = NULL;
>> -       const char *confname = "/etc/rebound.conf";
>> -       FILE *conf;
>> +       const char *confname = "/etc/resolv.conf";
>>
>>         while ((ch = getopt(argc, argv, "c:d")) != -1) {
>>                 switch (ch) {
>> @@ -726,17 +757,15 @@ main(int argc, char **argv)
>>                 logerr("bind: %s", strerror(errno));
>>         if (listen(ld, 10) == -1)
>>                 logerr("listen: %s", strerror(errno));
>> -
>> -       conf = fopen(confname, "r");
>> -       if (!conf)
>> -               logerr("failed to open config %s", confname);
>> -
>> +
>>         signal(SIGPIPE, SIG_IGN);
>>         signal(SIGUSR1, SIG_IGN);
>>         signal(SIGHUP, SIG_IGN);
>>
>> -       if (debug)
>> -               return launch(conf, ud, ld, -1);
>> +       if (debug) {
>> +               conffd = openconfig(confname, -1);
>> +               return launch(conffd, ud, ld);
>> +       }
>>
>>         if (daemon(0, 0) == -1)
>>                 logerr("daemon: %s", strerror(errno));
>> @@ -744,12 +773,14 @@ main(int argc, char **argv)
>>
>>         kq = kqueue();
>>
>> +       conffd = openconfig(confname, kq);
>> +
>>         EV_SET(&kev, SIGHUP, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
>>         kevent(kq, &kev, 1, NULL, 0, NULL);
>>         while (1) {
>>                 hupped = 0;
>>                 childdead = 0;
>> -               child = launch(conf, ud, ld, kq);
>> +               child = launch(conffd, ud, ld);
>>                 if (child == -1)
>>                         logerr("failed to launch");
>>
>> @@ -767,6 +798,12 @@ main(int argc, char **argv)
>>                         if (r == 0) {
>>                                 /* timeout expired */
>>                                 logerr("child died without HUP");
>> +                       } else if (kev.filter == EVFILT_VNODE) {
>> +                               /* config file changed */
>> +                               logmsg(LOG_INFO, "config changed,
>> reloading");
>> +                               close(conffd);
>> +                               sleep(1);
>> +                               raise(SIGHUP);
>>                         } else if (kev.filter == EVFILT_SIGNAL) {
>>                                 /* signaled. kill child. */
>>                                 logmsg(LOG_INFO, "received HUP,
>> restarting");
>> @@ -774,10 +811,7 @@ main(int argc, char **argv)
>>                                 if (childdead)
>>                                         break;
>>                                 kill(child, SIGHUP);
>> -                               conf = fopen(confname, "r");
>> -                               if (!conf)
>> -                                       logerr("failed to open config %s",
>> -                                           confname);
>> +                               conffd = openconfig(confname, kq);
>>                         } else if (kev.filter == EVFILT_PROC) {
>>                                 /* child died. wait for our own HUP. */
>>                                 logmsg(LOG_INFO, "observed child exit");
>>
>
>
Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Erling Westenvik-2
In reply to this post by Ted Unangst-6
On Wed, Sep 14, 2016 at 09:19:07PM -0400, Ted Unangst wrote:
> 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.

I'm sure there's a cat(ch)...

--
Erling Westenvik

Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Remi Locherer
In reply to this post by Theo de Raadt-2
On Wed, Sep 14, 2016 at 08:10:29PM -0600, Theo de Raadt wrote:
> > > wont this also mean if it is not running i have to wait for the localhost
> > > attempt to fail before the resolver moves on? (ASR_STATE_NEXT_NS, etc) so i
> > > slow everything down for a timeout?
> >
> > Not if he connects to the TCP port 53 instead of the UDP; it looks like
> > rebound binds to both.
>
> OK.  But I suspect this is multiple system-call roundtrip for everyone
> not running rebound.

What about this:

Add "rebound" as possible value to the lookup keyword in resolv.conf.
If this is set the libc resolver sends dns requests to the unix socket
/var/run/rebound.sock where rebound listens. rebound can use the
nameservers from /etc/resolv.conf without the risk of creating "loops".

Remi

Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Stuart Henderson
On 2016/09/15 10:39, Remi Locherer wrote:

> On Wed, Sep 14, 2016 at 08:10:29PM -0600, Theo de Raadt wrote:
> > > > wont this also mean if it is not running i have to wait for the localhost
> > > > attempt to fail before the resolver moves on? (ASR_STATE_NEXT_NS, etc) so i
> > > > slow everything down for a timeout?
> > >
> > > Not if he connects to the TCP port 53 instead of the UDP; it looks like
> > > rebound binds to both.
> >
> > OK.  But I suspect this is multiple system-call roundtrip for everyone
> > not running rebound.
>
> What about this:
>
> Add "rebound" as possible value to the lookup keyword in resolv.conf.
> If this is set the libc resolver sends dns requests to the unix socket
> /var/run/rebound.sock where rebound listens. rebound can use the
> nameservers from /etc/resolv.conf without the risk of creating "loops".
>
> Remi
>

Non-standard things in resolv.conf hurt; some programs parse this directly.

Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Remi Locherer
On Thu, Sep 15, 2016 at 10:04:00AM +0100, Stuart Henderson wrote:

> On 2016/09/15 10:39, Remi Locherer wrote:
> > On Wed, Sep 14, 2016 at 08:10:29PM -0600, Theo de Raadt wrote:
> > > > > wont this also mean if it is not running i have to wait for the localhost
> > > > > attempt to fail before the resolver moves on? (ASR_STATE_NEXT_NS, etc) so i
> > > > > slow everything down for a timeout?
> > > >
> > > > Not if he connects to the TCP port 53 instead of the UDP; it looks like
> > > > rebound binds to both.
> > >
> > > OK.  But I suspect this is multiple system-call roundtrip for everyone
> > > not running rebound.
> >
> > What about this:
> >
> > Add "rebound" as possible value to the lookup keyword in resolv.conf.
> > If this is set the libc resolver sends dns requests to the unix socket
> > /var/run/rebound.sock where rebound listens. rebound can use the
> > nameservers from /etc/resolv.conf without the risk of creating "loops".
> >
> > Remi
> >
>
> Non-standard things in resolv.conf hurt; some programs parse this directly.

I did not think of this. Was there a big fallout in 2009 when the family
option was added? How do programs that parse /etc/resolv.conf directly deal
with "lookup yp"? (I know, lookup yp hase been removed recently).

Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Florian Obser-2
In reply to this post by Ted Unangst-6
On Wed, Sep 14, 2016 at 09:19:07PM -0400, Ted Unangst wrote:

> 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.

Not everything listening on localhost port 53 is a recursive resolver.
nsd(8) per defaults listens on 0.0.0.0 and will respond with REFUSED for
almost every query. asr stops in that case and does not try the next
resolver in the list.

--
I'm not entirely sure you are real.

Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Ted Unangst-6
Florian Obser wrote:
> Not everything listening on localhost port 53 is a recursive resolver.
> nsd(8) per defaults listens on 0.0.0.0 and will respond with REFUSED for
> almost every query. asr stops in that case and does not try the next
> resolver in the list.

Ah! There's the catch. The good news is I think we can still bind to
localhost:53 if nsd is on *:53 (right?). This matters if rebound isn't
listening.

Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Henning Brauer-7
* Ted Unangst <[hidden email]> [2016-09-15 16:15]:
> The good news is I think we can still bind to
> localhost:53 if nsd is on *:53 (right?).

right.

--
Henning Brauer, [hidden email], [hidden email]
BS Web Services GmbH, http://bsws.de, Full-Service ISP
Secure Hosting, Mail and DNS. Virtual & Dedicated Servers, Root to Fully Managed
Henning Brauer Consulting, http://henningbrauer.com/

Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Bryan Steele-2
In reply to this post by Ted Unangst-6
On Thu, Sep 15, 2016 at 10:14:51AM -0400, Ted Unangst wrote:
> Florian Obser wrote:
> > Not everything listening on localhost port 53 is a recursive resolver.
> > nsd(8) per defaults listens on 0.0.0.0 and will respond with REFUSED for
> > almost every query. asr stops in that case and does not try the next
> > resolver in the list.
>
> Ah! There's the catch. The good news is I think we can still bind to
> localhost:53 if nsd is on *:53 (right?). This matters if rebound isn't
> listening.

Perhaps I'm confused, but what happens when rebound is stopped by the
user or it crashes? I think that would mean requests would fallback to
nsd on *:53 which as Florian mentioned, would not try the next
nameserver in resolv.conf.

-Bryan.

Reply | Threaded
Open this post in threaded view
|

Re: rebound quantum entanglement

Stuart Henderson
In reply to this post by Remi Locherer
On 2016/09/15 06:23, Jiri B wrote:

> On Thu, Sep 15, 2016 at 10:04:00AM +0100, Stuart Henderson wrote:
> > > What about this:
> > >
> > > Add "rebound" as possible value to the lookup keyword in resolv.conf.
> > > If this is set the libc resolver sends dns requests to the unix socket
> > > /var/run/rebound.sock where rebound listens. rebound can use the
> > > nameservers from /etc/resolv.conf without the risk of creating "loops".
> > >
> > > Remi
> > >
> >
> > Non-standard things in resolv.conf hurt; some programs parse this directly.
>
> Why not having rebound as proxy and use PF anchor for that?
> Or having a sysctl knob to "hijack" it somehow?

There are certainly plenty of use cases where having it as
a hijacking proxy would be a problem (for example, when you want
to do a direct DNS lookup from an auth server).

On 2016/09/15 13:42, Remi Locherer wrote:
> On Thu, Sep 15, 2016 at 10:04:00AM +0100, Stuart Henderson wrote:
> >
> > Non-standard things in resolv.conf hurt; some programs parse this directly.
>
> I did not think of this. Was there a big fallout in 2009 when the family
> option was added? How do programs that parse /etc/resolv.conf directly deal
> with "lookup yp"? (I know, lookup yp hase been removed recently).

Not sure about "family". There were definitely problems with the
extension to allow using a particular port.

12