1/*
2 * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29/*	$KAME: config.c,v 1.84 2003/08/05 12:34:23 itojun Exp $	*/
30
31/*
32 * Copyright (C) 1998 WIDE Project.
33 * All rights reserved.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 *    notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 *    notice, this list of conditions and the following disclaimer in the
42 *    documentation and/or other materials provided with the distribution.
43 * 3. Neither the name of the project nor the names of its contributors
44 *    may be used to endorse or promote products derived from this software
45 *    without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 */
59
60#include <sys/param.h>
61#include <sys/ioctl.h>
62#include <sys/socket.h>
63#include <sys/time.h>
64#include <sys/sysctl.h>
65
66#include <net/if.h>
67#include <net/if_var.h>
68#include <net/route.h>
69#include <net/if_dl.h>
70
71#include <netinet/in.h>
72#include <netinet/in_var.h>
73#include <netinet/ip6.h>
74#include <netinet6/ip6_var.h>
75#include <netinet/icmp6.h>
76#include <netinet6/nd6.h>
77
78#include <arpa/inet.h>
79
80#include <stdio.h>
81#include <syslog.h>
82#include <errno.h>
83#include <string.h>
84#include <search.h>
85#include <stdlib.h>
86#include <unistd.h>
87#include <ifaddrs.h>
88#include <stddef.h>
89
90#include "rtadvd.h"
91#include "advcap.h"
92#include "timer.h"
93#include "if.h"
94#include "config.h"
95
96static time_t prefix_timo = (60 * 120);	/* 2 hours.
97					 * XXX: should be configurable. */
98extern struct rainfo *ralist;
99
100static struct rtadvd_timer *prefix_timeout(void *);
101static void makeentry(char *, size_t, int, char *);
102static int getinet6sysctl(int);
103static int encode_domain(char *, u_char *);
104
105void
106getconfig(intface)
107	char *intface;
108{
109	int stat, i;
110	int rdnss_length;
111	int dnssl_length;
112	char tbuf[BUFSIZ];
113	struct rainfo *tmp;
114	long val;
115	int64_t val64;
116	char buf[BUFSIZ];
117	char *bp = buf;
118	char *addr, *flagstr;
119	static int forwarding = -1;
120
121#define MUSTHAVE(var, cap)	\
122    do {								\
123	int64_t t;							\
124	if ((t = agetnum(cap)) < 0) {					\
125		fprintf(stderr, "rtadvd: need %s for interface %s\n",	\
126			cap, intface);					\
127		exit(1);						\
128	}								\
129	var = t;							\
130     } while (0)
131#define MAYHAVE(var, cap, def)	\
132     do {								\
133	if ((var = agetnum(cap)) < 0)					\
134		var = def;						\
135     } while (0)
136
137	if ((stat = agetent(tbuf, intface)) <= 0) {
138		memset(tbuf, 0, sizeof(tbuf));
139		syslog(LOG_INFO,
140		       "<%s> %s isn't defined in the configuration file"
141		       " or the configuration file doesn't exist."
142		       " Treat it as default",
143		        __func__, intface);
144	}
145
146	tmp = (struct rainfo *)malloc(sizeof(*ralist));
147	if (tmp == NULL) {
148		syslog(LOG_INFO, "<%s> %s: can't allocate enough memory",
149		    __func__, intface);
150		exit(1);
151	}
152	memset(tmp, 0, sizeof(*tmp));
153	tmp->prefix.next = tmp->prefix.prev = &tmp->prefix;
154#ifdef ROUTEINFO
155	tmp->route.next = tmp->route.prev = &tmp->route;
156#endif
157	tmp->rdnss_list.next = tmp->rdnss_list.prev = &tmp->rdnss_list;
158	tmp->dnssl_list.next = tmp->dnssl_list.prev = &tmp->dnssl_list;
159
160	/* check if we are allowed to forward packets (if not determined) */
161	if (forwarding < 0) {
162		if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0)
163			exit(1);
164	}
165
166	/* get interface information */
167	if (agetflag("nolladdr"))
168		tmp->advlinkopt = 0;
169	else
170		tmp->advlinkopt = 1;
171	if (tmp->advlinkopt) {
172		if ((tmp->sdl = if_nametosdl(intface)) == NULL) {
173			syslog(LOG_ERR,
174			       "<%s> can't get information of %s",
175			       __func__, intface);
176			exit(1);
177		}
178		tmp->ifindex = tmp->sdl->sdl_index;
179	} else
180		tmp->ifindex = if_nametoindex(intface);
181	strncpy(tmp->ifname, intface, sizeof(tmp->ifname));
182	if ((tmp->phymtu = if_getmtu(intface)) == 0) {
183		tmp->phymtu = IPV6_MMTU;
184		syslog(LOG_WARNING,
185		       "<%s> can't get interface mtu of %s. Treat as %d",
186		       __func__, intface, IPV6_MMTU);
187	}
188
189	/*
190	 * set router configuration variables.
191	 */
192	MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL);
193	if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) {
194		syslog(LOG_ERR,
195		       "<%s> maxinterval (%ld) on %s is invalid "
196		       "(must be between %u and %u)", __func__, val,
197		       intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
198		exit(1);
199	}
200	tmp->maxinterval = (u_int)val;
201	MAYHAVE(val, "mininterval", tmp->maxinterval/3);
202	if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) {
203		syslog(LOG_ERR,
204		       "<%s> mininterval (%ld) on %s is invalid "
205		       "(must be between %d and %d)",
206		       __func__, val, intface, MIN_MININTERVAL,
207		       (tmp->maxinterval * 3) / 4);
208		exit(1);
209	}
210	tmp->mininterval = (u_int)val;
211
212	MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT);
213	tmp->hoplimit = val & 0xff;
214
215	if ((flagstr = (char *)agetstr("raflags", &bp))) {
216		val = 0;
217		if (strchr(flagstr, 'm'))
218			val |= ND_RA_FLAG_MANAGED;
219		if (strchr(flagstr, 'o'))
220			val |= ND_RA_FLAG_OTHER;
221		if (strchr(flagstr, 'h'))
222			val |= ND_RA_FLAG_RTPREF_HIGH;
223		if (strchr(flagstr, 'l')) {
224			if ((val & ND_RA_FLAG_RTPREF_HIGH)) {
225				syslog(LOG_ERR, "<%s> the \'h\' and \'l\'"
226				    " router flags are exclusive", __func__);
227				exit(1);
228			}
229			val |= ND_RA_FLAG_RTPREF_LOW;
230		}
231	} else {
232		MAYHAVE(val, "raflags", 0);
233	}
234	tmp->managedflg = val & ND_RA_FLAG_MANAGED;
235	tmp->otherflg = val & ND_RA_FLAG_OTHER;
236#ifndef ND_RA_FLAG_RTPREF_MASK
237#define ND_RA_FLAG_RTPREF_MASK	0x18 /* 00011000 */
238#define ND_RA_FLAG_RTPREF_RSV	0x10 /* 00010000 */
239#endif
240	tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
241	if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) {
242		syslog(LOG_ERR, "<%s> invalid router preference (%02x) on %s",
243		       __func__, tmp->rtpref, intface);
244		exit(1);
245	}
246
247	MAYHAVE(val, "rltime", tmp->maxinterval * 3);
248	if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) {
249		syslog(LOG_ERR,
250		       "<%s> router lifetime (%ld) on %s is invalid "
251		       "(must be 0 or between %d and %d)",
252		       __func__, val, intface,
253		       tmp->maxinterval,
254		       MAXROUTERLIFETIME);
255		exit(1);
256	}
257	/*
258	 * Basically, hosts MUST NOT send Router Advertisement messages at any
259	 * time (RFC 2461, Section 6.2.3). However, it would sometimes be
260	 * useful to allow hosts to advertise some parameters such as prefix
261	 * information and link MTU. Thus, we allow hosts to invoke rtadvd
262	 * only when router lifetime (on every advertising interface) is
263	 * explicitly set zero. (see also the above section)
264	 */
265	if (val && forwarding == 0) {
266		syslog(LOG_ERR,
267		       "<%s> non zero router lifetime is specified for %s, "
268		       "which must not be allowed for hosts.  you must "
269		       "change router lifetime or enable IPv6 forwarding.",
270		       __func__, intface);
271		exit(1);
272	}
273	tmp->lifetime = val & 0xffff;
274
275	MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME);
276	if (val < 0 || val > MAXREACHABLETIME) {
277		syslog(LOG_ERR,
278		       "<%s> reachable time (%ld) on %s is invalid "
279		       "(must be no greater than %d)",
280		       __func__, val, intface, MAXREACHABLETIME);
281		exit(1);
282	}
283	tmp->reachabletime = (u_int32_t)val;
284
285	MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER);
286	if (val64 < 0 || val64 > 0xffffffff) {
287		syslog(LOG_ERR, "<%s> retrans time (%lld) on %s out of range",
288		       __func__, (long long)val64, intface);
289		exit(1);
290	}
291	tmp->retranstimer = (u_int32_t)val64;
292
293	if (agetnum("hapref") != -1 || agetnum("hatime") != -1) {
294		syslog(LOG_ERR,
295		       "<%s> mobile-ip6 configuration not supported",
296		       __func__);
297		exit(1);
298	}
299	/* prefix information */
300
301	/*
302	 * This is an implementation specific parameter to consider
303	 * link propagation delays and poorly synchronized clocks when
304	 * checking consistency of advertised lifetimes.
305	 */
306	MAYHAVE(val, "clockskew", 0);
307	tmp->clockskew = val;
308
309	tmp->pfxs = 0;
310	for (i = -1; i < MAXPREFIX; i++) {
311		struct prefix *pfx;
312		char entbuf[256];
313
314		makeentry(entbuf, sizeof(entbuf), i, "addr");
315		addr = (char *)agetstr(entbuf, &bp);
316		if (addr == NULL)
317			continue;
318
319		/* allocate memory to store prefix information */
320		if ((pfx = malloc(sizeof(struct prefix))) == NULL) {
321			syslog(LOG_ERR,
322			       "<%s> can't allocate enough memory",
323			       __func__);
324			exit(1);
325		}
326		memset(pfx, 0, sizeof(*pfx));
327
328		/* link into chain */
329		insque(pfx, &tmp->prefix);
330		tmp->pfxs++;
331		pfx->rainfo = tmp;
332
333		pfx->origin = PREFIX_FROM_CONFIG;
334
335		if (inet_pton(AF_INET6, addr, &pfx->prefix) != 1) {
336			syslog(LOG_ERR,
337			       "<%s> inet_pton failed for %s",
338			       __func__, addr);
339			exit(1);
340		}
341		if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) {
342			syslog(LOG_ERR,
343			       "<%s> multicast prefix (%s) must "
344			       "not be advertised on %s",
345			       __func__, addr, intface);
346			exit(1);
347		}
348		if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix))
349			syslog(LOG_NOTICE,
350			       "<%s> link-local prefix (%s) will be"
351			       " advertised on %s",
352			       __func__, addr, intface);
353
354		makeentry(entbuf, sizeof(entbuf), i, "prefixlen");
355		MAYHAVE(val, entbuf, 64);
356		if (val < 0 || val > 128) {
357			syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s "
358			       "on %s out of range",
359			       __func__, val, addr, intface);
360			exit(1);
361		}
362		pfx->prefixlen = (int)val;
363
364		makeentry(entbuf, sizeof(entbuf), i, "pinfoflags");
365		if ((flagstr = (char *)agetstr(entbuf, &bp))) {
366			val = 0;
367			if (strchr(flagstr, 'l'))
368				val |= ND_OPT_PI_FLAG_ONLINK;
369			if (strchr(flagstr, 'a'))
370				val |= ND_OPT_PI_FLAG_AUTO;
371		} else {
372			MAYHAVE(val, entbuf,
373			    (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO));
374		}
375		pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK;
376		pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO;
377
378		makeentry(entbuf, sizeof(entbuf), i, "vltime");
379		MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
380		if (val64 < 0 || val64 > 0xffffffff) {
381			syslog(LOG_ERR, "<%s> vltime (%lld) for "
382			    "%s/%d on %s is out of range",
383			    __func__, (long long)val64,
384			    addr, pfx->prefixlen, intface);
385			exit(1);
386		}
387		pfx->validlifetime = (u_int32_t)val64;
388
389		makeentry(entbuf, sizeof(entbuf), i, "vltimedecr");
390		if (agetflag(entbuf)) {
391			struct timeval now;
392			gettimeofday(&now, 0);
393			pfx->vltimeexpire =
394				now.tv_sec + pfx->validlifetime;
395		}
396
397		makeentry(entbuf, sizeof(entbuf), i, "pltime");
398		MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME);
399		if (val64 < 0 || val64 > 0xffffffff) {
400			syslog(LOG_ERR,
401			    "<%s> pltime (%lld) for %s/%d on %s "
402			    "is out of range",
403			    __func__, (long long)val64,
404			    addr, pfx->prefixlen, intface);
405			exit(1);
406		}
407		pfx->preflifetime = (u_int32_t)val64;
408
409		makeentry(entbuf, sizeof(entbuf), i, "pltimedecr");
410		if (agetflag(entbuf)) {
411			struct timeval now;
412			gettimeofday(&now, 0);
413			pfx->pltimeexpire =
414				now.tv_sec + pfx->preflifetime;
415		}
416	}
417	if (tmp->pfxs == 0)
418		get_prefix(tmp);
419
420	MAYHAVE(val, "mtu", 0);
421	if (val < 0 || val > 0xffffffff) {
422		syslog(LOG_ERR,
423		       "<%s> mtu (%ld) on %s out of range",
424		       __func__, val, intface);
425		exit(1);
426	}
427	tmp->linkmtu = (u_int32_t)val;
428	if (tmp->linkmtu == 0) {
429		char *mtustr;
430
431		if ((mtustr = (char *)agetstr("mtu", &bp)) &&
432		    strcmp(mtustr, "auto") == 0)
433			tmp->linkmtu = tmp->phymtu;
434	}
435	else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) {
436		syslog(LOG_ERR,
437		       "<%s> advertised link mtu (%lu) on %s is invalid (must "
438		       "be between least MTU (%d) and physical link MTU (%d)",
439		       __func__, (unsigned long)tmp->linkmtu, intface,
440		       IPV6_MMTU, tmp->phymtu);
441		exit(1);
442	}
443
444#ifdef SIOCSIFINFO_IN6
445	{
446		struct in6_ndireq ndi;
447		int s;
448
449		if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
450			syslog(LOG_ERR, "<%s> socket: %s", __func__,
451			       strerror(errno));
452			exit(1);
453		}
454		memset(&ndi, 0, sizeof(ndi));
455		strncpy(ndi.ifname, intface, IFNAMSIZ);
456		if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&ndi) < 0) {
457			syslog(LOG_INFO, "<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s",
458			     __func__, intface, strerror(errno));
459		}
460
461		/* reflect the RA info to the host variables in kernel */
462		ndi.ndi.chlim = tmp->hoplimit;
463		ndi.ndi.retrans = tmp->retranstimer;
464		ndi.ndi.basereachable = tmp->reachabletime;
465		if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&ndi) < 0) {
466			syslog(LOG_INFO, "<%s> ioctl:SIOCSIFINFO_IN6 at %s: %s",
467			     __func__, intface, strerror(errno));
468		}
469		close(s);
470	}
471#endif
472
473	/* route information */
474#ifdef ROUTEINFO
475	tmp->routes = 0;
476	for (i = -1; i < MAXROUTE; i++) {
477		struct rtinfo *rti;
478		char entbuf[256], oentbuf[256];
479
480		makeentry(entbuf, sizeof(entbuf), i, "rtprefix");
481		addr = (char *)agetstr(entbuf, &bp);
482		if (addr == NULL) {
483			makeentry(oentbuf, sizeof(oentbuf), i, "rtrprefix");
484			addr = (char *)agetstr(oentbuf, &bp);
485			if (addr) {
486				fprintf(stderr, "%s was obsoleted.  Use %s.\n",
487					oentbuf, entbuf);
488			}
489		}
490		if (addr == NULL)
491			continue;
492
493		/* allocate memory to store prefix information */
494		if ((rti = malloc(sizeof(struct rtinfo))) == NULL) {
495			syslog(LOG_ERR,
496			       "<%s> can't allocate enough memory",
497			       __func__);
498			exit(1);
499		}
500		memset(rti, 0, sizeof(*rti));
501
502		/* link into chain */
503		insque(rti, &tmp->route);
504		tmp->routes++;
505
506		if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) {
507			syslog(LOG_ERR, "<%s> inet_pton failed for %s",
508			       __func__, addr);
509			exit(1);
510		}
511#if 0
512		/*
513		 * XXX: currently there's no restriction in route information
514		 * prefix according to
515		 * draft-ietf-ipngwg-router-selection-00.txt.
516		 * However, I think the similar restriction be necessary.
517		 */
518		MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
519		if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) {
520			syslog(LOG_ERR,
521			       "<%s> multicast route (%s) must "
522			       "not be advertised on %s",
523			       __func__, addr, intface);
524			exit(1);
525		}
526		if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) {
527			syslog(LOG_NOTICE,
528			       "<%s> link-local route (%s) will "
529			       "be advertised on %s",
530			       __func__, addr, intface);
531			exit(1);
532		}
533#endif
534
535		makeentry(entbuf, sizeof(entbuf), i, "rtplen");
536		/* XXX: 256 is a magic number for compatibility check. */
537		MAYHAVE(val, entbuf, 256);
538		if (val == 256) {
539			makeentry(oentbuf, sizeof(oentbuf), i, "rtrplen");
540			MAYHAVE(val, oentbuf, 256);
541			if (val != 256) {
542				fprintf(stderr, "%s was obsoleted.  Use %s.\n",
543					oentbuf, entbuf);
544			} else
545				val = 64;
546		}
547		if (val < 0 || val > 128) {
548			syslog(LOG_ERR, "<%s> prefixlen (%ld) for %s on %s "
549			       "out of range",
550			       __func__, val, addr, intface);
551			exit(1);
552		}
553		rti->prefixlen = (int)val;
554
555		makeentry(entbuf, sizeof(entbuf), i, "rtflags");
556		if ((flagstr = (char *)agetstr(entbuf, &bp))) {
557			val = 0;
558			if (strchr(flagstr, 'h'))
559				val |= ND_RA_FLAG_RTPREF_HIGH;
560			if (strchr(flagstr, 'l')) {
561				if ((val & ND_RA_FLAG_RTPREF_HIGH)) {
562					syslog(LOG_ERR,
563					    "<%s> the \'h\' and \'l\' route"
564					    " preferences are exclusive",
565					    __func__);
566					exit(1);
567				}
568				val |= ND_RA_FLAG_RTPREF_LOW;
569			}
570		} else
571			MAYHAVE(val, entbuf, 256); /* XXX */
572		if (val == 256) {
573			makeentry(oentbuf, sizeof(oentbuf), i, "rtrflags");
574			MAYHAVE(val, oentbuf, 256);
575			if (val != 256) {
576				fprintf(stderr, "%s was obsoleted.  Use %s.\n",
577					oentbuf, entbuf);
578			} else
579				val = 0;
580		}
581		rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
582		if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) {
583			syslog(LOG_ERR, "<%s> invalid route preference (%02x) "
584			       "for %s/%d on %s",
585			       __func__, rti->rtpref, addr,
586			       rti->prefixlen, intface);
587			exit(1);
588		}
589
590		/*
591		 * Since the spec does not a default value, we should make
592		 * this entry mandatory.  However, FreeBSD 4.4 has shipped
593		 * with this field being optional, we use the router lifetime
594		 * as an ad-hoc default value with a warning message.
595		 */
596		makeentry(entbuf, sizeof(entbuf), i, "rtltime");
597		MAYHAVE(val64, entbuf, -1);
598		if (val64 == -1) {
599			makeentry(oentbuf, sizeof(oentbuf), i, "rtrltime");
600			MAYHAVE(val64, oentbuf, -1);
601			if (val64 != -1) {
602				fprintf(stderr, "%s was obsoleted.  Use %s.\n",
603					oentbuf, entbuf);
604			} else {
605				fprintf(stderr, "%s should be specified "
606					"for interface %s.\n",
607					entbuf, intface);
608				val64 = tmp->lifetime;
609			}
610		}
611		if (val64 < 0 || val64 > 0xffffffff) {
612			syslog(LOG_ERR, "<%s> route lifetime (%lld) for "
613			    "%s/%d on %s out of range", __func__,
614			    (long long)val64, addr, rti->prefixlen, intface);
615			exit(1);
616		}
617		rti->ltime = (u_int32_t)val64;
618	}
619#endif
620
621	/* RDNSS option (RFC5006) */
622	MAYHAVE(val, "rdnsslifetime", 2 * tmp->maxinterval);
623	if (val < tmp->maxinterval || val > (2 * tmp->maxinterval)) {
624	    syslog(LOG_NOTICE,
625		   "<%s> rdnsslifetime (%lu) on %s SHOULD "
626		   "be between %u and %u", __func__, val,
627		   intface, tmp->maxinterval, 2 * tmp->maxinterval);
628	}
629	tmp->rdnss_lifetime = val;
630	if ((rdnss_length = agetnum("rdnssaddrs")) < 0) {
631	    tmp->rdnss_length = 0;
632	}
633	else {
634	    tmp->rdnss_length = rdnss_length;
635
636	    /* traverse in reverse order so that the queue has correct order */
637	    for (i = (rdnss_length - 1); i >= 0; i--) {
638		struct rdnss *rdnss;
639		char entbuf[256];
640
641		/* allocate memory to store server address information */
642		if ((rdnss = malloc(sizeof(struct rdnss))) == NULL) {
643			syslog(LOG_ERR,
644			       "<%s> can't allocate enough memory",
645			       __func__);
646			exit(1);
647		}
648		memset(rdnss, 0, sizeof(*rdnss));
649
650		/* link into chain */
651		insque(rdnss, &tmp->rdnss_list);
652
653		makeentry(entbuf, sizeof(entbuf), i, "rdnssaddr");
654		addr = (char *)agetstr(entbuf, &bp);
655
656		if (addr == NULL && rdnss_length == 1) {
657		    makeentry(entbuf, sizeof(entbuf), -1, "rdnssaddr");
658                    addr = agetstr(entbuf, &bp);
659		}
660
661		if (addr == NULL) {
662		    syslog(LOG_ERR,
663			   "<%s> need %s as a DNS server address for "
664			   "interface %s",
665			   __func__, entbuf, intface);
666		    exit(1);
667		}
668
669		if (inet_pton(AF_INET6, addr, &rdnss->addr) != 1) {
670			syslog(LOG_ERR,
671			       "<%s> inet_pton failed for %s",
672			       __func__, addr);
673			exit(1);
674		}
675		if (IN6_IS_ADDR_MULTICAST(&rdnss->addr)) {
676			syslog(LOG_ERR,
677			       "<%s> multicast address (%s) must "
678			       "not be advertised as recursive DNS server",
679			       __func__, addr);
680			exit(1);
681		}
682	    }
683	}
684
685	/* DNSSL option (RFC6106) */
686
687	/* Parse the DNSSL lifetime from the config */
688	MAYHAVE(val, "dnssllifetime", 2 * tmp->maxinterval);
689	if (val < tmp->maxinterval || val > (2 * tmp->maxinterval)) {
690	    syslog(LOG_NOTICE,
691		   "<%s> dnssllifetime (%lu) on %s SHOULD "
692		   "be between %u and %u", __func__, val,
693		   intface, tmp->maxinterval, 2 * tmp->maxinterval);
694	}
695	tmp->dnssl_lifetime = val;
696	tmp->dnssl_option_length = 8; /* 8 bytes for the option header */
697
698	/* Parse the DNSSL domain list from the config */
699	if ((dnssl_length = agetnum("dnssldomains")) < 0) {
700	    tmp->dnssl_length = 0;
701	} else {
702	    tmp->dnssl_length = dnssl_length;
703
704	    for (i = (tmp->dnssl_length - 1); i >= 0; i--) {
705		unsigned char *dnssl_buf;
706		struct dnssl *dnssl;
707		int dnssl_len;
708		char entbuf[sizeof("dnssldomain") + 20];
709		char *domain;
710		int domain_len;
711
712		makeentry(entbuf, sizeof(entbuf), i, "dnssldomain");
713		domain = agetstr(entbuf, &bp);
714
715		if (domain == NULL && tmp->dnssl_length == 1) {
716		    makeentry(entbuf, sizeof(entbuf), -1, "dnssldomain");
717		    domain = agetstr(entbuf, &bp);
718		}
719
720		if (domain == NULL) {
721		    syslog(LOG_ERR,
722			   "<%s> need %s as a DNS search domain for "
723			   "interface %s",
724			   __func__, entbuf, intface);
725		    exit(1);
726		}
727
728		domain_len = strlen(domain);
729
730		/* Trim off leading dots */
731		while (domain_len > 0 && domain[0] == '.') {
732		    domain++;
733		    domain_len--;
734		}
735
736		/* Trim off trailing dots */
737		while (domain_len > 0 && domain[domain_len-1] == '.') {
738		    domain_len--;
739		}
740
741		if (domain_len > 0) {
742		    dnssl_len = sizeof(struct dnssl) + domain_len + 1;
743		    dnssl_buf = (unsigned char *)malloc(dnssl_len);
744
745		    memset(dnssl_buf, 0, dnssl_len);
746
747		    dnssl = (struct dnssl *)dnssl_buf;
748		    insque(dnssl, &tmp->dnssl_list);
749
750		    /* Copy the domain name in at the end of the dnssl struct */
751		    memcpy(dnssl_buf + offsetof(struct dnssl, domain), domain,
752		           domain_len);
753
754		    /* Add 2 for leading length byte and the trailing 0 byte */
755		    tmp->dnssl_option_length += domain_len + 2;
756		}
757	    }
758
759	    /* Round up to the next multiple of 8 */
760	    tmp->dnssl_option_length += (8 - (tmp->dnssl_option_length & 0x7));
761	}
762
763	/* okey */
764	tmp->next = ralist;
765	ralist = tmp;
766
767	/* construct the sending packet */
768	make_packet(tmp);
769
770	/* set timer */
771	tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update,
772				      tmp, tmp);
773	ra_timer_update((void *)tmp, &tmp->timer->tm);
774	rtadvd_set_timer(&tmp->timer->tm, tmp->timer);
775}
776
777void
778get_prefix(struct rainfo *rai)
779{
780	struct ifaddrs *ifap, *ifa;
781	struct prefix *pp;
782	struct in6_addr *a;
783	u_char *p, *ep, *m, *lim;
784	char ntopbuf[INET6_ADDRSTRLEN];
785
786	if (getifaddrs(&ifap) < 0) {
787		syslog(LOG_ERR,
788		       "<%s> can't get interface addresses",
789		       __func__);
790		exit(1);
791	}
792
793	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
794		int plen;
795
796		if (strcmp(ifa->ifa_name, rai->ifname) != 0)
797			continue;
798		if (ifa->ifa_addr->sa_family != AF_INET6)
799			continue;
800		a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
801		if (IN6_IS_ADDR_LINKLOCAL(a))
802			continue;
803		/* get prefix length */
804		m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
805		lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len;
806		plen = prefixlen(m, lim);
807		if (plen <= 0 || plen > 128) {
808			syslog(LOG_ERR, "<%s> failed to get prefixlen "
809			       "or prefix is invalid",
810			       __func__);
811			exit(1);
812		}
813		if (plen == 128)	/* XXX */
814			continue;
815		if (find_prefix(rai, a, plen)) {
816			/* ignore a duplicated prefix. */
817			continue;
818		}
819
820		/* allocate memory to store prefix info. */
821		if ((pp = malloc(sizeof(*pp))) == NULL) {
822			syslog(LOG_ERR,
823			       "<%s> can't get allocate buffer for prefix",
824			       __func__);
825			exit(1);
826		}
827		memset(pp, 0, sizeof(*pp));
828
829		/* set prefix, sweep bits outside of prefixlen */
830		pp->prefixlen = plen;
831		memcpy(&pp->prefix, a, sizeof(*a));
832		p = (u_char *)&pp->prefix;
833		ep = (u_char *)(&pp->prefix + 1);
834		while (m < lim && p < ep)
835			*p++ &= *m++;
836		while (p < ep)
837			*p++ = 0x00;
838	        if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf,
839	            sizeof(ntopbuf))) {
840			syslog(LOG_ERR, "<%s> inet_ntop failed", __func__);
841			exit(1);
842		}
843		syslog(LOG_DEBUG,
844		       "<%s> add %s/%d to prefix list on %s",
845		       __func__, ntopbuf, pp->prefixlen, rai->ifname);
846
847		/* set other fields with protocol defaults */
848		pp->validlifetime = DEF_ADVVALIDLIFETIME;
849		pp->preflifetime = DEF_ADVPREFERREDLIFETIME;
850		pp->onlinkflg = 1;
851		pp->autoconfflg = 1;
852		pp->origin = PREFIX_FROM_KERNEL;
853		pp->rainfo = rai;
854
855		/* link into chain */
856		insque(pp, &rai->prefix);
857
858		/* counter increment */
859		rai->pfxs++;
860	}
861
862	freeifaddrs(ifap);
863}
864
865static void
866makeentry(buf, len, id, string)
867	char *buf;
868	size_t len;
869	int id;
870	char *string;
871{
872
873	if (id < 0)
874		strlcpy(buf, string, len);
875	else
876		snprintf(buf, len, "%s%d", string, id);
877}
878
879/*
880 * Add a prefix to the list of specified interface and reconstruct
881 * the outgoing packet.
882 * The prefix must not be in the list.
883 * XXX: other parameters of the prefix (e.g. lifetime) should be
884 * able to be specified.
885 */
886static void
887add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr)
888{
889	struct prefix *prefix;
890	char ntopbuf[INET6_ADDRSTRLEN];
891
892	if ((prefix = malloc(sizeof(*prefix))) == NULL) {
893		syslog(LOG_ERR, "<%s> memory allocation failed",
894		       __func__);
895		return;		/* XXX: error or exit? */
896	}
897	memset(prefix, 0, sizeof(*prefix));
898	prefix->prefix = ipr->ipr_prefix.sin6_addr;
899	prefix->prefixlen = ipr->ipr_plen;
900	prefix->validlifetime = ipr->ipr_vltime;
901	prefix->preflifetime = ipr->ipr_pltime;
902	prefix->onlinkflg = ipr->ipr_raf_onlink;
903	prefix->autoconfflg = ipr->ipr_raf_auto;
904	prefix->origin = PREFIX_FROM_DYNAMIC;
905
906	insque(prefix, &rai->prefix);
907	prefix->rainfo = rai;
908
909	syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s",
910	       __func__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr,
911				       ntopbuf, INET6_ADDRSTRLEN),
912	       ipr->ipr_plen, rai->ifname);
913
914	/* free the previous packet */
915	free(rai->ra_data);
916	rai->ra_data = NULL;
917
918	/* reconstruct the packet */
919	rai->pfxs++;
920	make_packet(rai);
921}
922
923/*
924 * Delete a prefix to the list of specified interface and reconstruct
925 * the outgoing packet.
926 * The prefix must be in the list.
927 */
928void
929delete_prefix(struct prefix *prefix)
930{
931	char ntopbuf[INET6_ADDRSTRLEN];
932	struct rainfo *rai = prefix->rainfo;
933
934	remque(prefix);
935	syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s",
936	       __func__, inet_ntop(AF_INET6, &prefix->prefix,
937				       ntopbuf, INET6_ADDRSTRLEN),
938	       prefix->prefixlen, rai->ifname);
939	if (prefix->timer)
940		rtadvd_remove_timer(&prefix->timer);
941	free(prefix);
942	rai->pfxs--;
943}
944
945void
946invalidate_prefix(struct prefix *prefix)
947{
948	char ntopbuf[INET6_ADDRSTRLEN];
949	struct timeval timo;
950	struct rainfo *rai = prefix->rainfo;
951
952	if (prefix->timer) {	/* sanity check */
953		syslog(LOG_ERR,
954		    "<%s> assumption failure: timer already exists",
955		    __func__);
956		exit(1);
957	}
958
959	syslog(LOG_DEBUG, "<%s> prefix %s/%d was invalidated on %s, "
960	    "will expire in %ld seconds", __func__,
961	    inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, INET6_ADDRSTRLEN),
962	    prefix->prefixlen, rai->ifname, (long)prefix_timo);
963
964	/* set the expiration timer */
965	prefix->timer = rtadvd_add_timer(prefix_timeout, NULL, prefix, NULL);
966	if (prefix->timer == NULL) {
967		syslog(LOG_ERR, "<%s> failed to add a timer for a prefix. "
968		    "remove the prefix", __func__);
969		delete_prefix(prefix);
970	}
971	timo.tv_sec = prefix_timo;
972	timo.tv_usec = 0;
973	rtadvd_set_timer(&timo, prefix->timer);
974}
975
976static struct rtadvd_timer *
977prefix_timeout(void *arg)
978{
979	struct prefix *prefix = (struct prefix *)arg;
980
981	delete_prefix(prefix);
982
983	return(NULL);
984}
985
986void
987update_prefix(struct prefix * prefix)
988{
989	char ntopbuf[INET6_ADDRSTRLEN];
990	struct rainfo *rai = prefix->rainfo;
991
992	if (prefix->timer == NULL) { /* sanity check */
993		syslog(LOG_ERR,
994		    "<%s> assumption failure: timer does not exist",
995		    __func__);
996		exit(1);
997	}
998
999	syslog(LOG_DEBUG, "<%s> prefix %s/%d was re-enabled on %s",
1000	    __func__, inet_ntop(AF_INET6, &prefix->prefix, ntopbuf,
1001	    INET6_ADDRSTRLEN), prefix->prefixlen, rai->ifname);
1002
1003	/* stop the expiration timer */
1004	rtadvd_remove_timer(&prefix->timer);
1005}
1006
1007/*
1008 * Try to get an in6_prefixreq contents for a prefix which matches
1009 * ipr->ipr_prefix and ipr->ipr_plen and belongs to
1010 * the interface whose name is ipr->ipr_name[].
1011 */
1012static int
1013init_prefix(struct in6_prefixreq *ipr)
1014{
1015#if 0
1016	int s;
1017
1018	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1019		syslog(LOG_ERR, "<%s> socket: %s", __func__,
1020		       strerror(errno));
1021		exit(1);
1022	}
1023
1024	if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) {
1025		syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __func__,
1026		       strerror(errno));
1027
1028		ipr->ipr_vltime = DEF_ADVVALIDLIFETIME;
1029		ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME;
1030		ipr->ipr_raf_onlink = 1;
1031		ipr->ipr_raf_auto = 1;
1032		/* omit other field initialization */
1033	}
1034	else if (ipr->ipr_origin < PR_ORIG_RR) {
1035		char ntopbuf[INET6_ADDRSTRLEN];
1036
1037		syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is"
1038		       "lower than PR_ORIG_RR(router renumbering)."
1039		       "This should not happen if I am router", __func__,
1040		       inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf,
1041				 sizeof(ntopbuf)), ipr->ipr_origin);
1042		close(s);
1043		return 1;
1044	}
1045
1046	close(s);
1047	return 0;
1048#else
1049	ipr->ipr_vltime = DEF_ADVVALIDLIFETIME;
1050	ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME;
1051	ipr->ipr_raf_onlink = 1;
1052	ipr->ipr_raf_auto = 1;
1053	return 0;
1054#endif
1055}
1056
1057void
1058make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen)
1059{
1060	struct in6_prefixreq ipr;
1061
1062	memset(&ipr, 0, sizeof(ipr));
1063	if (if_indextoname(ifindex, ipr.ipr_name) == NULL) {
1064		syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't"
1065		       "exist. This should not happen! %s", __func__,
1066		       ifindex, strerror(errno));
1067		exit(1);
1068	}
1069	ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix);
1070	ipr.ipr_prefix.sin6_family = AF_INET6;
1071	ipr.ipr_prefix.sin6_addr = *addr;
1072	ipr.ipr_plen = plen;
1073
1074	if (init_prefix(&ipr))
1075		return; /* init failed by some error */
1076	add_prefix(rai, &ipr);
1077}
1078
1079void
1080make_packet(struct rainfo *rainfo)
1081{
1082	size_t packlen, lladdroptlen = 0;
1083	u_char *buf;
1084	struct nd_router_advert *ra;
1085	struct nd_opt_prefix_info *ndopt_pi;
1086	struct nd_opt_mtu *ndopt_mtu;
1087#ifdef ROUTEINFO
1088	struct nd_opt_route_info *ndopt_rti;
1089	struct rtinfo *rti;
1090#endif
1091	struct prefix *pfx;
1092
1093	/* calculate total length */
1094	packlen = sizeof(struct nd_router_advert);
1095	if (rainfo->advlinkopt) {
1096		if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) {
1097			syslog(LOG_INFO,
1098			       "<%s> link-layer address option has"
1099			       " null length on %s.  Treat as not included.",
1100			       __func__, rainfo->ifname);
1101			rainfo->advlinkopt = 0;
1102		}
1103		packlen += lladdroptlen;
1104	}
1105	if (rainfo->pfxs)
1106		packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs;
1107	if (rainfo->linkmtu)
1108		packlen += sizeof(struct nd_opt_mtu);
1109#ifdef ROUTEINFO
1110	for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next)
1111		packlen += sizeof(struct nd_opt_route_info) +
1112			   ((rti->prefixlen + 0x3f) >> 6) * 8;
1113#endif
1114	if (rainfo->rdnss_length > 0)
1115		packlen += 8 + sizeof(struct in6_addr) * rainfo->rdnss_length;
1116
1117	if (rainfo->dnssl_length > 0) {
1118		packlen += rainfo->dnssl_option_length;
1119	}
1120
1121	/* allocate memory for the packet */
1122	if ((buf = malloc(packlen)) == NULL) {
1123		syslog(LOG_ERR,
1124		       "<%s> can't get enough memory for an RA packet",
1125		       __func__);
1126		exit(1);
1127	}
1128	if (rainfo->ra_data) {
1129		/* free the previous packet */
1130		free(rainfo->ra_data);
1131		rainfo->ra_data = NULL;
1132	}
1133	rainfo->ra_data = buf;
1134	/* XXX: what if packlen > 576? */
1135	rainfo->ra_datalen = packlen;
1136
1137	/*
1138	 * construct the packet
1139	 */
1140	ra = (struct nd_router_advert *)buf;
1141	ra->nd_ra_type = ND_ROUTER_ADVERT;
1142	ra->nd_ra_code = 0;
1143	ra->nd_ra_cksum = 0;
1144	ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit);
1145	ra->nd_ra_flags_reserved = 0; /* just in case */
1146	/*
1147	 * XXX: the router preference field, which is a 2-bit field, should be
1148	 * initialized before other fields.
1149	 */
1150	ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref;
1151	ra->nd_ra_flags_reserved |=
1152		rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0;
1153	ra->nd_ra_flags_reserved |=
1154		rainfo->otherflg ? ND_RA_FLAG_OTHER : 0;
1155	ra->nd_ra_router_lifetime = htons(rainfo->lifetime);
1156	ra->nd_ra_reachable = htonl(rainfo->reachabletime);
1157	ra->nd_ra_retransmit = htonl(rainfo->retranstimer);
1158	buf += sizeof(*ra);
1159
1160	if (rainfo->advlinkopt) {
1161		lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf);
1162		buf += lladdroptlen;
1163	}
1164
1165	if (rainfo->linkmtu) {
1166		ndopt_mtu = (struct nd_opt_mtu *)buf;
1167		ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU;
1168		ndopt_mtu->nd_opt_mtu_len = 1;
1169		ndopt_mtu->nd_opt_mtu_reserved = 0;
1170		ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu);
1171		buf += sizeof(struct nd_opt_mtu);
1172	}
1173
1174	for (pfx = rainfo->prefix.next;
1175	     pfx != &rainfo->prefix; pfx = pfx->next) {
1176		u_int32_t vltime, pltime;
1177		struct timeval now;
1178
1179		ndopt_pi = (struct nd_opt_prefix_info *)buf;
1180		ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
1181		ndopt_pi->nd_opt_pi_len = 4;
1182		ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen;
1183		ndopt_pi->nd_opt_pi_flags_reserved = 0;
1184		if (pfx->onlinkflg)
1185			ndopt_pi->nd_opt_pi_flags_reserved |=
1186				ND_OPT_PI_FLAG_ONLINK;
1187		if (pfx->autoconfflg)
1188			ndopt_pi->nd_opt_pi_flags_reserved |=
1189				ND_OPT_PI_FLAG_AUTO;
1190		if (pfx->timer)
1191			vltime = 0;
1192		else {
1193			if (pfx->vltimeexpire || pfx->pltimeexpire)
1194				gettimeofday(&now, NULL);
1195			if (pfx->vltimeexpire == 0)
1196				vltime = pfx->validlifetime;
1197			else
1198				vltime = (pfx->vltimeexpire > now.tv_sec) ?
1199				    pfx->vltimeexpire - now.tv_sec : 0;
1200		}
1201		if (pfx->timer)
1202			pltime = 0;
1203		else {
1204			if (pfx->pltimeexpire == 0)
1205				pltime = pfx->preflifetime;
1206			else
1207				pltime = (pfx->pltimeexpire > now.tv_sec) ?
1208				    pfx->pltimeexpire - now.tv_sec : 0;
1209		}
1210		if (vltime < pltime) {
1211			/*
1212			 * this can happen if vltime is decrement but pltime
1213			 * is not.
1214			 */
1215			pltime = vltime;
1216		}
1217		ndopt_pi->nd_opt_pi_valid_time = htonl(vltime);
1218		ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime);
1219		ndopt_pi->nd_opt_pi_reserved2 = 0;
1220		ndopt_pi->nd_opt_pi_prefix = pfx->prefix;
1221
1222		buf += sizeof(struct nd_opt_prefix_info);
1223	}
1224
1225#ifdef ROUTEINFO
1226	for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) {
1227		u_int8_t psize = (rti->prefixlen + 0x3f) >> 6;
1228
1229		ndopt_rti = (struct nd_opt_route_info *)buf;
1230		ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO;
1231		ndopt_rti->nd_opt_rti_len = 1 + psize;
1232		ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen;
1233		ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref;
1234		ndopt_rti->nd_opt_rti_lifetime = htonl(rti->ltime);
1235		memcpy(ndopt_rti + 1, &rti->prefix, psize * 8);
1236		buf += sizeof(struct nd_opt_route_info) + psize * 8;
1237	}
1238#endif
1239
1240	if (rainfo->rdnss_length > 0) {
1241	    	struct nd_opt_rdnss *	ndopt_rdnss;
1242		struct rdnss * 		rdnss;
1243
1244		ndopt_rdnss = (struct nd_opt_rdnss*) buf;
1245		ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
1246		ndopt_rdnss->nd_opt_rdnss_len = 1 + (rainfo->rdnss_length * 2);
1247		ndopt_rdnss->nd_opt_rdnss_reserved = 0;
1248		ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rainfo->rdnss_lifetime);
1249		buf += 8;
1250
1251		for (rdnss = rainfo->rdnss_list.next;
1252		     rdnss != &rainfo->rdnss_list;
1253		     rdnss = rdnss->next)
1254		{
1255			struct in6_addr* addr6 = (struct in6_addr*) buf;
1256			*addr6 = rdnss->addr;
1257			buf += sizeof *addr6;
1258		}
1259	}
1260
1261	if (rainfo->dnssl_length > 0) {
1262		struct nd_opt_dnssl *	dnssl_opt;
1263		struct dnssl *		dnssl;
1264		int			domains_length = 0;
1265		u_char *		cursor = buf;
1266
1267		memset(cursor, 0, rainfo->dnssl_option_length);
1268
1269		dnssl_opt = (struct nd_opt_dnssl *)cursor;
1270		dnssl_opt->nd_opt_dnssl_type = ND_OPT_DNSSL;
1271		/*
1272		 * Length is in units of 8 octets. Divide total byte length
1273		 * of the option by 8.
1274		 */
1275		dnssl_opt->nd_opt_dnssl_len = rainfo->dnssl_option_length >> 3;
1276		dnssl_opt->nd_opt_dnssl_reserved = 0;
1277		dnssl_opt->nd_opt_dnssl_lifetime =
1278		    htonl(rainfo->dnssl_lifetime);
1279
1280		cursor += offsetof(struct nd_opt_dnssl, nd_opt_dnssl_domains);
1281
1282		for (dnssl = rainfo->dnssl_list.next;
1283		     dnssl != &rainfo->dnssl_list;
1284		     dnssl = dnssl->next)
1285		{
1286			int encodeLen = encode_domain(dnssl->domain, cursor);
1287			cursor += encodeLen;
1288			domains_length += encodeLen;
1289		}
1290
1291		buf += rainfo->dnssl_option_length;
1292	}
1293
1294	return;
1295}
1296
1297static int
1298getinet6sysctl(int code)
1299{
1300	int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
1301	int value;
1302	size_t size;
1303
1304	mib[3] = code;
1305	size = sizeof(value);
1306	if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0)
1307	    < 0) {
1308		syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s",
1309		       __func__, code,
1310		       strerror(errno));
1311		return(-1);
1312	}
1313	else
1314		return(value);
1315}
1316
1317/*
1318 * Encode a domain name into a buffer according to the rules in RFC 1035 section
1319 * 3.1. Do not use the compression techniques outlined in section 4.1.4.
1320 */
1321int
1322encode_domain(char *domain, u_char *dst)
1323{
1324	char *domainCopy = strdup(domain);
1325	char *input = domainCopy;
1326	char *label;
1327	u_char *cursor = dst;
1328
1329	while ((label = strsep(&input, ".")) != NULL) {
1330		int label_len = strlen(label) & 0x3f; /* Max length is 63 */
1331		if (label_len > 0) {
1332			*cursor = (u_char)label_len;
1333			cursor++;
1334			memcpy(cursor, label, label_len);
1335			cursor += label_len;
1336		}
1337	}
1338	*cursor = 0;
1339	cursor++;
1340
1341	free(domainCopy);
1342
1343	return (cursor - dst);
1344}
1345