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");