I really like this idea, modulo the comments that Florian made.

On 2015 Jul 19 (Sun) at 13:08:46 +0200 (+0200), Gregor Best wrote:
:Hello,
:
:the following is a patch that adds an option called `update_unbound' to
:dhclient.conf. With this option enabled, dhclient will call
:
:       unbound-control forwards <ns1> <ns2> <ns3>
:
:instead of rewriting /etc/resolv.conf.
:
:My usage scenario is that I'm running unbound on my laptop as a local
:resolver. /etc/resolv.conf is configured to only use 127.0.0.1 as the
:nameserver.
:
:I use this because I have a few VPN connections that have custom DNS
:namespaces, which I manage with Unbound's forward zones.  Since
:sometimes I am in networks that have a split horizon DNS (e.g.
:University, hackerspace, etc...), I can't use a statically configured
:fallback forward zone for all my requests. Manually calling using
:unbound-control to change the forward DNS became too annoying, so I
:wrote this patch.
:
:Does the patch make sense in OpenBSD or should I keep it as a local
:change?
:
:-- 
:       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  9 Jul 2015 14:54:56 -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 9 Jul 2015 15:52:41 -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,88 @@ 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;
:+      int i, rslt;
:+      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";
:+      for (i = 0; i < MAXNS; i++) {
:+              p = strsep(&ns, " ");
:+              if (p == NULL)
:+                      break;
:+              if (*p == '\0')
:+                      continue;
:+              rslt = asprintf(&args[i + 2], "%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 (!args[i + 2])
:+                      continue;
:+              free(args[i + 2]);
:+      }
: }
: 
: /*
: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    9 Jul 2015 16:24:32 -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    9 Jul 2015 14:51:11 -0000
:@@ -146,6 +146,7 @@ struct client_config {
:       time_t                   backoff_cutoff;
:       enum { IGNORE, ACCEPT, PREFER }
:                                bootp_policy;
:+      int                      update_unbound: 1;
:       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 *);
:

-- 
QUOTE OF THE DAY:

       `

Reply via email to