On Sun, Jul 19, 2015 at 07:03:59PM +0100, Stuart Henderson wrote:
> [...]
> I'm uncertain about whether dhclient should do this at all, it seems
> to be the opposite of the direction dhclient has been going in
> recently,
> [...]

I've had a similar intuition at first, but it's one less thing to run
versus the "monitor lease file" approach and it only calls one static
external command with relatively fixed parameters instead of what the
removed `script' option did. In the end, it's a matter of personal
taste, I think.

> [...]
> but if it is added, it probably wants to be disabled for the ramdisk.
> [...]

I've attached an updated patch, in case this is still interesting to
someone. Do I need to add anything other than `#ifdef SMALL' in the
appropriate places?

-- 
        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   19 Jul 2015 18:44:12 -0000
@@ -75,6 +75,9 @@ read_client_conf(void)
        config->backoff_cutoff = 15;
        config->initial_interval = 3;
        config->bootp_policy = ACCEPT;
+#ifndef SMALL
+       config->update_unbound = 0;
+#endif
        config->requested_options
            [config->requested_option_count++] = DHO_SUBNET_MASK;
        config->requested_options
@@ -270,6 +273,12 @@ parse_client_statement(FILE *cfile)
                if (parse_ip_addr(cfile, &config->next_server))
                        parse_semi(cfile);
                break;
+#ifndef SMALL
+       case TOK_UPDATE_UNBOUND:
+               config->update_unbound = 1;
+               parse_semi(cfile);
+               break;
+#endif
        default:
                parse_warn("expecting a statement.");
                if (token != ';')
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 18:48:00 -0000
@@ -341,7 +341,10 @@ static const struct keywords {
        { "send",                               TOK_SEND },
        { "server-name",                        TOK_SERVER_NAME },
        { "supersede",                          TOK_SUPERSEDE },
-       { "timeout",                            TOK_TIMEOUT }
+       { "timeout",                            TOK_TIMEOUT },
+#ifndef SMALL
+       { "update-unbound",                     TOK_UPDATE_UNBOUND }
+#endif
 };
 
 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 18:45:28 -0000
@@ -97,6 +97,9 @@ int            res_hnok(const char *dn);
 
 void            fork_privchld(int, int);
 void            get_ifname(char *);
+#ifndef SMALL
+void            update_unbound_forwards(struct option_data *);
+#endif
 char           *resolv_conf_contents(struct option_data  *,
                     struct option_data *);
 void            write_resolv_conf(u_int8_t *, size_t);
@@ -903,8 +906,15 @@ bind_lease(void)
                goto newlease;
        }
 
-       client->new->resolv_conf = resolv_conf_contents(
-           &options[DHO_DOMAIN_NAME], &options[DHO_DOMAIN_NAME_SERVERS]);
+#ifndef SMALL
+       if (config->update_unbound) {
+               update_unbound_forwards(&options[DHO_DOMAIN_NAME_SERVERS]);
+       } else
+#endif
+       {
+               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;
@@ -2043,6 +2053,91 @@ get_ifname(char *arg)
        } else if (strlcpy(ifi->name, arg, IFNAMSIZ) >= IFNAMSIZ)
                error("Interface name too long");
 }
+
+#ifndef SMALL
+/*
+ * 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]);
+       }
+}
+#endif /* SMALL */
 
 /*
  * Update resolv.conf.
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 18:45:57 -0000
@@ -146,6 +146,9 @@ struct client_config {
        time_t                   backoff_cutoff;
        enum { IGNORE, ACCEPT, PREFER }
                                 bootp_policy;
+#ifndef SMALL
+       int                      update_unbound;
+#endif
        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  19 Jul 2015 18:43:36 -0000
@@ -78,6 +78,9 @@
 #define TOK_REJECT             292
 #define TOK_LINK_TIMEOUT       294
 #define TOK_IGNORE             295
+#ifndef SMALL
+#define TOK_UPDATE_UNBOUND     296
+#endif /* SMALL */
 
 #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   19 Jul 2015 18:46:06 -0000
@@ -93,6 +93,11 @@ dispatch_imsg(struct imsgbuf *ibuf)
                case IMSG_WRITE_OPTION_DB:
                        priv_write_option_db(&imsg);
                        break;
+#ifndef SMALL
+               case IMSG_UPDATE_UNBOUND_FORWARDS:
+                       priv_update_unbound_forwards(&imsg);
+                       break;
+#endif
 
                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   19 Jul 2015 18:46:55 -0000
@@ -29,7 +29,10 @@ enum imsg_code {
        IMSG_SET_INTERFACE_MTU,
        IMSG_HUP,
        IMSG_WRITE_RESOLV_CONF,
-       IMSG_WRITE_OPTION_DB
+       IMSG_WRITE_OPTION_DB,
+#ifndef SMALL
+       IMSG_UPDATE_UNBOUND_FORWARDS
+#endif
 };
 
 struct imsg_delete_address {
@@ -72,3 +75,6 @@ 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);
+#ifndef SMALL
+void   priv_update_unbound_forwards(struct imsg *);
+#endif

Reply via email to