Home | History | Annotate | Download | only in dhcpcd
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright (c) 2006-2012 Roy Marples <roy (at) marples.name>
      4  * All rights reserved
      5 
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/param.h>
     29 #include <sys/socket.h>
     30 #include <net/if.h>
     31 #include <netinet/in.h>
     32 #include <netinet/ip6.h>
     33 #include <netinet/icmp6.h>
     34 
     35 #include <errno.h>
     36 #include <stddef.h>
     37 #include <stdlib.h>
     38 #include <string.h>
     39 #include <syslog.h>
     40 
     41 #ifdef __linux__
     42 #  define _LINUX_IN6_H
     43 #  include <linux/ipv6.h>
     44 #endif
     45 
     46 #define ELOOP_QUEUE 1
     47 #include "bind.h"
     48 #include "common.h"
     49 #include "configure.h"
     50 #include "dhcpcd.h"
     51 #include "eloop.h"
     52 #include "ipv6rs.h"
     53 
     54 #define ALLROUTERS "ff02::2"
     55 #define HOPLIMIT 255
     56 
     57 #define ROUNDUP8(a) (1 + (((a) - 1) | 7))
     58 
     59 #define RTR_SOLICITATION_INTERVAL       4 /* seconds */
     60 #define MAX_RTR_SOLICITATIONS           3 /* times */
     61 
     62 #ifndef ND_OPT_RDNSS
     63 #define ND_OPT_RDNSS			25
     64 struct nd_opt_rdnss {           /* RDNSS option RFC 6106 */
     65 	uint8_t		nd_opt_rdnss_type;
     66 	uint8_t		nd_opt_rdnss_len;
     67 	uint16_t	nd_opt_rdnss_reserved;
     68 	uint32_t	nd_opt_rdnss_lifetime;
     69         /* followed by list of IP prefixes */
     70 } _packed;
     71 #endif
     72 
     73 #ifndef ND_OPT_DNSSL
     74 #define ND_OPT_DNSSL			31
     75 struct nd_opt_dnssl {		/* DNSSL option RFC 6106 */
     76 	uint8_t		nd_opt_dnssl_type;
     77 	uint8_t		nd_opt_dnssl_len;
     78 	uint16_t	nd_opt_dnssl_reserved;
     79 	uint32_t	nd_opt_dnssl_lifetime;
     80 	/* followed by list of DNS servers */
     81 } _packed;
     82 #endif
     83 
     84 static int sock;
     85 static struct sockaddr_in6 allrouters, from;
     86 static struct msghdr sndhdr;
     87 static struct iovec sndiov[2];
     88 static unsigned char *sndbuf;
     89 static struct msghdr rcvhdr;
     90 static struct iovec rcviov[2];
     91 static unsigned char *rcvbuf;
     92 static unsigned char ansbuf[1500];
     93 static char ntopbuf[INET6_ADDRSTRLEN];
     94 
     95 #if DEBUG_MEMORY
     96 static void
     97 ipv6rs_cleanup(void)
     98 {
     99 
    100 	free(sndbuf);
    101 	free(rcvbuf);
    102 }
    103 #endif
    104 
    105 int
    106 ipv6rs_open(void)
    107 {
    108 	int on;
    109 	int len;
    110 	struct icmp6_filter filt;
    111 
    112 	memset(&allrouters, 0, sizeof(allrouters));
    113 	allrouters.sin6_family = AF_INET6;
    114 #ifdef SIN6_LEN
    115 	allrouters.sin6_len = sizeof(allrouters);
    116 #endif
    117 	if (inet_pton(AF_INET6, ALLROUTERS, &allrouters.sin6_addr.s6_addr) != 1)
    118 		return -1;
    119 	sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
    120 	if (sock == -1)
    121 		return -1;
    122 	on = 1;
    123 	if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
    124 		&on, sizeof(on)) == -1)
    125 		return -1;
    126 
    127 	on = 1;
    128 	if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
    129 		&on, sizeof(on)) == -1)
    130 		return -1;
    131 
    132 	ICMP6_FILTER_SETBLOCKALL(&filt);
    133 	ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
    134 	if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER,
    135 		&filt, sizeof(filt)) == -1)
    136 		return -1;
    137 
    138 #if DEBUG_MEMORY
    139 	atexit(ipv6rs_cleanup);
    140 #endif
    141 
    142 	len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int));
    143 	sndbuf = xzalloc(len);
    144 	if (sndbuf == NULL)
    145 		return -1;
    146 	sndhdr.msg_namelen = sizeof(struct sockaddr_in6);
    147 	sndhdr.msg_iov = sndiov;
    148 	sndhdr.msg_iovlen = 1;
    149 	sndhdr.msg_control = sndbuf;
    150 	sndhdr.msg_controllen = len;
    151 	rcvbuf = xzalloc(len);
    152 	if (rcvbuf == NULL)
    153 		return -1;
    154 	rcvhdr.msg_name = &from;
    155 	rcvhdr.msg_namelen = sizeof(from);
    156 	rcvhdr.msg_iov = rcviov;
    157 	rcvhdr.msg_iovlen = 1;
    158 	rcvhdr.msg_control = rcvbuf;
    159 	rcvhdr.msg_controllen = len;
    160 	rcviov[0].iov_base = ansbuf;
    161 	rcviov[0].iov_len = sizeof(ansbuf);
    162 	return sock;
    163 }
    164 
    165 static int
    166 ipv6rs_makeprobe(struct interface *ifp)
    167 {
    168 	struct nd_router_solicit *rs;
    169 	struct nd_opt_hdr *nd;
    170 
    171 	free(ifp->rs);
    172 	ifp->rslen = sizeof(*rs) + ROUNDUP8(ifp->hwlen + 2);
    173 	ifp->rs = xzalloc(ifp->rslen);
    174 	if (ifp->rs == NULL)
    175 		return -1;
    176 	rs = (struct nd_router_solicit *)ifp->rs;
    177 	rs->nd_rs_type = ND_ROUTER_SOLICIT;
    178 	rs->nd_rs_code = 0;
    179 	rs->nd_rs_cksum = 0;
    180 	rs->nd_rs_reserved = 0;
    181 	nd = (struct nd_opt_hdr *)(ifp->rs + sizeof(*rs));
    182 	nd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
    183 	nd->nd_opt_len = (ROUNDUP8(ifp->hwlen + 2)) >> 3;
    184 	memcpy(nd + 1, ifp->hwaddr, ifp->hwlen);
    185 	return 0;
    186 }
    187 
    188 static void
    189 ipv6rs_sendprobe(void *arg)
    190 {
    191 	struct interface *ifp = arg;
    192 	struct sockaddr_in6 dst;
    193 	struct cmsghdr *cm;
    194 	struct in6_pktinfo pi;
    195 	int hoplimit = HOPLIMIT;
    196 
    197 	dst = allrouters;
    198 	//dst.sin6_scope_id = ifp->linkid;
    199 
    200 	ipv6rs_makeprobe(ifp);
    201 	sndhdr.msg_name = (caddr_t)&dst;
    202 	sndhdr.msg_iov[0].iov_base = ifp->rs;
    203 	sndhdr.msg_iov[0].iov_len = ifp->rslen;
    204 
    205 	/* Set the outbound interface */
    206 	cm = CMSG_FIRSTHDR(&sndhdr);
    207 	cm->cmsg_level = IPPROTO_IPV6;
    208 	cm->cmsg_type = IPV6_PKTINFO;
    209 	cm->cmsg_len = CMSG_LEN(sizeof(pi));
    210 	memset(&pi, 0, sizeof(pi));
    211 	pi.ipi6_ifindex = if_nametoindex(ifp->name);
    212 	memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
    213 
    214 	/* Hop limit */
    215 	cm = CMSG_NXTHDR(&sndhdr, cm);
    216 	cm->cmsg_level = IPPROTO_IPV6;
    217 	cm->cmsg_type = IPV6_HOPLIMIT;
    218 	cm->cmsg_len = CMSG_LEN(sizeof(hoplimit));
    219 	memcpy(CMSG_DATA(cm), &hoplimit, sizeof(hoplimit));
    220 
    221 	syslog(LOG_INFO, "%s: sending IPv6 Router Solicitation", ifp->name);
    222 	if (sendmsg(sock, &sndhdr, 0) == -1)
    223 		syslog(LOG_ERR, "%s: sendmsg: %m", ifp->name);
    224 
    225 	if (ifp->rsprobes++ < MAX_RTR_SOLICITATIONS)
    226 		add_timeout_sec(RTR_SOLICITATION_INTERVAL,
    227 		    ipv6rs_sendprobe, ifp);
    228 	else
    229 		syslog(LOG_INFO, "%s: no IPv6 Routers available", ifp->name);
    230 }
    231 
    232 static void
    233 ipv6rs_sort(struct interface *ifp)
    234 {
    235 	struct ra *rap, *sorted, *ran, *rat;
    236 
    237 	if (ifp->ras == NULL || ifp->ras->next == NULL)
    238 		return;
    239 
    240 	/* Sort our RA's - most recent first */
    241 	sorted = ifp->ras;
    242 	ifp->ras = ifp->ras->next;
    243 	sorted->next = NULL;
    244 	for (rap = ifp->ras; rap && (ran = rap->next, 1); rap = ran) {
    245 		/* Are we the new head? */
    246 		if (timercmp(&rap->received, &sorted->received, <)) {
    247 			rap->next = sorted;
    248 			sorted = rap;
    249 			continue;
    250 		}
    251 		/* Do we fit in the middle? */
    252 		for (rat = sorted; rat->next; rat = rat->next) {
    253 			if (timercmp(&rap->received, &rat->next->received, <)) {
    254 				rap->next = rat->next;
    255 				rat->next = rap;
    256 				break;
    257 			}
    258 		}
    259 		/* We must be at the end */
    260 		if (!rat->next) {
    261 			rat->next = rap;
    262 			rap->next = NULL;
    263 		}
    264 	}
    265 }
    266 
    267 void
    268 ipv6rs_handledata(_unused void *arg)
    269 {
    270 	ssize_t len, l, n, olen;
    271 	struct cmsghdr *cm;
    272 	int hoplimit;
    273 	struct in6_pktinfo pkt;
    274 	struct icmp6_hdr *icp;
    275 	struct interface *ifp;
    276 	const char *sfrom;
    277 	struct nd_router_advert *nd_ra;
    278 	struct nd_opt_prefix_info *pi;
    279 	struct nd_opt_mtu *mtu;
    280 	struct nd_opt_rdnss *rdnss;
    281 	struct nd_opt_dnssl *dnssl;
    282 	uint32_t lifetime;
    283 	uint8_t *p, *op;
    284 	struct in6_addr addr;
    285 	char buf[INET6_ADDRSTRLEN];
    286 	const char *cbp;
    287 	struct ra *rap;
    288 	struct nd_opt_hdr *ndo;
    289 	struct ra_opt *rao, *raol;
    290 	char *opt;
    291 	struct timeval expire;
    292 	int has_dns;
    293 
    294 	len = recvmsg(sock, &rcvhdr, 0);
    295 	if (len == -1) {
    296 		syslog(LOG_ERR, "recvmsg: %m");
    297 		return;
    298 	}
    299 	sfrom = inet_ntop(AF_INET6, &from.sin6_addr,
    300 	    ntopbuf, INET6_ADDRSTRLEN);
    301 	if ((size_t)len < sizeof(struct nd_router_advert)) {
    302 		syslog(LOG_ERR, "IPv6 RA packet too short from %s", sfrom);
    303 		return;
    304 	}
    305 
    306 	pkt.ipi6_ifindex = hoplimit = 0;
    307 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvhdr);
    308 	     cm;
    309 	     cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvhdr, cm))
    310 	{
    311 		if (cm->cmsg_level != IPPROTO_IPV6)
    312 			continue;
    313 		switch(cm->cmsg_type) {
    314 		case IPV6_PKTINFO:
    315 			if (cm->cmsg_len == CMSG_LEN(sizeof(pkt)))
    316 				memcpy(&pkt, CMSG_DATA(cm), sizeof(pkt));
    317 			break;
    318 		case IPV6_HOPLIMIT:
    319 			if (cm->cmsg_len == CMSG_LEN(sizeof(int)))
    320 				memcpy(&hoplimit, CMSG_DATA(cm), sizeof(int));
    321 			break;
    322 		}
    323 	}
    324 
    325 	if (pkt.ipi6_ifindex == 0 || hoplimit == 0) {
    326 		syslog(LOG_ERR,
    327 		    "IPv6 RA did not contain index or hop limit from %s",
    328 		    sfrom);
    329 		return;
    330 	}
    331 
    332 	icp = (struct icmp6_hdr *)rcvhdr.msg_iov[0].iov_base;
    333 	if (icp->icmp6_type != ND_ROUTER_ADVERT ||
    334 	    icp->icmp6_code != 0)
    335 	{
    336 		syslog(LOG_ERR, "invalid IPv6 type or code from %s", sfrom);
    337 		return;
    338 	}
    339 
    340 	if (!IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) {
    341 		syslog(LOG_ERR, "RA recieved from non local IPv6 address %s",
    342 		    sfrom);
    343 		return;
    344 	}
    345 
    346 	for (ifp = ifaces; ifp; ifp = ifp->next)
    347 		if (if_nametoindex(ifp->name) == (unsigned int)pkt.ipi6_ifindex)
    348 			break;
    349 	if (ifp == NULL) {
    350 		syslog(LOG_ERR,"received RA for unexpected interface from %s",
    351 		    sfrom);
    352 		return;
    353 	}
    354 	for (rap = ifp->ras; rap; rap = rap->next) {
    355 		if (memcmp(rap->from.s6_addr, from.sin6_addr.s6_addr,
    356 		    sizeof(rap->from.s6_addr)) == 0)
    357 			break;
    358 	}
    359 
    360 	/* We don't want to spam the log with the fact we got an RA every
    361 	 * 30 seconds or so, so only spam the log if it's different. */
    362 	if (options & DHCPCD_DEBUG || rap == NULL ||
    363 	    (rap->expired || rap->data_len != len ||
    364 	     memcmp(rap->data, (unsigned char *)icp, rap->data_len) != 0))
    365 	{
    366 		if (rap) {
    367 			free(rap->data);
    368 			rap->data_len = 0;
    369 		}
    370 		syslog(LOG_INFO, "%s: Router Advertisement from %s",
    371 		    ifp->name, sfrom);
    372 	}
    373 
    374 	if (rap == NULL) {
    375 		rap = xmalloc(sizeof(*rap));
    376 		rap->next = ifp->ras;
    377 		rap->options = NULL;
    378 		ifp->ras = rap;
    379 		memcpy(rap->from.s6_addr, from.sin6_addr.s6_addr,
    380 		    sizeof(rap->from.s6_addr));
    381 		strlcpy(rap->sfrom, sfrom, sizeof(rap->sfrom));
    382 		rap->data_len = 0;
    383 	}
    384 	if (rap->data_len == 0) {
    385 		rap->data = xmalloc(len);
    386 		memcpy(rap->data, icp, len);
    387 		rap->data_len = len;
    388 	}
    389 
    390 	get_monotonic(&rap->received);
    391 	nd_ra = (struct nd_router_advert *)icp;
    392 	rap->lifetime = ntohs(nd_ra->nd_ra_router_lifetime);
    393 	rap->expired = 0;
    394 
    395 	len -= sizeof(struct nd_router_advert);
    396 	p = ((uint8_t *)icp) + sizeof(struct nd_router_advert);
    397 	olen = 0;
    398 	lifetime = ~0U;
    399 	has_dns = 0;
    400 	for (olen = 0; len > 0; p += olen, len -= olen) {
    401 		if ((size_t)len < sizeof(struct nd_opt_hdr)) {
    402 			syslog(LOG_ERR, "%s: Short option", ifp->name);
    403 			break;
    404 		}
    405 		ndo = (struct nd_opt_hdr *)p;
    406 		olen = ndo->nd_opt_len * 8 ;
    407 		if (olen == 0) {
    408 			syslog(LOG_ERR, "%s: zero length option", ifp->name);
    409 			break;
    410 		}
    411 		if (olen > len) {
    412 			syslog(LOG_ERR,
    413 			    "%s: Option length exceeds message", ifp->name);
    414 			break;
    415 		}
    416 
    417 		opt = NULL;
    418 		switch (ndo->nd_opt_type) {
    419 		case ND_OPT_PREFIX_INFORMATION:
    420 			pi = (struct nd_opt_prefix_info *)ndo;
    421 			if (pi->nd_opt_pi_len != 4) {
    422 				syslog(LOG_ERR,
    423 				    "%s: invalid option len for prefix",
    424 				    ifp->name);
    425 				break;
    426 			}
    427 			if (pi->nd_opt_pi_prefix_len > 128) {
    428 				syslog(LOG_ERR, "%s: invalid prefix len",
    429 				    ifp->name);
    430 				break;
    431 			}
    432 			if (IN6_IS_ADDR_MULTICAST(&pi->nd_opt_pi_prefix) ||
    433 			    IN6_IS_ADDR_LINKLOCAL(&pi->nd_opt_pi_prefix))
    434 			{
    435 				syslog(LOG_ERR,
    436 				    "%s: invalid prefix in RA", ifp->name);
    437 				break;
    438 			}
    439 			opt = xstrdup(inet_ntop(AF_INET6,
    440 			    pi->nd_opt_pi_prefix.s6_addr,
    441 			    ntopbuf, INET6_ADDRSTRLEN));
    442 			if (opt) {
    443 				rap->prefix_len = pi->nd_opt_pi_prefix_len;
    444 				rap->prefix_vltime =
    445 					ntohl(pi->nd_opt_pi_valid_time);
    446 				rap->prefix_pltime =
    447 					ntohl(pi->nd_opt_pi_preferred_time);
    448 			}
    449 			break;
    450 
    451 		case ND_OPT_MTU:
    452 			mtu = (struct nd_opt_mtu *)p;
    453 			snprintf(buf, sizeof(buf), "%d",
    454 			    ntohl(mtu->nd_opt_mtu_mtu));
    455 			opt = xstrdup(buf);
    456 			break;
    457 
    458 		case ND_OPT_RDNSS:
    459 			rdnss = (struct nd_opt_rdnss *)p;
    460 			lifetime = ntohl(rdnss->nd_opt_rdnss_lifetime);
    461 			op = (uint8_t *)ndo;
    462 			op += offsetof(struct nd_opt_rdnss,
    463 			    nd_opt_rdnss_lifetime);
    464 			op += sizeof(rdnss->nd_opt_rdnss_lifetime);
    465 			l = 0;
    466 			for (n = ndo->nd_opt_len - 1; n > 1; n -= 2) {
    467 				memcpy(&addr.s6_addr, op, sizeof(addr.s6_addr));
    468 				cbp = inet_ntop(AF_INET6, &addr,
    469 				    ntopbuf, INET6_ADDRSTRLEN);
    470 				if (cbp == NULL) {
    471 					syslog(LOG_ERR,
    472 					    "%s: invalid RDNSS address",
    473 					    ifp->name);
    474 				} else {
    475 					if (opt) {
    476 						l = strlen(opt);
    477 						opt = xrealloc(opt,
    478 							l + strlen(cbp) + 2);
    479 						opt[l] = ' ';
    480 						strcpy(opt + l + 1, cbp);
    481 					} else
    482 						opt = xstrdup(cbp);
    483 					if (lifetime > 0)
    484 						has_dns = 1;
    485 				}
    486 		        	op += sizeof(addr.s6_addr);
    487 			}
    488 			break;
    489 
    490 		case ND_OPT_DNSSL:
    491 			dnssl = (struct nd_opt_dnssl *)p;
    492 			lifetime = ntohl(dnssl->nd_opt_dnssl_lifetime);
    493 			op = p + offsetof(struct nd_opt_dnssl,
    494 			    nd_opt_dnssl_lifetime);
    495 			op += sizeof(dnssl->nd_opt_dnssl_lifetime);
    496 			n = (dnssl->nd_opt_dnssl_len - 1) * 8;
    497 			l = decode_rfc3397(NULL, 0, n, op);
    498 			if (l < 1) {
    499 				syslog(LOG_ERR, "%s: invalid DNSSL option",
    500 				    ifp->name);
    501 			} else {
    502 				opt = xmalloc(l);
    503 				decode_rfc3397(opt, l, n, op);
    504 			}
    505 			break;
    506 		}
    507 
    508 		if (opt == NULL)
    509 			continue;
    510 		for (raol = NULL, rao = rap->options;
    511 		    rao;
    512 		    raol = rao, rao = rao->next)
    513 		{
    514 			if (rao->type == ndo->nd_opt_type &&
    515 			    strcmp(rao->option, opt) == 0)
    516 				break;
    517 		}
    518 		if (lifetime == 0) {
    519 			if (rao) {
    520 				if (raol)
    521 					raol->next = rao->next;
    522 				else
    523 					rap->options = rao->next;
    524 				free(rao->option);
    525 				free(rao);
    526 			}
    527 			continue;
    528 		}
    529 
    530 		if (rao == NULL) {
    531 			rao = xmalloc(sizeof(*rao));
    532 			rao->next = rap->options;
    533 			rap->options = rao;
    534 			rao->type = ndo->nd_opt_type;
    535 			rao->option = opt;
    536 		} else
    537 			free(opt);
    538 		if (lifetime == ~0U)
    539 			timerclear(&rao->expire);
    540 		else {
    541 			expire.tv_sec = lifetime;
    542 			expire.tv_usec = 0;
    543 			timeradd(&rap->received, &expire, &rao->expire);
    544 		}
    545 	}
    546 
    547 	ipv6rs_sort(ifp);
    548 	run_script_reason(ifp, options & DHCPCD_TEST ? "TEST" : "ROUTERADVERT");
    549 	if (options & DHCPCD_TEST)
    550 		exit(EXIT_SUCCESS);
    551 
    552 	/* If we don't require RDNSS then set has_dns = 1 so we fork */
    553 	if (!(ifp->state->options->options & DHCPCD_IPV6RA_REQRDNSS))
    554 		has_dns = 1;
    555 
    556 	if (has_dns)
    557 		delete_q_timeout(0, handle_exit_timeout, NULL);
    558 	delete_timeout(NULL, ifp);
    559 	ipv6rs_expire(ifp);
    560 	if (has_dns)
    561 		daemonise();
    562 	else if (options & DHCPCD_DAEMONISE && !(options & DHCPCD_DAEMONISED))
    563 		syslog(LOG_WARNING,
    564 		    "%s: did not fork due to an absent RDNSS option in the RA",
    565 		    ifp->name);
    566 }
    567 
    568 ssize_t
    569 ipv6rs_env(char **env, const char *prefix, const struct interface *ifp)
    570 {
    571 	ssize_t l;
    572 	struct timeval now;
    573 	const struct ra *rap;
    574 	const struct ra_opt *rao;
    575 	int i;
    576 	char buffer[32], buffer2[32];
    577 	const char *optn;
    578 
    579 	l = 0;
    580 	get_monotonic(&now);
    581 	for (rap = ifp->ras, i = 1; rap; rap = rap->next, i++) {
    582 		if (env) {
    583 			snprintf(buffer, sizeof(buffer),
    584 			    "ra%d_from", i);
    585 			setvar(&env, prefix, buffer, rap->sfrom);
    586 		}
    587 		l++;
    588 
    589 		for (rao = rap->options; rao; rao = rao->next) {
    590 			if (rao->option == NULL)
    591 				continue;
    592 			if (env == NULL) {
    593 				switch (rao->type) {
    594 				case ND_OPT_PREFIX_INFORMATION:
    595 					l += 4;
    596 					break;
    597 				default:
    598 					l++;
    599 				}
    600 				continue;
    601 			}
    602 			switch (rao->type) {
    603 			case ND_OPT_PREFIX_INFORMATION:
    604 				optn = "prefix";
    605 				break;
    606 			case ND_OPT_MTU:
    607 				optn = "mtu";
    608 				break;
    609 			case ND_OPT_RDNSS:
    610 				optn = "rdnss";
    611 				break;
    612 			case ND_OPT_DNSSL:
    613 				optn = "dnssl";
    614 				break;
    615 			default:
    616 				continue;
    617 			}
    618 			snprintf(buffer, sizeof(buffer), "ra%d_%s", i, optn);
    619 			setvar(&env, prefix, buffer, rao->option);
    620 			l++;
    621 			switch (rao->type) {
    622 			case ND_OPT_PREFIX_INFORMATION:
    623 				snprintf(buffer, sizeof(buffer),
    624 				    "ra%d_prefix_len", i);
    625 				snprintf(buffer2, sizeof(buffer2),
    626 				    "%d", rap->prefix_len);
    627 				setvar(&env, prefix, buffer, buffer2);
    628 
    629 				snprintf(buffer, sizeof(buffer),
    630 				    "ra%d_prefix_vltime", i);
    631 				snprintf(buffer2, sizeof(buffer2),
    632 				    "%d", rap->prefix_vltime);
    633 				setvar(&env, prefix, buffer, buffer2);
    634 
    635 				snprintf(buffer, sizeof(buffer),
    636 				    "ra%d_prefix_pltime", i);
    637 				snprintf(buffer2, sizeof(buffer2),
    638 				    "%d", rap->prefix_pltime);
    639 				setvar(&env, prefix, buffer, buffer2);
    640 				l += 3;
    641 				break;
    642 			}
    643 
    644 		}
    645 	}
    646 
    647 	if (env)
    648 		setvard(&env, prefix, "ra_count", i - 1);
    649 	l++;
    650 	return l;
    651 }
    652 
    653 static void
    654 ipv6rs_free_opts(struct ra *rap)
    655 {
    656 	struct ra_opt *rao, *raon;
    657 
    658 	for (rao = rap->options; rao && (raon = rao->next, 1); rao = raon) {
    659 		free(rao->option);
    660 		free(rao);
    661 	}
    662 }
    663 
    664 void
    665 ipv6rs_free(struct interface *ifp)
    666 {
    667 	struct ra *rap, *ran;
    668 
    669 	free(ifp->rs);
    670 	ifp->rs = NULL;
    671 	for (rap = ifp->ras; rap && (ran = rap->next, 1); rap = ran) {
    672 		ipv6rs_free_opts(rap);
    673 		free(rap->data);
    674 		free(rap);
    675 	}
    676 	ifp->ras = NULL;
    677 }
    678 
    679 void
    680 ipv6rs_expire(void *arg)
    681 {
    682 	struct interface *ifp;
    683 	struct ra *rap, *ran, *ral;
    684 	struct ra_opt *rao, *raol, *raon;
    685 	struct timeval now, lt, expire, next;
    686 	int expired;
    687 	uint32_t expire_secs;
    688 
    689 	ifp = arg;
    690 	get_monotonic(&now);
    691 	expired = 0;
    692 	expire_secs = ~0U;
    693 	timerclear(&next);
    694 
    695 	for (rap = ifp->ras, ral = NULL;
    696 	    rap && (ran = rap->next, 1);
    697 	    ral = rap, rap = ran)
    698 	{
    699 		lt.tv_sec = rap->lifetime;
    700 		lt.tv_usec = 0;
    701 		timeradd(&rap->received, &lt, &expire);
    702 		if (timercmp(&now, &expire, >)) {
    703 			syslog(LOG_INFO, "%s: %s: expired Router Advertisement",
    704 			    ifp->name, rap->sfrom);
    705 			rap->expired = expired = 1;
    706 			if (ral)
    707 				ral->next = ran;
    708 			else
    709 				ifp->ras = ran;
    710 			ipv6rs_free_opts(rap);
    711 			free(rap);
    712 			continue;
    713 		}
    714 		timersub(&expire, &now, &lt);
    715 		if (!timerisset(&next) || timercmp(&next, &lt, >))
    716 			next = lt;
    717 
    718 		for (rao = rap->options, raol = NULL;
    719 		    rao && (raon = rao->next);
    720 		    raol = rao, rao = raon)
    721 		{
    722 			if (!timerisset(&rao->expire))
    723 				continue;
    724 			if (timercmp(&now, &rao->expire, >)) {
    725 				syslog(LOG_INFO,
    726 				    "%s: %s: expired option %d",
    727 				    ifp->name, rap->sfrom, rao->type);
    728 				rap->expired = expired = 1;
    729 				if (raol)
    730 					raol = raon;
    731 				else
    732 					rap->options = raon;
    733 				continue;
    734 			}
    735 			timersub(&rao->expire, &now, &lt);
    736 			if (!timerisset(&next) || timercmp(&next, &lt, >))
    737 				next = lt;
    738 		}
    739 	}
    740 
    741 	if (timerisset(&next))
    742 		add_timeout_tv(&next, ipv6rs_expire, ifp);
    743 	if (expired)
    744 		run_script_reason(ifp, "ROUTERADVERT");
    745 }
    746 
    747 int
    748 ipv6rs_start(struct interface *ifp)
    749 {
    750 
    751 	delete_timeout(NULL, ifp);
    752 
    753 	/* Always make a new probe as the underlying hardware
    754 	 * address could have changed. */
    755 	ipv6rs_makeprobe(ifp);
    756 	if (ifp->rs == NULL)
    757 		return -1;
    758 
    759 	ifp->rsprobes = 0;
    760 	ipv6rs_sendprobe(ifp);
    761 	return 0;
    762 }
    763