1 /* $NetBSD: config.c,v 1.34 2015/06/05 14:09:20 roy Exp $ */
2 /* $KAME: config.c,v 1.93 2005/10/17 14:40:02 suz Exp $ */
5 * Copyright (C) 1998 WIDE Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/param.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
37 #include <sys/sysctl.h>
40 #include <net/route.h>
41 #include <net/if_dl.h>
43 #include <net/if_var.h>
46 #include <netinet/in.h>
47 #include <netinet/in_var.h>
48 #include <netinet/ip6.h>
49 #include <netinet6/ip6_var.h>
50 #include <netinet/icmp6.h>
51 #include <netinet6/nd6.h>
53 #include <arpa/inet.h>
72 #define __arraycount(__x) (sizeof(__x) / sizeof(__x[0]))
75 static time_t prefix_timo
= (60 * 120); /* 2 hours.
76 * XXX: should be configurable. */
77 static struct rtadvd_timer
*prefix_timeout(void *);
78 static void makeentry(char *, size_t, int, const char *);
79 static int getinet6sysctl(int);
82 encode_domain(char *dst
, const char *src
)
88 while (src
&& (len
= strlen(src
)) != 0) {
90 *dst
++ = len
= MIN(63, p
== NULL
? len
: p
- src
);
91 memcpy(dst
, src
, len
);
103 free_rainfo(struct rainfo
*rai
)
108 struct rdnss_addr
*rdnsa
;
110 struct dnssl_domain
*dnsd
;
112 rtadvd_remove_timer(&rai
->timer
);
114 while ((pfx
= TAILQ_FIRST(&rai
->prefix
))) {
115 TAILQ_REMOVE(&rai
->prefix
, pfx
, next
);
119 while ((rti
= TAILQ_FIRST(&rai
->route
))) {
120 TAILQ_REMOVE(&rai
->route
, rti
, next
);
124 while ((rdnss
= TAILQ_FIRST(&rai
->rdnss
))) {
125 TAILQ_REMOVE(&rai
->rdnss
, rdnss
, next
);
126 while ((rdnsa
= TAILQ_FIRST(&rdnss
->list
))) {
127 TAILQ_REMOVE(&rdnss
->list
, rdnsa
, next
);
133 while ((dnssl
= TAILQ_FIRST(&rai
->dnssl
))) {
134 TAILQ_REMOVE(&rai
->dnssl
, dnssl
, next
);
135 while ((dnsd
= TAILQ_FIRST(&dnssl
->list
))) {
136 TAILQ_REMOVE(&dnssl
->list
, dnsd
, next
);
148 getconfig(const char *intface
, int exithard
)
152 struct rainfo
*tmp
, *rai
;
157 char *addr
, *flagstr
, *ap
;
158 static int forwarding
= -1;
159 char entbuf
[256], abuf
[256];
163 #define MUSTHAVE(var, cap) \
166 if ((t = agetnum(cap)) < 0) { \
167 fprintf(stderr, "rtadvd: need %s for interface %s\n", \
173 #define MAYHAVE(var, cap, def) \
175 if ((var = agetnum(cap)) < 0) \
178 #define ELM_MALLOC(p) \
180 p = calloc(1, sizeof(*p)); \
182 syslog(LOG_ERR, "<%s> calloc failed: %m", \
186 } while(/*CONSTCOND*/0)
188 if (if_nametoindex(intface
) == 0) {
189 syslog(LOG_INFO
, "<%s> interface %s not found, ignoring",
194 syslog(LOG_DEBUG
, "<%s> loading configuration for interface %s",
197 if ((stat
= agetent(tbuf
, intface
)) <= 0) {
198 memset(tbuf
, 0, sizeof(tbuf
));
200 "<%s> %s isn't defined in the configuration file"
201 " or the configuration file doesn't exist."
202 " Treat it as default",
207 TAILQ_INIT(&tmp
->prefix
);
208 TAILQ_INIT(&tmp
->route
);
209 TAILQ_INIT(&tmp
->rdnss
);
210 TAILQ_INIT(&tmp
->dnssl
);
212 /* check if we are allowed to forward packets (if not determined) */
213 if (forwarding
< 0) {
214 if ((forwarding
= getinet6sysctl(IPV6CTL_FORWARDING
)) < 0)
218 /* get interface information */
219 if (agetflag("nolladdr"))
223 if (tmp
->advlinkopt
) {
224 if ((tmp
->sdl
= if_nametosdl(intface
)) == NULL
) {
226 "<%s> can't get information of %s",
230 tmp
->ifindex
= tmp
->sdl
->sdl_index
;
232 tmp
->ifindex
= if_nametoindex(intface
);
233 if (tmp
->ifindex
== 0) {
235 "<%s> can't get information of %s",
240 tmp
->ifflags
= if_getflags(tmp
->ifindex
, 0);
241 strlcpy(tmp
->ifname
, intface
, sizeof(tmp
->ifname
));
242 if ((tmp
->phymtu
= if_getmtu(intface
)) == 0) {
243 tmp
->phymtu
= IPV6_MMTU
;
245 "<%s> can't get interface mtu of %s. Treat as %d",
246 __func__
, intface
, IPV6_MMTU
);
250 * set router configuration variables.
252 MAYHAVE(val
, "maxinterval", DEF_MAXRTRADVINTERVAL
);
253 if (val
< MIN_MAXINTERVAL
|| val
> MAX_MAXINTERVAL
) {
255 "<%s> maxinterval (%d) on %s is invalid "
256 "(must be between %u and %u)", __func__
, val
,
257 intface
, MIN_MAXINTERVAL
, MAX_MAXINTERVAL
);
260 tmp
->maxinterval
= val
;
261 MAYHAVE(val
, "mininterval", tmp
->maxinterval
/3);
262 if (val
< MIN_MININTERVAL
|| val
> (tmp
->maxinterval
* 3) / 4) {
264 "<%s> mininterval (%d) on %s is invalid "
265 "(must be between %u and %d)",
266 __func__
, val
, intface
, MIN_MININTERVAL
,
267 (tmp
->maxinterval
* 3) / 4);
270 tmp
->mininterval
= val
;
272 MAYHAVE(val
, "chlim", DEF_ADVCURHOPLIMIT
);
273 tmp
->hoplimit
= val
& 0xff;
275 if ((flagstr
= (char *)agetstr("raflags", &bp
))) {
277 if (strchr(flagstr
, 'm'))
278 val
|= ND_RA_FLAG_MANAGED
;
279 if (strchr(flagstr
, 'o'))
280 val
|= ND_RA_FLAG_OTHER
;
281 if (strchr(flagstr
, 'h'))
282 val
|= ND_RA_FLAG_RTPREF_HIGH
;
283 if (strchr(flagstr
, 'l')) {
284 if ((val
& ND_RA_FLAG_RTPREF_HIGH
)) {
285 syslog(LOG_ERR
, "<%s> the \'h\' and \'l\'"
286 " router flags are exclusive", __func__
);
289 val
|= ND_RA_FLAG_RTPREF_LOW
;
292 MAYHAVE(val
, "raflags", 0);
294 tmp
->managedflg
= val
& ND_RA_FLAG_MANAGED
;
295 tmp
->otherflg
= val
& ND_RA_FLAG_OTHER
;
296 #ifndef ND_RA_FLAG_RTPREF_MASK
297 #define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
298 #define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */
300 tmp
->rtpref
= val
& ND_RA_FLAG_RTPREF_MASK
;
301 if (tmp
->rtpref
== ND_RA_FLAG_RTPREF_RSV
) {
302 syslog(LOG_ERR
, "<%s> invalid router preference (%02x) on %s",
303 __func__
, tmp
->rtpref
, intface
);
307 MAYHAVE(val
, "rltime", tmp
->maxinterval
* 3);
308 if (val
&& (val
< tmp
->maxinterval
|| val
> MAXROUTERLIFETIME
)) {
310 "<%s> router lifetime (%d) on %s is invalid "
311 "(must be 0 or between %d and %d)",
312 __func__
, val
, intface
,
313 tmp
->maxinterval
, MAXROUTERLIFETIME
);
317 * Basically, hosts MUST NOT send Router Advertisement messages at any
318 * time (RFC 2461, Section 6.2.3). However, it would sometimes be
319 * useful to allow hosts to advertise some parameters such as prefix
320 * information and link MTU. Thus, we allow hosts to invoke rtadvd
321 * only when router lifetime (on every advertising interface) is
322 * explicitly set zero. (see also the above section)
324 if (val
&& forwarding
== 0) {
326 "<%s> non zero router lifetime is specified for %s, "
327 "which must not be allowed for hosts. you must "
328 "change router lifetime or enable IPv6 forwarding.",
332 tmp
->lifetime
= val
& 0xffff;
334 MAYHAVE(val
, "rtime", DEF_ADVREACHABLETIME
);
335 if (val
< 0 || val
> MAXREACHABLETIME
) {
337 "<%s> reachable time (%d) on %s is invalid "
338 "(must be no greater than %d)",
339 __func__
, val
, intface
, MAXREACHABLETIME
);
342 tmp
->reachabletime
= (uint32_t)val
;
344 MAYHAVE(val64
, "retrans", DEF_ADVRETRANSTIMER
);
345 if (val64
< 0 || val64
> 0xffffffff) {
346 syslog(LOG_ERR
, "<%s> retrans time (%lld) on %s out of range",
347 __func__
, (long long)val64
, intface
);
350 tmp
->retranstimer
= (uint32_t)val64
;
352 if (agetnum("hapref") != -1 || agetnum("hatime") != -1) {
354 "<%s> mobile-ip6 configuration not supported",
358 /* prefix information */
361 * This is an implementation specific parameter to consider
362 * link propagation delays and poorly synchronized clocks when
363 * checking consistency of advertised lifetimes.
365 MAYHAVE(val
, "clockskew", 0);
366 tmp
->clockskew
= val
;
369 for (i
= -1; i
< MAXPREFIX
; i
++) {
372 makeentry(entbuf
, sizeof(entbuf
), i
, "addr");
373 addr
= (char *)agetstr(entbuf
, &bp
);
377 /* allocate memory to store prefix information */
378 if ((pfx
= calloc(1, sizeof(*pfx
))) == NULL
) {
380 "<%s> can't allocate memory: %m",
385 TAILQ_INSERT_TAIL(&tmp
->prefix
, pfx
, next
);
389 pfx
->origin
= PREFIX_FROM_CONFIG
;
391 if (inet_pton(AF_INET6
, addr
, &pfx
->prefix
) != 1) {
393 "<%s> inet_pton failed for %s",
397 if (IN6_IS_ADDR_MULTICAST(&pfx
->prefix
)) {
399 "<%s> multicast prefix (%s) must "
400 "not be advertised on %s",
401 __func__
, addr
, intface
);
404 if (IN6_IS_ADDR_LINKLOCAL(&pfx
->prefix
))
406 "<%s> link-local prefix (%s) will be"
408 __func__
, addr
, intface
);
410 makeentry(entbuf
, sizeof(entbuf
), i
, "prefixlen");
411 MAYHAVE(val
, entbuf
, 64);
412 if (val
< 0 || val
> 128) {
413 syslog(LOG_ERR
, "<%s> prefixlen (%d) for %s "
414 "on %s out of range",
415 __func__
, val
, addr
, intface
);
418 pfx
->prefixlen
= (int)val
;
420 makeentry(entbuf
, sizeof(entbuf
), i
, "pinfoflags");
421 if ((flagstr
= (char *)agetstr(entbuf
, &bp
))) {
423 if (strchr(flagstr
, 'l'))
424 val
|= ND_OPT_PI_FLAG_ONLINK
;
425 if (strchr(flagstr
, 'a'))
426 val
|= ND_OPT_PI_FLAG_AUTO
;
429 (ND_OPT_PI_FLAG_ONLINK
|ND_OPT_PI_FLAG_AUTO
));
431 pfx
->onlinkflg
= val
& ND_OPT_PI_FLAG_ONLINK
;
432 pfx
->autoconfflg
= val
& ND_OPT_PI_FLAG_AUTO
;
434 makeentry(entbuf
, sizeof(entbuf
), i
, "vltime");
435 MAYHAVE(val64
, entbuf
, DEF_ADVVALIDLIFETIME
);
436 if (val64
< 0 || val64
> 0xffffffff) {
437 syslog(LOG_ERR
, "<%s> vltime (%lld) for "
438 "%s/%d on %s is out of range",
439 __func__
, (long long)val64
,
440 addr
, pfx
->prefixlen
, intface
);
443 pfx
->validlifetime
= (uint32_t)val64
;
445 makeentry(entbuf
, sizeof(entbuf
), i
, "vltimedecr");
446 if (agetflag(entbuf
)) {
448 clock_gettime(CLOCK_MONOTONIC
, &now
);
450 now
.tv_sec
+ pfx
->validlifetime
;
453 makeentry(entbuf
, sizeof(entbuf
), i
, "pltime");
454 MAYHAVE(val64
, entbuf
, DEF_ADVPREFERREDLIFETIME
);
455 if (val64
< 0 || val64
> 0xffffffff) {
457 "<%s> pltime (%lld) for %s/%d on %s "
459 __func__
, (long long)val64
,
460 addr
, pfx
->prefixlen
, intface
);
463 pfx
->preflifetime
= (uint32_t)val64
;
465 makeentry(entbuf
, sizeof(entbuf
), i
, "pltimedecr");
466 if (agetflag(entbuf
)) {
468 clock_gettime(CLOCK_MONOTONIC
, &now
);
470 now
.tv_sec
+ pfx
->preflifetime
;
473 if (TAILQ_FIRST(&tmp
->prefix
) == NULL
&& !agetflag("noifprefix"))
476 MAYHAVE(val64
, "mtu", 0);
477 if (val64
< 0 || val64
> 0xffffffff) {
479 "<%s> mtu (%" PRIi64
") on %s out of range",
480 __func__
, val64
, intface
);
483 tmp
->linkmtu
= (uint32_t)val64
;
484 if (tmp
->linkmtu
== 0) {
487 if ((mtustr
= (char *)agetstr("mtu", &bp
)) &&
488 strcmp(mtustr
, "auto") == 0)
489 tmp
->linkmtu
= tmp
->phymtu
;
491 else if (tmp
->linkmtu
< IPV6_MMTU
|| tmp
->linkmtu
> tmp
->phymtu
) {
493 "<%s> advertised link mtu (%d) on %s is invalid (must "
494 "be between least MTU (%d) and physical link MTU (%d)",
495 __func__
, tmp
->linkmtu
, intface
,
496 IPV6_MMTU
, tmp
->phymtu
);
500 #ifdef SIOCSIFINFO_IN6
502 struct in6_ndireq ndi
;
505 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
506 syslog(LOG_ERR
, "<%s> socket: %m", __func__
);
509 memset(&ndi
, 0, sizeof(ndi
));
510 strncpy(ndi
.ifname
, intface
, IFNAMSIZ
);
511 if (ioctl(s
, SIOCGIFINFO_IN6
, &ndi
) < 0) {
512 syslog(LOG_INFO
, "<%s> ioctl:SIOCGIFINFO_IN6 at %s: %m",
516 /* reflect the RA info to the host variables in kernel */
517 ndi
.ndi
.chlim
= tmp
->hoplimit
;
518 ndi
.ndi
.retrans
= tmp
->retranstimer
;
519 ndi
.ndi
.basereachable
= tmp
->reachabletime
;
520 if (ioctl(s
, SIOCSIFINFO_IN6
, &ndi
) < 0) {
521 syslog(LOG_INFO
, "<%s> ioctl:SIOCSIFINFO_IN6 at %s: %m",
528 /* route information */
529 for (i
= -1; i
< MAXROUTE
; i
++) {
533 makeentry(entbuf
, sizeof(entbuf
), i
, "rtprefix");
534 addr
= (char *)agetstr(entbuf
, &bp
);
536 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrprefix");
537 addr
= (char *)agetstr(oentbuf
, &bp
);
539 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
547 memset(rti
, 0, sizeof(*rti
));
549 /* link into chain */
550 TAILQ_INSERT_TAIL(&tmp
->route
, rti
, next
);
552 if (inet_pton(AF_INET6
, addr
, &rti
->prefix
) != 1) {
553 syslog(LOG_ERR
, "<%s> inet_pton failed for %s",
559 * XXX: currently there's no restriction in route information
560 * prefix according to
561 * draft-ietf-ipngwg-router-selection-00.txt.
562 * However, I think the similar restriction be necessary.
564 MAYHAVE(val64
, entbuf
, DEF_ADVVALIDLIFETIME
);
565 if (IN6_IS_ADDR_MULTICAST(&rti
->prefix
)) {
567 "<%s> multicast route (%s) must "
568 "not be advertised on %s",
569 __func__
, addr
, intface
);
572 if (IN6_IS_ADDR_LINKLOCAL(&rti
->prefix
)) {
574 "<%s> link-local route (%s) will "
575 "be advertised on %s",
576 __func__
, addr
, intface
);
581 makeentry(entbuf
, sizeof(entbuf
), i
, "rtplen");
582 /* XXX: 256 is a magic number for compatibility check. */
583 MAYHAVE(val
, entbuf
, 256);
585 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrplen");
586 MAYHAVE(val
, oentbuf
, 256);
588 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
593 if (val
< 0 || val
> 128) {
594 syslog(LOG_ERR
, "<%s> prefixlen (%d) for %s on %s "
596 __func__
, val
, addr
, intface
);
599 rti
->prefixlen
= (int)val
;
601 makeentry(entbuf
, sizeof(entbuf
), i
, "rtflags");
602 if ((flagstr
= (char *)agetstr(entbuf
, &bp
))) {
604 if (strchr(flagstr
, 'h'))
605 val
|= ND_RA_FLAG_RTPREF_HIGH
;
606 if (strchr(flagstr
, 'l')) {
607 if ((val
& ND_RA_FLAG_RTPREF_HIGH
)) {
609 "<%s> the \'h\' and \'l\' route"
610 " preferences are exclusive",
614 val
|= ND_RA_FLAG_RTPREF_LOW
;
617 MAYHAVE(val
, entbuf
, 256); /* XXX */
619 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrflags");
620 MAYHAVE(val
, oentbuf
, 256);
622 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
627 rti
->rtpref
= val
& ND_RA_FLAG_RTPREF_MASK
;
628 if (rti
->rtpref
== ND_RA_FLAG_RTPREF_RSV
) {
629 syslog(LOG_ERR
, "<%s> invalid route preference (%02x) "
631 __func__
, rti
->rtpref
, addr
,
632 rti
->prefixlen
, intface
);
637 * Since the spec does not a default value, we should make
638 * this entry mandatory. However, FreeBSD 4.4 has shipped
639 * with this field being optional, we use the router lifetime
640 * as an ad-hoc default value with a warning message.
642 makeentry(entbuf
, sizeof(entbuf
), i
, "rtltime");
643 MAYHAVE(val64
, entbuf
, -1);
645 makeentry(oentbuf
, sizeof(oentbuf
), i
, "rtrltime");
646 MAYHAVE(val64
, oentbuf
, -1);
648 fprintf(stderr
, "%s was obsoleted. Use %s.\n",
651 fprintf(stderr
, "%s should be specified "
652 "for interface %s.\n",
654 val64
= tmp
->lifetime
;
657 if (val64
< 0 || val64
> 0xffffffff) {
658 syslog(LOG_ERR
, "<%s> route lifetime (%lld) for "
659 "%s/%d on %s out of range", __func__
,
660 (long long)val64
, addr
, rti
->prefixlen
, intface
);
663 rti
->ltime
= (uint32_t)val64
;
667 for (i
= -1; i
< MAXRDNSS
; i
++) {
668 struct rdnss_addr
*rdnsa
;
670 makeentry(entbuf
, sizeof(entbuf
), i
, "rdnss");
671 addr
= (char *)agetstr(entbuf
, &bp
);
676 TAILQ_INSERT_TAIL(&tmp
->rdnss
, rdnss
, next
);
677 TAILQ_INIT(&rdnss
->list
);
679 for (ap
= addr
; ap
- addr
< (ssize_t
)strlen(addr
); ap
+= c
+1) {
680 c
= strcspn(ap
, ",");
681 strncpy(abuf
, ap
, c
);
684 TAILQ_INSERT_TAIL(&rdnss
->list
, rdnsa
, next
);
685 if (inet_pton(AF_INET6
, abuf
, &rdnsa
->addr
) != 1) {
686 syslog(LOG_ERR
, "<%s> inet_pton failed for %s",
692 makeentry(entbuf
, sizeof(entbuf
), i
, "rdnssltime");
693 MAYHAVE(val64
, entbuf
, tmp
->maxinterval
* 3 / 2);
694 if (val64
< tmp
->maxinterval
||
695 val64
> tmp
->maxinterval
* 2)
697 syslog(LOG_ERR
, "<%s> %s (%lld) on %s is invalid",
698 __func__
, entbuf
, (long long)val64
, intface
);
701 rdnss
->lifetime
= (uint32_t)val64
;
706 TAILQ_INIT(&tmp
->dnssl
);
707 for (i
= -1; i
< MAXDNSSL
; i
++) {
708 struct dnssl_domain
*dnsd
;
710 makeentry(entbuf
, sizeof(entbuf
), i
, "dnssl");
711 addr
= (char *)agetstr(entbuf
, &bp
);
716 TAILQ_INSERT_TAIL(&tmp
->dnssl
, dnssl
, next
);
717 TAILQ_INIT(&dnssl
->list
);
719 for (ap
= addr
; ap
- addr
< (ssize_t
)strlen(addr
); ap
+= c
+1) {
720 c
= strcspn(ap
, ",");
721 strncpy(abuf
, ap
, c
);
724 TAILQ_INSERT_TAIL(&dnssl
->list
, dnsd
, next
);
725 dnsd
->len
= encode_domain(dnsd
->domain
, abuf
);
728 makeentry(entbuf
, sizeof(entbuf
), i
, "dnsslltime");
729 MAYHAVE(val64
, entbuf
, tmp
->maxinterval
* 3 / 2);
730 if (val64
< tmp
->maxinterval
||
731 val64
> tmp
->maxinterval
* 2)
733 syslog(LOG_ERR
, "<%s> %s (%lld) on %s is invalid",
734 __func__
, entbuf
, (long long)val64
, intface
);
737 dnssl
->lifetime
= (uint32_t)val64
;
741 TAILQ_FOREACH(rai
, &ralist
, next
) {
742 if (rai
->ifindex
== tmp
->ifindex
) {
743 TAILQ_REMOVE(&ralist
, rai
, next
);
744 /* If we already have a leaving RA use that
745 * as this config hasn't been advertised */
747 tmp
->leaving
= rai
->leaving
;
750 rai
->leaving_for
= tmp
;
754 TAILQ_FOREACH(rdnss
, &rai
->rdnss
, next
)
756 TAILQ_FOREACH(dnssl
, &rai
->dnssl
, next
)
758 rai
->leaving_for
= tmp
;
760 rai
->initcounter
= MAX_INITIAL_RTR_ADVERTISEMENTS
;
761 rai
->mininterval
= MIN_DELAY_BETWEEN_RAS
;
762 rai
->maxinterval
= MIN_DELAY_BETWEEN_RAS
;
763 rai
->leaving_adv
= MAX_FINAL_RTR_ADVERTISEMENTS
;
764 if (rai
->timer
== NULL
)
765 rai
->timer
= rtadvd_add_timer(ra_timeout
,
768 ra_timer_update((void *)rai
, &rai
->timer
->tm
);
769 rtadvd_set_timer(&rai
->timer
->tm
, rai
->timer
);
775 TAILQ_INSERT_TAIL(&ralist
, tmp
, next
);
777 /* construct the sending packet */
783 tmp
->timer
= rtadvd_add_timer(ra_timeout
, ra_timer_update
,
785 ra_timer_set_short_delay(tmp
);
796 get_prefix(struct rainfo
*rai
)
798 struct ifaddrs
*ifap
, *ifa
;
801 unsigned char *p
, *ep
, *m
, *lim
;
802 char ntopbuf
[INET6_ADDRSTRLEN
];
804 if (getifaddrs(&ifap
) < 0) {
806 "<%s> can't get interface addresses",
811 for (ifa
= ifap
; ifa
; ifa
= ifa
->ifa_next
) {
814 if (strcmp(ifa
->ifa_name
, rai
->ifname
) != 0)
816 if (ifa
->ifa_addr
->sa_family
!= AF_INET6
)
818 a
= &((struct sockaddr_in6
*)ifa
->ifa_addr
)->sin6_addr
;
819 if (IN6_IS_ADDR_LINKLOCAL(a
))
821 /* get prefix length */
822 m
= (unsigned char *)&((struct sockaddr_in6
*)ifa
->ifa_netmask
)->sin6_addr
;
823 lim
= (unsigned char *)(ifa
->ifa_netmask
) + ifa
->ifa_netmask
->sa_len
;
824 plen
= prefixlen(m
, lim
);
825 if (plen
<= 0 || plen
> 128) {
826 syslog(LOG_ERR
, "<%s> failed to get prefixlen "
827 "or prefix is invalid",
831 if (plen
== 128) /* XXX */
833 if (find_prefix(rai
, a
, plen
)) {
834 /* ignore a duplicated prefix. */
838 /* allocate memory to store prefix info. */
839 if ((pp
= calloc(1, sizeof(*pp
))) == NULL
) {
841 "<%s> can't get allocate buffer for prefix",
846 /* set prefix, sweep bits outside of prefixlen */
847 pp
->prefixlen
= plen
;
848 memcpy(&pp
->prefix
, a
, sizeof(*a
));
851 p
= (unsigned char *)&pp
->prefix
;
852 ep
= (unsigned char *)(&pp
->prefix
+ 1);
853 while (m
< lim
&& p
< ep
)
858 if (!inet_ntop(AF_INET6
, &pp
->prefix
, ntopbuf
,
860 syslog(LOG_ERR
, "<%s> inet_ntop failed", __func__
);
864 "<%s> add %s/%d to prefix list on %s",
865 __func__
, ntopbuf
, pp
->prefixlen
, rai
->ifname
);
867 /* set other fields with protocol defaults */
868 pp
->validlifetime
= DEF_ADVVALIDLIFETIME
;
869 pp
->preflifetime
= DEF_ADVPREFERREDLIFETIME
;
872 pp
->origin
= PREFIX_FROM_KERNEL
;
875 /* link into chain */
876 TAILQ_INSERT_TAIL(&rai
->prefix
, pp
, next
);
884 makeentry(char *buf
, size_t len
, int id
, const char *string
)
888 strlcpy(buf
, string
, len
);
890 snprintf(buf
, len
, "%s%d", string
, id
);
894 * Add a prefix to the list of specified interface and reconstruct
895 * the outgoing packet.
896 * The prefix must not be in the list.
897 * XXX: other parameters of the prefix(e.g. lifetime) should be
898 * able to be specified.
901 add_prefix(struct rainfo
*rai
, struct in6_prefixreq
*ipr
)
903 struct prefix
*prefix
;
904 char ntopbuf
[INET6_ADDRSTRLEN
];
906 if ((prefix
= calloc(1, sizeof(*prefix
))) == NULL
) {
907 syslog(LOG_ERR
, "<%s> memory allocation failed",
909 return; /* XXX: error or exit? */
911 prefix
->prefix
= ipr
->ipr_prefix
.sin6_addr
;
912 prefix
->prefixlen
= ipr
->ipr_plen
;
913 prefix
->validlifetime
= ipr
->ipr_vltime
;
914 prefix
->preflifetime
= ipr
->ipr_pltime
;
915 prefix
->onlinkflg
= ipr
->ipr_raf_onlink
;
916 prefix
->autoconfflg
= ipr
->ipr_raf_auto
;
917 prefix
->origin
= PREFIX_FROM_DYNAMIC
;
919 prefix
->rainfo
= rai
;
920 TAILQ_INSERT_TAIL(&rai
->prefix
, prefix
, next
);
923 syslog(LOG_DEBUG
, "<%s> new prefix %s/%d was added on %s",
924 __func__
, inet_ntop(AF_INET6
, &ipr
->ipr_prefix
.sin6_addr
,
925 ntopbuf
, INET6_ADDRSTRLEN
),
926 ipr
->ipr_plen
, rai
->ifname
);
928 /* free the previous packet */
932 /* reconstruct the packet */
937 * Delete a prefix to the list of specified interface and reconstruct
938 * the outgoing packet.
939 * The prefix must be in the list.
942 delete_prefix(struct prefix
*prefix
)
944 char ntopbuf
[INET6_ADDRSTRLEN
];
945 struct rainfo
*rai
= prefix
->rainfo
;
947 TAILQ_REMOVE(&rai
->prefix
, prefix
, next
);
949 syslog(LOG_DEBUG
, "<%s> prefix %s/%d was deleted on %s",
950 __func__
, inet_ntop(AF_INET6
, &prefix
->prefix
,
951 ntopbuf
, INET6_ADDRSTRLEN
),
952 prefix
->prefixlen
, rai
->ifname
);
953 rtadvd_remove_timer(&prefix
->timer
);
958 invalidate_prefix(struct prefix
*prefix
)
960 char ntopbuf
[INET6_ADDRSTRLEN
];
961 struct timespec timo
;
962 struct rainfo
*rai
= prefix
->rainfo
;
964 if (prefix
->timer
) { /* sanity check */
966 "<%s> assumption failure: timer already exists",
971 syslog(LOG_DEBUG
, "<%s> prefix %s/%d was invalidated on %s, "
972 "will expire in %ld seconds", __func__
,
973 inet_ntop(AF_INET6
, &prefix
->prefix
, ntopbuf
, INET6_ADDRSTRLEN
),
974 prefix
->prefixlen
, rai
->ifname
, (long)prefix_timo
);
976 /* set the expiration timer */
977 prefix
->timer
= rtadvd_add_timer(prefix_timeout
, NULL
, prefix
, NULL
);
978 if (prefix
->timer
== NULL
) {
979 syslog(LOG_ERR
, "<%s> failed to add a timer for a prefix. "
980 "remove the prefix", __func__
);
981 delete_prefix(prefix
);
983 timo
.tv_sec
= prefix_timo
;
985 rtadvd_set_timer(&timo
, prefix
->timer
);
988 static struct rtadvd_timer
*
989 prefix_timeout(void *arg
)
991 struct prefix
*prefix
= (struct prefix
*)arg
;
993 delete_prefix(prefix
);
999 update_prefix(struct prefix
* prefix
)
1001 char ntopbuf
[INET6_ADDRSTRLEN
];
1002 struct rainfo
*rai
= prefix
->rainfo
;
1004 if (prefix
->timer
== NULL
) { /* sanity check */
1006 "<%s> assumption failure: timer does not exist",
1011 syslog(LOG_DEBUG
, "<%s> prefix %s/%d was re-enabled on %s",
1012 __func__
, inet_ntop(AF_INET6
, &prefix
->prefix
, ntopbuf
,
1013 INET6_ADDRSTRLEN
), prefix
->prefixlen
, rai
->ifname
);
1015 /* stop the expiration timer */
1016 rtadvd_remove_timer(&prefix
->timer
);
1020 * Try to get an in6_prefixreq contents for a prefix which matches
1021 * ipr->ipr_prefix and ipr->ipr_plen and belongs to
1022 * the interface whose name is ipr->ipr_name[].
1025 init_prefix(struct in6_prefixreq
*ipr
)
1030 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
1031 syslog(LOG_ERR
, "<%s> socket: %m", __func__
);
1035 if (ioctl(s
, SIOCGIFPREFIX_IN6
, ipr
) < 0) {
1036 syslog(LOG_INFO
, "<%s> ioctl:SIOCGIFPREFIX: %m", __func__
);
1038 ipr
->ipr_vltime
= DEF_ADVVALIDLIFETIME
;
1039 ipr
->ipr_pltime
= DEF_ADVPREFERREDLIFETIME
;
1040 ipr
->ipr_raf_onlink
= 1;
1041 ipr
->ipr_raf_auto
= 1;
1042 /* omit other field initialization */
1044 else if (ipr
->ipr_origin
< PR_ORIG_RR
) {
1045 char ntopbuf
[INET6_ADDRSTRLEN
];
1047 syslog(LOG_WARNING
, "<%s> Added prefix(%s)'s origin %d is"
1048 "lower than PR_ORIG_RR(router renumbering)."
1049 "This should not happen if I am router", __func__
,
1050 inet_ntop(AF_INET6
, &ipr
->ipr_prefix
.sin6_addr
, ntopbuf
,
1051 sizeof(ntopbuf
)), ipr
->ipr_origin
);
1059 ipr
->ipr_vltime
= DEF_ADVVALIDLIFETIME
;
1060 ipr
->ipr_pltime
= DEF_ADVPREFERREDLIFETIME
;
1061 ipr
->ipr_raf_onlink
= 1;
1062 ipr
->ipr_raf_auto
= 1;
1068 make_prefix(struct rainfo
*rai
, int ifindex
, struct in6_addr
*addr
, int plen
)
1070 struct in6_prefixreq ipr
;
1072 memset(&ipr
, 0, sizeof(ipr
));
1073 if (if_indextoname(ifindex
, ipr
.ipr_name
) == NULL
) {
1074 syslog(LOG_ERR
, "<%s> Prefix added interface No.%d doesn't"
1075 "exist. This should not happen: %m", __func__
,
1079 ipr
.ipr_prefix
.sin6_len
= sizeof(ipr
.ipr_prefix
);
1080 ipr
.ipr_prefix
.sin6_family
= AF_INET6
;
1081 ipr
.ipr_prefix
.sin6_addr
= *addr
;
1082 ipr
.ipr_plen
= plen
;
1084 if (init_prefix(&ipr
))
1085 return; /* init failed by some error */
1086 add_prefix(rai
, &ipr
);
1090 make_packet(struct rainfo
*rainfo
)
1092 size_t packlen
, lladdroptlen
= 0;
1094 struct nd_router_advert
*ra
;
1095 struct nd_opt_prefix_info
*ndopt_pi
;
1096 struct nd_opt_mtu
*ndopt_mtu
;
1098 struct nd_opt_route_info
*ndopt_rti
;
1100 struct nd_opt_rdnss
*ndopt_rdnss
;
1102 struct rdnss_addr
*rdnsa
;
1103 struct nd_opt_dnssl
*ndopt_dnssl
;
1105 struct dnssl_domain
*dnsd
;
1108 /* calculate total length */
1109 packlen
= sizeof(struct nd_router_advert
);
1110 if (rainfo
->advlinkopt
) {
1111 if ((lladdroptlen
= lladdropt_length(rainfo
->sdl
)) == 0) {
1113 "<%s> link-layer address option has"
1114 " null length on %s. Treat as not included.",
1115 __func__
, rainfo
->ifname
);
1116 rainfo
->advlinkopt
= 0;
1118 packlen
+= lladdroptlen
;
1120 if (TAILQ_FIRST(&rainfo
->prefix
) != NULL
)
1121 packlen
+= sizeof(struct nd_opt_prefix_info
) * rainfo
->pfxs
;
1122 if (rainfo
->linkmtu
)
1123 packlen
+= sizeof(struct nd_opt_mtu
);
1124 TAILQ_FOREACH(rti
, &rainfo
->route
, next
)
1125 packlen
+= sizeof(struct nd_opt_route_info
) +
1126 ((rti
->prefixlen
+ 0x3f) >> 6) * 8;
1128 TAILQ_FOREACH(rdns
, &rainfo
->rdnss
, next
) {
1129 packlen
+= sizeof(struct nd_opt_rdnss
);
1130 TAILQ_FOREACH(rdnsa
, &rdns
->list
, next
)
1131 packlen
+= sizeof(rdnsa
->addr
);
1133 TAILQ_FOREACH(dnsl
, &rainfo
->dnssl
, next
) {
1134 packlen
+= sizeof(struct nd_opt_dnssl
);
1136 TAILQ_FOREACH(dnsd
, &dnsl
->list
, next
)
1138 len
+= len
% 8 ? 8 - len
% 8 : 0;
1142 /* allocate memory for the packet */
1143 if ((buf
= realloc(rainfo
->ra_data
, packlen
)) == NULL
) {
1145 "<%s> can't get enough memory for an RA packet %m",
1149 rainfo
->ra_data
= buf
;
1150 /* XXX: what if packlen > 576? */
1151 rainfo
->ra_datalen
= packlen
;
1152 #define CHECKLEN(size) \
1154 if (buf + size > rainfo->ra_data + packlen) { \
1156 "<%s, %d> RA packet does not fit in %zu",\
1157 __func__, __LINE__, packlen); \
1160 } while (/*CONSTCOND*/0)
1162 * construct the packet
1164 CHECKLEN(sizeof(*ra
));
1165 ra
= (struct nd_router_advert
*)buf
;
1166 ra
->nd_ra_type
= ND_ROUTER_ADVERT
;
1168 ra
->nd_ra_cksum
= 0;
1169 ra
->nd_ra_curhoplimit
= (uint8_t)(0xff & rainfo
->hoplimit
);
1170 ra
->nd_ra_flags_reserved
= 0; /* just in case */
1172 * XXX: the router preference field, which is a 2-bit field, should be
1173 * initialized before other fields.
1175 ra
->nd_ra_flags_reserved
= 0xff & rainfo
->rtpref
;
1176 ra
->nd_ra_flags_reserved
|=
1177 rainfo
->managedflg
? ND_RA_FLAG_MANAGED
: 0;
1178 ra
->nd_ra_flags_reserved
|=
1179 rainfo
->otherflg
? ND_RA_FLAG_OTHER
: 0;
1180 ra
->nd_ra_router_lifetime
= htons(rainfo
->lifetime
);
1181 ra
->nd_ra_reachable
= htonl(rainfo
->reachabletime
);
1182 ra
->nd_ra_retransmit
= htonl(rainfo
->retranstimer
);
1185 if (rainfo
->advlinkopt
) {
1186 CHECKLEN(sizeof(struct nd_opt_hdr
));
1187 lladdropt_fill(rainfo
->sdl
, (struct nd_opt_hdr
*)buf
);
1188 buf
+= lladdroptlen
;
1191 if (rainfo
->linkmtu
) {
1192 CHECKLEN(sizeof(*ndopt_mtu
));
1193 ndopt_mtu
= (struct nd_opt_mtu
*)buf
;
1194 ndopt_mtu
->nd_opt_mtu_type
= ND_OPT_MTU
;
1195 ndopt_mtu
->nd_opt_mtu_len
= 1;
1196 ndopt_mtu
->nd_opt_mtu_reserved
= 0;
1197 ndopt_mtu
->nd_opt_mtu_mtu
= htonl(rainfo
->linkmtu
);
1198 buf
+= sizeof(struct nd_opt_mtu
);
1201 TAILQ_FOREACH(pfx
, &rainfo
->prefix
, next
) {
1202 uint32_t vltime
, pltime
;
1203 struct timespec now
;
1205 CHECKLEN(sizeof(*ndopt_pi
));
1206 ndopt_pi
= (struct nd_opt_prefix_info
*)buf
;
1207 ndopt_pi
->nd_opt_pi_type
= ND_OPT_PREFIX_INFORMATION
;
1208 ndopt_pi
->nd_opt_pi_len
= 4;
1209 ndopt_pi
->nd_opt_pi_prefix_len
= pfx
->prefixlen
;
1210 ndopt_pi
->nd_opt_pi_flags_reserved
= 0;
1212 ndopt_pi
->nd_opt_pi_flags_reserved
|=
1213 ND_OPT_PI_FLAG_ONLINK
;
1214 if (pfx
->autoconfflg
)
1215 ndopt_pi
->nd_opt_pi_flags_reserved
|=
1216 ND_OPT_PI_FLAG_AUTO
;
1220 if (pfx
->vltimeexpire
|| pfx
->pltimeexpire
)
1221 clock_gettime(CLOCK_MONOTONIC
, &now
);
1222 if (pfx
->vltimeexpire
== 0)
1223 vltime
= pfx
->validlifetime
;
1225 vltime
= (pfx
->vltimeexpire
> now
.tv_sec
) ?
1226 pfx
->vltimeexpire
- now
.tv_sec
: 0;
1231 if (pfx
->pltimeexpire
== 0)
1232 pltime
= pfx
->preflifetime
;
1234 pltime
= (pfx
->pltimeexpire
> now
.tv_sec
) ?
1235 pfx
->pltimeexpire
- now
.tv_sec
: 0;
1237 if (vltime
< pltime
) {
1239 * this can happen if vltime is decrement but pltime
1244 ndopt_pi
->nd_opt_pi_valid_time
= htonl(vltime
);
1245 ndopt_pi
->nd_opt_pi_preferred_time
= htonl(pltime
);
1246 ndopt_pi
->nd_opt_pi_reserved2
= 0;
1247 ndopt_pi
->nd_opt_pi_prefix
= pfx
->prefix
;
1249 buf
+= sizeof(struct nd_opt_prefix_info
);
1252 TAILQ_FOREACH(rti
, &rainfo
->route
, next
) {
1253 uint8_t psize
= (rti
->prefixlen
+ 0x3f) >> 6;
1255 CHECKLEN(sizeof(*ndopt_rti
));
1256 ndopt_rti
= (struct nd_opt_route_info
*)buf
;
1257 ndopt_rti
->nd_opt_rti_type
= ND_OPT_ROUTE_INFO
;
1258 ndopt_rti
->nd_opt_rti_len
= 1 + psize
;
1259 ndopt_rti
->nd_opt_rti_prefixlen
= rti
->prefixlen
;
1260 ndopt_rti
->nd_opt_rti_flags
= 0xff & rti
->rtpref
;
1261 ndopt_rti
->nd_opt_rti_lifetime
= htonl(rti
->ltime
);
1262 memcpy(ndopt_rti
+ 1, &rti
->prefix
, psize
* 8);
1263 buf
+= sizeof(struct nd_opt_route_info
) + psize
* 8;
1266 TAILQ_FOREACH(rdns
, &rainfo
->rdnss
, next
) {
1267 CHECKLEN(sizeof(*ndopt_rdnss
));
1268 ndopt_rdnss
= (struct nd_opt_rdnss
*)buf
;
1269 ndopt_rdnss
->nd_opt_rdnss_type
= ND_OPT_RDNSS
;
1270 ndopt_rdnss
->nd_opt_rdnss_len
= 1;
1271 ndopt_rdnss
->nd_opt_rdnss_reserved
= 0;
1272 ndopt_rdnss
->nd_opt_rdnss_lifetime
= htonl(rdns
->lifetime
);
1273 buf
+= sizeof(*ndopt_rdnss
);
1275 TAILQ_FOREACH(rdnsa
, &rdns
->list
, next
) {
1276 CHECKLEN(sizeof(rdnsa
->addr
));
1277 memcpy(buf
, &rdnsa
->addr
, sizeof(rdnsa
->addr
));
1278 ndopt_rdnss
->nd_opt_rdnss_len
+= 2;
1279 buf
+= sizeof(rdnsa
->addr
);
1283 TAILQ_FOREACH(dnsl
, &rainfo
->dnssl
, next
) {
1284 CHECKLEN(sizeof(*ndopt_dnssl
));
1285 ndopt_dnssl
= (struct nd_opt_dnssl
*)buf
;
1286 ndopt_dnssl
->nd_opt_dnssl_type
= ND_OPT_DNSSL
;
1287 ndopt_dnssl
->nd_opt_dnssl_len
= 0;
1288 ndopt_dnssl
->nd_opt_dnssl_reserved
= 0;
1289 ndopt_dnssl
->nd_opt_dnssl_lifetime
= htonl(dnsl
->lifetime
);
1290 buf
+= sizeof(*ndopt_dnssl
);
1292 TAILQ_FOREACH(dnsd
, &dnsl
->list
, next
) {
1293 CHECKLEN(dnsd
->len
);
1294 memcpy(buf
, dnsd
->domain
, dnsd
->len
);
1297 /* Ensure our length is padded correctly */
1298 len
= buf
- (char *)ndopt_dnssl
;
1299 plen
= len
% 8 ? 8 - len
% 8 : 0;
1301 memset(buf
, 0, plen
);
1303 ndopt_dnssl
->nd_opt_dnssl_len
= (len
+ plen
) / 8;
1305 memset(buf
, 0, packlen
- (buf
- rainfo
->ra_data
));
1309 getinet6sysctl(int code
)
1311 const int mib
[] = { CTL_NET
, PF_INET6
, IPPROTO_IPV6
, code
};
1315 size
= sizeof(value
);
1316 if (sysctl(mib
, __arraycount(mib
), &value
, &size
, NULL
, 0)
1318 syslog(LOG_ERR
, "<%s>: failed to get ip6 sysctl(%d): %m",