Re: [patch] update unbound forwards with dhclient nameservers

2015-07-19 Thread Florian Obser
On Sun, Jul 19, 2015 at 08:53:04PM +0200, Gregor Best wrote:
> 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.

Indeed, I prodded krw@ to have a look / final say.

If it's inaproriate for dhclient we might re-consider this for the
magical "manage-network-daemon" if/when it shows up.

As far as I'm concerned having unbound run on localhost is a sensible
setup. Btw. my use case is for stupid networks that require that you
use their resolvers.


-- 
I'm not entirely sure you are real.



Re: [patch] update unbound forwards with dhclient nameservers

2015-07-19 Thread Gregor Best
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 -  1.92
+++ clparse.c   19 Jul 2015 18:44:12 -
@@ -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 -  1.32
+++ conflex.c   19 Jul 2015 18:48:00 -
@@ -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
 };
 
 intkw_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 -  1.361
+++ dhclient.c  19 Jul 2015 18:45:28 -
@@ -97,6 +97,9 @@ intres_hnok(const char *dn);
 
 voidfork_privchld(int, int);
 voidget_ifname(char *);
+#ifndef SMALL
+voidupdate_unbound_forwards(struct option_data *);
+#endif
 char   *resolv_conf_contents(struct option_data  *,
 struct option_data *);
 voidwrite_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;
+  

Re: [patch] update unbound forwards with dhclient nameservers

2015-07-19 Thread Stuart Henderson
On 2015/07/19 19:53, Gregor Best wrote:
> On Sun, Jul 19, 2015 at 03:31:33PM +, 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.

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,
but if it is added, it probably wants to be disabled for the ramdisk.



Re: [patch] update unbound forwards with dhclient nameservers

2015-07-19 Thread Gregor Best
On Sun, Jul 19, 2015 at 03:31:33PM +, 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 -  1.92
+++ clparse.c   9 Jul 2015 15:00:05 -
@@ -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 -  1.32
+++ conflex.c   19 Jul 2015 17:31:13 -
@@ -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 }
 };
 
 intkw_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 -  1.361
+++ dhclient.c  19 Jul 2015 17:48:11 -
@@ -97,6 +97,7 @@ intres_hnok(const char *dn);
 
 voidfork_privchld(int, int);
 voidget_ifname(char *);
+voidupdate_unbound_forwards(struct option_data *);
 char   *resolv_conf_contents(struct option_data  *,
 struct option_data *);
 voidwrite_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')

Re: [patch] update unbound forwards with dhclient nameservers

2015-07-19 Thread Peter Hessler
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   
:
: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 -  1.92
:+++ clparse.c  9 Jul 2015 15:00:05 -
:@@ -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 -  1.32
:+++ conflex.c  9 Jul 2015 14:54:56 -
:@@ -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 -  1.361
:+++ dhclient.c 9 Jul 2015 15:52:41 -
:@@ -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_updat

Re: [patch] update unbound forwards with dhclient nameservers

2015-07-19 Thread Stuart Henderson
On 2015/07/19 13:08, 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   
> 
> 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'm doing this without patches, using a script run by entr (from packages)
to watch the lease file (written with -L /etc/dhclient.lease.,
i.e. "!dhclient -L /etc/dhclient.lease.iwn0 iwn0" in /etc/hostname.iwn0).

The code doing -L in dhclient takes care to keep the same inode for this
file specifically to support doing this.

$ cat dhcp-watcher
#!/bin/sh
gw=$(route -n get -inet 0.0.0.0 | awk '/interface/ {print $2}')
dns=$(awk '/domain-name-servers/ {gsub("[;,]", " ", $3); print $3;}' 
/etc/dhclient.lease.$gw)
unbound-control forward_add . $dns > /dev/null
echo "default now on $gw: $(unbound-control list_forwards)" | logger -t 
dhcp-watcher

$ cat dhcp-watcher.run
#!/bin/sh
/etc/dhcp-watcher
echo /etc/dhclient.lease.* | tr ' ' '\n' | /usr/local/bin/entr /etc/dhcp-watcher



Re: [patch] update unbound forwards with dhclient nameservers

2015-07-19 Thread Florian Obser
On Sun, Jul 19, 2015 at 01:08:46PM +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   
> 
> 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.
> 

Oh god, yes please. I always wanted to write this diff myself ;)
More comments in the diff below.

> 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 -  1.92
> +++ clparse.c 9 Jul 2015 15:00:05 -
> @@ -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 -  1.32
> +++ conflex.c 9 Jul 2015 14:54:56 -
> @@ -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 }

Use update-unbound (minus, not underscrore) for the keyword; also
update the man page. 


>  };
>  
>  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.c18 May 2015 14:59:42 -  1.361
> +++ dhclient.c9 Jul 2015 15:52:41 -
> @@ -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) {
> + 

[patch] update unbound forwards with dhclient nameservers

2015-07-19 Thread Gregor Best
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   

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 -  1.92
+++ clparse.c   9 Jul 2015 15:00:05 -
@@ -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 -  1.32
+++ conflex.c   9 Jul 2015 14:54:56 -
@@ -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 }
 };
 
 intkw_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 -  1.361
+++ dhclient.c  9 Jul 2015 15:52:41 -
@@ -97,6 +97,7 @@ intres_hnok(const char *dn);
 
 voidfork_privchld(int, int);
 voidget_ifname(char *);
+voidupdate_unbound_forwards(struct option_data *);
 char   *resolv_conf_contents(struct option_data  *,
 struct option_data *);
 voidwrite_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;