This has been committed, many thanks for the diffs and sorry for the delay.
On 2012 Feb 23 (Thu) at 21:18:30 -0800 (-0800), Stephane A. Sezer wrote: :On Fri, 27 Jan 2012 15:20:29 +0100 :"Stephane A. Sezer" <s...@cd80.net> wrote: : :> 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, : :Same thing here: updated patch that applies correctly on -current. : :-- :Stephane A. Sezer : : :Index: sys/netinet/icmp6.h :=================================================================== :RCS file: /cvs/src/sys/netinet/icmp6.h,v :retrieving revision 1.33 :diff -u sys/netinet/icmp6.h :--- sys/netinet/icmp6.h 22 Mar 2010 12:23:32 -0000 1.33 :+++ sys/netinet/icmp6.h 22 Feb 2012 03:52:17 -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 usr.sbin/rtadvd/config.c :--- usr.sbin/rtadvd/config.c 23 Apr 2008 10:17:50 -0000 1.26 :+++ usr.sbin/rtadvd/config.c 22 Feb 2012 03:52:25 -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,7 +720,21 @@ : 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) : fatal("malloc"); :@@ -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 usr.sbin/rtadvd/config.h :--- usr.sbin/rtadvd/config.h 18 Jun 2003 02:26:58 -0000 1.6 :+++ usr.sbin/rtadvd/config.h 22 Feb 2012 03:52:25 -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 usr.sbin/rtadvd/dump.c :--- usr.sbin/rtadvd/dump.c 21 Jul 2008 19:14:15 -0000 1.10 :+++ usr.sbin/rtadvd/dump.c 22 Feb 2012 03:52:25 -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 usr.sbin/rtadvd/rtadvd.c :--- usr.sbin/rtadvd/rtadvd.c 2 Mar 2011 17:30:48 -0000 1.39 :+++ usr.sbin/rtadvd/rtadvd.c 22 Feb 2012 03:52:26 -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 usr.sbin/rtadvd/rtadvd.conf :--- usr.sbin/rtadvd/rtadvd.conf 19 Jul 2008 10:35:31 -0000 1.6 :+++ usr.sbin/rtadvd/rtadvd.conf 22 Feb 2012 03:52:26 -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 usr.sbin/rtadvd/rtadvd.conf.5 :--- usr.sbin/rtadvd/rtadvd.conf.5 19 Sep 2010 21:59:23 -0000 1.25 :+++ usr.sbin/rtadvd/rtadvd.conf.5 22 Feb 2012 03:52:26 -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 usr.sbin/rtadvd/rtadvd.h :--- usr.sbin/rtadvd/rtadvd.h 9 Jun 2008 22:53:24 -0000 1.11 :+++ usr.sbin/rtadvd/rtadvd.h 22 Feb 2012 03:52:26 -0000 :@@ -82,7 +82,28 @@ : 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; : struct sockaddr_in6 addr; :@@ -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 */ : -- [Crash programs] fail because they are based on the theory that, with nine women pregnant, you can get a baby a month. -- Wernher von Braun