On Sun, Jul 19, 2015 at 03:31:33PM +0000, Florian Obser wrote:
> [...]
> Oh god, yes please. I always wanted to write this diff myself ;)
> More comments in the diff below.
> [...]

Great to read. I've attached an updated patch.

-- 
        Gregor Best

Index: clparse.c
===================================================================
RCS file: /mnt/media/cvs/src/sbin/dhclient/clparse.c,v
retrieving revision 1.92
diff -u -p -r1.92 clparse.c
--- clparse.c   18 May 2015 17:51:21 -0000      1.92
+++ clparse.c   9 Jul 2015 15:00:05 -0000
@@ -75,6 +75,7 @@ read_client_conf(void)
        config->backoff_cutoff = 15;
        config->initial_interval = 3;
        config->bootp_policy = ACCEPT;
+       config->update_unbound = 0;
        config->requested_options
            [config->requested_option_count++] = DHO_SUBNET_MASK;
        config->requested_options
@@ -269,6 +270,10 @@ parse_client_statement(FILE *cfile)
        case TOK_NEXT_SERVER:
                if (parse_ip_addr(cfile, &config->next_server))
                        parse_semi(cfile);
+               break;
+       case TOK_UPDATE_UNBOUND:
+               config->update_unbound = 1;
+               parse_semi(cfile);
                break;
        default:
                parse_warn("expecting a statement.");
Index: conflex.c
===================================================================
RCS file: /mnt/media/cvs/src/sbin/dhclient/conflex.c,v
retrieving revision 1.32
diff -u -p -r1.32 conflex.c
--- conflex.c   18 May 2015 17:51:21 -0000      1.32
+++ conflex.c   19 Jul 2015 17:31:13 -0000
@@ -341,7 +341,8 @@ static const struct keywords {
        { "send",                               TOK_SEND },
        { "server-name",                        TOK_SERVER_NAME },
        { "supersede",                          TOK_SUPERSEDE },
-       { "timeout",                            TOK_TIMEOUT }
+       { "timeout",                            TOK_TIMEOUT },
+       { "update-unbound",                     TOK_UPDATE_UNBOUND }
 };
 
 int    kw_cmp(const void *k, const void *e);
Index: dhclient.c
===================================================================
RCS file: /mnt/media/cvs/src/sbin/dhclient/dhclient.c,v
retrieving revision 1.361
diff -u -p -r1.361 dhclient.c
--- dhclient.c  18 May 2015 14:59:42 -0000      1.361
+++ dhclient.c  19 Jul 2015 17:48:11 -0000
@@ -97,6 +97,7 @@ int            res_hnok(const char *dn);
 
 void            fork_privchld(int, int);
 void            get_ifname(char *);
+void            update_unbound_forwards(struct option_data *);
 char           *resolv_conf_contents(struct option_data  *,
                     struct option_data *);
 void            write_resolv_conf(u_int8_t *, size_t);
@@ -903,8 +904,12 @@ bind_lease(void)
                goto newlease;
        }
 
-       client->new->resolv_conf = resolv_conf_contents(
-           &options[DHO_DOMAIN_NAME], &options[DHO_DOMAIN_NAME_SERVERS]);
+       if (config->update_unbound) {
+               update_unbound_forwards(&options[DHO_DOMAIN_NAME_SERVERS]);
+       } else {
+               client->new->resolv_conf = resolv_conf_contents(
+                   &options[DHO_DOMAIN_NAME], 
&options[DHO_DOMAIN_NAME_SERVERS]);
+       }
 
        /* Replace the old active lease with the new one. */
        client->active = client->new;
@@ -2042,6 +2047,89 @@ get_ifname(char *arg)
                close(s);
        } else if (strlcpy(ifi->name, arg, IFNAMSIZ) >= IFNAMSIZ)
                error("Interface name too long");
+}
+
+/*
+ * Update unbound forwarder list
+ */
+void
+update_unbound_forwards(struct option_data *nameservers)
+{
+       char *ns;
+       int rslt;
+
+       if (!nameservers->len) {
+               return;
+       }
+
+       ns = pretty_print_option(DHO_DOMAIN_NAME_SERVERS, nameservers, 0);
+
+       rslt = imsg_compose(unpriv_ibuf, IMSG_UPDATE_UNBOUND_FORWARDS,
+           0, 0, -1, ns, strlen(ns) + 1);
+
+       if (rslt == -1) {
+               warning("update_unbound_forwards: imsg_compose: %s",
+                       strerror(errno));
+       }
+
+       flush_unpriv_ibuf("update_unbound_forwards");
+}
+
+void
+priv_update_unbound_forwards(struct imsg *imsg)
+{
+       char *args[MAXNS + 3]; /* `unbound-control', `forward', final NULL */
+       char *ns, *p, **srv;
+       int rslt, i = 0;
+       size_t sz;
+       pid_t child;
+
+       if (imsg->hdr.len < IMSG_HEADER_SIZE) {
+               warning("short IMSG_UPDATE_UNBOUND_FORWARDS");
+               return;
+       }
+
+       ns = imsg->data;
+       sz = imsg->hdr.len - IMSG_HEADER_SIZE;
+       ns[sz] = '\0'; /* Make sure we're terminated properly */
+
+       /* Construct unbound-control arguments */
+       memset(args, 0, sizeof(args));
+       args[0] = "unbound-control";
+       args[1] = "forward";
+       srv = &args[2];
+       while (i < MAXNS) {
+               p = strsep(&ns, " ");
+               if (p == NULL)
+                       break;
+               if (*p == '\0')
+                       continue;
+               rslt = asprintf(&srv[i++], "%s", p);
+               if (rslt == -1)
+                       error("no memory for nameserver");
+       }
+
+       switch ((child = fork())) {
+               case -1:
+                       error("cannot fork");
+                       break;
+               case 0:
+                       fclose(stdout); /* Prevent noise from unbound-control */
+                       execvp("unbound-control", args);
+                       error("execve failed: %s", strerror(errno));
+                       break;
+               default:
+                       if (waitpid(child, NULL, 0) < 0) {
+                               error("waitpid: %s", strerror(errno));
+                       }
+                       break;
+       }
+
+       for (i = 0; i < MAXNS; i++) {
+               if (!srv[i])
+                       break;
+               free(srv[i]);
+       }
 }
 
 /*
Index: dhclient.conf.5
===================================================================
RCS file: /mnt/media/cvs/src/sbin/dhclient/dhclient.conf.5,v
retrieving revision 1.31
diff -u -p -r1.31 dhclient.conf.5
--- dhclient.conf.5     11 Nov 2013 15:39:20 -0000      1.31
+++ dhclient.conf.5     19 Jul 2015 17:31:34 -0000
@@ -406,6 +406,16 @@ specified name.
 Interfaces for which there is no interface declaration will use the
 parameters declared outside of any interface declaration,
 or the default settings.
+.It Ic update-unbound ;
+The
+.Ic update-unbound
+statement causes dhclient to update the unbound forward DNS list with received
+name servers instead of updating /etc/resolv.conf.
+This is essentially the same as calling 
+.Pp
+.D1 unbound-control forward <ns1> <ns2> <ns3>
+.Pp
+after acquiring a lease that contains name server information.
 .El
 .Sh EXAMPLES
 The following configuration file is used on a laptop
Index: dhcpd.h
===================================================================
RCS file: /mnt/media/cvs/src/sbin/dhclient/dhcpd.h,v
retrieving revision 1.150
diff -u -p -r1.150 dhcpd.h
--- dhcpd.h     18 May 2015 14:59:42 -0000      1.150
+++ dhcpd.h     19 Jul 2015 17:32:27 -0000
@@ -146,6 +146,7 @@ struct client_config {
        time_t                   backoff_cutoff;
        enum { IGNORE, ACCEPT, PREFER }
                                 bootp_policy;
+       int                      update_unbound;
        TAILQ_HEAD(, reject_elem) reject_list;
        char                    *resolv_tail;
        char                    *filename;
Index: dhctoken.h
===================================================================
RCS file: /mnt/media/cvs/src/sbin/dhclient/dhctoken.h,v
retrieving revision 1.9
diff -u -p -r1.9 dhctoken.h
--- dhctoken.h  5 Dec 2013 22:31:35 -0000       1.9
+++ dhctoken.h  9 Jul 2015 14:55:15 -0000
@@ -78,6 +78,7 @@
 #define TOK_REJECT             292
 #define TOK_LINK_TIMEOUT       294
 #define TOK_IGNORE             295
+#define TOK_UPDATE_UNBOUND     296
 
 #define is_identifier(x)       ((x) >= TOK_FIRST_TOKEN &&      \
                                 (x) != TOK_STRING &&   \
Index: privsep.c
===================================================================
RCS file: /mnt/media/cvs/src/sbin/dhclient/privsep.c,v
retrieving revision 1.39
diff -u -p -r1.39 privsep.c
--- privsep.c   7 Feb 2015 10:08:06 -0000       1.39
+++ privsep.c   9 Jul 2015 15:20:34 -0000
@@ -93,6 +93,9 @@ dispatch_imsg(struct imsgbuf *ibuf)
                case IMSG_WRITE_OPTION_DB:
                        priv_write_option_db(&imsg);
                        break;
+               case IMSG_UPDATE_UNBOUND_FORWARDS:
+                       priv_update_unbound_forwards(&imsg);
+                       break;
 
                default:
                        warning("received unknown message, code %u",
Index: privsep.h
===================================================================
RCS file: /mnt/media/cvs/src/sbin/dhclient/privsep.h,v
retrieving revision 1.28
diff -u -p -r1.28 privsep.h
--- privsep.h   10 Feb 2015 04:20:26 -0000      1.28
+++ privsep.h   9 Jul 2015 15:21:18 -0000
@@ -19,6 +19,7 @@
 #include <arpa/inet.h>
 
 #include <imsg.h>
+#include <resolv.h>
 
 enum imsg_code {
        IMSG_NONE,
@@ -29,7 +30,8 @@ enum imsg_code {
        IMSG_SET_INTERFACE_MTU,
        IMSG_HUP,
        IMSG_WRITE_RESOLV_CONF,
-       IMSG_WRITE_OPTION_DB
+       IMSG_WRITE_OPTION_DB,
+       IMSG_UPDATE_UNBOUND_FORWARDS
 };
 
 struct imsg_delete_address {
@@ -72,3 +74,4 @@ void  priv_set_interface_mtu(struct imsg_
 void   priv_write_resolv_conf(struct imsg *);
 void   priv_write_option_db(struct imsg *);
 void   priv_write_file(char *, int, mode_t, uid_t, gid_t, u_int8_t *, size_t);
+void   priv_update_unbound_forwards(struct imsg *);

Reply via email to