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 */

Reply via email to