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;