Hi,

Yesterday I was messing with my network and particularily my workstation with
the goal of having an internal nameserver serve "internal.centroid.eu" zones
for my computers at home, and also do "168.192.in-addr.arpa" reverse.  I had
no luck diverting this from BIND, and then something unexpected happened to me.

I accidentally put the internal nameserver in the first nameserver entry of 
/etc/resolv.conf and it looked up the internal zones and replied "REFUSED"
on anything not configured on the nameserver.  The resolver in OpenBSD then
immediately switched to the second nameserver (not even a 1 ms latency) and
looked up the external address there.  Needless to say this does what I tried
to do with BIND.

Then came rebound into the picture and it doesn't do this, why?  Because
rebound only uses 1 nameserver entry in the config.  I did a quick hack around
rebound (please don't use it probably has memory problems) and determined that
it was able to do this with some code modification and if done in a style that
Ted uses it could fit in the code without sticking out too much.  So take my
hack as a proof-of-concept and it's just for show.

My ultimate question then is "why does the resolver do it this way?" was this
on purpose?  (probably a question for Eric).  I don't mind this and don't want
to instigate a "oh this is wrong" and then have someone change the behaviour...
Because it works for me without having to reconfigure the recursing nameserver.
And, I have a query log locally if I turn up logging on my authoritative name-
server, which can be good for analysis with scripts.

So the rebound patch is after my signature, it works but probably is not in
a style that openbsd wants in their code or that Ted would want in his code.
Take it as a proof of concept.  But... can we have something like that in 
rebound?  Otherwise rebound won't be used here.

-peter


Index: rebound.c
===================================================================
RCS file: /cvs/src/usr.sbin/rebound/rebound.c,v
retrieving revision 1.98
diff -u -p -u -r1.98 rebound.c
--- rebound.c   1 May 2018 15:14:43 -0000       1.98
+++ rebound.c   14 Jul 2018 05:03:07 -0000
@@ -52,6 +52,10 @@ union sockun {
        struct sockaddr_in6 i6;
 };
 
+struct cfg {
+       union sockun r[6];
+};
+
 static struct timespec now;
 static int debug;
 static int daemonized;
@@ -340,8 +344,9 @@ servfail(int ud, uint16_t id, struct soc
 }
 
 static struct request *
-newrequest(int ud, struct sockaddr *remoteaddr)
+newrequest(int ud, struct cfg *cfg)
 {
+       struct sockaddr *remoteaddr = &cfg->r->a;
        union sockun from;
        socklen_t fromlen;
        struct request *req;
@@ -369,6 +374,15 @@ newrequest(int ud, struct sockaddr *remo
 
        conntotal += 1;
        if (hit) {
+               if (hit->resp->flags & (0x8000 | 0x5)) { /* got a refused */
+                       struct cfg *ncfg = cfg;
+                       ncfg++;
+                       if (ncfg->r->a.sa_family != AF_INET ||
+                               ncfg->r->a.sa_family != AF_INET6)
+                               return NULL;
+
+                       return (newrequest(ud, ncfg));
+               }
                hit->resp->id = dnsreq->id;
                memcpy(hit->resp->qname, dnsreq->qname, namelen);
                sendto(ud, hit->resp, hit->resplen, 0, &from.a, fromlen);
@@ -560,8 +574,9 @@ fail:
 }
 
 static struct request *
-newtcprequest(int ld, struct sockaddr *remoteaddr)
+newtcprequest(int ld, struct cfg *cfg)
 {
+       struct sockaddr *remoteaddr = &cfg->r->a;
        struct request *req;
        int client;
 
@@ -719,16 +734,17 @@ preloadPTR(const char *ip, const char *n
 }
 
 static int
-readconfig(int conffd, union sockun *remoteaddr)
+readconfig(int conffd, struct cfg *cfg)
 {
        const char ns[] = "nameserver";
        const char rc[] = "record";
        char buf[1024];
        char *p;
-       struct sockaddr_in *sin = &remoteaddr->i;
-       struct sockaddr_in6 *sin6 = &remoteaddr->i6;
+       struct sockaddr_in *sin = &cfg[0].r->i;
+       struct sockaddr_in6 *sin6 = &cfg[0].r->i6;
        FILE *conf;
        int rv = -1;
+       int num_ns = 0;
 
        conf = fdopen(conffd, "r");
 
@@ -744,7 +760,10 @@ readconfig(int conffd, union sockun *rem
                        if (strcmp(p, "127.0.0.1") == 0)
                                continue;
 
-                       memset(remoteaddr, 0, sizeof(*remoteaddr));
+                       if (num_ns >= 5)
+                               continue;
+
+                       memset(&cfg[num_ns].r, 0, sizeof(union sockun));
                        if (inet_pton(AF_INET, p, &sin->sin_addr) == 1) {
                                sin->sin_len = sizeof(*sin);
                                sin->sin_family = AF_INET;
@@ -756,6 +775,9 @@ readconfig(int conffd, union sockun *rem
                                sin6->sin6_port = htons(53);
                                rv = AF_INET6;
                        }
+                       num_ns++;
+                       sin = &cfg[num_ns].r->i;
+                       sin6 = &cfg[num_ns].r->i6;
                } else if (strncmp(buf, rc, strlen(rc)) == 0) {
                        char rectype[16], name[256], value[256];
                        p = buf + strlen(rc) + 1;
@@ -819,7 +841,7 @@ workerinit(void)
 static int
 workerloop(int conffd, int ud, int ld, int ud6, int ld6)
 {
-       union sockun remoteaddr;
+       struct cfg cfg;
        struct kevent ch[2], kev[4];
        struct timespec ts, *timeout = NULL;
        struct request *req;
@@ -838,7 +860,8 @@ workerloop(int conffd, int ud, int ld, i
 
        workerinit();
 
-       af = readconfig(conffd, &remoteaddr);
+       memset(&cfg, 0, sizeof(cfg));
+       af = readconfig(conffd, &cfg);
        if (af == -1)
                logerr("parse error in config file");
 
@@ -899,13 +922,13 @@ workerloop(int conffd, int ud, int ld, i
                                break;
                        case EVFILT_READ:
                                if (ke->ident == ud || ke->ident == ud6) {
-                                       if ((req = newrequest(ke->ident, 
&remoteaddr.a))) {
+                                       if ((req = newrequest(ke->ident, 
&cfg))) {
                                                EV_SET(&ch[0], req->s, 
EVFILT_READ,
                                                    EV_ADD, 0, 0, req);
                                                kevent(kq, ch, 1, NULL, 0, 
NULL);
                                        }
                                } else if (ke->ident == ld || ke->ident == ld6) 
{
-                                       if ((req = newtcprequest(ke->ident, 
&remoteaddr.a))) {
+                                       if ((req = newtcprequest(ke->ident, 
&cfg))) {
                                                EV_SET(&ch[0], req->s,
                                                    req->tcp == 1 ? 
EVFILT_WRITE :
                                                    EVFILT_READ, EV_ADD, 0, 0, 
req);

Reply via email to