2 * Copyright (c) 2009-2017 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
;
119 static int forwarding
= -1;
121 #define MUSTHAVE(var, cap) \
124 if ((t = agetnum(cap)) < 0) { \
125 fprintf(stderr, "rtadvd: need %s for interface %s\n", \
131 #define MAYHAVE(var, cap, def) \
133 if ((var = agetnum(cap)) < 0) \
137 if ((stat
= agetent(tbuf
, intface
)) <= 0) {
138 memset(tbuf
, 0, sizeof(tbuf
));
139 errorlog("<%s> %s isn't defined in the configuration file"
140 " or the configuration file doesn't exist."
141 " Treat it as default",
145 ELM_MALLOC(rai
, exit(1));
146 rai
->prefix
.next
= rai
->prefix
.prev
= &rai
->prefix
;
148 rai
->route
.next
= rai
->route
.prev
= &rai
->route
;
150 rai
->rdnss_list
.next
= rai
->rdnss_list
.prev
= &rai
->rdnss_list
;
151 rai
->dnssl_list
.next
= rai
->dnssl_list
.prev
= &rai
->dnssl_list
;
153 /* check if we are allowed to forward packets (if not determined) */
154 if (forwarding
< 0) {
155 if ((forwarding
= getinet6sysctl(IPV6CTL_FORWARDING
)) < 0)
159 /* get interface information */
160 if (agetflag("nolladdr"))
164 if (rai
->advlinkopt
) {
165 if ((rai
->sdl
= if_nametosdl(intface
)) == NULL
) {
166 errorlog("<%s> can't get information of %s",
170 rai
->ifindex
= rai
->sdl
->sdl_index
;
172 rai
->ifindex
= if_nametoindex(intface
);
173 strlcpy(rai
->ifname
, intface
, sizeof(rai
->ifname
));
174 if ((rai
->phymtu
= if_getmtu(intface
)) == 0) {
175 rai
->phymtu
= IPV6_MMTU
;
176 errorlog("<%s> can't get interface mtu of %s. Treat as %d",
177 __func__
, intface
, IPV6_MMTU
);
181 * set router configuration variables.
183 MAYHAVE(val
, "maxinterval", DEF_MAXRTRADVINTERVAL
);
184 if (val
< MIN_MAXINTERVAL
|| val
> MAX_MAXINTERVAL
) {
185 errorlog("<%s> maxinterval (%ld) on %s is invalid "
186 "(must be between %u and %u)", __func__
, val
,
187 intface
, MIN_MAXINTERVAL
, MAX_MAXINTERVAL
);
190 rai
->maxinterval
= (u_int
)val
;
191 MAYHAVE(val
, "mininterval", rai
->maxinterval
/3);
192 if (val
< MIN_MININTERVAL
|| val
> (rai
->maxinterval
* 3) / 4) {
193 errorlog("<%s> mininterval (%ld) on %s is invalid "
194 "(must be between %d and %d)",
195 __func__
, val
, intface
, MIN_MININTERVAL
,
196 (rai
->maxinterval
* 3) / 4);
199 rai
->mininterval
= (u_int
)val
;
201 MAYHAVE(val
, "chlim", DEF_ADVCURHOPLIMIT
);
202 rai
->hoplimit
= val
& 0xff;
204 if ((flagstr
= (char *)agetstr("raflags", &bp
))) {
206 if (strchr(flagstr
, 'm'))
207 val
|= ND_RA_FLAG_MANAGED
;
208 if (strchr(flagstr
, 'o'))
209 val
|= ND_RA_FLAG_OTHER
;
210 if (strchr(flagstr
, 'h'))
211 val
|= ND_RA_FLAG_RTPREF_HIGH
;
212 if (strchr(flagstr
, 'l')) {
213 if ((val
& ND_RA_FLAG_RTPREF_HIGH
)) {
214 errorlog("<%s> the \'h\' and \'l\'"
215 " router flags are exclusive", __func__
);
218 val
|= ND_RA_FLAG_RTPREF_LOW
;
221 MAYHAVE(val
, "raflags", 0);
223 rai
->managedflg
= val
& ND_RA_FLAG_MANAGED
;
224 rai
->otherflg
= val
& ND_RA_FLAG_OTHER
;
225 #ifndef ND_RA_FLAG_RTPREF_MASK
226 #define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
227 #define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */
229 rai
->rtpref
= val
& ND_RA_FLAG_RTPREF_MASK
;
230 if (rai
->rtpref
== ND_RA_FLAG_RTPREF_RSV
) {
231 errorlog("<%s> invalid router preference (%02x) on %s",
232 __func__
, rai
->rtpref
, intface
);
236 MAYHAVE(val
, "rltime", rai
->maxinterval
* 3);
237 if (val
&& (val
< rai
->maxinterval
|| val
> MAXROUTERLIFETIME
)) {
238 errorlog("<%s> router lifetime (%ld) on %s is invalid "
239 "(must be 0 or between %d and %d)",
240 __func__
, val
, intface
,
246 * Basically, hosts MUST NOT send Router Advertisement messages at any
247 * time (RFC 2461, Section 6.2.3). However, it would sometimes be
248 * useful to allow hosts to advertise some parameters such as prefix
249 * information and link MTU. Thus, we allow hosts to invoke rtadvd
250 * only when router lifetime (on every advertising interface) is
251 * explicitly set zero. (see also the above section)
253 if (val
&& forwarding
== 0) {
254 errorlog("<%s> non zero router lifetime is specified for %s, "
255 "which must not be allowed for hosts. you must "
256 "change router lifetime or enable IPv6 forwarding.",
260 rai
->lifetime
= val
& 0xffff;
262 MAYHAVE(val
, "rtime", DEF_ADVREACHABLETIME
);
263 if (val
< 0 || val
> MAXREACHABLETIME
) {
264 errorlog("<%s> reachable time (%ld) on %s is invalid "
265 "(must be no greater than %d)",
266 __func__
, val
, intface
, MAXREACHABLETIME
);
269 rai
->reachabletime
= (u_int32_t
)val
;
271 MAYHAVE(val64
, "retrans", DEF_ADVRETRANSTIMER
);
272 if (val64
< 0 || val64
> 0xffffffff) {
273 errorlog("<%s> retrans time (%lld) on %s out of range",
274 __func__
, (long long)val64
, intface
);
277 rai
->retranstimer
= (u_int32_t
)val64
;
279 if (agetnum("hapref") != -1 || agetnum("hatime") != -1) {
280 errorlog("<%s> mobile-ip6 configuration not supported",
284 /* prefix information */
287 * This is an implementation specific parameter to consider
288 * link propagation delays and poorly synchronized clocks when
289 * checking consistency of advertised lifetimes.
291 MAYHAVE(val
, "clockskew", 0);
292 rai
->clockskew
= val
;
295 for (i
= -1; i
< MAXPREFIX
; i
++) {
299 makeentry(entbuf
, sizeof(entbuf
), i
, "addr");
300 addr
= (char *)agetstr(entbuf
, &bp
);
304 /* allocate memory to store prefix information */
305 ELM_MALLOC(pfx
, exit(1));
308 pfx
->origin
= PREFIX_FROM_CONFIG
;
310 if (inet_pton(AF_INET6
, addr
, &pfx
->prefix
) != 1) {
311 errorlog("<%s> inet_pton failed for %s",
315 if (IN6_IS_ADDR_MULTICAST(&pfx
->prefix
)) {
316 errorlog("<%s> multicast prefix (%s) must "
317 "not be advertised on %s",
318 __func__
, addr
, intface
);
321 if (IN6_IS_ADDR_LINKLOCAL(&pfx
->prefix
))
322 noticelog("<%s> link-local prefix (%s) will be"
324 __func__
, addr
, intface
);
326 makeentry(entbuf
, sizeof(entbuf
), i
, "prefixlen");
327 MAYHAVE(val
, entbuf
, 64);
328 if (val
< 0 || val
> 128) {
329 errorlog("<%s> prefixlen (%ld) for %s "
330 "on %s out of range",
331 __func__
, val
, addr
, intface
);
334 pfx
->prefixlen
= (int)val
;
336 makeentry(entbuf
, sizeof(entbuf
), i
, "pinfoflags");
337 if ((flagstr
= (char *)agetstr(entbuf
, &bp
))) {
339 if (strchr(flagstr
, 'l'))
340 val
|= ND_OPT_PI_FLAG_ONLINK
;
341 if (strchr(flagstr
, 'a'))
342 val
|= ND_OPT_PI_FLAG_AUTO
;
345 (ND_OPT_PI_FLAG_ONLINK
|ND_OPT_PI_FLAG_AUTO
));
347 pfx
->onlinkflg
= val
& ND_OPT_PI_FLAG_ONLINK
;
348 pfx
->autoconfflg
= val
& ND_OPT_PI_FLAG_AUTO
;
350 makeentry(entbuf
, sizeof(entbuf
), i
, "vltime");
351 MAYHAVE(val64
, entbuf
, DEF_ADVVALIDLIFETIME
);
352 if (val64
< 0 || val64
> 0xffffffff) {
353 errorlog("<%s> vltime (%lld) for "
354 "%s/%d on %s is out of range",
355 __func__
, (long long)val64
,
356 addr
, pfx
->prefixlen
, intface
);
359 pfx
->validlifetime
= (u_int32_t
)val64
;
361 makeentry(entbuf
, sizeof(entbuf
), i
, "vltimedecr");
362 if (agetflag(entbuf
)) {
364 gettimeofday(&now
, 0);
366 now
.tv_sec
+ pfx
->validlifetime
;
369 makeentry(entbuf
, sizeof(entbuf
), i
, "pltime");
370 MAYHAVE(val64
, entbuf
, DEF_ADVPREFERREDLIFETIME
);
371 if (val64
< 0 || val64
> 0xffffffff) {
372 errorlog("<%s> pltime (%lld) for %s/%d on %s "
374 __func__
, (long long)val64
,
375 addr
, pfx
->prefixlen
, intface
);
378 pfx
->preflifetime
= (u_int32_t
)val64
;
380 makeentry(entbuf
, sizeof(entbuf
), i
, "pltimedecr");
381 if (agetflag(entbuf
)) {
383 gettimeofday(&now
, 0);
385 now
.tv_sec
+ pfx
->preflifetime
;
387 /* link into chain */
388 insque(pfx
, &rai
->prefix
);
394 MAYHAVE(val
, "mtu", 0);
395 if (val
< 0 || val
> 0xffffffff) {
396 errorlog("<%s> mtu (%ld) on %s out of range",
397 __func__
, val
, intface
);
400 rai
->linkmtu
= (u_int32_t
)val
;
401 if (rai
->linkmtu
== 0) {
404 if ((mtustr
= (char *)agetstr("mtu", &bp
)) &&
405 strcmp(mtustr
, "auto") == 0)
406 rai
->linkmtu
= rai
->phymtu
;
408 else if (rai
->linkmtu
< IPV6_MMTU
|| rai
->linkmtu
> rai
->phymtu
) {
409 errorlog("<%s> advertised link mtu (%lu) on %s is invalid (must "
410 "be between least MTU (%d) and physical link MTU (%d)",
411 __func__
, (unsigned long)rai
->linkmtu
, intface
,
412 IPV6_MMTU
, rai
->phymtu
);
416 #ifdef SIOCSIFINFO_IN6
418 struct in6_ndireq ndi
;
421 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
422 errorlog("<%s> socket: %s", __func__
,
426 memset(&ndi
, 0, sizeof(ndi
));
427 strlcpy(ndi
.ifname
, intface
, sizeof(ndi
.ifname
));
428 if (ioctl(s
, SIOCGIFINFO_IN6
, (caddr_t
)&ndi
) < 0) {
429 infolog("<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s",
430 __func__
, intface
, strerror(errno
));
433 /* reflect the RA info to the host variables in kernel */
434 ndi
.ndi
.chlim
= rai
->hoplimit
;
435 ndi
.ndi
.retrans
= rai
->retranstimer
;
436 ndi
.ndi
.basereachable
= rai
->reachabletime
;
437 if (ioctl(s
, SIOCSIFINFO_IN6
, (caddr_t
)&ndi
) < 0) {
438 infolog("<%s> ioctl:SIOCSIFINFO_IN6 at %s: %s",
439 __func__
, intface
, strerror(errno
));
445 /* route information */
448 for (i
= -1; i
< MAXROUTE
; i
++) {
450 char entbuf
[256], oentbuf
[256];
452 makeentry(entbuf
, sizeof(entbuf
), i
, "rtprefix");
453 addr
= (char *)agetstr(entbuf
, &bp
);
455 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrprefix");
456 addr
= (char *)agetstr(oentbuf
, &bp
);
458 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
465 /* allocate memory to store prefix information */
466 ELM_MALLOC(rti
, exit(1));
468 /* link into chain */
469 insque(rti
, &rai
->route
);
472 if (inet_pton(AF_INET6
, addr
, &rti
->prefix
) != 1) {
473 errorlog( "<%s> inet_pton failed for %s",
479 * XXX: currently there's no restriction in route information
480 * prefix according to
481 * draft-ietf-ipngwg-router-selection-00.txt.
482 * However, I think the similar restriction be necessary.
484 MAYHAVE(val64
, entbuf
, DEF_ADVVALIDLIFETIME
);
485 if (IN6_IS_ADDR_MULTICAST(&rti
->prefix
)) {
486 errorlog("<%s> multicast route (%s) must "
487 "not be advertised on %s",
488 __func__
, addr
, intface
);
491 if (IN6_IS_ADDR_LINKLOCAL(&rti
->prefix
)) {
492 noticelog("<%s> link-local route (%s) will "
493 "be advertised on %s",
494 __func__
, addr
, intface
);
499 makeentry(entbuf
, sizeof(entbuf
), i
, "rtplen");
500 /* XXX: 256 is a magic number for compatibility check. */
501 MAYHAVE(val
, entbuf
, 256);
503 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrplen");
504 MAYHAVE(val
, oentbuf
, 256);
506 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
511 if (val
< 0 || val
> 128) {
512 errorlog("<%s> prefixlen (%ld) for %s on %s "
514 __func__
, val
, addr
, intface
);
517 rti
->prefixlen
= (int)val
;
519 makeentry(entbuf
, sizeof(entbuf
), i
, "rtflags");
520 if ((flagstr
= (char *)agetstr(entbuf
, &bp
))) {
522 if (strchr(flagstr
, 'h'))
523 val
|= ND_RA_FLAG_RTPREF_HIGH
;
524 if (strchr(flagstr
, 'l')) {
525 if ((val
& ND_RA_FLAG_RTPREF_HIGH
)) {
527 "<%s> the \'h\' and \'l\' route"
528 " preferences are exclusive",
532 val
|= ND_RA_FLAG_RTPREF_LOW
;
535 MAYHAVE(val
, entbuf
, 256); /* XXX */
537 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrflags");
538 MAYHAVE(val
, oentbuf
, 256);
540 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
545 rti
->rtpref
= val
& ND_RA_FLAG_RTPREF_MASK
;
546 if (rti
->rtpref
== ND_RA_FLAG_RTPREF_RSV
) {
547 errorlog("<%s> invalid route preference (%02x) "
549 __func__
, rti
->rtpref
, addr
,
550 rti
->prefixlen
, intface
);
555 * Since the spec does not a default value, we should make
556 * this entry mandatory. However, FreeBSD 4.4 has shipped
557 * with this field being optional, we use the router lifetime
558 * as an ad-hoc default value with a warning message.
560 makeentry(entbuf
, sizeof(entbuf
), i
, "rtltime");
561 MAYHAVE(val64
, entbuf
, -1);
563 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrltime");
564 MAYHAVE(val64
, oentbuf
, -1);
566 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
569 fprintf(stderr
, "%s should be specified "
570 "for interface %s.\n",
572 val64
= rai
->lifetime
;
575 if (val64
< 0 || val64
> 0xffffffff) {
576 errorlog( "<%s> route lifetime (%lld) for "
577 "%s/%d on %s out of range", __func__
,
578 (long long)val64
, addr
, rti
->prefixlen
, intface
);
581 rti
->ltime
= (u_int32_t
)val64
;
585 /* RDNSS option (RFC5006) */
586 MAYHAVE(val
, "rdnsslifetime", 2 * rai
->maxinterval
);
587 if (val
< rai
->maxinterval
|| val
> (2 * rai
->maxinterval
)) {
588 noticelog("<%s> rdnsslifetime (%lu) on %s SHOULD "
589 "be between %u and %u", __func__
, val
,
590 intface
, rai
->maxinterval
, 2 * rai
->maxinterval
);
592 rai
->rdnss_lifetime
= val
;
593 if ((rdnss_length
= agetnum("rdnssaddrs")) < 0) {
594 rai
->rdnss_length
= 0;
597 rai
->rdnss_length
= rdnss_length
;
599 /* traverse in reverse order so that the queue has correct order */
600 for (i
= (rdnss_length
- 1); i
>= 0; i
--) {
604 /* allocate memory to store server address information */
605 ELM_MALLOC(rdnss
, exit(1));
606 /* link into chain */
607 insque(rdnss
, &rai
->rdnss_list
);
609 makeentry(entbuf
, sizeof(entbuf
), i
, "rdnssaddr");
610 addr
= (char *)agetstr(entbuf
, &bp
);
612 if (addr
== NULL
&& rdnss_length
== 1) {
613 makeentry(entbuf
, sizeof(entbuf
), -1, "rdnssaddr");
614 addr
= agetstr(entbuf
, &bp
);
618 errorlog("<%s> need %s as a DNS server address for "
620 __func__
, entbuf
, intface
);
624 if (inet_pton(AF_INET6
, addr
, &rdnss
->addr
) != 1) {
625 errorlog("<%s> inet_pton failed for %s",
629 if (IN6_IS_ADDR_MULTICAST(&rdnss
->addr
)) {
630 errorlog("<%s> multicast address (%s) must "
631 "not be advertised as recursive DNS server",
638 /* DNSSL option (RFC6106) */
640 /* Parse the DNSSL lifetime from the config */
641 MAYHAVE(val
, "dnssllifetime", 2 * rai
->maxinterval
);
642 if (val
< rai
->maxinterval
|| val
> (2 * rai
->maxinterval
)) {
643 noticelog("<%s> dnssllifetime (%lu) on %s SHOULD "
644 "be between %u and %u", __func__
, val
,
645 intface
, rai
->maxinterval
, 2 * rai
->maxinterval
);
647 rai
->dnssl_lifetime
= val
;
648 rai
->dnssl_option_length
= 8; /* 8 bytes for the option header */
650 /* Parse the DNSSL domain list from the config */
651 if ((dnssl_length
= agetnum("dnssldomains")) < 0) {
652 rai
->dnssl_length
= 0;
654 rai
->dnssl_length
= dnssl_length
;
656 for (i
= (rai
->dnssl_length
- 1); i
>= 0; i
--) {
657 unsigned char *dnssl_buf
;
660 char entbuf
[sizeof("dnssldomain") + 20];
664 makeentry(entbuf
, sizeof(entbuf
), i
, "dnssldomain");
665 domain
= agetstr(entbuf
, &bp
);
667 if (domain
== NULL
&& rai
->dnssl_length
== 1) {
668 makeentry(entbuf
, sizeof(entbuf
), -1, "dnssldomain");
669 domain
= agetstr(entbuf
, &bp
);
672 if (domain
== NULL
) {
673 errorlog("<%s> need %s as a DNS search domain for "
675 __func__
, entbuf
, intface
);
679 domain_len
= strlen(domain
);
681 /* Trim off leading dots */
682 while (domain_len
> 0 && domain
[0] == '.') {
687 /* Trim off trailing dots */
688 while (domain_len
> 0 && domain
[domain_len
-1] == '.') {
692 if (domain_len
> 0) {
693 dnssl_len
= sizeof(struct dnssl
) + domain_len
+ 1;
694 dnssl_buf
= (unsigned char *)malloc(dnssl_len
);
696 memset(dnssl_buf
, 0, dnssl_len
);
698 dnssl
= (struct dnssl
*)dnssl_buf
;
699 insque(dnssl
, &rai
->dnssl_list
);
701 /* Copy the domain name in at the end of the dnssl struct */
702 memcpy(dnssl_buf
+ offsetof(struct dnssl
, domain
), domain
,
705 /* Add 2 for leading length byte and the trailing 0 byte */
706 rai
->dnssl_option_length
+= domain_len
+ 2;
710 /* Round up to the next multiple of 8 */
711 rai
->dnssl_option_length
+= (8 - (rai
->dnssl_option_length
& 0x7));
718 /* construct the sending packet */
722 rai
->timer
= rtadvd_add_timer(ra_timeout
, ra_timer_update
,
724 ra_timer_update((void *)rai
, &rai
->timer
->tm
);
725 rtadvd_set_timer(&rai
->timer
->tm
, rai
->timer
);
729 get_prefix(struct rainfo
*rai
)
731 struct ifaddrs
*ifap
, *ifa
;
734 u_char
*p
, *ep
, *m
, *lim
;
735 char ntopbuf
[INET6_ADDRSTRLEN
];
737 if (getifaddrs(&ifap
) < 0) {
739 "<%s> can't get interface addresses",
744 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
747 if (strcmp(ifa
->ifa_name
, rai
->ifname
) != 0)
749 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
)
751 a
= &((struct sockaddr_in6
*)ifa
->ifa_addr
)->sin6_addr
;
752 if (IN6_IS_ADDR_LINKLOCAL(a
))
754 /* get prefix length */
755 m
= (u_char
*)&((struct sockaddr_in6
*)ifa
->ifa_netmask
)->sin6_addr
;
756 lim
= (u_char
*)(ifa
->ifa_netmask
) + ifa
->ifa_netmask
->sa_len
;
757 plen
= prefixlen(m
, lim
);
758 if (plen
<= 0 || plen
> 128) {
759 errorlog( "<%s> failed to get prefixlen "
760 "or prefix is invalid",
764 if (plen
== 128) /* XXX */
766 if (find_prefix(rai
, a
, plen
)) {
767 /* ignore a duplicated prefix. */
771 /* allocate memory to store prefix info. */
772 ELM_MALLOC(pfx
, exit(1));
773 /* set prefix, sweep bits outside of prefixlen */
774 pfx
->prefixlen
= plen
;
775 memcpy(&pfx
->prefix
, a
, sizeof(*a
));
776 p
= (u_char
*)&pfx
->prefix
;
777 ep
= (u_char
*)(&pfx
->prefix
+ 1);
778 while (m
< lim
&& p
< ep
)
782 if (!inet_ntop(AF_INET6
, &pfx
->prefix
, ntopbuf
,
784 errorlog("<%s> inet_ntop failed", __func__
);
787 debuglog("<%s> add %s/%d to prefix list on %s",
788 __func__
, ntopbuf
, pfx
->prefixlen
, rai
->ifname
);
790 /* set other fields with protocol defaults */
791 pfx
->validlifetime
= DEF_ADVVALIDLIFETIME
;
792 pfx
->preflifetime
= DEF_ADVPREFERREDLIFETIME
;
794 pfx
->autoconfflg
= 1;
795 pfx
->origin
= PREFIX_FROM_KERNEL
;
798 /* link into chain */
799 insque(pfx
, &rai
->prefix
);
801 /* counter increment */
809 makeentry(buf
, len
, id
, string
)
817 strlcpy(buf
, string
, len
);
819 snprintf(buf
, len
, "%s%d", string
, id
);
823 * Add a prefix to the list of specified interface and reconstruct
824 * the outgoing packet.
825 * The prefix must not be in the list.
826 * XXX: other parameters of the prefix (e.g. lifetime) should be
827 * able to be specified.
830 add_prefix(struct rainfo
*rai
, struct in6_prefixreq
*ipr
)
832 struct prefix
*prefix
;
833 char ntopbuf
[INET6_ADDRSTRLEN
];
835 ELM_MALLOC(prefix
, exit(1));
836 prefix
->prefix
= ipr
->ipr_prefix
.sin6_addr
;
837 prefix
->prefixlen
= ipr
->ipr_plen
;
838 prefix
->validlifetime
= ipr
->ipr_vltime
;
839 prefix
->preflifetime
= ipr
->ipr_pltime
;
840 prefix
->onlinkflg
= ipr
->ipr_raf_onlink
;
841 prefix
->autoconfflg
= ipr
->ipr_raf_auto
;
842 prefix
->origin
= PREFIX_FROM_DYNAMIC
;
843 prefix
->rainfo
= rai
;
845 insque(prefix
, &rai
->prefix
);
847 debuglog("<%s> new prefix %s/%d was added on %s",
848 __func__
, inet_ntop(AF_INET6
, &ipr
->ipr_prefix
.sin6_addr
,
849 ntopbuf
, INET6_ADDRSTRLEN
),
850 ipr
->ipr_plen
, rai
->ifname
);
852 /* free the previous packet */
856 /* reconstruct the packet */
862 * Delete a prefix to the list of specified interface and reconstruct
863 * the outgoing packet.
864 * The prefix must be in the list.
867 delete_prefix(struct prefix
*prefix
)
869 char ntopbuf
[INET6_ADDRSTRLEN
];
870 struct rainfo
*rai
= prefix
->rainfo
;
873 debuglog("<%s> prefix %s/%d was deleted on %s",
874 __func__
, inet_ntop(AF_INET6
, &prefix
->prefix
,
875 ntopbuf
, INET6_ADDRSTRLEN
),
876 prefix
->prefixlen
, rai
->ifname
);
878 rtadvd_remove_timer(&prefix
->timer
);
884 invalidate_prefix(struct prefix
*prefix
)
886 char ntopbuf
[INET6_ADDRSTRLEN
];
888 struct rainfo
*rai
= prefix
->rainfo
;
890 if (prefix
->timer
) { /* sanity check */
891 errorlog("<%s> assumption failure: timer already exists",
896 debuglog("<%s> prefix %s/%d was invalidated on %s, "
897 "will expire in %ld seconds", __func__
,
898 inet_ntop(AF_INET6
, &prefix
->prefix
, ntopbuf
, INET6_ADDRSTRLEN
),
899 prefix
->prefixlen
, rai
->ifname
, (long)prefix_timo
);
901 /* set the expiration timer */
902 prefix
->timer
= rtadvd_add_timer(prefix_timeout
, NULL
, prefix
, NULL
);
903 if (prefix
->timer
== NULL
) {
904 errorlog("<%s> failed to add a timer for a prefix. "
905 "remove the prefix", __func__
);
906 delete_prefix(prefix
);
909 timo
.tv_sec
= prefix_timo
;
911 rtadvd_set_timer(&timo
, prefix
->timer
);
914 static struct rtadvd_timer
*
915 prefix_timeout(void *arg
)
917 struct prefix
*prefix
= (struct prefix
*)arg
;
919 delete_prefix(prefix
);
925 update_prefix(struct prefix
* prefix
)
927 char ntopbuf
[INET6_ADDRSTRLEN
];
928 struct rainfo
*rai
= prefix
->rainfo
;
930 if (prefix
->timer
== NULL
) { /* sanity check */
931 errorlog("<%s> assumption failure: timer does not exist",
936 debuglog("<%s> prefix %s/%d was re-enabled on %s",
937 __func__
, inet_ntop(AF_INET6
, &prefix
->prefix
, ntopbuf
,
938 INET6_ADDRSTRLEN
), prefix
->prefixlen
, rai
->ifname
);
940 /* stop the expiration timer */
941 rtadvd_remove_timer(&prefix
->timer
);
945 * Try to get an in6_prefixreq contents for a prefix which matches
946 * ipr->ipr_prefix and ipr->ipr_plen and belongs to
947 * the interface whose name is ipr->ipr_name[].
950 init_prefix(struct in6_prefixreq
*ipr
)
955 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
956 errorlog("<%s> socket: %s", __func__
,
961 if (ioctl(s
, SIOCGIFPREFIX_IN6
, (caddr_t
)ipr
) < 0) {
962 infolog("<%s> ioctl:SIOCGIFPREFIX %s", __func__
,
965 ipr
->ipr_vltime
= DEF_ADVVALIDLIFETIME
;
966 ipr
->ipr_pltime
= DEF_ADVPREFERREDLIFETIME
;
967 ipr
->ipr_raf_onlink
= 1;
968 ipr
->ipr_raf_auto
= 1;
969 /* omit other field initialization */
971 else if (ipr
->ipr_origin
< PR_ORIG_RR
) {
972 char ntopbuf
[INET6_ADDRSTRLEN
];
974 noticelog("<%s> Added prefix(%s)'s origin %d is"
975 "lower than PR_ORIG_RR(router renumbering)."
976 "This should not happen if I am router", __func__
,
977 inet_ntop(AF_INET6
, &ipr
->ipr_prefix
.sin6_addr
, ntopbuf
,
978 sizeof(ntopbuf
)), ipr
->ipr_origin
);
986 ipr
->ipr_vltime
= DEF_ADVVALIDLIFETIME
;
987 ipr
->ipr_pltime
= DEF_ADVPREFERREDLIFETIME
;
988 ipr
->ipr_raf_onlink
= 1;
989 ipr
->ipr_raf_auto
= 1;
995 make_prefix(struct rainfo
*rai
, int ifindex
, struct in6_addr
*addr
, int plen
)
997 struct in6_prefixreq ipr
;
999 memset(&ipr
, 0, sizeof(ipr
));
1000 if (if_indextoname(ifindex
, ipr
.ipr_name
) == NULL
) {
1001 errorlog("<%s> Prefix added interface No.%d doesn't"
1002 "exist. This should not happen! %s", __func__
,
1003 ifindex
, strerror(errno
));
1006 ipr
.ipr_prefix
.sin6_len
= sizeof(ipr
.ipr_prefix
);
1007 ipr
.ipr_prefix
.sin6_family
= AF_INET6
;
1008 ipr
.ipr_prefix
.sin6_addr
= *addr
;
1009 ipr
.ipr_plen
= plen
;
1011 if (init_prefix(&ipr
))
1012 return; /* init failed by some error */
1013 add_prefix(rai
, &ipr
);
1017 make_packet(struct rainfo
*rainfo
)
1019 size_t packlen
, lladdroptlen
= 0;
1021 struct nd_router_advert
*ra
;
1022 struct nd_opt_prefix_info
*ndopt_pi
;
1023 struct nd_opt_mtu
*ndopt_mtu
;
1025 struct nd_opt_route_info
*ndopt_rti
;
1030 /* calculate total length */
1031 packlen
= sizeof(struct nd_router_advert
);
1032 if (rainfo
->advlinkopt
) {
1033 if ((lladdroptlen
= lladdropt_length(rainfo
->sdl
)) == 0) {
1034 infolog("<%s> link-layer address option has"
1035 " null length on %s. Treat as not included.",
1036 __func__
, rainfo
->ifname
);
1037 rainfo
->advlinkopt
= 0;
1039 packlen
+= lladdroptlen
;
1042 packlen
+= sizeof(struct nd_opt_prefix_info
) * rainfo
->pfxs
;
1043 if (rainfo
->linkmtu
)
1044 packlen
+= sizeof(struct nd_opt_mtu
);
1046 for (rti
= rainfo
->route
.next
; rti
!= &rainfo
->route
; rti
= rti
->next
)
1047 packlen
+= sizeof(struct nd_opt_route_info
) +
1048 ((rti
->prefixlen
+ 0x3f) >> 6) * 8;
1050 if (rainfo
->rdnss_length
> 0)
1051 packlen
+= 8 + sizeof(struct in6_addr
) * rainfo
->rdnss_length
;
1053 if (rainfo
->dnssl_length
> 0) {
1054 packlen
+= rainfo
->dnssl_option_length
;
1057 /* allocate memory for the packet */
1058 if ((buf
= malloc(packlen
)) == NULL
) {
1059 errorlog("<%s> can't get enough memory for an RA packet",
1063 if (rainfo
->ra_data
) {
1064 /* free the previous packet */
1065 free(rainfo
->ra_data
);
1066 rainfo
->ra_data
= NULL
;
1068 rainfo
->ra_data
= buf
;
1069 /* XXX: what if packlen > 576? */
1070 rainfo
->ra_datalen
= packlen
;
1073 * construct the packet
1075 ra
= (struct nd_router_advert
*)buf
;
1076 ra
->nd_ra_type
= ND_ROUTER_ADVERT
;
1078 ra
->nd_ra_cksum
= 0;
1079 ra
->nd_ra_curhoplimit
= (u_int8_t
)(0xff & rainfo
->hoplimit
);
1080 ra
->nd_ra_flags_reserved
= 0; /* just in case */
1082 * XXX: the router preference field, which is a 2-bit field, should be
1083 * initialized before other fields.
1085 ra
->nd_ra_flags_reserved
= 0xff & rainfo
->rtpref
;
1086 ra
->nd_ra_flags_reserved
|=
1087 rainfo
->managedflg
? ND_RA_FLAG_MANAGED
: 0;
1088 ra
->nd_ra_flags_reserved
|=
1089 rainfo
->otherflg
? ND_RA_FLAG_OTHER
: 0;
1090 ra
->nd_ra_router_lifetime
= htons(rainfo
->lifetime
);
1091 ra
->nd_ra_reachable
= htonl(rainfo
->reachabletime
);
1092 ra
->nd_ra_retransmit
= htonl(rainfo
->retranstimer
);
1095 if (rainfo
->advlinkopt
) {
1096 lladdropt_fill(rainfo
->sdl
, (struct nd_opt_hdr
*)buf
);
1097 buf
+= lladdroptlen
;
1100 if (rainfo
->linkmtu
) {
1101 ndopt_mtu
= (struct nd_opt_mtu
*)buf
;
1102 ndopt_mtu
->nd_opt_mtu_type
= ND_OPT_MTU
;
1103 ndopt_mtu
->nd_opt_mtu_len
= 1;
1104 ndopt_mtu
->nd_opt_mtu_reserved
= 0;
1105 ndopt_mtu
->nd_opt_mtu_mtu
= htonl(rainfo
->linkmtu
);
1106 buf
+= sizeof(struct nd_opt_mtu
);
1109 for (pfx
= rainfo
->prefix
.next
;
1110 pfx
!= &rainfo
->prefix
; pfx
= pfx
->next
) {
1111 u_int32_t vltime
, pltime
;
1114 ndopt_pi
= (struct nd_opt_prefix_info
*)buf
;
1115 ndopt_pi
->nd_opt_pi_type
= ND_OPT_PREFIX_INFORMATION
;
1116 ndopt_pi
->nd_opt_pi_len
= 4;
1117 ndopt_pi
->nd_opt_pi_prefix_len
= pfx
->prefixlen
;
1118 ndopt_pi
->nd_opt_pi_flags_reserved
= 0;
1120 ndopt_pi
->nd_opt_pi_flags_reserved
|=
1121 ND_OPT_PI_FLAG_ONLINK
;
1122 if (pfx
->autoconfflg
)
1123 ndopt_pi
->nd_opt_pi_flags_reserved
|=
1124 ND_OPT_PI_FLAG_AUTO
;
1128 if (pfx
->vltimeexpire
|| pfx
->pltimeexpire
)
1129 gettimeofday(&now
, NULL
);
1130 if (pfx
->vltimeexpire
== 0)
1131 vltime
= pfx
->validlifetime
;
1133 vltime
= (pfx
->vltimeexpire
> now
.tv_sec
) ?
1134 pfx
->vltimeexpire
- now
.tv_sec
: 0;
1139 if (pfx
->pltimeexpire
== 0)
1140 pltime
= pfx
->preflifetime
;
1142 pltime
= (pfx
->pltimeexpire
> now
.tv_sec
) ?
1143 pfx
->pltimeexpire
- now
.tv_sec
: 0;
1145 if (vltime
< pltime
) {
1147 * this can happen if vltime is decrement but pltime
1152 ndopt_pi
->nd_opt_pi_valid_time
= htonl(vltime
);
1153 ndopt_pi
->nd_opt_pi_preferred_time
= htonl(pltime
);
1154 ndopt_pi
->nd_opt_pi_reserved2
= 0;
1155 ndopt_pi
->nd_opt_pi_prefix
= pfx
->prefix
;
1157 buf
+= sizeof(struct nd_opt_prefix_info
);
1161 for (rti
= rainfo
->route
.next
; rti
!= &rainfo
->route
; rti
= rti
->next
) {
1162 u_int8_t psize
= (rti
->prefixlen
+ 0x3f) >> 6;
1164 ndopt_rti
= (struct nd_opt_route_info
*)buf
;
1165 ndopt_rti
->nd_opt_rti_type
= ND_OPT_ROUTE_INFO
;
1166 ndopt_rti
->nd_opt_rti_len
= 1 + psize
;
1167 ndopt_rti
->nd_opt_rti_prefixlen
= rti
->prefixlen
;
1168 ndopt_rti
->nd_opt_rti_flags
= 0xff & rti
->rtpref
;
1169 ndopt_rti
->nd_opt_rti_lifetime
= htonl(rti
->ltime
);
1170 memcpy(ndopt_rti
+ 1, &rti
->prefix
, psize
* 8);
1171 buf
+= sizeof(struct nd_opt_route_info
) + psize
* 8;
1175 if (rainfo
->rdnss_length
> 0) {
1176 struct nd_opt_rdnss
* ndopt_rdnss
;
1177 struct rdnss
* rdnss
;
1179 ndopt_rdnss
= (struct nd_opt_rdnss
*) buf
;
1180 ndopt_rdnss
->nd_opt_rdnss_type
= ND_OPT_RDNSS
;
1181 ndopt_rdnss
->nd_opt_rdnss_len
= 1 + (rainfo
->rdnss_length
* 2);
1182 ndopt_rdnss
->nd_opt_rdnss_reserved
= 0;
1183 ndopt_rdnss
->nd_opt_rdnss_lifetime
= htonl(rainfo
->rdnss_lifetime
);
1186 for (rdnss
= rainfo
->rdnss_list
.next
;
1187 rdnss
!= &rainfo
->rdnss_list
;
1188 rdnss
= rdnss
->next
)
1190 struct in6_addr
* addr6
= (struct in6_addr
*) buf
;
1191 *addr6
= rdnss
->addr
;
1192 buf
+= sizeof *addr6
;
1196 if (rainfo
->dnssl_length
> 0) {
1197 struct nd_opt_dnssl
* dnssl_opt
;
1198 struct dnssl
* dnssl
;
1199 int domains_length
= 0;
1200 u_char
* cursor
= buf
;
1202 memset(cursor
, 0, rainfo
->dnssl_option_length
);
1204 dnssl_opt
= (struct nd_opt_dnssl
*)cursor
;
1205 dnssl_opt
->nd_opt_dnssl_type
= ND_OPT_DNSSL
;
1207 * Length is in units of 8 octets. Divide total byte length
1208 * of the option by 8.
1210 dnssl_opt
->nd_opt_dnssl_len
= rainfo
->dnssl_option_length
>> 3;
1211 dnssl_opt
->nd_opt_dnssl_reserved
= 0;
1212 dnssl_opt
->nd_opt_dnssl_lifetime
=
1213 htonl(rainfo
->dnssl_lifetime
);
1215 cursor
+= offsetof(struct nd_opt_dnssl
, nd_opt_dnssl_domains
);
1217 for (dnssl
= rainfo
->dnssl_list
.next
;
1218 dnssl
!= &rainfo
->dnssl_list
;
1219 dnssl
= dnssl
->next
)
1221 int encodeLen
= encode_domain(dnssl
->domain
, cursor
);
1222 cursor
+= encodeLen
;
1223 domains_length
+= encodeLen
;
1226 buf
+= rainfo
->dnssl_option_length
;
1233 getinet6sysctl(int code
)
1235 int mib
[] = { CTL_NET
, PF_INET6
, IPPROTO_IPV6
, 0 };
1240 size
= sizeof(value
);
1241 if (sysctl(mib
, sizeof(mib
)/sizeof(mib
[0]), &value
, &size
, NULL
, 0)
1243 errorlog( "<%s>: failed to get ip6 sysctl(%d): %s",
1253 * Encode a domain name into a buffer according to the rules in RFC 1035 section
1254 * 3.1. Do not use the compression techniques outlined in section 4.1.4.
1257 encode_domain(char *domain
, u_char
*dst
)
1259 char *domainCopy
= strdup(domain
);
1260 char *input
= domainCopy
;
1262 u_char
*cursor
= dst
;
1264 while ((label
= strsep(&input
, ".")) != NULL
) {
1265 int label_len
= strlen(label
) & 0x3f; /* Max length is 63 */
1266 if (label_len
> 0) {
1267 *cursor
= (u_char
)label_len
;
1269 memcpy(cursor
, label
, label_len
);
1270 cursor
+= label_len
;
1278 return (cursor
- dst
);