summaryrefslogtreecommitdiffstats
path: root/usr.sbin/rtadvd
diff options
context:
space:
mode:
authorhrs <hrs@FreeBSD.org>2011-05-29 05:24:58 +0000
committerhrs <hrs@FreeBSD.org>2011-05-29 05:24:58 +0000
commitfd7e38fffccde0c416b15246c4d16e08574e6cd6 (patch)
tree4cd9cf7fe969ac1015d7876862d4a2561baef047 /usr.sbin/rtadvd
parenteeba75618c9b27faad1e2ef180870038ea161d68 (diff)
downloadFreeBSD-src-fd7e38fffccde0c416b15246c4d16e08574e6cd6.zip
FreeBSD-src-fd7e38fffccde0c416b15246c4d16e08574e6cd6.tar.gz
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
Diffstat (limited to 'usr.sbin/rtadvd')
-rw-r--r--usr.sbin/rtadvd/Makefile2
-rw-r--r--usr.sbin/rtadvd/config.c232
-rw-r--r--usr.sbin/rtadvd/config.h2
-rw-r--r--usr.sbin/rtadvd/dump.c64
-rw-r--r--usr.sbin/rtadvd/if.c1
-rw-r--r--usr.sbin/rtadvd/rrenum.c1
-rw-r--r--usr.sbin/rtadvd/rtadvd.c69
-rw-r--r--usr.sbin/rtadvd/rtadvd.conf3
-rw-r--r--usr.sbin/rtadvd/rtadvd.conf.585
-rw-r--r--usr.sbin/rtadvd/rtadvd.h42
10 files changed, 482 insertions, 19 deletions
diff --git a/usr.sbin/rtadvd/Makefile b/usr.sbin/rtadvd/Makefile
index 9dbfc99..29c26fe 100644
--- a/usr.sbin/rtadvd/Makefile
+++ b/usr.sbin/rtadvd/Makefile
@@ -21,7 +21,7 @@ SRCS= rtadvd.c rrenum.c advcap.c if.c config.c timer.c dump.c
DPADD= ${LIBUTIL}
LDADD= -lutil
-CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H -DROUTEINFO
+CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H -DROUTEINFO -DRDNSS
WARNS?= 1
diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c
index 5eadcc5..086a23c 100644
--- a/usr.sbin/rtadvd/config.c
+++ b/usr.sbin/rtadvd/config.c
@@ -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;
}
diff --git a/usr.sbin/rtadvd/config.h b/usr.sbin/rtadvd/config.h
index 2d02b8a..3fa14f9 100644
--- a/usr.sbin/rtadvd/config.h
+++ b/usr.sbin/rtadvd/config.h
@@ -45,3 +45,5 @@ extern void get_prefix(struct rainfo *);
*/
#define MAXPREFIX 100
#define MAXROUTE 100
+#define MAXRDNSSENT 100
+#define MAXDNSSLENT 100
diff --git a/usr.sbin/rtadvd/dump.c b/usr.sbin/rtadvd/dump.c
index d37f5db..a94a62e 100644
--- a/usr.sbin/rtadvd/dump.c
+++ b/usr.sbin/rtadvd/dump.c
@@ -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);
+}
diff --git a/usr.sbin/rtadvd/if.c b/usr.sbin/rtadvd/if.c
index d8ed088..6cd8dd8 100644
--- a/usr.sbin/rtadvd/if.c
+++ b/usr.sbin/rtadvd/if.c
@@ -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>
diff --git a/usr.sbin/rtadvd/rrenum.c b/usr.sbin/rtadvd/rrenum.c
index aafa0f9..b2ea902 100644
--- a/usr.sbin/rtadvd/rrenum.c
+++ b/usr.sbin/rtadvd/rrenum.c
@@ -45,6 +45,7 @@
#include <arpa/inet.h>
#include <errno.h>
+#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <syslog.h>
diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c
index 02e3dc7..3652e20 100644
--- a/usr.sbin/rtadvd/rtadvd.c
+++ b/usr.sbin/rtadvd/rtadvd.c
@@ -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_advert *ra,
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 limit,
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 limit,
* 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 limit,
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:
diff --git a/usr.sbin/rtadvd/rtadvd.conf b/usr.sbin/rtadvd/rtadvd.conf
index 33ab7f3..6213c4e 100644
--- a/usr.sbin/rtadvd/rtadvd.conf
+++ b/usr.sbin/rtadvd/rtadvd.conf
@@ -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":
diff --git a/usr.sbin/rtadvd/rtadvd.conf.5 b/usr.sbin/rtadvd/rtadvd.conf.5
index 81ffa70..f6003cd 100644
--- a/usr.sbin/rtadvd/rtadvd.conf.5
+++ b/usr.sbin/rtadvd/rtadvd.conf.5
@@ -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
diff --git a/usr.sbin/rtadvd/rtadvd.h b/usr.sbin/rtadvd/rtadvd.h
index 828fec6..e346a1a 100644
--- a/usr.sbin/rtadvd/rtadvd.h
+++ b/usr.sbin/rtadvd/rtadvd.h
@@ -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
OpenPOWER on IntegriCloud