Hello tech@,

I'm working on implementing RFC6106 (IPv6 Router Advertisement Options
for DNS Configuration) in rtadvd(8).

The attached patch adds support for RDNSS (recursive DNS servers)
option. It is tested and seems to work well with rdnssd under linux.  It
adds an option for /etc/rtadvd.conf to specify the list of dns servers
to advertise.

Support for DNSSL (DNS search list) is on the way too.

Just looking for comments about the code.

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 18 Jan 2011 21:19:30 -0000
@@ -282,6 +282,7 @@
 #define ND_OPT_PREFIX_INFORMATION      3
 #define ND_OPT_REDIRECTED_HEADER       4
 #define ND_OPT_MTU                     5
+#define ND_OPT_RDNSS                   25
 
 struct nd_opt_prefix_info {    /* prefix information */
        u_int8_t        nd_opt_pi_type;
@@ -310,6 +311,14 @@
        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;
 
 /*
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    18 Jan 2011 21:19:38 -0000
@@ -109,6 +109,7 @@
                fatal("malloc");
 
        TAILQ_INIT(&tmp->prefixes);
+       TAILQ_INIT(&tmp->rdnsss);
        SLIST_INIT(&tmp->soliciters);
 
        /* check if we are allowed to forward packets (if not determined) */
@@ -323,6 +324,55 @@
        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 "
+                           "(must be between %d and %d)",
+                           entbuf, val, intface, tmp->maxinterval,
+                           tmp->maxinterval * 2);
+                       exit(1);
+               }
+               rds->lifetime = val;
+
+               val = rds->servercnt - 1;
+               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--;
+               }
+       }
+
        MAYHAVE(val, "mtu", 0);
        if (val < 0 || val > 0xffffffff) {
                log_warnx("mtu (%ld) on %s out of range", val, intface);
@@ -596,7 +646,9 @@
        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 prefix *pfx;
+       struct rdnss *rds;
 
        /* calculate total length */
        packlen = sizeof(struct nd_router_advert);
@@ -613,6 +665,8 @@
                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;
 
        /* allocate memory for the packet */
        if ((buf = malloc(packlen)) == NULL)
@@ -705,6 +759,19 @@
                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;
        }
 
        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    18 Jan 2011 21:19:38 -0000
@@ -38,7 +38,8 @@
 
 
 /*
- * 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
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      18 Jan 2011 21:19:38 -0000
@@ -103,6 +103,7 @@
 {
        struct rainfo *rai;
        struct prefix *pfx;
+       struct rdnss *rds;
        char prefixbuf[INET6_ADDRSTRLEN];
        int first;
        struct timeval now;
@@ -212,6 +213,17 @@
                        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);
                }
        }
 }
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    18 Jan 2011 21:19:38 -0000
@@ -1104,7 +1104,8 @@
                        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)
                {
                        log_info("unknown ND option(type %d)",
                            hdr->nd_opt_type);
@@ -1121,7 +1122,9 @@
                 * 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 - sizeof(struct nd_opt_rdnss)) % 16 == 0)) ||
+                   (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 +1136,7 @@
                case ND_OPT_SOURCE_LINKADDR:
                case ND_OPT_TARGET_LINKADDR:
                case ND_OPT_REDIRECTED_HEADER:
+               case ND_OPT_RDNSS:
                        break;  /* we don't care about these options */
                case ND_OPT_MTU:
                        if (ndopts->nd_opt_array[hdr->nd_opt_type]) {
@@ -1154,7 +1158,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 18 Jan 2011 21:19:38 -0000
@@ -18,4 +18,4 @@
 #   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":
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       18 Jan 2011 21:19:39 -0000
@@ -216,6 +216,19 @@
 will be set to the interface MTU automatically.
 .El
 .Pp
+The following items are for ICMPv6 RDNSS option, used to give a liste 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) Valid lifetime field
+.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 +285,14 @@
 .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.
+.Bd -literal -offset indent
+em0:\e
+       :rdnss="2001:db8:ffff:1000::1,2001:db8:ffff:1000::2":
 .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    18 Jan 2011 21:19:39 -0000
@@ -82,6 +82,13 @@
        struct in6_addr prefix;
 };
 
+struct rdnss {
+       TAILQ_ENTRY(rdnss) entry;
+
+       u_int32_t lifetime;
+       int servercnt;
+       struct in6_addr servers[];
+};
 
 struct soliciter {
        SLIST_ENTRY(soliciter) entry;
@@ -118,6 +125,8 @@
        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 */
        long    clockskew;      /* used for consisitency check of lifetimes */

Reply via email to