On Sat, Jul 07, 2012 at 12:47:32PM +0200, Peter Hessler wrote: > ressurecting an old patch. > > OK from me, anyone else?
With my sysadmin-deplying-IPv6-at-my-dayjob hat, I'd love to see that go in, but I can't test it before next week. I only had a quick glance at the code (never looked at rtadvd source code before), didn't spot anything dubious... > > > ----- Forwarded message from "Stephane A. Sezer" <s...@cd80.net> ----- > > Date: Thu, 23 Feb 2012 21:18:30 -0800 > From: "Stephane A. Sezer" <s...@cd80.net> > To: tech@openbsd.org > Subject: Re: rtadvd(8) patch 2/2 : finalize server-side RFC 6106 support > List-ID: <tech.openbsd.org> > X-Loop: tech@openbsd.org > > 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 */ > > > ----- End forwarded message ----- > > -- > Blood flows down one leg and up the other. > -- Matthieu Herrb