summaryrefslogtreecommitdiff
path: root/usr.sbin/rtadvd/config.c
diff options
context:
space:
mode:
authorPeter Hessler <phessler@cvs.openbsd.org>2012-07-08 10:46:01 +0000
committerPeter Hessler <phessler@cvs.openbsd.org>2012-07-08 10:46:01 +0000
commit17fa738432936ad818f1c5f3a9ffb3f8ce1469f5 (patch)
treef3f609d5a2c30008802f036a763b943ac707588b /usr.sbin/rtadvd/config.c
parent65dbabae5e7ce8992e221b17756d79049c3bed88 (diff)
Add support for advertising dns servers and search paths in router
advertisements, according to RFC 6106. original diff from Stephane A. Sezer on tech@, many thanks! OK phessler@, todd@
Diffstat (limited to 'usr.sbin/rtadvd/config.c')
-rw-r--r--usr.sbin/rtadvd/config.c179
1 files changed, 178 insertions, 1 deletions
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;
}