Ted Unangst wrote:
> 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.
> 
> Move the hijacking into the kernel. rebound sets a sysctl, and then the kernel
> gives it all the dns connections. libc knows nothing. if rebound dies, dns
> dies. still listening on :53 because it has to listen somewhere.

configurable jack port, rebound uses 54.


Index: sys/kern/kern_sysctl.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sysctl.c,v
retrieving revision 1.311
diff -u -p -r1.311 kern_sysctl.c
--- sys/kern/kern_sysctl.c      21 Sep 2016 14:06:50 -0000      1.311
+++ sys/kern/kern_sysctl.c      21 Sep 2016 16:06:16 -0000
@@ -598,6 +598,10 @@ kern_sysctl(int *name, u_int namelen, vo
                return sysctl_int(oldp, oldlenp, newp, newlen, &global_ptrace);
        }
 #endif
+       case KERN_DNSJACKING: {
+               extern int dnsjacking;
+               return sysctl_int(oldp, oldlenp, newp, newlen, &dnsjacking);
+       }
        default:
                return (EOPNOTSUPP);
        }
Index: sys/kern/uipc_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_syscalls.c,v
retrieving revision 1.133
diff -u -p -r1.133 uipc_syscalls.c
--- sys/kern/uipc_syscalls.c    9 Aug 2016 02:25:35 -0000       1.133
+++ sys/kern/uipc_syscalls.c    15 Sep 2016 22:32:55 -0000
@@ -67,6 +67,8 @@ extern        struct fileops socketops;
 int    copyaddrout(struct proc *, struct mbuf *, struct sockaddr *, socklen_t,
            socklen_t *);
 
+int dnsjacking = 0;
+
 int
 sys_socket(struct proc *p, void *v, register_t *retval)
 {
@@ -395,6 +397,16 @@ sys_connect(struct proc *p, void *v, reg
                        FRELE(fp, p);
                        m_freem(nam);
                        return (error);
+               }
+               if (dnsjacking) {
+                       struct sockaddr_in sin;
+                       memset(&sin, 0, sizeof(sin));
+                       sin.sin_len = sizeof(sin);
+                       sin.sin_family = AF_INET;
+                       sin.sin_port = htons(dnsjacking);
+                       sin.sin_addr.s_addr = INADDR_LOOPBACK;
+                       memcpy(mtod(nam, void *), &sin, sizeof(sin));
+                       nam->m_len = sizeof(sin);
                }
        }
 
Index: sys/sys/sysctl.h
===================================================================
RCS file: /cvs/src/sys/sys/sysctl.h,v
retrieving revision 1.166
diff -u -p -r1.166 sysctl.h
--- sys/sys/sysctl.h    21 Sep 2016 14:06:50 -0000      1.166
+++ sys/sys/sysctl.h    21 Sep 2016 16:06:16 -0000
@@ -113,7 +113,7 @@ struct ctlname {
 #define        KERN_HOSTNAME           10      /* string: hostname */
 #define        KERN_HOSTID             11      /* int: host identifier */
 #define        KERN_CLOCKRATE          12      /* struct: struct clockinfo */
-/* was KERN_VNODE              13      */
+#define        KERN_DNSJACKING         13      /* hijack dns sockets */
 /* was KERN_PROC               14      */
 /* was KERN_FILE               15      */
 #define        KERN_PROF               16      /* node: kernel profiling info 
*/
@@ -200,7 +200,7 @@ struct ctlname {
        { "hostname", CTLTYPE_STRING }, \
        { "hostid", CTLTYPE_INT }, \
        { "clockrate", CTLTYPE_STRUCT }, \
-       { "gap", 0 }, \
+       { "dnsjacking", CTLTYPE_INT }, \
        { "gap", 0 }, \
        { "gap", 0 }, \
        { "profiling", CTLTYPE_NODE }, \
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  29 Sep 2016 01:20:02 -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  29 Sep 2016 01:33:04 -0000
@@ -24,6 +24,7 @@
 #include <sys/resource.h>
 #include <sys/time.h>
 #include <sys/wait.h>
+#include <sys/sysctl.h>
 
 #include <signal.h>
 #include <syslog.h>
@@ -33,10 +34,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 +458,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 +510,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 +543,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 +663,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_ATTRIB, 0, NULL);
+               kevent(kq, &kev, 1, NULL, 0, NULL);
+       }
+       return conffd;
+}
+
 static void __dead
 usage(void)
 {
@@ -657,16 +690,16 @@ usage(void)
 int
 main(int argc, char **argv)
 {
+       int dnsjacking[2] = { CTL_KERN, KERN_DNSJACKING };
+       int jackport = 54;
        union sockun bindaddr;
-       int r, kq, ld, ud, ch;
-       int one;
-       int childdead, hupped;
+       int r, kq, ld, ud, ch, conffd;
+       int one = 1;
        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) {
@@ -708,7 +741,7 @@ main(int argc, char **argv)
        memset(&bindaddr, 0, sizeof(bindaddr));
        bindaddr.i.sin_len = sizeof(bindaddr.i);
        bindaddr.i.sin_family = AF_INET;
-       bindaddr.i.sin_port = htons(53);
+       bindaddr.i.sin_port = htons(jackport);
        inet_aton("127.0.0.1", &bindaddr.i.sin_addr);
 
        ud = socket(AF_INET, SOCK_DGRAM, 0);
@@ -720,23 +753,22 @@ main(int argc, char **argv)
        ld = socket(AF_INET, SOCK_STREAM, 0);
        if (ld == -1)
                logerr("socket: %s", strerror(errno));
-       one = 1;
        setsockopt(ld, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
        if (bind(ld, &bindaddr.a, bindaddr.a.sa_len) == -1)
                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);
-
+       sysctl(dnsjacking, 2, NULL, NULL, &jackport, sizeof(jackport));
+       
        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));
@@ -747,9 +779,12 @@ main(int argc, char **argv)
        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);
+               int hupped = 0;
+               int childdead = 0;
+       
+               conffd = openconfig(confname, kq);
+
+               child = launch(conffd, ud, ld);
                if (child == -1)
                        logerr("failed to launch");
 
@@ -767,6 +802,11 @@ 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");
+                               sleep(1);
+                               raise(SIGHUP);
                        } else if (kev.filter == EVFILT_SIGNAL) {
                                /* signaled. kill child. */
                                logmsg(LOG_INFO, "received HUP, restarting");
@@ -774,10 +814,6 @@ main(int argc, char **argv)
                                if (childdead)
                                        break;
                                kill(child, SIGHUP);
-                               conf = fopen(confname, "r");
-                               if (!conf)
-                                       logerr("failed to open config %s",
-                                           confname);
                        } else if (kev.filter == EVFILT_PROC) {
                                /* child died. wait for our own HUP. */
                                logmsg(LOG_INFO, "observed child exit");
@@ -791,6 +827,7 @@ main(int argc, char **argv)
                                logerr("don't know what happened");
                        }
                }
+               close(conffd);
                wait(NULL);
        }
        return 1;

Reply via email to