From owner-svn-src-user@FreeBSD.ORG Sun May 29 05:24:59 2011 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 44152106566B; Sun, 29 May 2011 05:24:59 +0000 (UTC) (envelope-from hrs@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id EFC5A8FC08; Sun, 29 May 2011 05:24:58 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p4T5OwvL016103; Sun, 29 May 2011 05:24:58 GMT (envelope-from hrs@svn.freebsd.org) Received: (from hrs@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p4T5Owot016088; Sun, 29 May 2011 05:24:58 GMT (envelope-from hrs@svn.freebsd.org) Message-Id: <201105290524.p4T5Owot016088@svn.freebsd.org> From: Hiroki Sato Date: Sun, 29 May 2011 05:24:58 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r222442 - in user/hrs/ipv6: sys/netinet usr.sbin/rtadvd usr.sbin/rtsold X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 29 May 2011 05:24:59 -0000 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 #include #include +#include #include #include #include @@ -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 +#include #include #include #include @@ -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 #include #include +#include #include #include #include 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 #include +#include #include #include #include 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 #include +#include #include #include #include @@ -52,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -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 +#include #include #include #include @@ -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 ***