RDNSS and DNSSL data in router advertisements.
diff --git a/CHANGELOG b/CHANGELOG
index fb773e1..dca25d5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -69,9 +69,12 @@
 
 	    Fix bug in address6_available() which caused DHCPv6 lease
 	    aquistion to fail of more than one dhcp-range in use.
+
+	    Provide RDNSS and DNSSL data in router advertisements,
+	    using the settings provided for DHCP options
+	    option6:domain-search and option6:dns-server.
 	    
 
- 
 version 2.60
             Fix compilation problem in Mac OS X Lion. Thanks to Olaf
             Flebbe for the patch.
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index acc1920..4189d45 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -1343,6 +1343,10 @@
 the "use SLAAC" bit is reset. This can be changed for individual
 subnets with the mode keywords described in
 .B --dhcp-range.
+RFC6106 DNS parameters are included in the advertisements. By default,
+the relevant link-local address of the machine running dnsmasq is sent
+as recursive DNS server. If provided, the DHCPv6 options dns-server and
+domain-search are used for RDNSS and DNSSL.
 .TP
 .B --enable-tftp[=<interface>]
 Enable the TFTP server function. This is deliberately limited to that
diff --git a/src/dhcp6-protocol.h b/src/dhcp6-protocol.h
index 7910920..166fc90 100644
--- a/src/dhcp6-protocol.h
+++ b/src/dhcp6-protocol.h
@@ -54,6 +54,7 @@
 #define OPTION6_RECONFIGURE_MSG 19
 #define OPTION6_RECONF_ACCEPT   20
 #define OPTION6_DNS_SERVER      23
+#define OPTION6_DOMAIN_SEARCH   24
 #define OPTION6_REMOTE_ID       37
 #define OPTION6_SUBSCRIBER_ID   38
 #define OPTION6_FQDN            39
diff --git a/src/option.c b/src/option.c
index 6f5fe62..611b599 100644
--- a/src/option.c
+++ b/src/option.c
@@ -1000,6 +1000,7 @@
 	      while (arg && *arg)
 		{
 		  u16 len = strlen(arg);
+		  unhide_metas(arg);
 		  PUTSHORT(len, p);
 		  memcpy(p, arg, len);
 		  p += len; 
@@ -1013,29 +1014,40 @@
 	    }
 	  else if (comma && (opt_len & OT_RFC1035_NAME))
 	    {
-	      int i, commas = 1;
-	      unsigned char *p, *newp;
-	      
-	      for (i = 0; comma[i]; i++)
-		if (comma[i] == ',')
-		  commas++;
-	      
-	      newp = opt_malloc(strlen(comma)+(2*commas));
-	      p = newp;
+	      unsigned char *p = NULL, *newp, *end;
+	      int len = 0;
 	      arg = comma;
 	      comma = split(arg);
 	      
 	      while (arg && *arg)
 		{
-		  p = do_rfc1035_name(p, arg);
-		  *p++ = 0;
+		  char *dom = canonicalise_opt(arg);
+		  if (!dom)
+		    {
+		      problem = _("bad domain in dhcp-option");
+		      break;
+		    }
 		  
+		  newp = opt_malloc(len + strlen(dom) + 2);
+		  
+		  if (p)
+		    {
+		      memcpy(newp, p, len);
+		      free(p);
+		    }
+		  
+		  p = newp;
+		  end = do_rfc1035_name(p + len, dom);
+		  *end++ = 0;
+		  len = end - p;
+		  free(dom);
+
 		  arg = comma;
 		  comma = split(arg);
 		}
 	      
-	      new->val = newp;
-	      new->len = p - newp;
+	      new->val = p;
+	      new->len = len;
 	    }
 #endif
 	  else
diff --git a/src/radv-protocol.h b/src/radv-protocol.h
index 8e83169..1f95395 100644
--- a/src/radv-protocol.h
+++ b/src/radv-protocol.h
@@ -43,6 +43,7 @@
 #define ICMP6_OPT_PREFIX       3
 #define ICMP6_OPT_MTU          5
 #define ICMP6_OPT_RDNSS       25
+#define ICMP6_OPT_DNSSL       31
 
 
 
diff --git a/src/radv.c b/src/radv.c
index 3998792..af8c943 100644
--- a/src/radv.c
+++ b/src/radv.c
@@ -29,6 +29,7 @@
 struct ra_param {
   int ind, managed, other, found_context, first;
   char *if_name;
+  struct dhcp_netid *tags;
   struct in6_addr link_local;
 };
 
@@ -189,7 +190,10 @@
   struct ifreq ifr;
   struct sockaddr_in6 addr;
   struct dhcp_context *context;
-
+  struct dhcp_netid iface_id;
+  struct dhcp_opt *opt_cfg;
+  int done_dns = 0;
+ 
   save_counter(0);
   ra = expand(sizeof(struct ra_packet));
   
@@ -208,9 +212,17 @@
   parm.if_name = iface_name;
   parm.first = 1;
 
-  for (context = daemon->ra_contexts; context; context = context->next)
-    context->flags &= ~CONTEXT_RA_DONE;
+  /* set tag with name == interface */
+  iface_id.net = iface_name;
+  iface_id.next = NULL;
+  parm.tags = &iface_id; 
   
+  for (context = daemon->ra_contexts; context; context = context->next)
+    {
+      context->flags &= ~CONTEXT_RA_DONE;
+      context->netid.next = &context->netid;
+    }
+
   if (!iface_enumerate(AF_INET6, &parm, add_prefixes) ||
       !parm.found_context)
     return;
@@ -226,14 +238,63 @@
     }
      
   iface_enumerate(AF_LOCAL, &iface, add_lla);
+ 
+  /* RDNSS, RFC 6106, use relevant DHCP6 options */
+  (void)option_filter(parm.tags, NULL, daemon->dhcp_opts6);
   
-  /* RDNSS, RFC 6106 */
-  put_opt6_char(ICMP6_OPT_RDNSS);
-  put_opt6_char(3);
-  put_opt6_short(0);
-  put_opt6_long(1800); /* lifetime - twice RA retransmit */
-  put_opt6(&parm.link_local, IN6ADDRSZ);
+  for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
+    {
+      int i;
+      
+      /* netids match and not encapsulated? */
+      if (!(opt_cfg->flags & DHOPT_TAGOK))
+        continue;
+      
+      if (opt_cfg->opt == OPTION6_DNS_SERVER)
+        {
+	  struct in6_addr *a = (struct in6_addr *)opt_cfg->val;
 
+	  done_dns = 1;
+          if (opt_cfg->len == 0)
+            continue;
+	  
+	  put_opt6_char(ICMP6_OPT_RDNSS);
+	  put_opt6_char((opt_cfg->len/8) + 1);
+	  put_opt6_short(0);
+	  put_opt6_long(1800); /* lifetime - twice RA retransmit */
+	  /* zero means "self" */
+	  for (i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
+	    if (IN6_IS_ADDR_UNSPECIFIED(a))
+	      put_opt6(&parm.link_local, IN6ADDRSZ);
+	    else
+	      put_opt6(a, IN6ADDRSZ);
+	}
+      
+      if (opt_cfg->opt == OPTION6_DOMAIN_SEARCH && opt_cfg->len != 0)
+	{
+	  int len = ((opt_cfg->len+7)/8);
+	  
+	  put_opt6_char(ICMP6_OPT_DNSSL);
+	  put_opt6_char(len + 1);
+	  put_opt6_short(0);
+	  put_opt6_long(1800); /* lifetime - twice RA retransmit */
+	  put_opt6(opt_cfg->val, opt_cfg->len);
+	  
+	  /* pad */
+	  for (i = opt_cfg->len; i < len * 8; i++)
+	    put_opt6_char(0);
+	}
+    }
+	
+  if (!done_dns)
+    {
+      /* default == us. */
+      put_opt6_char(ICMP6_OPT_RDNSS);
+      put_opt6_char(3);
+      put_opt6_short(0);
+      put_opt6_long(1800); /* lifetime - twice RA retransmit */
+      put_opt6(&parm.link_local, IN6ADDRSZ);
+    }
 
   /* set managed bits unless we're providing only RA on this link */
   if (parm.managed)
@@ -323,7 +384,14 @@
 		  context->ra_time = 0;
 		param->first = 0;
 		param->found_context = 1;
-		
+
+		/* collect dhcp-range tags */
+		if (context->netid.next == &context->netid && context->netid.net)
+		  {
+		    context->netid.next = param->tags;
+		    param->tags = &context->netid;
+		  }
+		  
 		if (!(context->flags & CONTEXT_RA_DONE))
 		  {
 		    context->flags |= CONTEXT_RA_DONE;