Hello again tech@,
Here's also the updated version of a patch I wrote approx. one year ago
to support RFC 6106 in rtadvd(8). J.R. Oldroyd told me there was a bug
in the generation of the DNS search list and that the format of the
packets generated was not valid.
I fixed that, so here is the patch.
Regards,
--
Stephane A. Sezer
Index: sys/netinet/icmp6.h
===================================================================
RCS file: /cvs/src/sys/netinet/icmp6.h,v
retrieving revision 1.33
diff -u -r1.33 icmp6.h
--- sys/netinet/icmp6.h 22 Mar 2010 12:23:32 -0000 1.33
+++ sys/netinet/icmp6.h 26 Jan 2012 17:11:40 -0000
@@ -282,6 +282,8 @@
#define ND_OPT_PREFIX_INFORMATION 3
#define ND_OPT_REDIRECTED_HEADER 4
#define ND_OPT_MTU 5
+#define ND_OPT_RDNSS 25
+#define ND_OPT_DNSSL 31
struct nd_opt_prefix_info { /* prefix information */
u_int8_t nd_opt_pi_type;
@@ -310,6 +312,22 @@
u_int8_t nd_opt_mtu_len;
u_int16_t nd_opt_mtu_reserved;
u_int32_t nd_opt_mtu_mtu;
+} __packed;
+
+struct nd_opt_rdnss { /* RDNSS option */
+ u_int8_t nd_opt_rdnss_type;
+ u_int8_t nd_opt_rdnss_len;
+ u_int16_t nd_opt_rdnss_reserved;
+ u_int32_t nd_opt_rdnss_lifetime;
+ /* followed by list of recursive DNS servers */
+} __packed;
+
+struct nd_opt_dnssl { /* DNSSL option */
+ u_int8_t nd_opt_dnssl_type;
+ u_int8_t nd_opt_dnssl_len;
+ u_int16_t nd_opt_dnssl_reserved;
+ u_int32_t nd_opt_dnssl_lifetime;
+ /* followed by list of DNS search domains */
} __packed;
/*
Index: usr.sbin/rtadvd/config.c
===================================================================
RCS file: /cvs/src/usr.sbin/rtadvd/config.c,v
retrieving revision 1.26
diff -u -r1.26 config.c
--- usr.sbin/rtadvd/config.c 23 Apr 2008 10:17:50 -0000 1.26
+++ usr.sbin/rtadvd/config.c 26 Jan 2012 17:11:42 -0000
@@ -109,6 +109,8 @@
fatal("malloc");
TAILQ_INIT(&tmp->prefixes);
+ TAILQ_INIT(&tmp->rdnsss);
+ TAILQ_INIT(&tmp->dnssls);
SLIST_INIT(&tmp->soliciters);
/* check if we are allowed to forward packets (if not determined) */
@@ -323,6 +325,106 @@
if (tmp->pfxs == 0)
get_prefix(tmp);
+ tmp->rdnsscnt = 0;
+ for (i = -1; i < MAXRDNSS; ++i) {
+ struct rdnss *rds;
+ char entbuf[256];
+ char *tmpaddr;
+
+ makeentry(entbuf, sizeof(entbuf), i, "rdnss");
+ addr = agetstr(entbuf, &bp);
+ if (addr == NULL)
+ continue;
+
+ /* servers are separated by commas in the config file */
+ val = 1;
+ tmpaddr = addr;
+ while (*tmpaddr++)
+ if (*tmpaddr == ',')
+ ++val;
+
+ rds = malloc(sizeof(struct rdnss) + val * sizeof(struct
in6_addr));
+ if (rds == NULL)
+ fatal("malloc");
+
+ TAILQ_INSERT_TAIL(&tmp->rdnsss, rds, entry);
+ tmp->rdnsscnt++;
+
+ rds->servercnt = val;
+
+ makeentry(entbuf, sizeof(entbuf), i, "rdnssltime");
+ MAYHAVE(val, entbuf, (tmp->maxinterval * 3) / 2);
+ if (val < tmp->maxinterval || val > tmp->maxinterval * 2) {
+ log_warnx("%s (%ld) on %s is invalid "
+ "(should be between %d and %d)",
+ entbuf, val, intface, tmp->maxinterval,
+ tmp->maxinterval * 2);
+ }
+ rds->lifetime = val;
+
+ val = 0;
+ while ((tmpaddr = strsep(&addr, ","))) {
+ if (inet_pton(AF_INET6, tmpaddr, &rds->servers[val]) !=
1) {
+ log_warn("inet_pton failed for %s", tmpaddr);
+ exit(1);
+ }
+ val++;
+ }
+ }
+
+ tmp->dnsslcnt = 0;
+ for (i = -1; i < MAXDNSSL; ++i) {
+ struct dnssl *dsl;
+ char entbuf[256];
+ char *tmpsl;
+
+ makeentry(entbuf, sizeof(entbuf), i, "dnssl");
+ addr = agetstr(entbuf, &bp);
+ if (addr == NULL)
+ continue;
+
+ dsl = malloc(sizeof(struct dnssl));
+ if (dsl == NULL)
+ fatal("malloc");
+
+ TAILQ_INIT(&dsl->dnssldoms);
+
+ while ((tmpsl = strsep(&addr, ","))) {
+ struct dnssldom *dnsd;
+ ssize_t len;
+
+ len = strlen(tmpsl);
+
+ /* if the domain is not "dot-terminated", add it */
+ if (tmpsl[len - 1] != '.')
+ len += 1;
+
+ dnsd = malloc(sizeof(struct dnssldom) + len + 1);
+ if (dnsd == NULL)
+ fatal("malloc");
+
+ dnsd->length = len;
+ strlcpy(dnsd->domain, tmpsl, len + 1);
+ dnsd->domain[len - 1] = '.';
+ dnsd->domain[len] = '\0';
+
+ TAILQ_INSERT_TAIL(&dsl->dnssldoms, dnsd, entry);
+ }
+
+ TAILQ_INSERT_TAIL(&tmp->dnssls, dsl, entry);
+ tmp->dnsslcnt++;
+
+ makeentry(entbuf, sizeof(entbuf), i, "dnsslltime");
+ MAYHAVE(val, entbuf, (tmp->maxinterval * 3) / 2);
+ if (val < tmp->maxinterval || val > tmp->maxinterval * 2) {
+ log_warnx("%s (%ld) on %s is invalid "
+ "(should be between %d and %d)",
+ entbuf, val, intface, tmp->maxinterval,
+ tmp->maxinterval * 2);
+ }
+ dsl->lifetime = val;
+ }
+
MAYHAVE(val, "mtu", 0);
if (val < 0 || val > 0xffffffff) {
log_warnx("mtu (%ld) on %s out of range", val, intface);
@@ -596,7 +698,12 @@
struct nd_router_advert *ra;
struct nd_opt_prefix_info *ndopt_pi;
struct nd_opt_mtu *ndopt_mtu;
+ struct nd_opt_rdnss *ndopt_rdnss;
+ struct nd_opt_dnssl *ndopt_dnssl;
struct prefix *pfx;
+ struct rdnss *rds;
+ struct dnssl *dsl;
+ struct dnssldom *dnsd;
/* calculate total length */
packlen = sizeof(struct nd_router_advert);
@@ -613,6 +720,20 @@
packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs;
if (rainfo->linkmtu)
packlen += sizeof(struct nd_opt_mtu);
+ TAILQ_FOREACH(rds, &rainfo->rdnsss, entry)
+ packlen += sizeof(struct nd_opt_rdnss) + 16 * rds->servercnt;
+ TAILQ_FOREACH(dsl, &rainfo->dnssls, entry) {
+ size_t domains_size = 0;
+
+ packlen += sizeof(struct nd_opt_dnssl);
+
+ TAILQ_FOREACH(dnsd, &dsl->dnssldoms, entry)
+ domains_size += dnsd->length;
+
+ domains_size = (domains_size + 7) & ~7;
+
+ packlen += domains_size;
+ }
/* allocate memory for the packet */
if ((buf = malloc(packlen)) == NULL)
@@ -705,6 +826,62 @@
ndopt_pi->nd_opt_pi_prefix = pfx->prefix;
buf += sizeof(struct nd_opt_prefix_info);
+ }
+
+ TAILQ_FOREACH(rds, &rainfo->rdnsss, entry) {
+ ndopt_rdnss = (struct nd_opt_rdnss *)buf;
+ ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
+ ndopt_rdnss->nd_opt_rdnss_len = 1 + rds->servercnt * 2;
+ ndopt_rdnss->nd_opt_rdnss_reserved = 0;
+ ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rds->lifetime);
+
+ buf += sizeof(struct nd_opt_rdnss);
+
+ memcpy(buf, rds->servers, rds->servercnt * 16);
+ buf += rds->servercnt * 16;
+ }
+
+ TAILQ_FOREACH(dsl, &rainfo->dnssls, entry) {
+ u_int32_t size;
+ char *curlabel_begin;
+ char *curlabel_end;
+
+ ndopt_dnssl = (struct nd_opt_dnssl *)buf;
+ ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL;
+ ndopt_dnssl->nd_opt_dnssl_reserved = 0;
+ ndopt_dnssl->nd_opt_dnssl_lifetime = htonl(dsl->lifetime);
+
+ size = 0;
+ TAILQ_FOREACH(dnsd, &dsl->dnssldoms, entry)
+ size += dnsd->length;
+ /* align size on the next 8 byte boundary */
+ size = (size + 7) & ~7;
+ ndopt_dnssl->nd_opt_dnssl_len = 1 + size / 8;
+
+ buf += sizeof(struct nd_opt_dnssl);
+
+ TAILQ_FOREACH(dnsd, &dsl->dnssldoms, entry) {
+ curlabel_begin = dnsd->domain;
+ while ((curlabel_end = strchr(curlabel_begin, '.')) &&
+ (curlabel_end - curlabel_begin) > 1)
+ {
+ size_t curlabel_size;
+
+ curlabel_size = curlabel_end - curlabel_begin;
+ *buf = curlabel_size;
+ ++buf;
+ strncpy(buf, curlabel_begin, curlabel_size);
+ buf += curlabel_size;
+ curlabel_begin = curlabel_end + 1;
+ }
+
+ /* null-terminate the current domain */
+ *buf++ = '\0';
+ }
+
+ /* zero out the end of the current option */
+ while ((int)buf % 8 != 0)
+ *buf++ = '\0';
}
return;
Index: usr.sbin/rtadvd/config.h
===================================================================
RCS file: /cvs/src/usr.sbin/rtadvd/config.h,v
retrieving revision 1.6
diff -u -r1.6 config.h
--- usr.sbin/rtadvd/config.h 18 Jun 2003 02:26:58 -0000 1.6
+++ usr.sbin/rtadvd/config.h 26 Jan 2012 17:11:42 -0000
@@ -38,7 +38,9 @@
/*
- * it is highly unlikely to have 100 prefix information options,
+ * it is highly unlikely to have 100 prefix, rdnss or dnssl information
options,
* so it should be okay to limit it
*/
#define MAXPREFIX 100
+#define MAXRDNSS 100
+#define MAXDNSSL 100
Index: usr.sbin/rtadvd/dump.c
===================================================================
RCS file: /cvs/src/usr.sbin/rtadvd/dump.c,v
retrieving revision 1.10
diff -u -r1.10 dump.c
--- usr.sbin/rtadvd/dump.c 21 Jul 2008 19:14:15 -0000 1.10
+++ usr.sbin/rtadvd/dump.c 26 Jan 2012 17:11:42 -0000
@@ -103,6 +103,9 @@
{
struct rainfo *rai;
struct prefix *pfx;
+ struct rdnss *rds;
+ struct dnssl *dsl;
+ struct dnssldom *dnsd;
char prefixbuf[INET6_ADDRSTRLEN];
int first;
struct timeval now;
@@ -212,6 +215,29 @@
free(vltime);
free(pltime);
free(flags);
+ }
+
+ if (!TAILQ_EMPTY(&rai->rdnsss))
+ log_info(" Recursive DNS servers:");
+ TAILQ_FOREACH(rds, &rai->rdnsss, entry) {
+ log_info(" Servers:");
+ for (first = 0; first < rds->servercnt; ++first) {
+ inet_ntop(AF_INET6, &rds->servers[first],
+ prefixbuf, sizeof(prefixbuf));
+ log_info(" %s", prefixbuf);
+ }
+ log_info(" Lifetime: %u", rds->lifetime);
+ }
+
+ if (!TAILQ_EMPTY(&rai->dnssls))
+ log_info(" DNS search lists:");
+ TAILQ_FOREACH(dsl, &rai->dnssls, entry) {
+ log_info(" Domains:");
+
+ TAILQ_FOREACH(dnsd, &dsl->dnssldoms, entry)
+ log_info(" %s", dnsd->domain);
+
+ log_info(" Lifetime: %u", dsl->lifetime);
}
}
}
Index: usr.sbin/rtadvd/rtadvd.c
===================================================================
RCS file: /cvs/src/usr.sbin/rtadvd/rtadvd.c,v
retrieving revision 1.39
diff -u -r1.39 rtadvd.c
--- usr.sbin/rtadvd/rtadvd.c 2 Mar 2011 17:30:48 -0000 1.39
+++ usr.sbin/rtadvd/rtadvd.c 26 Jan 2012 17:11:42 -0000
@@ -114,15 +114,22 @@
#define nd_opts_mtu nd_opt_each.mtu
#define nd_opts_list nd_opt_each.list
-#define NDOPT_FLAG_SRCLINKADDR 0x1
-#define NDOPT_FLAG_TGTLINKADDR 0x2
-#define NDOPT_FLAG_PREFIXINFO 0x4
-#define NDOPT_FLAG_RDHDR 0x8
-#define NDOPT_FLAG_MTU 0x10
+#define NDOPT_FLAG_SRCLINKADDR (1 << 0)
+#define NDOPT_FLAG_TGTLINKADDR (1 << 1)
+#define NDOPT_FLAG_PREFIXINFO (1 << 2)
+#define NDOPT_FLAG_RDHDR (1 << 3)
+#define NDOPT_FLAG_MTU (1 << 4)
+#define NDOPT_FLAG_RDNSS (1 << 5)
+#define NDOPT_FLAG_DNSSL (1 << 6)
u_int32_t ndopt_flags[] = {
- 0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR,
- NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU,
+ [ND_OPT_SOURCE_LINKADDR] = NDOPT_FLAG_SRCLINKADDR,
+ [ND_OPT_TARGET_LINKADDR] = NDOPT_FLAG_TGTLINKADDR,
+ [ND_OPT_PREFIX_INFORMATION] = NDOPT_FLAG_PREFIXINFO,
+ [ND_OPT_REDIRECTED_HEADER] = NDOPT_FLAG_RDHDR,
+ [ND_OPT_MTU] = NDOPT_FLAG_MTU,
+ [ND_OPT_RDNSS] = NDOPT_FLAG_RDNSS,
+ [ND_OPT_DNSSL] = NDOPT_FLAG_DNSSL,
};
int main(int, char *[]);
@@ -804,8 +811,8 @@
SLIST_INIT(&ndopts.nd_opts_list);
if (nd6_options((struct nd_opt_hdr *)(ra + 1),
len - sizeof(struct nd_router_advert),
- &ndopts, NDOPT_FLAG_SRCLINKADDR |
- NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) {
+ &ndopts, NDOPT_FLAG_SRCLINKADDR | NDOPT_FLAG_PREFIXINFO
+ | NDOPT_FLAG_MTU | NDOPT_FLAG_RDNSS |
NDOPT_FLAG_DNSSL)) {
log_warnx("ND option check failed for an RA from %s on %s",
inet_ntop(AF_INET6, &from->sin6_addr,
ntopbuf, INET6_ADDRSTRLEN),
@@ -1104,7 +1111,9 @@
goto bad;
}
- if (hdr->nd_opt_type > ND_OPT_MTU)
+ if (hdr->nd_opt_type > ND_OPT_MTU &&
+ hdr->nd_opt_type != ND_OPT_RDNSS &&
+ hdr->nd_opt_type != ND_OPT_DNSSL)
{
log_info("unknown ND option(type %d)",
hdr->nd_opt_type);
@@ -1121,7 +1130,10 @@
* Option length check. Do it here for all fixed-length
* options.
*/
- if ((hdr->nd_opt_type == ND_OPT_MTU &&
+ if ((hdr->nd_opt_type == ND_OPT_RDNSS && (optlen < 24 ||
+ ((optlen - sizeof(struct nd_opt_rdnss)) % 16 != 0))) ||
+ (hdr->nd_opt_type == ND_OPT_DNSSL && optlen < 16) ||
+ (hdr->nd_opt_type == ND_OPT_MTU &&
(optlen != sizeof(struct nd_opt_mtu))) ||
((hdr->nd_opt_type == ND_OPT_PREFIX_INFORMATION &&
optlen != sizeof(struct nd_opt_prefix_info)))) {
@@ -1133,6 +1145,8 @@
case ND_OPT_SOURCE_LINKADDR:
case ND_OPT_TARGET_LINKADDR:
case ND_OPT_REDIRECTED_HEADER:
+ case ND_OPT_RDNSS:
+ case ND_OPT_DNSSL:
break; /* we don't care about these options */
case ND_OPT_MTU:
if (ndopts->nd_opt_array[hdr->nd_opt_type]) {
@@ -1154,7 +1168,7 @@
log_warn("malloc");
goto bad;
}
-
+
pfx->opt = hdr;
SLIST_INSERT_HEAD(&ndopts->nd_opts_list, pfx, entry);
Index: usr.sbin/rtadvd/rtadvd.conf
===================================================================
RCS file: /cvs/src/usr.sbin/rtadvd/rtadvd.conf,v
retrieving revision 1.6
diff -u -r1.6 rtadvd.conf
--- usr.sbin/rtadvd/rtadvd.conf 19 Jul 2008 10:35:31 -0000 1.6
+++ usr.sbin/rtadvd/rtadvd.conf 26 Jan 2012 17:11:42 -0000
@@ -18,4 +18,5 @@
# this part by hand, and then invoke rtadvd with the -s option.
#ef0:\
-# :addr="2001:db8:ffff:1000::":prefixlen#64:
+# :addr="2001:db8:ffff:1000::":prefixlen#64:\
+# :rdnss="2001:db8:ffff:1000::1":dnssl="example.com":
Index: usr.sbin/rtadvd/rtadvd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/rtadvd/rtadvd.conf.5,v
retrieving revision 1.25
diff -u -r1.25 rtadvd.conf.5
--- usr.sbin/rtadvd/rtadvd.conf.5 19 Sep 2010 21:59:23 -0000 1.25
+++ usr.sbin/rtadvd/rtadvd.conf.5 26 Jan 2012 17:11:42 -0000
@@ -216,6 +216,30 @@
will be set to the interface MTU automatically.
.El
.Pp
+The following items are for ICMPv6 RDNSS option, used to give a list of
+recursive DNS servers to hosts. If this item is omitted, no information
+about DNS servers will be advertised.
+.Bl -tag -width indent
+.It Cm \&rdnss
+(str) The list of advertised recursive DNS servers, separated by commas.
+.It Cm \&rdnssltime
+(num) Validity of the list of DNS servers
+.Pq unit: seconds .
+The default value is 1.5 * the value of maxinterval.
+.El
+.Pp
+The following items are used for ICMPv6 DNSSL option which specifies a
+list of DNS suffixes advertised to hosts. If this option is not
+specified, not DNS suffix will be sent to hosts.
+.Bl -tag -width indent
+.It Cm \&dnssl
+(str) The list of advertised DNS suffixes, separated by commas.
+.It Cm \&dnsslltime
+(num) Validity of the list of DNS suffixes
+.Pq unit: seconds .
+The default value is 1.5 * the value of maxinterval.
+.El
+.Pp
The following item controls ICMPv6 source link-layer address option,
which will be attached to router advertisement header.
As noted above, you can just omit the item, then
@@ -272,6 +296,18 @@
.Bd -literal -offset indent
ef0:\e
:addr="2001:db8:ffff:1000::":prefixlen#64:
+.Ed
+.Pp
+The following example configures two recursive DNS servers for the
+.Li em0
+interface and sets the DNS search suffix to
+.Do
+example.com
+.Dc .
+.Bd -literal -offset indent
+em0:\e
+ :rdnss="2001:db8:ffff:1000::1,2001:db8:ffff:1000::2":\e
+ :dnssl="example.com":
.Ed
.Pp
The following example presents the default values in an explicit manner.
Index: usr.sbin/rtadvd/rtadvd.h
===================================================================
RCS file: /cvs/src/usr.sbin/rtadvd/rtadvd.h,v
retrieving revision 1.11
diff -u -r1.11 rtadvd.h
--- usr.sbin/rtadvd/rtadvd.h 9 Jun 2008 22:53:24 -0000 1.11
+++ usr.sbin/rtadvd/rtadvd.h 26 Jan 2012 17:11:42 -0000
@@ -82,6 +82,27 @@
struct in6_addr prefix;
};
+struct rdnss {
+ TAILQ_ENTRY(rdnss) entry;
+
+ u_int32_t lifetime;
+ int servercnt;
+ struct in6_addr servers[];
+};
+
+struct dnssldom {
+ TAILQ_ENTRY(dnssldom) entry;
+
+ u_int32_t length;
+ char domain[];
+};
+
+struct dnssl {
+ TAILQ_ENTRY(dnssl) entry;
+
+ u_int32_t lifetime;
+ TAILQ_HEAD(dnssldomlist, dnssldom) dnssldoms;
+};
struct soliciter {
SLIST_ENTRY(soliciter) entry;
@@ -118,6 +139,10 @@
u_int hoplimit; /* AdvCurHopLimit */
TAILQ_HEAD(prefixlist, prefix) prefixes; /* AdvPrefixList(link head) */
int pfxs; /* number of prefixes */
+ TAILQ_HEAD(rdnsslist, rdnss) rdnsss; /* advertised recursive dns
servers */
+ int rdnsscnt; /* number of rdnss entries */
+ TAILQ_HEAD(dnssllist, dnssl) dnssls;
+ int dnsslcnt;
long clockskew; /* used for consisitency check of lifetimes */