Hello tech@,
I recently sent a patch for RDNSS option support for rtadvd(8). Here is
a new patch which supports both RDNSS and DNSSL options.
For the DNSSL option, the code in option.c does not check if the server
list entered by the user is valid (i.e. if the servers can actually be
used as DNS suffixes). I looked at the behavior of dhcpd which does the
same thing, so I thought it should not be a problem.
Cheers,
--
Stephane 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 25 Jan 2011 01:40:48 -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 25 Jan 2011 01:40:56 -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,96 @@
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;
+ val = strlen(addr) + 1;
+ /* align size on a 8 bytes boundary for ndopt creation */
+ val = (val + 7) & ~7;
+
+ dsl = malloc(sizeof(struct dnssl) + val);
+ if (dsl == NULL)
+ fatal("malloc");
+
+ dsl->slsize = val;
+
+ val = 0;
+ while ((tmpsl = strsep(&addr, ","))) {
+ val += strlcpy(&dsl->searchlist[val], tmpsl, val -
dsl->slsize);
+ dsl->searchlist[val++] = 0;
+ }
+ /* zero out the end of the buffer */
+ while (val < dsl->slsize)
+ dsl->searchlist[val++] = 0;
+
+ 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 +688,11 @@
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;
/* calculate total length */
packlen = sizeof(struct nd_router_advert);
@@ -613,6 +709,10 @@
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)
+ packlen += sizeof(struct nd_opt_dnssl) + dsl->slsize;
/* allocate memory for the packet */
if ((buf = malloc(packlen)) == NULL)
@@ -705,6 +805,32 @@
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) {
+ ndopt_dnssl = (struct nd_opt_dnssl *)buf;
+ ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL;
+ ndopt_dnssl->nd_opt_dnssl_len = 1 + dsl->slsize / 8;
+ ndopt_dnssl->nd_opt_dnssl_reserved = 0;
+ ndopt_dnssl->nd_opt_dnssl_lifetime = htonl(dsl->lifetime);
+
+ buf += sizeof(struct nd_opt_dnssl);
+
+ memcpy(buf, dsl->searchlist, dsl->slsize);
+ buf += dsl->slsize;
}
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 25 Jan 2011 01:40:56 -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 25 Jan 2011 01:40:56 -0000
@@ -103,6 +103,8 @@
{
struct rainfo *rai;
struct prefix *pfx;
+ struct rdnss *rds;
+ struct dnssl *dsl;
char prefixbuf[INET6_ADDRSTRLEN];
int first;
struct timeval now;
@@ -212,6 +214,36 @@
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) {
+ int size = 0;
+
+ log_info(" Domains:");
+ while (size < dsl->slsize)
+ {
+ /* ignore the padding nul bytes at the end */
+ if (dsl->searchlist[size] == 0)
+ break;
+
+ log_info(" %s", &dsl->searchlist[size]);
+ size += strlen(&dsl->searchlist[size]) + 1;
+ }
+ 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.38
diff -u -r1.38 rtadvd.c
--- usr.sbin/rtadvd/rtadvd.c 21 Nov 2008 23:44:04 -0000 1.38
+++ usr.sbin/rtadvd/rtadvd.c 25 Jan 2011 01:40:56 -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 25 Jan 2011 01:40:56 -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 25 Jan 2011 01:40:56 -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 25 Jan 2011 01:40:57 -0000
@@ -82,6 +82,21 @@
struct in6_addr prefix;
};
+struct rdnss {
+ TAILQ_ENTRY(rdnss) entry;
+
+ u_int32_t lifetime;
+ int servercnt;
+ struct in6_addr servers[];
+};
+
+struct dnssl {
+ TAILQ_ENTRY(dnssl) entry;
+
+ u_int32_t lifetime;
+ int slsize;
+ char searchlist[];
+};
struct soliciter {
SLIST_ENTRY(soliciter) entry;
@@ -118,6 +133,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 */