2 * Copyright (c) 2009-2020 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 /* $KAME: config.c,v 1.84 2003/08/05 12:34:23 itojun Exp $ */
32 * Copyright (C) 1998 WIDE Project.
33 * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the project nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 #include <sys/param.h>
62 #include <sys/ioctl.h>
63 #include <sys/socket.h>
65 #include <sys/sysctl.h>
68 #include <net/if_var.h>
69 #include <net/route.h>
70 #include <net/if_dl.h>
72 #include <netinet/in.h>
73 #include <netinet/in_var.h>
74 #include <netinet/ip6.h>
75 #include <netinet6/ip6_var.h>
76 #include <netinet/icmp6.h>
77 #include <netinet6/nd6.h>
79 #include <arpa/inet.h>
96 static time_t prefix_timo
= (60 * 120); /* 2 hours.
97 * XXX: should be configurable. */
98 extern struct rainfo
*ralist
;
100 static struct rtadvd_timer
*prefix_timeout(void *);
101 static void makeentry(char *, size_t, int, char *);
102 static int getinet6sysctl(int);
103 static int encode_domain(char *, u_char
*);
118 char *addr
, *flagstr
;
120 static int forwarding
= -1;
122 #define MUSTHAVE(var, cap) \
125 if ((t = agetnum(cap)) < 0) { \
126 fprintf(stderr, "rtadvd: need %s for interface %s\n", \
132 #define MAYHAVE(var, cap, def) \
134 if ((var = agetnum(cap)) < 0) \
138 if ((stat
= agetent(tbuf
, intface
)) <= 0) {
139 memset(tbuf
, 0, sizeof(tbuf
));
140 errorlog("<%s> %s isn't defined in the configuration file"
141 " or the configuration file doesn't exist."
142 " Treat it as default",
146 ELM_MALLOC(rai
, exit(1));
147 rai
->prefix
.next
= rai
->prefix
.prev
= &rai
->prefix
;
149 rai
->route
.next
= rai
->route
.prev
= &rai
->route
;
151 rai
->rdnss_list
.next
= rai
->rdnss_list
.prev
= &rai
->rdnss_list
;
152 rai
->dnssl_list
.next
= rai
->dnssl_list
.prev
= &rai
->dnssl_list
;
154 /* check if we are allowed to forward packets (if not determined) */
155 if (forwarding
< 0) {
156 if ((forwarding
= getinet6sysctl(IPV6CTL_FORWARDING
)) < 0)
160 /* get interface information */
161 if (agetflag("nolladdr"))
165 if (rai
->advlinkopt
) {
166 if ((rai
->sdl
= if_nametosdl(intface
)) == NULL
) {
167 errorlog("<%s> can't get information of %s",
171 rai
->ifindex
= rai
->sdl
->sdl_index
;
173 rai
->ifindex
= if_nametoindex(intface
);
174 strlcpy(rai
->ifname
, intface
, sizeof(rai
->ifname
));
175 if ((rai
->phymtu
= if_getmtu(intface
)) == 0) {
176 rai
->phymtu
= IPV6_MMTU
;
177 errorlog("<%s> can't get interface mtu of %s. Treat as %d",
178 __func__
, intface
, IPV6_MMTU
);
182 * set router configuration variables.
184 MAYHAVE(val
, "maxinterval", DEF_MAXRTRADVINTERVAL
);
185 if (val
< MIN_MAXINTERVAL
|| val
> MAX_MAXINTERVAL
) {
186 errorlog("<%s> maxinterval (%ld) on %s is invalid "
187 "(must be between %u and %u)", __func__
, val
,
188 intface
, MIN_MAXINTERVAL
, MAX_MAXINTERVAL
);
191 rai
->maxinterval
= (u_int
)val
;
192 MAYHAVE(val
, "mininterval", rai
->maxinterval
/3);
193 if (val
< MIN_MININTERVAL
|| val
> (rai
->maxinterval
* 3) / 4) {
194 errorlog("<%s> mininterval (%ld) on %s is invalid "
195 "(must be between %d and %d)",
196 __func__
, val
, intface
, MIN_MININTERVAL
,
197 (rai
->maxinterval
* 3) / 4);
200 rai
->mininterval
= (u_int
)val
;
202 MAYHAVE(val
, "chlim", DEF_ADVCURHOPLIMIT
);
203 rai
->hoplimit
= val
& 0xff;
205 if ((flagstr
= (char *)agetstr("raflags", &bp
))) {
207 if (strchr(flagstr
, 'm'))
208 val
|= ND_RA_FLAG_MANAGED
;
209 if (strchr(flagstr
, 'o'))
210 val
|= ND_RA_FLAG_OTHER
;
211 if (strchr(flagstr
, 'h'))
212 val
|= ND_RA_FLAG_RTPREF_HIGH
;
213 if (strchr(flagstr
, 'l')) {
214 if ((val
& ND_RA_FLAG_RTPREF_HIGH
)) {
215 errorlog("<%s> the \'h\' and \'l\'"
216 " router flags are exclusive", __func__
);
219 val
|= ND_RA_FLAG_RTPREF_LOW
;
222 MAYHAVE(val
, "raflags", 0);
224 rai
->managedflg
= val
& ND_RA_FLAG_MANAGED
;
225 rai
->otherflg
= val
& ND_RA_FLAG_OTHER
;
226 #ifndef ND_RA_FLAG_RTPREF_MASK
227 #define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
228 #define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */
230 rai
->rtpref
= val
& ND_RA_FLAG_RTPREF_MASK
;
231 if (rai
->rtpref
== ND_RA_FLAG_RTPREF_RSV
) {
232 errorlog("<%s> invalid router preference (%02x) on %s",
233 __func__
, rai
->rtpref
, intface
);
237 MAYHAVE(val
, "rltime", rai
->maxinterval
* 3);
238 if (val
&& (val
< rai
->maxinterval
|| val
> MAXROUTERLIFETIME
)) {
239 errorlog("<%s> router lifetime (%ld) on %s is invalid "
240 "(must be 0 or between %d and %d)",
241 __func__
, val
, intface
,
247 * Basically, hosts MUST NOT send Router Advertisement messages at any
248 * time (RFC 2461, Section 6.2.3). However, it would sometimes be
249 * useful to allow hosts to advertise some parameters such as prefix
250 * information and link MTU. Thus, we allow hosts to invoke rtadvd
251 * only when router lifetime (on every advertising interface) is
252 * explicitly set zero. (see also the above section)
254 if (val
&& forwarding
== 0) {
255 errorlog("<%s> non zero router lifetime is specified for %s, "
256 "which must not be allowed for hosts. you must "
257 "change router lifetime or enable IPv6 forwarding.",
261 rai
->lifetime
= val
& 0xffff;
263 MAYHAVE(val
, "rtime", DEF_ADVREACHABLETIME
);
264 if (val
< 0 || val
> MAXREACHABLETIME
) {
265 errorlog("<%s> reachable time (%ld) on %s is invalid "
266 "(must be no greater than %d)",
267 __func__
, val
, intface
, MAXREACHABLETIME
);
270 rai
->reachabletime
= (u_int32_t
)val
;
272 MAYHAVE(val64
, "retrans", DEF_ADVRETRANSTIMER
);
273 if (val64
< 0 || val64
> 0xffffffff) {
274 errorlog("<%s> retrans time (%lld) on %s out of range",
275 __func__
, (long long)val64
, intface
);
278 rai
->retranstimer
= (u_int32_t
)val64
;
280 if (agetnum("hapref") != -1 || agetnum("hatime") != -1) {
281 errorlog("<%s> mobile-ip6 configuration not supported",
285 /* prefix information */
288 * This is an implementation specific parameter to consider
289 * link propagation delays and poorly synchronized clocks when
290 * checking consistency of advertised lifetimes.
292 MAYHAVE(val
, "clockskew", 0);
293 rai
->clockskew
= val
;
296 for (i
= -1; i
< MAXPREFIX
; i
++) {
300 makeentry(entbuf
, sizeof(entbuf
), i
, "addr");
301 addr
= (char *)agetstr(entbuf
, &bp
);
305 /* allocate memory to store prefix information */
306 ELM_MALLOC(pfx
, exit(1));
309 pfx
->origin
= PREFIX_FROM_CONFIG
;
311 if (inet_pton(AF_INET6
, addr
, &pfx
->prefix
) != 1) {
312 errorlog("<%s> inet_pton failed for %s",
316 if (IN6_IS_ADDR_MULTICAST(&pfx
->prefix
)) {
317 errorlog("<%s> multicast prefix (%s) must "
318 "not be advertised on %s",
319 __func__
, addr
, intface
);
322 if (IN6_IS_ADDR_LINKLOCAL(&pfx
->prefix
))
323 noticelog("<%s> link-local prefix (%s) will be"
325 __func__
, addr
, intface
);
327 makeentry(entbuf
, sizeof(entbuf
), i
, "prefixlen");
328 MAYHAVE(val
, entbuf
, 64);
329 if (val
< 0 || val
> 128) {
330 errorlog("<%s> prefixlen (%ld) for %s "
331 "on %s out of range",
332 __func__
, val
, addr
, intface
);
335 pfx
->prefixlen
= (int)val
;
337 makeentry(entbuf
, sizeof(entbuf
), i
, "pinfoflags");
338 if ((flagstr
= (char *)agetstr(entbuf
, &bp
))) {
340 if (strchr(flagstr
, 'l'))
341 val
|= ND_OPT_PI_FLAG_ONLINK
;
342 if (strchr(flagstr
, 'a'))
343 val
|= ND_OPT_PI_FLAG_AUTO
;
346 (ND_OPT_PI_FLAG_ONLINK
|ND_OPT_PI_FLAG_AUTO
));
348 pfx
->onlinkflg
= val
& ND_OPT_PI_FLAG_ONLINK
;
349 pfx
->autoconfflg
= val
& ND_OPT_PI_FLAG_AUTO
;
351 makeentry(entbuf
, sizeof(entbuf
), i
, "vltime");
352 MAYHAVE(val64
, entbuf
, DEF_ADVVALIDLIFETIME
);
353 if (val64
< 0 || val64
> 0xffffffff) {
354 errorlog("<%s> vltime (%lld) for "
355 "%s/%d on %s is out of range",
356 __func__
, (long long)val64
,
357 addr
, pfx
->prefixlen
, intface
);
360 pfx
->validlifetime
= (u_int32_t
)val64
;
362 makeentry(entbuf
, sizeof(entbuf
), i
, "vltimedecr");
363 if (agetflag(entbuf
)) {
365 gettimeofday(&now
, 0);
367 now
.tv_sec
+ pfx
->validlifetime
;
370 makeentry(entbuf
, sizeof(entbuf
), i
, "pltime");
371 MAYHAVE(val64
, entbuf
, DEF_ADVPREFERREDLIFETIME
);
372 if (val64
< 0 || val64
> 0xffffffff) {
373 errorlog("<%s> pltime (%lld) for %s/%d on %s "
375 __func__
, (long long)val64
,
376 addr
, pfx
->prefixlen
, intface
);
379 pfx
->preflifetime
= (u_int32_t
)val64
;
381 makeentry(entbuf
, sizeof(entbuf
), i
, "pltimedecr");
382 if (agetflag(entbuf
)) {
384 gettimeofday(&now
, 0);
386 now
.tv_sec
+ pfx
->preflifetime
;
388 /* link into chain */
389 insque(pfx
, &rai
->prefix
);
395 MAYHAVE(val
, "mtu", 0);
396 if (val
< 0 || val
> 0xffffffff) {
397 errorlog("<%s> mtu (%ld) on %s out of range",
398 __func__
, val
, intface
);
401 rai
->linkmtu
= (u_int32_t
)val
;
402 if (rai
->linkmtu
== 0) {
405 if ((mtustr
= (char *)agetstr("mtu", &bp
)) &&
406 strcmp(mtustr
, "auto") == 0)
407 rai
->linkmtu
= rai
->phymtu
;
409 else if (rai
->linkmtu
< IPV6_MMTU
|| rai
->linkmtu
> rai
->phymtu
) {
410 errorlog("<%s> advertised link mtu (%lu) on %s is invalid (must "
411 "be between least MTU (%d) and physical link MTU (%d)",
412 __func__
, (unsigned long)rai
->linkmtu
, intface
,
413 IPV6_MMTU
, rai
->phymtu
);
417 #ifdef SIOCSIFINFO_IN6
419 struct in6_ndireq ndi
;
422 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
423 errorlog("<%s> socket: %s", __func__
,
427 memset(&ndi
, 0, sizeof(ndi
));
428 strlcpy(ndi
.ifname
, intface
, sizeof(ndi
.ifname
));
429 if (ioctl(s
, SIOCGIFINFO_IN6
, (caddr_t
)&ndi
) < 0) {
430 infolog("<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s",
431 __func__
, intface
, strerror(errno
));
434 /* reflect the RA info to the host variables in kernel */
435 ndi
.ndi
.chlim
= rai
->hoplimit
;
436 ndi
.ndi
.retrans
= rai
->retranstimer
;
437 ndi
.ndi
.basereachable
= rai
->reachabletime
;
438 if (ioctl(s
, SIOCSIFINFO_IN6
, (caddr_t
)&ndi
) < 0) {
439 infolog("<%s> ioctl:SIOCSIFINFO_IN6 at %s: %s",
440 __func__
, intface
, strerror(errno
));
446 /* route information */
449 for (i
= -1; i
< MAXROUTE
; i
++) {
451 char entbuf
[256], oentbuf
[256];
453 makeentry(entbuf
, sizeof(entbuf
), i
, "rtprefix");
454 addr
= (char *)agetstr(entbuf
, &bp
);
456 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrprefix");
457 addr
= (char *)agetstr(oentbuf
, &bp
);
459 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
466 /* allocate memory to store prefix information */
467 ELM_MALLOC(rti
, exit(1));
469 /* link into chain */
470 insque(rti
, &rai
->route
);
473 if (inet_pton(AF_INET6
, addr
, &rti
->prefix
) != 1) {
474 errorlog( "<%s> inet_pton failed for %s",
480 * XXX: currently there's no restriction in route information
481 * prefix according to
482 * draft-ietf-ipngwg-router-selection-00.txt.
483 * However, I think the similar restriction be necessary.
485 MAYHAVE(val64
, entbuf
, DEF_ADVVALIDLIFETIME
);
486 if (IN6_IS_ADDR_MULTICAST(&rti
->prefix
)) {
487 errorlog("<%s> multicast route (%s) must "
488 "not be advertised on %s",
489 __func__
, addr
, intface
);
492 if (IN6_IS_ADDR_LINKLOCAL(&rti
->prefix
)) {
493 noticelog("<%s> link-local route (%s) will "
494 "be advertised on %s",
495 __func__
, addr
, intface
);
500 makeentry(entbuf
, sizeof(entbuf
), i
, "rtplen");
501 /* XXX: 256 is a magic number for compatibility check. */
502 MAYHAVE(val
, entbuf
, 256);
504 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrplen");
505 MAYHAVE(val
, oentbuf
, 256);
507 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
512 if (val
< 0 || val
> 128) {
513 errorlog("<%s> prefixlen (%ld) for %s on %s "
515 __func__
, val
, addr
, intface
);
518 rti
->prefixlen
= (int)val
;
520 makeentry(entbuf
, sizeof(entbuf
), i
, "rtflags");
521 if ((flagstr
= (char *)agetstr(entbuf
, &bp
))) {
523 if (strchr(flagstr
, 'h'))
524 val
|= ND_RA_FLAG_RTPREF_HIGH
;
525 if (strchr(flagstr
, 'l')) {
526 if ((val
& ND_RA_FLAG_RTPREF_HIGH
)) {
528 "<%s> the \'h\' and \'l\' route"
529 " preferences are exclusive",
533 val
|= ND_RA_FLAG_RTPREF_LOW
;
536 MAYHAVE(val
, entbuf
, 256); /* XXX */
538 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrflags");
539 MAYHAVE(val
, oentbuf
, 256);
541 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
546 rti
->rtpref
= val
& ND_RA_FLAG_RTPREF_MASK
;
547 if (rti
->rtpref
== ND_RA_FLAG_RTPREF_RSV
) {
548 errorlog("<%s> invalid route preference (%02x) "
550 __func__
, rti
->rtpref
, addr
,
551 rti
->prefixlen
, intface
);
556 * Since the spec does not a default value, we should make
557 * this entry mandatory. However, FreeBSD 4.4 has shipped
558 * with this field being optional, we use the router lifetime
559 * as an ad-hoc default value with a warning message.
561 makeentry(entbuf
, sizeof(entbuf
), i
, "rtltime");
562 MAYHAVE(val64
, entbuf
, -1);
564 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrltime");
565 MAYHAVE(val64
, oentbuf
, -1);
567 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
570 fprintf(stderr
, "%s should be specified "
571 "for interface %s.\n",
573 val64
= rai
->lifetime
;
576 if (val64
< 0 || val64
> 0xffffffff) {
577 errorlog( "<%s> route lifetime (%lld) for "
578 "%s/%d on %s out of range", __func__
,
579 (long long)val64
, addr
, rti
->prefixlen
, intface
);
582 rti
->ltime
= (u_int32_t
)val64
;
586 /* RDNSS option (RFC5006) */
587 MAYHAVE(val
, "rdnsslifetime", 2 * rai
->maxinterval
);
588 if (val
< rai
->maxinterval
|| val
> (2 * rai
->maxinterval
)) {
589 noticelog("<%s> rdnsslifetime (%lu) on %s SHOULD "
590 "be between %u and %u", __func__
, val
,
591 intface
, rai
->maxinterval
, 2 * rai
->maxinterval
);
593 rai
->rdnss_lifetime
= val
;
594 if ((rdnss_length
= agetnum("rdnssaddrs")) < 0) {
595 rai
->rdnss_length
= 0;
598 rai
->rdnss_length
= rdnss_length
;
600 /* traverse in reverse order so that the queue has correct order */
601 for (i
= (rdnss_length
- 1); i
>= 0; i
--) {
605 /* allocate memory to store server address information */
606 ELM_MALLOC(rdnss
, exit(1));
607 /* link into chain */
608 insque(rdnss
, &rai
->rdnss_list
);
610 makeentry(entbuf
, sizeof(entbuf
), i
, "rdnssaddr");
611 addr
= (char *)agetstr(entbuf
, &bp
);
613 if (addr
== NULL
&& rdnss_length
== 1) {
614 makeentry(entbuf
, sizeof(entbuf
), -1, "rdnssaddr");
615 addr
= agetstr(entbuf
, &bp
);
619 errorlog("<%s> need %s as a DNS server address for "
621 __func__
, entbuf
, intface
);
625 if (inet_pton(AF_INET6
, addr
, &rdnss
->addr
) != 1) {
626 errorlog("<%s> inet_pton failed for %s",
630 if (IN6_IS_ADDR_MULTICAST(&rdnss
->addr
)) {
631 errorlog("<%s> multicast address (%s) must "
632 "not be advertised as recursive DNS server",
639 /* DNSSL option (RFC6106) */
641 /* Parse the DNSSL lifetime from the config */
642 MAYHAVE(val
, "dnssllifetime", 2 * rai
->maxinterval
);
643 if (val
< rai
->maxinterval
|| val
> (2 * rai
->maxinterval
)) {
644 noticelog("<%s> dnssllifetime (%lu) on %s SHOULD "
645 "be between %u and %u", __func__
, val
,
646 intface
, rai
->maxinterval
, 2 * rai
->maxinterval
);
648 rai
->dnssl_lifetime
= val
;
649 rai
->dnssl_option_length
= 8; /* 8 bytes for the option header */
651 /* Parse the DNSSL domain list from the config */
652 if ((dnssl_length
= agetnum("dnssldomains")) < 0) {
653 rai
->dnssl_length
= 0;
655 rai
->dnssl_length
= dnssl_length
;
657 for (i
= (rai
->dnssl_length
- 1); i
>= 0; i
--) {
658 unsigned char *dnssl_buf
;
661 char entbuf
[sizeof("dnssldomain") + 20];
665 makeentry(entbuf
, sizeof(entbuf
), i
, "dnssldomain");
666 domain
= agetstr(entbuf
, &bp
);
668 if (domain
== NULL
&& rai
->dnssl_length
== 1) {
669 makeentry(entbuf
, sizeof(entbuf
), -1, "dnssldomain");
670 domain
= agetstr(entbuf
, &bp
);
673 if (domain
== NULL
) {
674 errorlog("<%s> need %s as a DNS search domain for "
676 __func__
, entbuf
, intface
);
680 domain_len
= strlen(domain
);
682 /* Trim off leading dots */
683 while (domain_len
> 0 && domain
[0] == '.') {
688 /* Trim off trailing dots */
689 while (domain_len
> 0 && domain
[domain_len
-1] == '.') {
693 if (domain_len
> 0) {
694 dnssl_len
= sizeof(struct dnssl
) + domain_len
+ 1;
695 dnssl_buf
= (unsigned char *)malloc(dnssl_len
);
697 memset(dnssl_buf
, 0, dnssl_len
);
699 dnssl
= (struct dnssl
*)dnssl_buf
;
700 insque(dnssl
, &rai
->dnssl_list
);
702 /* Copy the domain name in at the end of the dnssl struct */
703 memcpy(dnssl_buf
+ offsetof(struct dnssl
, domain
), domain
,
706 /* Add 2 for leading length byte and the trailing 0 byte */
707 rai
->dnssl_option_length
+= domain_len
+ 2;
711 /* Round up to the next multiple of 8 */
712 rai
->dnssl_option_length
+= (8 - (rai
->dnssl_option_length
& 0x7));
716 capport
= agetstr("capport", &bp
);
717 if (capport
!= NULL
) {
718 rai
->capport
= strdup(capport
);
719 rai
->capport_length
= strlen(capport
);
720 rai
->capport_option_length
721 = sizeof(struct nd_opt_hdr
) + rai
->capport_length
;
722 rai
->capport_option_length
723 += (8 - (rai
->capport_option_length
& 0x7));
730 /* construct the sending packet */
734 rai
->timer
= rtadvd_add_timer(ra_timeout
, ra_timer_update
,
736 ra_timer_update((void *)rai
, &rai
->timer
->tm
);
737 rtadvd_set_timer(&rai
->timer
->tm
, rai
->timer
);
741 get_prefix(struct rainfo
*rai
)
743 struct ifaddrs
*ifap
, *ifa
;
746 u_char
*p
, *ep
, *m
, *lim
;
747 char ntopbuf
[INET6_ADDRSTRLEN
];
749 if (getifaddrs(&ifap
) < 0) {
751 "<%s> can't get interface addresses",
756 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
759 if (strcmp(ifa
->ifa_name
, rai
->ifname
) != 0)
761 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
)
763 a
= &((struct sockaddr_in6
*)ifa
->ifa_addr
)->sin6_addr
;
764 if (IN6_IS_ADDR_LINKLOCAL(a
))
766 /* get prefix length */
767 m
= (u_char
*)&((struct sockaddr_in6
*)ifa
->ifa_netmask
)->sin6_addr
;
768 lim
= (u_char
*)(ifa
->ifa_netmask
) + ifa
->ifa_netmask
->sa_len
;
769 plen
= prefixlen(m
, lim
);
770 if (plen
<= 0 || plen
> 128) {
771 errorlog( "<%s> failed to get prefixlen "
772 "or prefix is invalid",
776 if (plen
== 128) /* XXX */
778 if (find_prefix(rai
, a
, plen
)) {
779 /* ignore a duplicated prefix. */
783 /* allocate memory to store prefix info. */
784 ELM_MALLOC(pfx
, exit(1));
785 /* set prefix, sweep bits outside of prefixlen */
786 pfx
->prefixlen
= plen
;
787 memcpy(&pfx
->prefix
, a
, sizeof(*a
));
788 p
= (u_char
*)&pfx
->prefix
;
789 ep
= (u_char
*)(&pfx
->prefix
+ 1);
790 while (m
< lim
&& p
< ep
)
794 if (!inet_ntop(AF_INET6
, &pfx
->prefix
, ntopbuf
,
796 errorlog("<%s> inet_ntop failed", __func__
);
799 debuglog("<%s> add %s/%d to prefix list on %s",
800 __func__
, ntopbuf
, pfx
->prefixlen
, rai
->ifname
);
802 /* set other fields with protocol defaults */
803 pfx
->validlifetime
= DEF_ADVVALIDLIFETIME
;
804 pfx
->preflifetime
= DEF_ADVPREFERREDLIFETIME
;
806 pfx
->autoconfflg
= 1;
807 pfx
->origin
= PREFIX_FROM_KERNEL
;
810 /* link into chain */
811 insque(pfx
, &rai
->prefix
);
813 /* counter increment */
821 makeentry(buf
, len
, id
, string
)
829 strlcpy(buf
, string
, len
);
831 snprintf(buf
, len
, "%s%d", string
, id
);
835 * Add a prefix to the list of specified interface and reconstruct
836 * the outgoing packet.
837 * The prefix must not be in the list.
838 * XXX: other parameters of the prefix (e.g. lifetime) should be
839 * able to be specified.
842 add_prefix(struct rainfo
*rai
, struct in6_prefixreq
*ipr
)
844 struct prefix
*prefix
;
845 char ntopbuf
[INET6_ADDRSTRLEN
];
847 ELM_MALLOC(prefix
, exit(1));
848 prefix
->prefix
= ipr
->ipr_prefix
.sin6_addr
;
849 prefix
->prefixlen
= ipr
->ipr_plen
;
850 prefix
->validlifetime
= ipr
->ipr_vltime
;
851 prefix
->preflifetime
= ipr
->ipr_pltime
;
852 prefix
->onlinkflg
= ipr
->ipr_raf_onlink
;
853 prefix
->autoconfflg
= ipr
->ipr_raf_auto
;
854 prefix
->origin
= PREFIX_FROM_DYNAMIC
;
855 prefix
->rainfo
= rai
;
857 insque(prefix
, &rai
->prefix
);
859 debuglog("<%s> new prefix %s/%d was added on %s",
860 __func__
, inet_ntop(AF_INET6
, &ipr
->ipr_prefix
.sin6_addr
,
861 ntopbuf
, INET6_ADDRSTRLEN
),
862 ipr
->ipr_plen
, rai
->ifname
);
864 /* free the previous packet */
868 /* reconstruct the packet */
874 * Delete a prefix to the list of specified interface and reconstruct
875 * the outgoing packet.
876 * The prefix must be in the list.
879 delete_prefix(struct prefix
*prefix
)
881 char ntopbuf
[INET6_ADDRSTRLEN
];
882 struct rainfo
*rai
= prefix
->rainfo
;
885 debuglog("<%s> prefix %s/%d was deleted on %s",
886 __func__
, inet_ntop(AF_INET6
, &prefix
->prefix
,
887 ntopbuf
, INET6_ADDRSTRLEN
),
888 prefix
->prefixlen
, rai
->ifname
);
890 rtadvd_remove_timer(&prefix
->timer
);
896 invalidate_prefix(struct prefix
*prefix
)
898 char ntopbuf
[INET6_ADDRSTRLEN
];
900 struct rainfo
*rai
= prefix
->rainfo
;
902 if (prefix
->timer
) { /* sanity check */
903 errorlog("<%s> assumption failure: timer already exists",
908 debuglog("<%s> prefix %s/%d was invalidated on %s, "
909 "will expire in %ld seconds", __func__
,
910 inet_ntop(AF_INET6
, &prefix
->prefix
, ntopbuf
, INET6_ADDRSTRLEN
),
911 prefix
->prefixlen
, rai
->ifname
, (long)prefix_timo
);
913 /* set the expiration timer */
914 prefix
->timer
= rtadvd_add_timer(prefix_timeout
, NULL
, prefix
, NULL
);
915 if (prefix
->timer
== NULL
) {
916 errorlog("<%s> failed to add a timer for a prefix. "
917 "remove the prefix", __func__
);
918 delete_prefix(prefix
);
921 timo
.tv_sec
= prefix_timo
;
923 rtadvd_set_timer(&timo
, prefix
->timer
);
926 static struct rtadvd_timer
*
927 prefix_timeout(void *arg
)
929 struct prefix
*prefix
= (struct prefix
*)arg
;
931 delete_prefix(prefix
);
937 update_prefix(struct prefix
* prefix
)
939 char ntopbuf
[INET6_ADDRSTRLEN
];
940 struct rainfo
*rai
= prefix
->rainfo
;
942 if (prefix
->timer
== NULL
) { /* sanity check */
943 errorlog("<%s> assumption failure: timer does not exist",
948 debuglog("<%s> prefix %s/%d was re-enabled on %s",
949 __func__
, inet_ntop(AF_INET6
, &prefix
->prefix
, ntopbuf
,
950 INET6_ADDRSTRLEN
), prefix
->prefixlen
, rai
->ifname
);
952 /* stop the expiration timer */
953 rtadvd_remove_timer(&prefix
->timer
);
957 * Try to get an in6_prefixreq contents for a prefix which matches
958 * ipr->ipr_prefix and ipr->ipr_plen and belongs to
959 * the interface whose name is ipr->ipr_name[].
962 init_prefix(struct in6_prefixreq
*ipr
)
967 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
968 errorlog("<%s> socket: %s", __func__
,
973 if (ioctl(s
, SIOCGIFPREFIX_IN6
, (caddr_t
)ipr
) < 0) {
974 infolog("<%s> ioctl:SIOCGIFPREFIX %s", __func__
,
977 ipr
->ipr_vltime
= DEF_ADVVALIDLIFETIME
;
978 ipr
->ipr_pltime
= DEF_ADVPREFERREDLIFETIME
;
979 ipr
->ipr_raf_onlink
= 1;
980 ipr
->ipr_raf_auto
= 1;
981 /* omit other field initialization */
983 else if (ipr
->ipr_origin
< PR_ORIG_RR
) {
984 char ntopbuf
[INET6_ADDRSTRLEN
];
986 noticelog("<%s> Added prefix(%s)'s origin %d is"
987 "lower than PR_ORIG_RR(router renumbering)."
988 "This should not happen if I am router", __func__
,
989 inet_ntop(AF_INET6
, &ipr
->ipr_prefix
.sin6_addr
, ntopbuf
,
990 sizeof(ntopbuf
)), ipr
->ipr_origin
);
998 ipr
->ipr_vltime
= DEF_ADVVALIDLIFETIME
;
999 ipr
->ipr_pltime
= DEF_ADVPREFERREDLIFETIME
;
1000 ipr
->ipr_raf_onlink
= 1;
1001 ipr
->ipr_raf_auto
= 1;
1007 make_prefix(struct rainfo
*rai
, int ifindex
, struct in6_addr
*addr
, int plen
)
1009 struct in6_prefixreq ipr
;
1011 memset(&ipr
, 0, sizeof(ipr
));
1012 if (if_indextoname(ifindex
, ipr
.ipr_name
) == NULL
) {
1013 errorlog("<%s> Prefix added interface No.%d doesn't"
1014 "exist. This should not happen! %s", __func__
,
1015 ifindex
, strerror(errno
));
1018 ipr
.ipr_prefix
.sin6_len
= sizeof(ipr
.ipr_prefix
);
1019 ipr
.ipr_prefix
.sin6_family
= AF_INET6
;
1020 ipr
.ipr_prefix
.sin6_addr
= *addr
;
1021 ipr
.ipr_plen
= plen
;
1023 if (init_prefix(&ipr
))
1024 return; /* init failed by some error */
1025 add_prefix(rai
, &ipr
);
1029 make_packet(struct rainfo
*rainfo
)
1031 size_t packlen
, lladdroptlen
= 0;
1033 struct nd_router_advert
*ra
;
1034 struct nd_opt_prefix_info
*ndopt_pi
;
1035 struct nd_opt_mtu
*ndopt_mtu
;
1037 struct nd_opt_route_info
*ndopt_rti
;
1042 /* calculate total length */
1043 packlen
= sizeof(struct nd_router_advert
);
1044 if (rainfo
->advlinkopt
) {
1045 if ((lladdroptlen
= lladdropt_length(rainfo
->sdl
)) == 0) {
1046 infolog("<%s> link-layer address option has"
1047 " null length on %s. Treat as not included.",
1048 __func__
, rainfo
->ifname
);
1049 rainfo
->advlinkopt
= 0;
1051 packlen
+= lladdroptlen
;
1054 packlen
+= sizeof(struct nd_opt_prefix_info
) * rainfo
->pfxs
;
1055 if (rainfo
->linkmtu
)
1056 packlen
+= sizeof(struct nd_opt_mtu
);
1058 for (rti
= rainfo
->route
.next
; rti
!= &rainfo
->route
; rti
= rti
->next
)
1059 packlen
+= sizeof(struct nd_opt_route_info
) +
1060 ((rti
->prefixlen
+ 0x3f) >> 6) * 8;
1062 if (rainfo
->rdnss_length
> 0)
1063 packlen
+= 8 + sizeof(struct in6_addr
) * rainfo
->rdnss_length
;
1065 if (rainfo
->dnssl_length
> 0) {
1066 packlen
+= rainfo
->dnssl_option_length
;
1068 if (rainfo
->capport_option_length
!= 0) {
1069 packlen
+= rainfo
->capport_option_length
;
1072 /* allocate memory for the packet */
1073 if ((buf
= malloc(packlen
)) == NULL
) {
1074 errorlog("<%s> can't get enough memory for an RA packet",
1078 if (rainfo
->ra_data
) {
1079 /* free the previous packet */
1080 free(rainfo
->ra_data
);
1081 rainfo
->ra_data
= NULL
;
1083 rainfo
->ra_data
= buf
;
1084 /* XXX: what if packlen > 576? */
1085 rainfo
->ra_datalen
= packlen
;
1088 * construct the packet
1090 ra
= (struct nd_router_advert
*)buf
;
1091 ra
->nd_ra_type
= ND_ROUTER_ADVERT
;
1093 ra
->nd_ra_cksum
= 0;
1094 ra
->nd_ra_curhoplimit
= (u_int8_t
)(0xff & rainfo
->hoplimit
);
1095 ra
->nd_ra_flags_reserved
= 0; /* just in case */
1097 * XXX: the router preference field, which is a 2-bit field, should be
1098 * initialized before other fields.
1100 ra
->nd_ra_flags_reserved
= 0xff & rainfo
->rtpref
;
1101 ra
->nd_ra_flags_reserved
|=
1102 rainfo
->managedflg
? ND_RA_FLAG_MANAGED
: 0;
1103 ra
->nd_ra_flags_reserved
|=
1104 rainfo
->otherflg
? ND_RA_FLAG_OTHER
: 0;
1105 ra
->nd_ra_router_lifetime
= htons(rainfo
->lifetime
);
1106 ra
->nd_ra_reachable
= htonl(rainfo
->reachabletime
);
1107 ra
->nd_ra_retransmit
= htonl(rainfo
->retranstimer
);
1110 if (rainfo
->advlinkopt
) {
1111 lladdropt_fill(rainfo
->sdl
, (struct nd_opt_hdr
*)buf
);
1112 buf
+= lladdroptlen
;
1115 if (rainfo
->linkmtu
) {
1116 ndopt_mtu
= (struct nd_opt_mtu
*)buf
;
1117 ndopt_mtu
->nd_opt_mtu_type
= ND_OPT_MTU
;
1118 ndopt_mtu
->nd_opt_mtu_len
= 1;
1119 ndopt_mtu
->nd_opt_mtu_reserved
= 0;
1120 ndopt_mtu
->nd_opt_mtu_mtu
= htonl(rainfo
->linkmtu
);
1121 buf
+= sizeof(struct nd_opt_mtu
);
1124 for (pfx
= rainfo
->prefix
.next
;
1125 pfx
!= &rainfo
->prefix
; pfx
= pfx
->next
) {
1126 u_int32_t vltime
, pltime
;
1129 ndopt_pi
= (struct nd_opt_prefix_info
*)buf
;
1130 ndopt_pi
->nd_opt_pi_type
= ND_OPT_PREFIX_INFORMATION
;
1131 ndopt_pi
->nd_opt_pi_len
= 4;
1132 ndopt_pi
->nd_opt_pi_prefix_len
= pfx
->prefixlen
;
1133 ndopt_pi
->nd_opt_pi_flags_reserved
= 0;
1135 ndopt_pi
->nd_opt_pi_flags_reserved
|=
1136 ND_OPT_PI_FLAG_ONLINK
;
1137 if (pfx
->autoconfflg
)
1138 ndopt_pi
->nd_opt_pi_flags_reserved
|=
1139 ND_OPT_PI_FLAG_AUTO
;
1143 if (pfx
->vltimeexpire
|| pfx
->pltimeexpire
)
1144 gettimeofday(&now
, NULL
);
1145 if (pfx
->vltimeexpire
== 0)
1146 vltime
= pfx
->validlifetime
;
1148 vltime
= (pfx
->vltimeexpire
> now
.tv_sec
) ?
1149 pfx
->vltimeexpire
- now
.tv_sec
: 0;
1154 if (pfx
->pltimeexpire
== 0)
1155 pltime
= pfx
->preflifetime
;
1157 pltime
= (pfx
->pltimeexpire
> now
.tv_sec
) ?
1158 pfx
->pltimeexpire
- now
.tv_sec
: 0;
1160 if (vltime
< pltime
) {
1162 * this can happen if vltime is decrement but pltime
1167 ndopt_pi
->nd_opt_pi_valid_time
= htonl(vltime
);
1168 ndopt_pi
->nd_opt_pi_preferred_time
= htonl(pltime
);
1169 ndopt_pi
->nd_opt_pi_reserved2
= 0;
1170 ndopt_pi
->nd_opt_pi_prefix
= pfx
->prefix
;
1172 buf
+= sizeof(struct nd_opt_prefix_info
);
1176 for (rti
= rainfo
->route
.next
; rti
!= &rainfo
->route
; rti
= rti
->next
) {
1177 u_int8_t psize
= (rti
->prefixlen
+ 0x3f) >> 6;
1179 ndopt_rti
= (struct nd_opt_route_info
*)buf
;
1180 ndopt_rti
->nd_opt_rti_type
= ND_OPT_ROUTE_INFO
;
1181 ndopt_rti
->nd_opt_rti_len
= 1 + psize
;
1182 ndopt_rti
->nd_opt_rti_prefixlen
= rti
->prefixlen
;
1183 ndopt_rti
->nd_opt_rti_flags
= 0xff & rti
->rtpref
;
1184 ndopt_rti
->nd_opt_rti_lifetime
= htonl(rti
->ltime
);
1185 memcpy(ndopt_rti
+ 1, &rti
->prefix
, psize
* 8);
1186 buf
+= sizeof(struct nd_opt_route_info
) + psize
* 8;
1190 if (rainfo
->rdnss_length
> 0) {
1191 struct nd_opt_rdnss
* ndopt_rdnss
;
1192 struct rdnss
* rdnss
;
1194 ndopt_rdnss
= (struct nd_opt_rdnss
*) buf
;
1195 ndopt_rdnss
->nd_opt_rdnss_type
= ND_OPT_RDNSS
;
1196 ndopt_rdnss
->nd_opt_rdnss_len
= 1 + (rainfo
->rdnss_length
* 2);
1197 ndopt_rdnss
->nd_opt_rdnss_reserved
= 0;
1198 ndopt_rdnss
->nd_opt_rdnss_lifetime
= htonl(rainfo
->rdnss_lifetime
);
1201 for (rdnss
= rainfo
->rdnss_list
.next
;
1202 rdnss
!= &rainfo
->rdnss_list
;
1203 rdnss
= rdnss
->next
)
1205 struct in6_addr
* addr6
= (struct in6_addr
*) buf
;
1206 *addr6
= rdnss
->addr
;
1207 buf
+= sizeof *addr6
;
1211 if (rainfo
->dnssl_length
> 0) {
1212 struct nd_opt_dnssl
* dnssl_opt
;
1213 struct dnssl
* dnssl
;
1214 int domains_length
= 0;
1215 u_char
* cursor
= buf
;
1217 memset(cursor
, 0, rainfo
->dnssl_option_length
);
1219 dnssl_opt
= (struct nd_opt_dnssl
*)cursor
;
1220 dnssl_opt
->nd_opt_dnssl_type
= ND_OPT_DNSSL
;
1222 * Length is in units of 8 octets. Divide total byte length
1223 * of the option by 8.
1225 dnssl_opt
->nd_opt_dnssl_len
= rainfo
->dnssl_option_length
>> 3;
1226 dnssl_opt
->nd_opt_dnssl_reserved
= 0;
1227 dnssl_opt
->nd_opt_dnssl_lifetime
=
1228 htonl(rainfo
->dnssl_lifetime
);
1230 cursor
+= offsetof(struct nd_opt_dnssl
, nd_opt_dnssl_domains
);
1232 for (dnssl
= rainfo
->dnssl_list
.next
;
1233 dnssl
!= &rainfo
->dnssl_list
;
1234 dnssl
= dnssl
->next
)
1236 int encodeLen
= encode_domain(dnssl
->domain
, cursor
);
1237 cursor
+= encodeLen
;
1238 domains_length
+= encodeLen
;
1241 buf
+= rainfo
->dnssl_option_length
;
1243 if (rainfo
->capport
!= NULL
) {
1244 struct nd_opt_hdr
* capport_opt
;
1245 u_int32_t zero_space
;
1247 capport_opt
= (struct nd_opt_hdr
*)buf
;
1248 #ifndef ND_OPT_CAPTIVE_PORTAL
1249 #define ND_OPT_CAPTIVE_PORTAL 37 /* RFC 7710 */
1250 #endif /* ND_OPT_CAPTIVE_PORTAL */
1251 capport_opt
->nd_opt_type
= ND_OPT_CAPTIVE_PORTAL
;
1252 capport_opt
->nd_opt_len
= rainfo
->capport_option_length
>> 3;
1253 buf
+= sizeof(*capport_opt
);
1254 bcopy(rainfo
->capport
, buf
, rainfo
->capport_length
);
1255 buf
+= rainfo
->capport_length
;
1256 zero_space
= rainfo
->capport_option_length
1257 - rainfo
->capport_length
;
1258 if (zero_space
> 0) {
1259 bzero(buf
, zero_space
);
1267 getinet6sysctl(int code
)
1269 int mib
[] = { CTL_NET
, PF_INET6
, IPPROTO_IPV6
, 0 };
1274 size
= sizeof(value
);
1275 if (sysctl(mib
, sizeof(mib
)/sizeof(mib
[0]), &value
, &size
, NULL
, 0)
1277 errorlog( "<%s>: failed to get ip6 sysctl(%d): %s",
1287 * Encode a domain name into a buffer according to the rules in RFC 1035 section
1288 * 3.1. Do not use the compression techniques outlined in section 4.1.4.
1291 encode_domain(char *domain
, u_char
*dst
)
1293 char *domainCopy
= strdup(domain
);
1294 char *input
= domainCopy
;
1296 u_char
*cursor
= dst
;
1298 while ((label
= strsep(&input
, ".")) != NULL
) {
1299 int label_len
= strlen(label
) & 0x3f; /* Max length is 63 */
1300 if (label_len
> 0) {
1301 *cursor
= (u_char
)label_len
;
1303 memcpy(cursor
, label
, label_len
);
1304 cursor
+= label_len
;
1312 return (cursor
- dst
);