diff options
-rw-r--r-- | sys/netinet/icmp6.h | 20 | ||||
-rw-r--r-- | usr.sbin/rtadvd/config.c | 179 | ||||
-rw-r--r-- | usr.sbin/rtadvd/config.h | 6 | ||||
-rw-r--r-- | usr.sbin/rtadvd/dump.c | 28 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.c | 40 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.conf | 5 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.conf.5 | 38 | ||||
-rw-r--r-- | usr.sbin/rtadvd/rtadvd.h | 27 |
8 files changed, 321 insertions, 22 deletions
diff --git a/sys/netinet/icmp6.h b/sys/netinet/icmp6.h index b89f6810e2a..58476b69aad 100644 --- a/sys/netinet/icmp6.h +++ b/sys/netinet/icmp6.h @@ -1,4 +1,4 @@ -/* $OpenBSD: icmp6.h,v 1.33 2010/03/22 12:23:32 jsg Exp $ */ +/* $OpenBSD: icmp6.h,v 1.34 2012/07/08 10:45:46 phessler Exp $ */ /* $KAME: icmp6.h,v 1.84 2003/04/23 10:26:51 itojun Exp $ */ /* @@ -282,6 +282,8 @@ struct nd_opt_hdr { /* Neighbor discovery option header */ #define ND_OPT_PREFIX_INFORMATION 3 #define ND_OPT_REDIRECTED_HEADER 4 #define ND_OPT_MTU 5 +#define ND_OPT_RDNSS 25 +#define ND_OPT_DNSSL 31 struct nd_opt_prefix_info { /* prefix information */ u_int8_t nd_opt_pi_type; @@ -312,6 +314,22 @@ struct nd_opt_mtu { /* MTU option */ u_int32_t nd_opt_mtu_mtu; } __packed; +struct nd_opt_rdnss { /* RDNSS option */ + u_int8_t nd_opt_rdnss_type; + u_int8_t nd_opt_rdnss_len; + u_int16_t nd_opt_rdnss_reserved; + u_int32_t nd_opt_rdnss_lifetime; + /* followed by list of recursive DNS servers */ +} __packed; + +struct nd_opt_dnssl { /* DNSSL option */ + u_int8_t nd_opt_dnssl_type; + u_int8_t nd_opt_dnssl_len; + u_int16_t nd_opt_dnssl_reserved; + u_int32_t nd_opt_dnssl_lifetime; + /* followed by list of DNS search domains */ +} __packed; + /* * icmp6 namelookup */ diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c index 374bb929928..581c4a4de20 100644 --- a/usr.sbin/rtadvd/config.c +++ b/usr.sbin/rtadvd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.27 2012/07/08 09:30:03 phessler Exp $ */ +/* $OpenBSD: config.c,v 1.28 2012/07/08 10:46:00 phessler Exp $ */ /* $KAME: config.c,v 1.62 2002/05/29 10:13:10 itojun Exp $ */ /* @@ -109,6 +109,8 @@ getconfig(intface) fatal("malloc"); TAILQ_INIT(&tmp->prefixes); + TAILQ_INIT(&tmp->rdnsss); + TAILQ_INIT(&tmp->dnssls); SLIST_INIT(&tmp->soliciters); /* check if we are allowed to forward packets (if not determined) */ @@ -323,6 +325,106 @@ getconfig(intface) if (tmp->pfxs == 0 && !agetflag("noifprefix")) get_prefix(tmp); + tmp->rdnsscnt = 0; + for (i = -1; i < MAXRDNSS; ++i) { + struct rdnss *rds; + char entbuf[256]; + char *tmpaddr; + + makeentry(entbuf, sizeof(entbuf), i, "rdnss"); + addr = agetstr(entbuf, &bp); + if (addr == NULL) + continue; + + /* servers are separated by commas in the config file */ + val = 1; + tmpaddr = addr; + while (*tmpaddr++) + if (*tmpaddr == ',') + ++val; + + rds = malloc(sizeof(struct rdnss) + val * sizeof(struct in6_addr)); + if (rds == NULL) + fatal("malloc"); + + TAILQ_INSERT_TAIL(&tmp->rdnsss, rds, entry); + tmp->rdnsscnt++; + + rds->servercnt = val; + + makeentry(entbuf, sizeof(entbuf), i, "rdnssltime"); + MAYHAVE(val, entbuf, (tmp->maxinterval * 3) / 2); + if (val < tmp->maxinterval || val > tmp->maxinterval * 2) { + log_warnx("%s (%ld) on %s is invalid " + "(should be between %d and %d)", + entbuf, val, intface, tmp->maxinterval, + tmp->maxinterval * 2); + } + rds->lifetime = val; + + val = 0; + while ((tmpaddr = strsep(&addr, ","))) { + if (inet_pton(AF_INET6, tmpaddr, &rds->servers[val]) != 1) { + log_warn("inet_pton failed for %s", tmpaddr); + exit(1); + } + val++; + } + } + + tmp->dnsslcnt = 0; + for (i = -1; i < MAXDNSSL; ++i) { + struct dnssl *dsl; + char entbuf[256]; + char *tmpsl; + + makeentry(entbuf, sizeof(entbuf), i, "dnssl"); + addr = agetstr(entbuf, &bp); + if (addr == NULL) + continue; + + dsl = malloc(sizeof(struct dnssl)); + if (dsl == NULL) + fatal("malloc"); + + TAILQ_INIT(&dsl->dnssldoms); + + while ((tmpsl = strsep(&addr, ","))) { + struct dnssldom *dnsd; + ssize_t len; + + len = strlen(tmpsl); + + /* if the domain is not "dot-terminated", add it */ + if (tmpsl[len - 1] != '.') + len += 1; + + dnsd = malloc(sizeof(struct dnssldom) + len + 1); + if (dnsd == NULL) + fatal("malloc"); + + dnsd->length = len; + strlcpy(dnsd->domain, tmpsl, len + 1); + dnsd->domain[len - 1] = '.'; + dnsd->domain[len] = '\0'; + + TAILQ_INSERT_TAIL(&dsl->dnssldoms, dnsd, entry); + } + + TAILQ_INSERT_TAIL(&tmp->dnssls, dsl, entry); + tmp->dnsslcnt++; + + makeentry(entbuf, sizeof(entbuf), i, "dnsslltime"); + MAYHAVE(val, entbuf, (tmp->maxinterval * 3) / 2); + if (val < tmp->maxinterval || val > tmp->maxinterval * 2) { + log_warnx("%s (%ld) on %s is invalid " + "(should be between %d and %d)", + entbuf, val, intface, tmp->maxinterval, + tmp->maxinterval * 2); + } + dsl->lifetime = val; + } + MAYHAVE(val, "mtu", 0); if (val < 0 || val > 0xffffffff) { log_warnx("mtu (%ld) on %s out of range", val, intface); @@ -596,7 +698,12 @@ make_packet(struct rainfo *rainfo) struct nd_router_advert *ra; struct nd_opt_prefix_info *ndopt_pi; struct nd_opt_mtu *ndopt_mtu; + struct nd_opt_rdnss *ndopt_rdnss; + struct nd_opt_dnssl *ndopt_dnssl; struct prefix *pfx; + struct rdnss *rds; + struct dnssl *dsl; + struct dnssldom *dnsd; /* calculate total length */ packlen = sizeof(struct nd_router_advert); @@ -613,6 +720,20 @@ make_packet(struct rainfo *rainfo) packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs; if (rainfo->linkmtu) packlen += sizeof(struct nd_opt_mtu); + TAILQ_FOREACH(rds, &rainfo->rdnsss, entry) + packlen += sizeof(struct nd_opt_rdnss) + 16 * rds->servercnt; + TAILQ_FOREACH(dsl, &rainfo->dnssls, entry) { + size_t domains_size = 0; + + packlen += sizeof(struct nd_opt_dnssl); + + TAILQ_FOREACH(dnsd, &dsl->dnssldoms, entry) + domains_size += dnsd->length; + + domains_size = (domains_size + 7) & ~7; + + packlen += domains_size; + } /* allocate memory for the packet */ if ((buf = malloc(packlen)) == NULL) @@ -707,6 +828,62 @@ make_packet(struct rainfo *rainfo) buf += sizeof(struct nd_opt_prefix_info); } + TAILQ_FOREACH(rds, &rainfo->rdnsss, entry) { + ndopt_rdnss = (struct nd_opt_rdnss *)buf; + ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS; + ndopt_rdnss->nd_opt_rdnss_len = 1 + rds->servercnt * 2; + ndopt_rdnss->nd_opt_rdnss_reserved = 0; + ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rds->lifetime); + + buf += sizeof(struct nd_opt_rdnss); + + memcpy(buf, rds->servers, rds->servercnt * 16); + buf += rds->servercnt * 16; + } + + TAILQ_FOREACH(dsl, &rainfo->dnssls, entry) { + u_int32_t size; + char *curlabel_begin; + char *curlabel_end; + + ndopt_dnssl = (struct nd_opt_dnssl *)buf; + ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL; + ndopt_dnssl->nd_opt_dnssl_reserved = 0; + ndopt_dnssl->nd_opt_dnssl_lifetime = htonl(dsl->lifetime); + + size = 0; + TAILQ_FOREACH(dnsd, &dsl->dnssldoms, entry) + size += dnsd->length; + /* align size on the next 8 byte boundary */ + size = (size + 7) & ~7; + ndopt_dnssl->nd_opt_dnssl_len = 1 + size / 8; + + buf += sizeof(struct nd_opt_dnssl); + + TAILQ_FOREACH(dnsd, &dsl->dnssldoms, entry) { + curlabel_begin = dnsd->domain; + while ((curlabel_end = strchr(curlabel_begin, '.')) && + (curlabel_end - curlabel_begin) > 1) + { + size_t curlabel_size; + + curlabel_size = curlabel_end - curlabel_begin; + *buf = curlabel_size; + ++buf; + strncpy(buf, curlabel_begin, curlabel_size); + buf += curlabel_size; + curlabel_begin = curlabel_end + 1; + } + + /* null-terminate the current domain */ + *buf++ = '\0'; + } + + /* zero out the end of the current option */ + while ((int)buf % 8 != 0) + *buf++ = '\0'; + } + return; } diff --git a/usr.sbin/rtadvd/config.h b/usr.sbin/rtadvd/config.h index fa63c115cfe..53b97bc3406 100644 --- a/usr.sbin/rtadvd/config.h +++ b/usr.sbin/rtadvd/config.h @@ -1,4 +1,4 @@ -/* $OpenBSD: config.h,v 1.6 2003/06/18 02:26:58 itojun Exp $ */ +/* $OpenBSD: config.h,v 1.7 2012/07/08 10:46:00 phessler Exp $ */ /* $KAME: config.h,v 1.3 2000/05/16 13:34:13 itojun Exp $ */ /* @@ -38,7 +38,9 @@ extern void get_prefix __P((struct rainfo *)); /* - * it is highly unlikely to have 100 prefix information options, + * it is highly unlikely to have 100 prefix, rdnss or dnssl information options, * so it should be okay to limit it */ #define MAXPREFIX 100 +#define MAXRDNSS 100 +#define MAXDNSSL 100 diff --git a/usr.sbin/rtadvd/dump.c b/usr.sbin/rtadvd/dump.c index f96fb8b9e3e..5dec0e6f37a 100644 --- a/usr.sbin/rtadvd/dump.c +++ b/usr.sbin/rtadvd/dump.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dump.c,v 1.10 2008/07/21 19:14:15 rainer Exp $ */ +/* $OpenBSD: dump.c,v 1.11 2012/07/08 10:46:00 phessler Exp $ */ /* $KAME: dump.c,v 1.27 2002/05/29 14:23:55 itojun Exp $ */ /* @@ -103,6 +103,9 @@ rtadvd_dump() { struct rainfo *rai; struct prefix *pfx; + struct rdnss *rds; + struct dnssl *dsl; + struct dnssldom *dnsd; char prefixbuf[INET6_ADDRSTRLEN]; int first; struct timeval now; @@ -213,5 +216,28 @@ rtadvd_dump() free(pltime); free(flags); } + + if (!TAILQ_EMPTY(&rai->rdnsss)) + log_info(" Recursive DNS servers:"); + TAILQ_FOREACH(rds, &rai->rdnsss, entry) { + log_info(" Servers:"); + for (first = 0; first < rds->servercnt; ++first) { + inet_ntop(AF_INET6, &rds->servers[first], + prefixbuf, sizeof(prefixbuf)); + log_info(" %s", prefixbuf); + } + log_info(" Lifetime: %u", rds->lifetime); + } + + if (!TAILQ_EMPTY(&rai->dnssls)) + log_info(" DNS search lists:"); + TAILQ_FOREACH(dsl, &rai->dnssls, entry) { + log_info(" Domains:"); + + TAILQ_FOREACH(dnsd, &dsl->dnssldoms, entry) + log_info(" %s", dnsd->domain); + + log_info(" Lifetime: %u", dsl->lifetime); + } } } diff --git a/usr.sbin/rtadvd/rtadvd.c b/usr.sbin/rtadvd/rtadvd.c index e6268b2e66d..37757b4e8ab 100644 --- a/usr.sbin/rtadvd/rtadvd.c +++ b/usr.sbin/rtadvd/rtadvd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtadvd.c,v 1.39 2011/03/02 17:30:48 bluhm Exp $ */ +/* $OpenBSD: rtadvd.c,v 1.40 2012/07/08 10:46:00 phessler Exp $ */ /* $KAME: rtadvd.c,v 1.66 2002/05/29 14:18:36 itojun Exp $ */ /* @@ -114,15 +114,22 @@ 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) +#define NDOPT_FLAG_RDNSS (1 << 5) +#define NDOPT_FLAG_DNSSL (1 << 6) u_int32_t ndopt_flags[] = { - 0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR, - NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU, + [ND_OPT_SOURCE_LINKADDR] = NDOPT_FLAG_SRCLINKADDR, + [ND_OPT_TARGET_LINKADDR] = NDOPT_FLAG_TGTLINKADDR, + [ND_OPT_PREFIX_INFORMATION] = NDOPT_FLAG_PREFIXINFO, + [ND_OPT_REDIRECTED_HEADER] = NDOPT_FLAG_RDHDR, + [ND_OPT_MTU] = NDOPT_FLAG_MTU, + [ND_OPT_RDNSS] = NDOPT_FLAG_RDNSS, + [ND_OPT_DNSSL] = NDOPT_FLAG_DNSSL, }; int main(int, char *[]); @@ -804,8 +811,8 @@ ra_input(int len, struct nd_router_advert *ra, SLIST_INIT(&ndopts.nd_opts_list); if (nd6_options((struct nd_opt_hdr *)(ra + 1), len - sizeof(struct nd_router_advert), - &ndopts, NDOPT_FLAG_SRCLINKADDR | - NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) { + &ndopts, NDOPT_FLAG_SRCLINKADDR | NDOPT_FLAG_PREFIXINFO + | NDOPT_FLAG_MTU | NDOPT_FLAG_RDNSS | NDOPT_FLAG_DNSSL)) { log_warnx("ND option check failed for an RA from %s on %s", inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf, INET6_ADDRSTRLEN), @@ -1104,7 +1111,9 @@ 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 && + hdr->nd_opt_type != ND_OPT_RDNSS && + hdr->nd_opt_type != ND_OPT_DNSSL) { log_info("unknown ND option(type %d)", hdr->nd_opt_type); @@ -1121,7 +1130,10 @@ nd6_options(struct nd_opt_hdr *hdr, int limit, * Option length check. Do it here for all fixed-length * options. */ - if ((hdr->nd_opt_type == ND_OPT_MTU && + if ((hdr->nd_opt_type == ND_OPT_RDNSS && (optlen < 24 || + ((optlen - sizeof(struct nd_opt_rdnss)) % 16 != 0))) || + (hdr->nd_opt_type == ND_OPT_DNSSL && optlen < 16) || + (hdr->nd_opt_type == ND_OPT_MTU && (optlen != sizeof(struct nd_opt_mtu))) || ((hdr->nd_opt_type == ND_OPT_PREFIX_INFORMATION && optlen != sizeof(struct nd_opt_prefix_info)))) { @@ -1133,6 +1145,8 @@ nd6_options(struct nd_opt_hdr *hdr, int limit, case ND_OPT_SOURCE_LINKADDR: case ND_OPT_TARGET_LINKADDR: case ND_OPT_REDIRECTED_HEADER: + case ND_OPT_RDNSS: + case ND_OPT_DNSSL: break; /* we don't care about these options */ case ND_OPT_MTU: if (ndopts->nd_opt_array[hdr->nd_opt_type]) { @@ -1154,7 +1168,7 @@ nd6_options(struct nd_opt_hdr *hdr, int limit, log_warn("malloc"); goto bad; } - + pfx->opt = hdr; SLIST_INSERT_HEAD(&ndopts->nd_opts_list, pfx, entry); diff --git a/usr.sbin/rtadvd/rtadvd.conf b/usr.sbin/rtadvd/rtadvd.conf index 07f7bc369b0..04725a4df34 100644 --- a/usr.sbin/rtadvd/rtadvd.conf +++ b/usr.sbin/rtadvd/rtadvd.conf @@ -1,4 +1,4 @@ -# $OpenBSD: rtadvd.conf,v 1.6 2008/07/19 10:35:31 reyk Exp $ +# $OpenBSD: rtadvd.conf,v 1.7 2012/07/08 10:46:00 phessler Exp $ # $KAME: rtadvd.conf,v 1.12 2001/01/21 14:56:38 itojun Exp $ # # Note: All of the following parameters have default values defined @@ -18,4 +18,5 @@ # this part by hand, and then invoke rtadvd with the -s option. #ef0:\ -# :addr="2001:db8:ffff:1000::":prefixlen#64: +# :addr="2001:db8:ffff:1000::":prefixlen#64:\ +# :rdnss="2001:db8:ffff:1000::1":dnssl="example.com": diff --git a/usr.sbin/rtadvd/rtadvd.conf.5 b/usr.sbin/rtadvd/rtadvd.conf.5 index c447b1b5f9c..5712be0e8b0 100644 --- a/usr.sbin/rtadvd/rtadvd.conf.5 +++ b/usr.sbin/rtadvd/rtadvd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: rtadvd.conf.5,v 1.27 2012/07/08 10:22:55 jmc Exp $ +.\" $OpenBSD: rtadvd.conf.5,v 1.28 2012/07/08 10:46:00 phessler Exp $ .\" $KAME: rtadvd.conf.5,v 1.46 2003/06/17 08:26:35 itojun Exp $ .\" .\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -231,6 +231,30 @@ is specified for this item, MTU option will be included and its value will be set to the interface MTU automatically. .El .Pp +The following items are for ICMPv6 RDNSS option, used to give a list of +recursive DNS servers to hosts. +If this item is omitted, no information about DNS servers will be advertised. +.Bl -tag -width indent +.It Cm \&rdnss +(str) The list of advertised recursive DNS servers, separated by commas. +.It Cm \&rdnssltime +(num) Validity of the list of DNS servers +.Pq unit: seconds . +The default value is 1.5 * the value of maxinterval. +.El +.Pp +The following items are used for ICMPv6 DNSSL option which specifies a +list of DNS suffixes advertised to hosts. +If this option is not specified, no DNS suffix will be sent to hosts. +.Bl -tag -width indent +.It Cm \&dnssl +(str) The list of advertised DNS suffixes, separated by commas. +.It Cm \&dnsslltime +(num) Validity of the list of DNS suffixes +.Pq unit: seconds . +The default value is 1.5 * the value of maxinterval. +.El +.Pp The following item controls ICMPv6 source link-layer address option, which will be attached to router advertisement header. As noted above, you can just omit the item, then @@ -289,6 +313,18 @@ ef0:\e :addr="2001:db8:ffff:1000::":prefixlen#64: .Ed .Pp +The following example configures two recursive DNS servers for the +.Li em0 +interface and sets the DNS search suffix to +.Do +example.com +.Dc . +.Bd -literal -offset indent +em0:\e + :rdnss="2001:db8:ffff:1000::1,2001:db8:ffff:1000::2":\e + :dnssl="example.com": +.Ed +.Pp The following example presents the default values in an explicit manner. The configuration is provided just for reference purposes; YOU DO NOT NEED TO HAVE IT AT ALL. diff --git a/usr.sbin/rtadvd/rtadvd.h b/usr.sbin/rtadvd/rtadvd.h index 50ce76d9346..320b90b7104 100644 --- a/usr.sbin/rtadvd/rtadvd.h +++ b/usr.sbin/rtadvd/rtadvd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rtadvd.h,v 1.11 2008/06/09 22:53:24 rainer Exp $ */ +/* $OpenBSD: rtadvd.h,v 1.12 2012/07/08 10:46:00 phessler Exp $ */ /* $KAME: rtadvd.h,v 1.20 2002/05/29 10:13:10 itojun Exp $ */ /* @@ -82,6 +82,27 @@ struct prefix { struct in6_addr prefix; }; +struct rdnss { + TAILQ_ENTRY(rdnss) entry; + + u_int32_t lifetime; + int servercnt; + struct in6_addr servers[]; +}; + +struct dnssldom { + TAILQ_ENTRY(dnssldom) entry; + + u_int32_t length; + char domain[]; +}; + +struct dnssl { + TAILQ_ENTRY(dnssl) entry; + + u_int32_t lifetime; + TAILQ_HEAD(dnssldomlist, dnssldom) dnssldoms; +}; struct soliciter { SLIST_ENTRY(soliciter) entry; @@ -118,6 +139,10 @@ struct rainfo { u_int hoplimit; /* AdvCurHopLimit */ TAILQ_HEAD(prefixlist, prefix) prefixes; /* AdvPrefixList(link head) */ int pfxs; /* number of prefixes */ + TAILQ_HEAD(rdnsslist, rdnss) rdnsss; /* advertised recursive dns servers */ + int rdnsscnt; /* number of rdnss entries */ + TAILQ_HEAD(dnssllist, dnssl) dnssls; + int dnsslcnt; long clockskew; /* used for consisitency check of lifetimes */ |