Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 29 May 2011 05:24:58 +0000 (UTC)
From:      Hiroki Sato <hrs@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r222442 - in user/hrs/ipv6: sys/netinet usr.sbin/rtadvd usr.sbin/rtsold
Message-ID:  <201105290524.p4T5Owot016088@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hrs
Date: Sun May 29 05:24:58 2011
New Revision: 222442
URL: http://svn.freebsd.org/changeset/base/222442

Log:
  Implemnt RDNSS and DNSSL options (RFC 6106, IPv6 Router Advertisement
  Options for DNS Configuration) into rtadvd(8) and rtsold(8).  DNS
  information received by rtsold(8) will go to resolv.conf(5) by
  resolvconf(8) script.  Lifetime handling is not supported at this
  moment.
  
  Note: when receiving a link-local scope address rtsold(8) adds a scope
  id into addresses in the script arguments based on the received
  interface in a representation defined in RFC 4007 (e.g. fe80::1%bge0).
  However, there are some shell scripts using printf(1) (including
  resolvconf(8)) cannot process it properly because printf(1) can
  recognize the character % as special.
  
  Based on work by:	J.R. Oldroyd
  PR:			kern/156259

Modified:
  user/hrs/ipv6/sys/netinet/icmp6.h
  user/hrs/ipv6/usr.sbin/rtadvd/Makefile
  user/hrs/ipv6/usr.sbin/rtadvd/config.c
  user/hrs/ipv6/usr.sbin/rtadvd/config.h
  user/hrs/ipv6/usr.sbin/rtadvd/dump.c
  user/hrs/ipv6/usr.sbin/rtadvd/if.c
  user/hrs/ipv6/usr.sbin/rtadvd/rrenum.c
  user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.c
  user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.conf
  user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.conf.5
  user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.h
  user/hrs/ipv6/usr.sbin/rtsold/rtsol.c
  user/hrs/ipv6/usr.sbin/rtsold/rtsold.8
  user/hrs/ipv6/usr.sbin/rtsold/rtsold.c
  user/hrs/ipv6/usr.sbin/rtsold/rtsold.h

Modified: user/hrs/ipv6/sys/netinet/icmp6.h
==============================================================================
--- user/hrs/ipv6/sys/netinet/icmp6.h	Sun May 29 05:12:24 2011	(r222441)
+++ user/hrs/ipv6/sys/netinet/icmp6.h	Sun May 29 05:24:58 2011	(r222442)
@@ -297,6 +297,8 @@ struct nd_opt_hdr {		/* Neighbor discove
 #define ND_OPT_PREFIX_INFORMATION	3
 #define ND_OPT_REDIRECTED_HEADER	4
 #define ND_OPT_MTU			5
+#define ND_OPT_RDNSS			25	/* RFC 6016 */
+#define ND_OPT_DNSSL			31	/* RFC 6016 */
 
 #define ND_OPT_ROUTE_INFO		200	/* draft-ietf-ipngwg-router-preference, not officially assigned yet */
 
@@ -338,6 +340,22 @@ struct nd_opt_route_info {	/* route info
 	/* prefix follows */
 } __packed;
 
+struct nd_opt_rdnss {		/* RDNSS option (RFC 6106) */
+	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 (RFC 6106) */
+	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;
+
 /*
  * icmp6 namelookup
  */

Modified: user/hrs/ipv6/usr.sbin/rtadvd/Makefile
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/Makefile	Sun May 29 05:12:24 2011	(r222441)
+++ user/hrs/ipv6/usr.sbin/rtadvd/Makefile	Sun May 29 05:24:58 2011	(r222442)
@@ -21,7 +21,7 @@ SRCS=	rtadvd.c rrenum.c advcap.c if.c co
 DPADD=	${LIBUTIL}
 LDADD=	-lutil
 
-CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H -DROUTEINFO
+CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H -DROUTEINFO -DRDNSS
 
 WARNS?=	1
 

Modified: user/hrs/ipv6/usr.sbin/rtadvd/config.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/config.c	Sun May 29 05:12:24 2011	(r222441)
+++ user/hrs/ipv6/usr.sbin/rtadvd/config.c	Sun May 29 05:24:58 2011	(r222442)
@@ -53,6 +53,7 @@
 #include <stdio.h>
 #include <syslog.h>
 #include <errno.h>
+#include <netdb.h>
 #include <string.h>
 #include <search.h>
 #include <stdlib.h>
@@ -65,6 +66,11 @@
 #include "if.h"
 #include "config.h"
 
+/* label of tcapcode + number + domain name + zero octet */
+static char entbuf[10 + 3 + NI_MAXHOST + 1];
+static char oentbuf[10 + 3 + NI_MAXHOST + 1];
+static char abuf[DNAME_LABELENC_MAXLEN];
+
 static time_t prefix_timo = (60 * 120);	/* 2 hours.
 					 * XXX: should be configurable. */
 extern struct rainfo *ralist;
@@ -72,6 +78,32 @@ extern struct rainfo *ralist;
 static struct rtadvd_timer *prefix_timeout(void *);
 static void makeentry(char *, size_t, int, char *);
 static int getinet6sysctl(int);
+static size_t dname_labelenc(char *, const char *);
+
+/* Encode domain name label encoding in RFC 1035 Section 3.1 */
+static size_t
+dname_labelenc(char *dst, const char *src)
+{
+	char *dst_origin;
+	size_t len;
+
+	dst_origin = dst;
+	len = strlen(src);
+
+	/* Length fields per 63 octets + '\0' (<= DNAME_LABELENC_MAXLEN) */
+	memset(dst, 0, len + len / 64 + 1 + 1);
+
+	syslog(LOG_DEBUG, "<%s> labelenc = %s", __func__, src);
+	while ((len = strlen(src)) != 0) {
+		/* Put a length field with 63 octet limitation first. */
+		*dst++ = len = MIN(63, len + 1);
+		memcpy(dst, src, len);
+		dst += len;
+		src += len;
+	}
+	syslog(LOG_DEBUG, "<%s> labellen = %d", __func__, dst - dst_origin);
+	return (dst - dst_origin);
+}
 
 void
 getconfig(intface)
@@ -123,6 +155,10 @@ getconfig(intface)
 #ifdef ROUTEINFO
 	tmp->route.next = tmp->route.prev = &tmp->route;
 #endif
+#ifdef RDNSS
+	TAILQ_INIT(&tmp->rdnss);
+	TAILQ_INIT(&tmp->dnssl);
+#endif
 
 	/* check if we are allowed to forward packets (if not determined) */
 	if (forwarding < 0) {
@@ -276,7 +312,6 @@ getconfig(intface)
 	tmp->pfxs = 0;
 	for (i = -1; i < MAXPREFIX; i++) {
 		struct prefix *pfx;
-		char entbuf[256];
 
 		makeentry(entbuf, sizeof(entbuf), i, "addr");
 		addr = (char *)agetstr(entbuf, &bp);
@@ -442,7 +477,6 @@ getconfig(intface)
 	tmp->routes = 0;
 	for (i = -1; i < MAXROUTE; i++) {
 		struct rtinfo *rti;
-		char entbuf[256], oentbuf[256];
 
 		makeentry(entbuf, sizeof(entbuf), i, "rtprefix");
 		addr = (char *)agetstr(entbuf, &bp);
@@ -585,6 +619,118 @@ getconfig(intface)
 	}
 #endif
 
+#ifdef RDNSS
+	/* DNS server and DNS search list information */
+	for (i = -1; i < MAXRDNSSENT ; i++) {
+		struct rdnss *rdn;
+		struct rdnss_addr *rdna;
+		char *ap;
+		int c;
+
+		makeentry(entbuf, sizeof(entbuf), i, "rdnss");
+		addr = (char *)agetstr(entbuf, &bp);
+		if (addr == NULL)
+			break;
+		rdn = malloc(sizeof(*rdn));
+		if (rdn == NULL) {
+			syslog(LOG_ERR,
+			   "<%s> can't get allocate buffer for rdnss entry",
+			   __func__);
+			exit(1);
+		}
+		memset(rdn, 0, sizeof(*rdn));
+		TAILQ_INIT(&rdn->rd_list);
+
+		for (ap = addr; ap - addr < strlen(addr); ap += c+1) {
+			c = strcspn(ap, ",");
+			strncpy(abuf, ap, c);
+			abuf[c] = '\0';
+			rdna = malloc(sizeof(*rdna));
+			if (rdna == NULL) {
+				syslog(LOG_ERR,
+				    "<%s> can't get allocate buffer for "
+				    "rdnss_addr entry",
+				    __func__);
+				exit(1);
+			}
+			memset(rdna, 0, sizeof(*rdna));
+			if (inet_pton(AF_INET6, abuf, &rdna->ra_dns) != 1) {
+				syslog(LOG_ERR, "<%s> inet_pton failed for %s",
+				    __func__, abuf);
+				exit(1);
+			} 
+			TAILQ_INSERT_TAIL(&rdn->rd_list, rdna, ra_next);
+		}
+
+		makeentry(entbuf, sizeof(entbuf), i, "rdnssltime");
+		MAYHAVE(val, entbuf, (tmp->maxinterval * 3 / 2));
+		if (val < tmp->maxinterval || val > tmp->maxinterval * 2) {
+			syslog(LOG_ERR, "%s (%ld) on %s is invalid "
+			    "(must be between %d and %d)",
+			    entbuf, val, intface, tmp->maxinterval,
+			    tmp->maxinterval * 2);
+			exit(1);
+		}
+		rdn->rd_ltime = val;
+
+		/* link into chain */
+		insque(rdn, &tmp->rdnss);
+	}
+
+	for (i = -1; i < MAXDNSSLENT ; i++) {
+		struct dnssl *dns;
+		struct dnssl_addr *dnsa;
+		char *ap;
+		int c;
+		char *p, *q;
+
+		makeentry(entbuf, sizeof(entbuf), i, "dnssl");
+		addr = (char *)agetstr(entbuf, &bp);
+		if (addr == NULL)
+			break;
+		dns = malloc(sizeof(*dns));
+		if (dns == NULL) {
+			syslog(LOG_ERR,
+			       "<%s> can't get allocate buffer for dnssl entry",
+			       __func__);
+			exit(1);
+		}
+		memset(dns, 0, sizeof(*dns));
+		TAILQ_INIT(&dns->dn_list);
+
+		for (ap = addr; ap - addr < strlen(addr); ap += c+1) {
+			c = strcspn(ap, ",");
+			strncpy(abuf, ap, c);
+			abuf[c] = '\0';
+			dnsa = malloc(sizeof(struct dnssl_addr));
+			if (dnsa == NULL) {
+				syslog(LOG_ERR,
+				    "<%s> can't get allocate buffer for "
+				    "dnssl_addr entry", __func__);
+				exit(1);
+			}
+			memset(dnsa, 0, sizeof(*dnsa));
+			dnsa->da_len = dname_labelenc(dnsa->da_dom, abuf);
+			syslog(LOG_DEBUG, "<%s>: dnsa->da_len = %d", __func__,
+			    dnsa->da_len);
+			TAILQ_INSERT_TAIL(&dns->dn_list, dnsa, da_next);
+		}
+
+		makeentry(entbuf, sizeof(entbuf), i, "dnsslltime");
+		MAYHAVE(val, entbuf, (tmp->maxinterval * 3 / 2));
+		if (val < tmp->maxinterval || val > tmp->maxinterval * 2) {
+			syslog(LOG_ERR, "%s (%ld) on %s is invalid "
+			    "(must be between %d and %d)",
+			    entbuf, val, intface, tmp->maxinterval,
+			    tmp->maxinterval * 2);
+			exit(1);
+		}
+		dns->dn_ltime = val;
+
+		/* link into chain */
+		insque(dns, &tmp->dnssl);
+	}
+#endif
 	/* okey */
 	tmp->next = ralist;
 	ralist = tmp;
@@ -913,6 +1059,13 @@ make_packet(struct rainfo *rainfo)
 	struct nd_opt_route_info *ndopt_rti;
 	struct rtinfo *rti;
 #endif
+#ifdef RDNSS
+	struct nd_opt_rdnss *ndopt_rdnss;
+	struct rdnss *rdn;
+	struct nd_opt_dnssl *ndopt_dnssl;
+	struct dnssl *dns;
+	size_t len;
+#endif
 	struct prefix *pfx;
 
 	/* calculate total length */
@@ -936,6 +1089,29 @@ make_packet(struct rainfo *rainfo)
 		packlen += sizeof(struct nd_opt_route_info) + 
 			   ((rti->prefixlen + 0x3f) >> 6) * 8;
 #endif
+#ifdef RDNSS
+	TAILQ_FOREACH(rdn, &rainfo->rdnss, rd_next) {
+		struct rdnss_addr *rdna;
+
+		packlen += sizeof(struct nd_opt_rdnss);
+		TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next)
+			packlen += sizeof(rdna->ra_dns);
+	}
+	TAILQ_FOREACH(dns, &rainfo->dnssl, dn_next) {
+		struct dnssl_addr *dnsa;
+
+		packlen += sizeof(struct nd_opt_dnssl);
+		len = 0;
+		TAILQ_FOREACH(dnsa, &dns->dn_list, da_next)
+			len += dnsa->da_len;
+
+		/* A zero octet and 8 octet boundary */
+		len++;
+		len += 8 - (len % 8);
+
+		packlen += len;
+	}
+#endif
 
 	/* allocate memory for the packet */
 	if ((buf = malloc(packlen)) == NULL) {
@@ -944,6 +1120,7 @@ make_packet(struct rainfo *rainfo)
 		       __func__);
 		exit(1);
 	}
+	memset(buf, 0, packlen);
 	if (rainfo->ra_data) {
 		/* free the previous packet */
 		free(rainfo->ra_data);
@@ -1056,6 +1233,57 @@ make_packet(struct rainfo *rainfo)
 	}
 #endif
 
+#ifdef RDNSS
+	TAILQ_FOREACH(rdn, &rainfo->rdnss, rd_next) {
+		struct rdnss_addr *rdna;
+
+		ndopt_rdnss = (struct nd_opt_rdnss *)buf;
+		ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
+		ndopt_rdnss->nd_opt_rdnss_len = 0;
+		ndopt_rdnss->nd_opt_rdnss_reserved = 0;
+		ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rdn->rd_ltime);
+		buf += sizeof(struct nd_opt_rdnss);
+
+		TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) {
+			memcpy(buf, &rdna->ra_dns, sizeof(rdna->ra_dns));
+			buf += sizeof(rdna->ra_dns);
+		}
+		/* Length field should be in 8 octets */
+		ndopt_rdnss->nd_opt_rdnss_len = (buf - (char *)ndopt_rdnss) / 8;
+
+		syslog(LOG_DEBUG, "<%s>: nd_opt_dnss_len = %d", __func__,
+			ndopt_rdnss->nd_opt_rdnss_len);
+	}
+	TAILQ_FOREACH(dns, &rainfo->dnssl, dn_next) {
+		struct dnssl_addr *dnsa;
+		size_t len = 0;
+
+		ndopt_dnssl = (struct nd_opt_dnssl *)buf;
+		ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL;
+		ndopt_dnssl->nd_opt_dnssl_len = 0;
+		ndopt_dnssl->nd_opt_dnssl_reserved = 0;
+		ndopt_dnssl->nd_opt_dnssl_lifetime = htonl(dns->dn_ltime);
+		buf += sizeof(*ndopt_dnssl);
+
+		TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) {
+			memcpy(buf, dnsa->da_dom, dnsa->da_len);
+			buf += dnsa->da_len;
+		}
+
+		/* A zero octet after encoded DNS server list. */
+		*buf++ = '\0';
+		
+		/* Padding to next 8 octets boundary */
+		len = buf - (char *)ndopt_dnssl;
+		len += 8 - (len % 8);
+
+		/* Length field must be in 8 octets */
+		ndopt_dnssl->nd_opt_dnssl_len = len / 8;
+
+		syslog(LOG_DEBUG, "<%s>: nd_opt_dnssl_len = %d", __func__,
+			ndopt_dnssl->nd_opt_dnssl_len);
+	}
+#endif
 	return;
 }
 

Modified: user/hrs/ipv6/usr.sbin/rtadvd/config.h
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/config.h	Sun May 29 05:12:24 2011	(r222441)
+++ user/hrs/ipv6/usr.sbin/rtadvd/config.h	Sun May 29 05:24:58 2011	(r222442)
@@ -45,3 +45,5 @@ extern void get_prefix(struct rainfo *);
  */
 #define MAXPREFIX	100
 #define MAXROUTE	100
+#define MAXRDNSSENT	100
+#define MAXDNSSLENT	100

Modified: user/hrs/ipv6/usr.sbin/rtadvd/dump.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/dump.c	Sun May 29 05:12:24 2011	(r222441)
+++ user/hrs/ipv6/usr.sbin/rtadvd/dump.c	Sun May 29 05:24:58 2011	(r222442)
@@ -45,6 +45,7 @@
 
 #include <arpa/inet.h>
 
+#include <netdb.h>
 #include <time.h>
 #include <stdio.h>
 #include <stdarg.h>
@@ -63,6 +64,7 @@ extern struct rainfo *ralist;
 
 static char *ether_str(struct sockaddr_dl *);
 static void if_dump(void);
+static size_t dname_labeldec(char *, const char *);
 
 static char *rtpref_str[] = {
 	"medium",		/* 00 */
@@ -96,6 +98,10 @@ if_dump()
 #ifdef ROUTEINFO
 	struct rtinfo *rti;
 #endif
+#ifdef RDNSS
+	struct rdnss *rdn;
+	struct dnssl *dns;
+#endif
 	char prefixbuf[INET6_ADDRSTRLEN];
 	int first;
 	struct timeval now;
@@ -230,6 +236,44 @@ if_dump()
 			fprintf(fp, ")\n");
 		}
 #endif
+#ifdef RDNSS
+		TAILQ_FOREACH(rdn, &rai->rdnss, rd_next) {
+			struct rdnss_addr *rdna;
+
+			if (rdn == TAILQ_FIRST(&rai->rdnss))
+				fprintf(fp, "  Recursive DNS servers:\n"
+					    "    Lifetime\tServers\n");
+
+			fprintf(fp, "    % 8u\t", rdn->rd_ltime);
+			TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) {
+				inet_ntop(AF_INET6, &rdna->ra_dns,
+				    prefixbuf, sizeof(prefixbuf));
+				
+				if (rdna != TAILQ_FIRST(&rdn->rd_list))
+					fprintf(fp, "            \t");
+				fprintf(fp, "%s\n", prefixbuf);
+			}
+			fprintf(fp, "\n");
+		}
+
+		TAILQ_FOREACH(dns, &rai->dnssl, dn_next) {
+			struct dnssl_addr *dnsa;
+			char buf[NI_MAXHOST + 1];
+
+			if (dns == TAILQ_FIRST(&rai->dnssl))
+				fprintf(fp, "  DNS search list:\n"
+					    "    Lifetime\tDomains\n");
+
+			fprintf(fp, "    % 8u\t", dns->dn_ltime);
+			TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) {
+				dname_labeldec(buf, dnsa->da_dom);
+				if (dnsa != TAILQ_FIRST(&dns->dn_list))
+					fprintf(fp, "            \t");
+				fprintf(fp, "%s(%d)\n", buf, dnsa->da_len);
+			}
+			fprintf(fp, "\n");
+		}
+#endif
 	}
 }
 
@@ -250,3 +294,23 @@ rtadvd_dump_file(dumpfile)
 
 	fclose(fp);
 }
+
+/* Decode domain name label encoding in RFC 1035 Section 3.1 */
+static size_t
+dname_labeldec(char *dst, const char *src)
+{
+	size_t len;
+	const char *src_origin;
+
+	src_origin = src;
+	while (*src && (len = (uint8_t)(*src++) & 0x3f) != 0) {
+		syslog(LOG_DEBUG, "<%s> labellen = %d", __func__, len);
+		memcpy(dst, src, len);
+		src += len;
+		dst += len;
+		if (*(dst - 1) == '\0')
+			break;
+	}
+
+	return (src - src_origin);
+}

Modified: user/hrs/ipv6/usr.sbin/rtadvd/if.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/if.c	Sun May 29 05:12:24 2011	(r222441)
+++ user/hrs/ipv6/usr.sbin/rtadvd/if.c	Sun May 29 05:24:58 2011	(r222442)
@@ -44,6 +44,7 @@
 #include <netinet/icmp6.h>
 #include <unistd.h>
 #include <errno.h>
+#include <netdb.h>
 #include <stdlib.h>
 #include <string.h>
 #include <syslog.h>

Modified: user/hrs/ipv6/usr.sbin/rtadvd/rrenum.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/rrenum.c	Sun May 29 05:12:24 2011	(r222441)
+++ user/hrs/ipv6/usr.sbin/rtadvd/rrenum.c	Sun May 29 05:24:58 2011	(r222442)
@@ -45,6 +45,7 @@
 #include <arpa/inet.h>
 
 #include <errno.h>
+#include <netdb.h>
 #include <string.h>
 #include <stdlib.h>
 #include <syslog.h>

Modified: user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.c	Sun May 29 05:12:24 2011	(r222441)
+++ user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.c	Sun May 29 05:24:58 2011	(r222442)
@@ -37,6 +37,7 @@
 #include <sys/queue.h>
 
 #include <net/if.h>
+#include <net/if_media.h>
 #include <net/route.h>
 #include <net/if_dl.h>
 #include <netinet/in.h>
@@ -52,6 +53,7 @@
 #include <err.h>
 #include <errno.h>
 #include <libutil.h>
+#include <netdb.h>
 #include <string.h>
 #include <stdlib.h>
 #include <syslog.h>
@@ -115,15 +117,26 @@ union nd_opts {
 #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)
+#ifdef RDNSS
+#define NDOPT_FLAG_RDNSS	(1 << 5)
+#define NDOPT_FLAG_DNSSL	(1 << 6)
+#endif
 
 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,
+#ifdef RDNSS
+	[ND_OPT_RDNSS]			= NDOPT_FLAG_RDNSS,
+	[ND_OPT_DNSSL]			= NDOPT_FLAG_DNSSL,
+#endif
 };
 
 int main(int, char *[]);
@@ -376,6 +389,10 @@ static void
 die()
 {
 	struct rainfo *ra;
+#ifdef RDNSS
+	struct rdnss *rdn;
+	struct dnssl *dns;
+#endif
 	int i;
 	const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS;
 
@@ -386,6 +403,12 @@ die()
 
 	for (ra = ralist; ra; ra = ra->next) {
 		ra->lifetime = 0;
+#ifdef RDNSS
+		TAILQ_FOREACH(rdn, &ra->rdnss, rd_next)
+			rdn->rd_ltime = 0;
+		TAILQ_FOREACH(dns, &ra->dnssl, dn_next)
+			dns->dn_ltime = 0;
+#endif
 		make_packet(ra);
 	}
 	for (i = 0; i < retrans; i++) {
@@ -961,7 +984,11 @@ ra_input(int len, struct nd_router_adver
 	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)) {
+			NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU
+#ifdef RDNSS
+			| NDOPT_FLAG_RDNSS | NDOPT_FLAG_DNSSL
+#endif
+	    )) {
 		syslog(LOG_INFO,
 		       "<%s> ND option check failed for an RA from %s on %s",
 		       __func__,
@@ -1300,7 +1327,12 @@ nd6_options(struct nd_opt_hdr *hdr, int 
 			goto bad;
 		}
 
-		if (hdr->nd_opt_type > ND_OPT_MTU) {
+		if (hdr->nd_opt_type > ND_OPT_MTU
+#ifdef RDNSS
+		    && hdr->nd_opt_type != ND_OPT_RDNSS &&
+		       hdr->nd_opt_type != ND_OPT_DNSSL
+#endif
+		    ) {
 			syslog(LOG_INFO, "<%s> unknown ND option(type %d)",
 			    __func__, hdr->nd_opt_type);
 			continue;
@@ -1317,9 +1349,18 @@ nd6_options(struct nd_opt_hdr *hdr, int 
 		 * options.
 		 */
 		if ((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)))) {
+			optlen != sizeof(struct nd_opt_mtu)) ||
+#ifdef RDNSS
+		    (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 ||
+			(optlen - sizeof(struct nd_opt_dnssl)) % 8 != 0)) ||
+#endif
+		    (hdr->nd_opt_type == ND_OPT_PREFIX_INFORMATION &&
+			optlen != sizeof(struct nd_opt_prefix_info))
+		) {
 			syslog(LOG_INFO, "<%s> invalid option length",
 			    __func__);
 			continue;
@@ -1328,6 +1369,10 @@ nd6_options(struct nd_opt_hdr *hdr, int 
 		switch (hdr->nd_opt_type) {
 		case ND_OPT_TARGET_LINKADDR:
 		case ND_OPT_REDIRECTED_HEADER:
+#ifdef RDNSS
+		case ND_OPT_RDNSS:
+		case ND_OPT_DNSSL:
+#endif
 			break;	/* we don't care about these options */
 		case ND_OPT_SOURCE_LINKADDR:
 		case ND_OPT_MTU:

Modified: user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.conf
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.conf	Sun May 29 05:12:24 2011	(r222441)
+++ user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.conf	Sun May 29 05:24:58 2011	(r222442)
@@ -18,4 +18,5 @@
 #   this part by hand, and then invoke rtadvd with the -s option.
  
 #ef0:\
-#	:addr="3ffe:501:ffff:1000::":prefixlen#64:
+#	:addr="2001:db8:ffff:1000::":prefixlen#64:\
+#	:rddns="2001:db8:ffff:1000::1":dnssl="foo.com":

Modified: user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.conf.5
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.conf.5	Sun May 29 05:12:24 2011	(r222441)
+++ user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.conf.5	Sun May 29 05:24:58 2011	(r222442)
@@ -29,7 +29,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd May 17, 1998
+.Dd May 28, 2011
 .Dt RTADVD.CONF 5
 .Os
 .Sh NAME
@@ -355,6 +355,65 @@ However, keywords that start with
 .Dq Li rtr
 have basically been obsoleted, and should not be used any more.
 .Pp
+The following items are for ICMPv6 Recursive DNS Server Option and
+DNS Search List Option
+.Pq RFC 6106 ,
+which will be attached to router advertisement header.
+These items are optional.
+.Bl -tag -width indent
+.It Cm \&rdnss
+(str) The IPv6 address of one or more recursive DNS servers.
+The argument must be inside double quotes.
+Multiple DNS servers can be specified in a comma-separated string.
+If different lifetimes are needed for different servers,
+separate entries can be given by using
+.Cm rdnss ,
+.Cm rdnss0 ,
+.Cm rdnss1 ,
+.Cm rdnss2 ...
+options with corresponding
+.Cm rdnssltime ,
+.Cm rdnssltime0 ,
+.Cm rdnssltime1 ,
+.Cm rdnssltime2 ...
+entries.
+Note that the maximum number of servers depends on the receiver side.
+See also
+.Xr resolver 5
+manual page for resolver implementation in
+.Fx .
+.It Cm \&rdnssltime
+The lifetime of the
+.Cm rdnss
+DNS server entries.  The default value is 3/2 of the interval
+time.
+.It Cm \&dnssl
+(str) One or more domain names in a comma-separated string.
+These domain names will be used when making DNS queries on a
+non-fully-qualified domain name.  If different lifetimes are needed for
+different domains, separate entries can be given by using
+.Cm dnssl ,
+.Cm dnssl0 ,
+.Cm dnssl1 ,
+.Cm dnssl2 ...
+options with corresponding
+.Cm dnsslltime ,
+.Cm dnsslltime0 ,
+.Cm dnsslltime1 ,
+.Cm dnsslltime2 ...
+entries.
+Note that the maximum number of names depends on the receiver side.
+See also
+.Xr resolver 5
+manual page for resolver implementation in
+.Fx .
+.It Cm \&dnsslltime
+The lifetime of the
+.Cm dnssl
+DNS search list entries.  The default value is 3/2 of the interval
+time.
+.El
+.Pp
 You can also refer one line from another by using
 .Cm tc
 capability.
@@ -388,7 +447,18 @@ option to
 .Xr rtadvd 8 .
 .Bd -literal -offset
 ef0:\\
-	:addr="3ffe:501:ffff:1000::":prefixlen#64:
+	:addr="2001:db8:ffff:1000::":prefixlen#64:
+.Ed
+.Pp
+The following example configures the
+.Li wlan0
+interface and adds two DNS servers and a DNS domain search options
+using the default option lifetime values.
+.Bd -literal -offset
+wlan0:\\
+	:addr="2001:db8:ffff:1000::":prefixlen#64:\\
+	:rdnss="2001:db8:ffff::10,2001:db8:ffff::2:43:\\
+	:dnssl="foo.com":
 .Ed
 .Pp
 The following example presents the default values in an explicit manner.
@@ -399,10 +469,11 @@ default:\\
 	:chlim#64:raflags#0:rltime#1800:rtime#0:retrans#0:\\
 	:pinfoflags="la":vltime#2592000:pltime#604800:mtu#0:
 ef0:\\
-	:addr="3ffe:501:ffff:1000::":prefixlen#64:tc=default:
+	:addr="2001:db8:ffff:1000::":prefixlen#64:tc=default:
 .Ed
 .Sh SEE ALSO
 .Xr termcap 5 ,
+.Xr resolver 5 ,
 .Xr rtadvd 8 ,
 .Xr rtsol 8
 .Rs
@@ -417,6 +488,14 @@ ef0:\\
 .%T Default Router Preferences and More-Specific Routes
 .%R draft-ietf-ipngwg-router-selection-xx.txt
 .Re
+.Rs
+.%A J. Jeong
+.%A S. Park
+.%A L. Beloeil
+.%A S. Madanapalli
+.%T IPv6 Router Advertisement Options for DNS Configuration
+.%R RFC 6106
+.Re
 .Sh HISTORY
 The
 .Xr rtadvd 8

Modified: user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.h
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.h	Sun May 29 05:12:24 2011	(r222441)
+++ user/hrs/ipv6/usr.sbin/rtadvd/rtadvd.h	Sun May 29 05:24:58 2011	(r222442)
@@ -94,6 +94,44 @@ struct rtinfo {
 };
 #endif
 
+#ifdef RDNSS
+struct rdnss_addr {
+	TAILQ_ENTRY(rdnss_addr)	ra_next;
+
+	struct in6_addr ra_dns;	/* DNS server entry */
+};
+struct rdnss {
+	TAILQ_ENTRY(rdnss) rd_next;
+
+	TAILQ_HEAD(, rdnss_addr) rd_list; /* list of DNS servers */
+	int rd_cnt;		/* number of DNS servers */
+	u_int32_t rd_ltime;	/* number of seconds valid */
+};
+
+/*
+ * The maximum length of a domain name in a DNS search list is calculated
+ * by a domain name + length fields per 63 octets + a zero octet at
+ * the tail and adding 8 octet boundary padding.
+ */
+#define _DNAME_LABELENC_MAXLEN \
+	(NI_MAXHOST + (NI_MAXHOST / 64 + 1) + 1)
+#define DNAME_LABELENC_MAXLEN \
+	(_DNAME_LABELENC_MAXLEN + 8 - _DNAME_LABELENC_MAXLEN % 8)
+
+struct dnssl_addr {
+	TAILQ_ENTRY(dnssl_addr)	da_next;
+
+	int da_len;			/* length of entry */
+	char da_dom[DNAME_LABELENC_MAXLEN];	/* search domain name entry */
+};
+struct dnssl {
+	TAILQ_ENTRY(dnssl)	dn_next;
+
+	TAILQ_HEAD(, dnssl_addr) dn_list; /* list of search domains */
+	u_int32_t dn_ltime;	/* number of seconds valid */
+};
+#endif
+
 struct soliciter {
 	struct soliciter *next;
 	struct sockaddr_in6 addr;
@@ -130,6 +168,10 @@ struct	rainfo {
 	u_int	hoplimit;	/* AdvCurHopLimit */
 	struct prefix prefix;	/* AdvPrefixList(link head) */
 	int	pfxs;		/* number of prefixes */
+#ifdef RDNSS
+	TAILQ_HEAD(, rdnss) rdnss;	/* DNS server list */
+	TAILQ_HEAD(, dnssl) dnssl;	/* search domain list */
+#endif
 	long	clockskew;	/* used for consisitency check of lifetimes */
 
 #ifdef ROUTEINFO

Modified: user/hrs/ipv6/usr.sbin/rtsold/rtsol.c
==============================================================================
--- user/hrs/ipv6/usr.sbin/rtsold/rtsol.c	Sun May 29 05:12:24 2011	(r222441)
+++ user/hrs/ipv6/usr.sbin/rtsold/rtsol.c	Sun May 29 05:24:58 2011	(r222442)
@@ -50,6 +50,7 @@
 
 #include <arpa/inet.h>
 
+#include <netdb.h>
 #include <time.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -77,9 +78,24 @@ static struct sockaddr_in6 sin6_allroute
 	.sin6_family =	AF_INET6,
 };
 
-static void call_script(char *, char *);
+struct script_msg {
+	TAILQ_ENTRY(script_msg)	sm_next;
+
+	char *sm_msg;
+};
+
+static void call_script(char **, void *);
+static size_t dname_labeldec(char *, const char *);
 static int safefile(const char *);
 
+#define _ARGS_OTHER	otherconf_script, ifi->ifname
+#define _ARGS_RESCONF	resolvconf_script, "-a", ifi->ifname
+#define CALL_SCRIPT(name, sm_head)	\
+	do {						\
+		char *sarg[] = { _ARGS_##name, NULL };	\
+		call_script(sarg, sm_head);		\
+	} while(0);
+
 int
 sockopen(void)
 {
@@ -234,17 +250,34 @@ rtsol_input(int s)
 {
 	u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
 	int ifindex = 0, *hlimp = NULL;
-	ssize_t i;
+	ssize_t msglen;
 	struct in6_pktinfo *pi = NULL;
 	struct ifinfo *ifi = NULL;
 	struct icmp6_hdr *icp;
 	struct nd_router_advert *nd_ra;
 	struct cmsghdr *cm;
+	char *raoptp;
+	char *p;
+	struct in6_addr *addr;
+	struct nd_opt_hdr *ndo;
+	struct nd_opt_rdnss *rdnss;
+	struct nd_opt_dnssl *dnssl;
+	size_t len;
+	struct script_msg *smp;
+	TAILQ_HEAD(, script_msg) sm_ns_head =
+		TAILQ_HEAD_INITIALIZER(sm_ns_head);
+	char nsbuf[11 + INET6_ADDRSTRLEN + 1 + IFNAMSIZ + 1 + 1];
+	/* 11 = sizeof("nameserver "), 1+1 = \n\0 termination */
+	TAILQ_HEAD(, script_msg) sm_sl_head =
+		TAILQ_HEAD_INITIALIZER(sm_sl_head);
+	char slbuf[7 + NI_MAXHOST + 1 + 1];
+	/* 7 = sizeof("search "), 1+1 = \n\0 termination */
+	char dname[NI_MAXHOST + 1];
 
 	/* get message.  namelen and controllen must always be initialized. */
 	rcvmhdr.msg_namelen = sizeof(from);
 	rcvmhdr.msg_controllen = rcvcmsglen;
-	if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) {
+	if ((msglen = recvmsg(s, &rcvmhdr, 0)) < 0) {
 		warnmsg(LOG_ERR, __func__, "recvmsg: %s", strerror(errno));
 		return;
 	}
@@ -275,9 +308,9 @@ rtsol_input(int s)
 		return;
 	}
 
-	if ((size_t)i < sizeof(struct nd_router_advert)) {
+	if ((size_t)msglen < sizeof(struct nd_router_advert)) {
 		warnmsg(LOG_INFO, __func__,
-		    "packet size(%zd) is too short", i);
+		    "packet size(%zd) is too short", msglen);
 		return;
 	}
 
@@ -354,9 +387,166 @@ rtsol_input(int s)
 		warnmsg(LOG_DEBUG, __func__,
 		    "OtherConfigFlag on %s is turned on", ifi->ifname);
 		ifi->otherconfig = 1;
-		call_script(otherconf_script, ifi->ifname);
+		CALL_SCRIPT(OTHER, NULL);
 	}
 
+#define RA_OPT_NEXT_HDR(x)	(struct nd_opt_hdr *)((char *)x + \
+				(((struct nd_opt_hdr *)x)->nd_opt_len * 8))
+	raoptp = (char *)icp + sizeof(struct nd_router_advert);
+
+	warnmsg(LOG_DEBUG, __func__, "Processing RA");
+	/* Process RA options. */
+	while (raoptp < (char *)icp + msglen) {
+		ndo = (struct nd_opt_hdr *)raoptp;
+		warnmsg(LOG_DEBUG, __func__, "ndo = %p", raoptp);
+		warnmsg(LOG_DEBUG, __func__, "ndo->nd_opt_type = %d",
+		    ndo->nd_opt_type);
+		warnmsg(LOG_DEBUG, __func__, "ndo->nd_opt_len = %d",
+		    ndo->nd_opt_len);
+
+		switch (ndo->nd_opt_type) {
+		case ND_OPT_RDNSS:
+			if (resolvconf_script == NULL)
+				break;
+			rdnss = (struct nd_opt_rdnss *)raoptp;
+			/* XXX: no lifetime handling now */
+
+			addr = (struct in6_addr *)(raoptp + sizeof(*rdnss));
+			while ((char *)addr < (char *)RA_OPT_NEXT_HDR(raoptp)) {
+				if (inet_ntop(AF_INET6, addr, ntopbuf,
+				    INET6_ADDRSTRLEN) == NULL) {
+					warnmsg(LOG_INFO, __func__,
+		    			"an invalid address in RDNSS option "
+					"in RA from %s was ignored.",
+					inet_ntop(AF_INET6, &from.sin6_addr,
+					ntopbuf, INET6_ADDRSTRLEN));
+
+					continue;
+				}
+				if (IN6_IS_ADDR_LINKLOCAL(addr))
+					/* XXX: % has to be escaped here */
+					sprintf(nsbuf, "nameserver "
+					    "%s%c%c%c%c%s\n",
+					    ntopbuf,
+					    SCOPE_DELIMITER,
+					    SCOPE_DELIMITER,
+					    SCOPE_DELIMITER,
+					    SCOPE_DELIMITER,
+					    ifi->ifname);
+				else
+					sprintf(nsbuf, "nameserver %s\n",
+					    ntopbuf);
+				warnmsg(LOG_DEBUG, __func__, "nsbuf = %s",
+				    nsbuf);
+
+				smp = malloc(sizeof(*smp));
+				if (smp == NULL) {
+					warnmsg(LOG_ERR, __func__,
+					    "malloc failed: %s",
+					    strerror(errno));
+					continue;
+				}
+				memset(smp, 0, sizeof(*smp));
+				smp->sm_msg = strdup(nsbuf);
+				if (smp->sm_msg == NULL) {
+					warnmsg(LOG_ERR, __func__,
+					    "strdup failed: %s",
+					    strerror(errno));
+					free(smp);
+					continue;
+				}
+				TAILQ_INSERT_TAIL(&sm_ns_head, smp, sm_next);
+				addr++;
+			}
+			break;
+		case ND_OPT_DNSSL:
+			if (resolvconf_script == NULL)
+				break;
+			dnssl = (struct nd_opt_dnssl *)raoptp;
+			/* XXX: no lifetime handling now */
+
+			if (TAILQ_EMPTY(&sm_sl_head)) {
+				smp = malloc(sizeof(*smp));
+				if (smp == NULL) {
+					warnmsg(LOG_ERR, __func__,
+					    "malloc failed: %s",
+					    strerror(errno));
+					break;
+				}
+				smp = malloc(sizeof(*smp));
+				smp->sm_msg = strdup("search ");
+				if (smp->sm_msg == NULL) {
+					warnmsg(LOG_ERR, __func__,
+					    "strdup failed: %s",
+					    strerror(errno));
+					free(smp);
+					break;
+				}
+				TAILQ_INSERT_TAIL(&sm_sl_head, smp, sm_next);
+			}
+
+			p = raoptp + sizeof(*dnssl);
+			while (0 < (len = dname_labeldec(dname, p))) {

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201105290524.p4T5Owot016088>