]> git.saurik.com Git - apple/network_cmds.git/blob - rtadvd.tproj/config.c
network_cmds-356.8.tar.gz
[apple/network_cmds.git] / rtadvd.tproj / config.c
1 /*
2 * Copyright (c) 2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /* $KAME: config.c,v 1.37 2001/05/25 07:34:00 itojun Exp $ */
30
31 /*
32 * Copyright (C) 1998 WIDE Project.
33 * All rights reserved.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. Neither the name of the project nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 *
59 * $FreeBSD: src/usr.sbin/rtadvd/config.c,v 1.3.2.3 2001/07/03 11:02:14 ume Exp $
60 */
61
62 #include <sys/param.h>
63 #include <sys/ioctl.h>
64 #include <sys/socket.h>
65 #include <sys/time.h>
66 #include <sys/sysctl.h>
67
68 #include <net/if.h>
69 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
70 #include <net/if_var.h>
71 #endif /* __FreeBSD__ >= 3 */
72 #include <net/route.h>
73 #include <net/if_dl.h>
74
75 #include <netinet/in.h>
76 #include <netinet/in_var.h>
77 #include <netinet/ip6.h>
78 #include <netinet6/ip6_var.h>
79 #include <netinet/icmp6.h>
80 #ifdef MIP6
81 #include <netinet6/mip6.h>
82 #endif
83
84 #include <arpa/inet.h>
85
86 #include <stdio.h>
87 #include <syslog.h>
88 #include <errno.h>
89 #include <string.h>
90 #include <stdlib.h>
91 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
92 #include <search.h>
93 #endif
94 #include <unistd.h>
95 #include <ifaddrs.h>
96
97 #include "rtadvd.h"
98 #include "advcap.h"
99 #include "timer.h"
100 #include "if.h"
101 #include "config.h"
102
103 static void makeentry (char *, size_t, int, char *, int);
104 static void get_prefix (struct rainfo *);
105 static int getinet6sysctl (int);
106
107 extern struct rainfo *ralist;
108
109 void
110 getconfig(char *intface)
111 {
112 int stat, pfxs, i;
113 int rdnss_length;
114 char tbuf[BUFSIZ];
115 struct rainfo *tmp;
116 long val;
117 long long val64;
118 char buf[BUFSIZ];
119 char *bp = buf;
120 char *addr;
121 static int forwarding = -1;
122
123 #define MUSTHAVE(var, cap) \
124 do { \
125 int t; \
126 if ((t = agetnum(cap)) < 0) { \
127 fprintf(stderr, "rtadvd: need %s for interface %s\n", \
128 cap, intface); \
129 exit(1); \
130 } \
131 var = t; \
132 } while (0)
133 #define MAYHAVE(var, cap, def) \
134 do { \
135 if ((var = agetnum(cap)) < 0) \
136 var = def; \
137 } while (0)
138
139 if ((stat = agetent(tbuf, intface)) <= 0) {
140 memset(tbuf, 0, sizeof(tbuf));
141 syslog(LOG_INFO,
142 "<%s> %s isn't defined in the configuration file"
143 " or the configuration file doesn't exist."
144 " Treat it as default",
145 __FUNCTION__, intface);
146 }
147
148 tmp = (struct rainfo *)malloc(sizeof(*ralist));
149 memset(tmp, 0, sizeof(*tmp));
150 tmp->prefix.next = tmp->prefix.prev = &tmp->prefix;
151 tmp->route.next = tmp->route.prev = &tmp->route;
152 tmp->rdnss_list.next = tmp->rdnss_list.prev = &tmp->rdnss_list;
153
154 /* check if we are allowed to forward packets (if not determined) */
155 if (forwarding < 0) {
156 if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0)
157 exit(1);
158 }
159
160 /* get interface information */
161 if (agetflag("nolladdr"))
162 tmp->advlinkopt = 0;
163 else
164 tmp->advlinkopt = 1;
165 if (tmp->advlinkopt) {
166 if ((tmp->sdl = if_nametosdl(intface)) == NULL) {
167 syslog(LOG_ERR,
168 "<%s> can't get information of %s",
169 __FUNCTION__, intface);
170 exit(1);
171 }
172 tmp->ifindex = tmp->sdl->sdl_index;
173 } else
174 tmp->ifindex = if_nametoindex(intface);
175 strncpy(tmp->ifname, intface, sizeof(tmp->ifname));
176 if ((tmp->phymtu = if_getmtu(intface)) == 0) {
177 tmp->phymtu = IPV6_MMTU;
178 syslog(LOG_WARNING,
179 "<%s> can't get interface mtu of %s. Treat as %d",
180 __FUNCTION__, intface, IPV6_MMTU);
181 }
182
183 /*
184 * set router configuration variables.
185 */
186 MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL);
187 if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) {
188 syslog(LOG_ERR,
189 "<%s> maxinterval must be between %e and %u",
190 __FUNCTION__, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
191 exit(1);
192 }
193 tmp->maxinterval = (u_int)val;
194 MAYHAVE(val, "mininterval", tmp->maxinterval/3);
195 if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4) {
196 syslog(LOG_ERR,
197 "<%s> mininterval must be between %e and %d",
198 __FUNCTION__,
199 MIN_MININTERVAL,
200 (tmp->maxinterval * 3) / 4);
201 exit(1);
202 }
203 tmp->mininterval = (u_int)val;
204
205 MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT);
206 tmp->hoplimit = val & 0xff;
207
208 MAYHAVE(val, "raflags", 0);
209 tmp->managedflg = val & ND_RA_FLAG_MANAGED;
210 tmp->otherflg = val & ND_RA_FLAG_OTHER;
211 #ifdef MIP6
212 if (mobileip6)
213 tmp->haflg = val & ND_RA_FLAG_HA;
214 #endif
215 #ifndef ND_RA_FLAG_RTPREF_MASK
216 #define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
217 #define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */
218 #endif
219 tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
220 if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV) {
221 syslog(LOG_ERR, "<%s> invalid router preference on %s",
222 __FUNCTION__, intface);
223 exit(1);
224 }
225
226 MAYHAVE(val, "rltime", tmp->maxinterval * 3);
227 if (val && (val < tmp->maxinterval || val > MAXROUTERLIFETIME)) {
228 syslog(LOG_ERR,
229 "<%s> router lifetime on %s must be 0 or"
230 " between %d and %d",
231 __FUNCTION__, intface,
232 tmp->maxinterval, MAXROUTERLIFETIME);
233 exit(1);
234 }
235 /*
236 * Basically, hosts MUST NOT send Router Advertisement messages at any
237 * time (RFC 2461, Section 6.2.3). However, it would sometimes be
238 * useful to allow hosts to advertise some parameters such as prefix
239 * information and link MTU. Thus, we allow hosts to invoke rtadvd
240 * only when router lifetime (on every advertising interface) is
241 * explicitly set zero. (see also the above section)
242 */
243 if (val && forwarding == 0) {
244 syslog(LOG_WARNING,
245 "<%s> non zero router lifetime is specified for %s, "
246 "which must not be allowed for hosts.",
247 __FUNCTION__, intface);
248 exit(1);
249 }
250 tmp->lifetime = val & 0xffff;
251
252 MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME);
253 if (val > MAXREACHABLETIME) {
254 syslog(LOG_ERR,
255 "<%s> reachable time must be no greater than %d",
256 __FUNCTION__, MAXREACHABLETIME);
257 exit(1);
258 }
259 tmp->reachabletime = (u_int32_t)val;
260
261 MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER);
262 if (val64 < 0 || val64 > 0xffffffff) {
263 syslog(LOG_ERR,
264 "<%s> retrans time out of range", __FUNCTION__);
265 exit(1);
266 }
267 tmp->retranstimer = (u_int32_t)val64;
268
269 #ifndef MIP6
270 if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) {
271 syslog(LOG_ERR,
272 "<%s> mobile-ip6 configuration not supported",
273 __FUNCTION__);
274 exit(1);
275 }
276 #else
277 if (!mobileip6) {
278 if (agetstr("hapref", &bp) || agetstr("hatime", &bp)) {
279 syslog(LOG_ERR,
280 "<%s> mobile-ip6 configuration without "
281 "proper command line option",
282 __FUNCTION__);
283 exit(1);
284 }
285 } else {
286 tmp->hapref = 0;
287 if ((val = agetnum("hapref")) >= 0)
288 tmp->hapref = (int16_t)val;
289 if (tmp->hapref != 0) {
290 tmp->hatime = 0;
291 MUSTHAVE(val, "hatime");
292 tmp->hatime = (u_int16_t)val;
293 if (tmp->hatime <= 0) {
294 syslog(LOG_ERR,
295 "<%s> home agent lifetime must be greater than 0",
296 __FUNCTION__);
297 exit(1);
298 }
299 }
300 }
301 #endif
302
303 /* prefix information */
304
305 /*
306 * This is an implementation specific parameter to consinder
307 * link propagation delays and poorly synchronized clocks when
308 * checking consistency of advertised lifetimes.
309 */
310 MAYHAVE(val, "clockskew", 0);
311 tmp->clockskew = val;
312
313 if ((pfxs = agetnum("addrs")) < 0) {
314 /* auto configure prefix information */
315 if (agetstr("addr", &bp) || agetstr("addr1", &bp)) {
316 syslog(LOG_ERR,
317 "<%s> conflicting prefix configuration for %s: "
318 "automatic and manual config at the same time",
319 __FUNCTION__, intface);
320 exit(1);
321 }
322 get_prefix(tmp);
323 }
324 else {
325 tmp->pfxs = pfxs;
326 for (i = 0; i < pfxs; i++) {
327 struct prefix *pfx;
328 char entbuf[256];
329 int added = (pfxs > 1) ? 1 : 0;
330
331 /* allocate memory to store prefix information */
332 if ((pfx = malloc(sizeof(struct prefix))) == NULL) {
333 syslog(LOG_ERR,
334 "<%s> can't allocate enough memory",
335 __FUNCTION__);
336 exit(1);
337 }
338 memset(pfx, 0, sizeof(*pfx));
339
340 /* link into chain */
341 insque(pfx, &tmp->prefix);
342
343 pfx->origin = PREFIX_FROM_CONFIG;
344
345 makeentry(entbuf, sizeof(entbuf), i, "prefixlen", added);
346 MAYHAVE(val, entbuf, 64);
347 if (val < 0 || val > 128) {
348 syslog(LOG_ERR,
349 "<%s> prefixlen out of range",
350 __FUNCTION__);
351 exit(1);
352 }
353 pfx->prefixlen = (int)val;
354
355 makeentry(entbuf, sizeof(entbuf), i, "pinfoflags", added);
356 #ifdef MIP6
357 if (mobileip6)
358 {
359 MAYHAVE(val, entbuf,
360 (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO|
361 ND_OPT_PI_FLAG_ROUTER));
362 } else
363 #endif
364 {
365 MAYHAVE(val, entbuf,
366 (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO));
367 }
368 pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK;
369 pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO;
370 #ifdef MIP6
371 pfx->routeraddr = val & ND_OPT_PI_FLAG_ROUTER;
372 #endif
373
374 makeentry(entbuf, sizeof(entbuf), i, "vltime", added);
375 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
376 if (val64 < 0 || val64 > 0xffffffff) {
377 syslog(LOG_ERR,
378 "<%s> vltime out of range",
379 __FUNCTION__);
380 exit(1);
381 }
382 pfx->validlifetime = (u_int32_t)val64;
383
384 makeentry(entbuf, sizeof(entbuf), i, "vltimedecr", added);
385 if (agetflag(entbuf)) {
386 struct timeval now;
387 gettimeofday(&now, 0);
388 pfx->vltimeexpire =
389 now.tv_sec + pfx->validlifetime;
390 }
391
392 makeentry(entbuf, sizeof(entbuf), i, "pltime", added);
393 MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME);
394 if (val64 < 0 || val64 > 0xffffffff) {
395 syslog(LOG_ERR,
396 "<%s> pltime out of range",
397 __FUNCTION__);
398 exit(1);
399 }
400 pfx->preflifetime = (u_int32_t)val64;
401
402 makeentry(entbuf, sizeof(entbuf), i, "pltimedecr", added);
403 if (agetflag(entbuf)) {
404 struct timeval now;
405 gettimeofday(&now, 0);
406 pfx->pltimeexpire =
407 now.tv_sec + pfx->preflifetime;
408 }
409
410 makeentry(entbuf, sizeof(entbuf), i, "addr", added);
411 addr = (char *)agetstr(entbuf, &bp);
412 if (addr == NULL) {
413 syslog(LOG_ERR,
414 "<%s> need %s as an prefix for "
415 "interface %s",
416 __FUNCTION__, entbuf, intface);
417 exit(1);
418 }
419 if (inet_pton(AF_INET6, addr,
420 &pfx->prefix) != 1) {
421 syslog(LOG_ERR,
422 "<%s> inet_pton failed for %s",
423 __FUNCTION__, addr);
424 exit(1);
425 }
426 if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) {
427 syslog(LOG_ERR,
428 "<%s> multicast prefix(%s) must "
429 "not be advertised (IF=%s)",
430 __FUNCTION__, addr, intface);
431 exit(1);
432 }
433 if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix))
434 syslog(LOG_NOTICE,
435 "<%s> link-local prefix(%s) will be"
436 " advertised on %s",
437 __FUNCTION__, addr, intface);
438 }
439 }
440
441 MAYHAVE(val, "mtu", 0);
442 if (val < 0 || val > 0xffffffff) {
443 syslog(LOG_ERR,
444 "<%s> mtu out of range", __FUNCTION__);
445 exit(1);
446 }
447 tmp->linkmtu = (u_int32_t)val;
448 if (tmp->linkmtu == 0) {
449 char *mtustr;
450
451 if ((mtustr = (char *)agetstr("mtu", &bp)) &&
452 strcmp(mtustr, "auto") == 0)
453 tmp->linkmtu = tmp->phymtu;
454 }
455 else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu) {
456 syslog(LOG_ERR,
457 "<%s> advertised link mtu must be between"
458 " least MTU and physical link MTU",
459 __FUNCTION__);
460 exit(1);
461 }
462
463 /* route information */
464
465 MAYHAVE(val, "routes", 0);
466 if (val < 0 || val > 0xffffffff) {
467 syslog(LOG_ERR,
468 "<%s> number of route information improper", __FUNCTION__);
469 exit(1);
470 }
471 tmp->routes = val;
472 for (i = 0; i < tmp->routes; i++) {
473 struct rtinfo *rti;
474 char entbuf[256];
475 int added = (tmp->routes > 1) ? 1 : 0;
476
477 /* allocate memory to store prefix information */
478 if ((rti = malloc(sizeof(struct rtinfo))) == NULL) {
479 syslog(LOG_ERR,
480 "<%s> can't allocate enough memory",
481 __FUNCTION__);
482 exit(1);
483 }
484 memset(rti, 0, sizeof(*rti));
485
486 /* link into chain */
487 insque(rti, &tmp->route);
488
489 makeentry(entbuf, sizeof(entbuf), i, "rtrplen", added);
490 MAYHAVE(val, entbuf, 64);
491 if (val < 0 || val > 128) {
492 syslog(LOG_ERR,
493 "<%s> prefixlen out of range",
494 __FUNCTION__);
495 exit(1);
496 }
497 rti->prefixlen = (int)val;
498
499 makeentry(entbuf, sizeof(entbuf), i, "rtrflags", added);
500 MAYHAVE(val, entbuf, 0);
501 rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
502 if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) {
503 syslog(LOG_ERR, "<%s> invalid router preference",
504 __FUNCTION__);
505 exit(1);
506 }
507
508 makeentry(entbuf, sizeof(entbuf), i, "rtrltime", added);
509 /*
510 * XXX: since default value of route lifetime is not defined in
511 * draft-draves-route-selection-01.txt, I took the default
512 * value of valid lifetime of prefix as its default.
513 * It need be much considered.
514 */
515 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
516 if (val64 < 0 || val64 > 0xffffffff) {
517 syslog(LOG_ERR,
518 "<%s> rtrltime out of range",
519 __FUNCTION__);
520 exit(1);
521 }
522 rti->ltime = (u_int32_t)val64;
523
524 makeentry(entbuf, sizeof(entbuf), i, "rtrprefix", added);
525 addr = (char *)agetstr(entbuf, &bp);
526 if (addr == NULL) {
527 syslog(LOG_ERR,
528 "<%s> need %s as an route for "
529 "interface %s",
530 __FUNCTION__, entbuf, intface);
531 exit(1);
532 }
533 if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) {
534 syslog(LOG_ERR,
535 "<%s> inet_pton failed for %s",
536 __FUNCTION__, addr);
537 exit(1);
538 }
539 #if 0
540 /*
541 * XXX: currently there's no restriction in route information
542 * prefix according to draft-draves-route-selection-01.txt,
543 * however I think the similar restriction be necessary.
544 */
545 MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
546 if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) {
547 syslog(LOG_ERR,
548 "<%s> multicast route (%s) must "
549 "not be advertised (IF=%s)",
550 __FUNCTION__, addr, intface);
551 exit(1);
552 }
553 if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) {
554 syslog(LOG_NOTICE,
555 "<%s> link-local route (%s) must "
556 "not be advertised on %s",
557 __FUNCTION__, addr, intface);
558 exit(1);
559 }
560 #endif
561 }
562
563 /* RDNSS option (RFC5006) */
564 MAYHAVE(val, "rdnsslifetime", 2 * tmp->maxinterval);
565 if (val < tmp->maxinterval || val > (2 * tmp->maxinterval)) {
566 syslog(LOG_NOTICE,
567 "<%s> rdnsslifetime (%lu) on %s SHOULD "
568 "be between %u and %u", __FUNCTION__, val,
569 intface, tmp->maxinterval, 2 * tmp->maxinterval);
570 }
571 tmp->rdnss_lifetime = val;
572 if ((rdnss_length = agetnum("rdnssaddrs")) < 0) {
573 tmp->rdnss_length = 0;
574 }
575 else {
576 tmp->rdnss_length = rdnss_length;
577
578 /* traverse in reverse order so that the queue has correct order */
579 for (i = (rdnss_length - 1); i >= 0; i--) {
580 struct rdnss *rdnss;
581 char entbuf[256];
582 int added = (rdnss_length > 1) ? 1 : 0;
583
584 /* allocate memory to store server address information */
585 if ((rdnss = malloc(sizeof(struct rdnss))) == NULL) {
586 syslog(LOG_ERR,
587 "<%s> can't allocate enough memory",
588 __FUNCTION__);
589 exit(1);
590 }
591 memset(rdnss, 0, sizeof(*rdnss));
592
593 /* link into chain */
594 insque(rdnss, &tmp->rdnss_list);
595
596 makeentry(entbuf, sizeof(entbuf), i, "rdnssaddr", added);
597 addr = (char *)agetstr(entbuf, &bp);
598 if (addr == NULL) {
599 syslog(LOG_ERR,
600 "<%s> need %s as a DNS server address for "
601 "interface %s",
602 __FUNCTION__, entbuf, intface);
603 exit(1);
604 }
605
606 if (inet_pton(AF_INET6, addr, &rdnss->addr) != 1) {
607 syslog(LOG_ERR,
608 "<%s> inet_pton failed for %s",
609 __FUNCTION__, addr);
610 exit(1);
611 }
612 if (IN6_IS_ADDR_MULTICAST(&rdnss->addr)) {
613 syslog(LOG_ERR,
614 "<%s> multicast address (%s) must "
615 "not be advertised as recursive DNS server",
616 __FUNCTION__, addr);
617 exit(1);
618 }
619 }
620 }
621
622 /* okey */
623 tmp->next = ralist;
624 ralist = tmp;
625
626 /* construct the sending packet */
627 make_packet(tmp);
628
629 /* set timer */
630 tmp->timer = rtadvd_add_timer(ra_timeout, ra_timer_update,
631 tmp, tmp);
632 ra_timer_update((void *)tmp, &tmp->timer->tm);
633 rtadvd_set_timer(&tmp->timer->tm, tmp->timer);
634 }
635
636 static void
637 get_prefix(struct rainfo *rai)
638 {
639 struct ifaddrs *ifap, *ifa;
640 struct prefix *pp;
641 struct in6_addr *a;
642 u_char *p, *ep, *m, *lim;
643 u_char ntopbuf[INET6_ADDRSTRLEN];
644
645 if (getifaddrs(&ifap) < 0) {
646 syslog(LOG_ERR,
647 "<%s> can't get interface addresses",
648 __FUNCTION__);
649 exit(1);
650 }
651 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
652 if (strcmp(ifa->ifa_name, rai->ifname) != 0)
653 continue;
654 if (ifa->ifa_addr->sa_family != AF_INET6)
655 continue;
656 a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
657 if (IN6_IS_ADDR_LINKLOCAL(a))
658 continue;
659
660 /* allocate memory to store prefix info. */
661 if ((pp = malloc(sizeof(*pp))) == NULL) {
662 syslog(LOG_ERR,
663 "<%s> can't get allocate buffer for prefix",
664 __FUNCTION__);
665 exit(1);
666 }
667 memset(pp, 0, sizeof(*pp));
668
669 /* set prefix length */
670 m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
671 lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len;
672 pp->prefixlen = prefixlen(m, lim);
673 if (pp->prefixlen < 0 || pp->prefixlen > 128) {
674 syslog(LOG_ERR,
675 "<%s> failed to get prefixlen "
676 "or prefix is invalid",
677 __FUNCTION__);
678 exit(1);
679 }
680
681 /* set prefix, sweep bits outside of prefixlen */
682 memcpy(&pp->prefix, a, sizeof(*a));
683 p = (u_char *)&pp->prefix;
684 ep = (u_char *)(&pp->prefix + 1);
685 while (m < lim)
686 *p++ &= *m++;
687 while (p < ep)
688 *p++ = 0x00;
689
690 if (!inet_ntop(AF_INET6, &pp->prefix, (char *)ntopbuf,
691 sizeof(ntopbuf))) {
692 syslog(LOG_ERR, "<%s> inet_ntop failed", __FUNCTION__);
693 exit(1);
694 }
695 syslog(LOG_DEBUG,
696 "<%s> add %s/%d to prefix list on %s",
697 __FUNCTION__, ntopbuf, pp->prefixlen, rai->ifname);
698
699 /* set other fields with protocol defaults */
700 pp->validlifetime = DEF_ADVVALIDLIFETIME;
701 pp->preflifetime = DEF_ADVPREFERREDLIFETIME;
702 pp->onlinkflg = 1;
703 pp->autoconfflg = 1;
704 pp->origin = PREFIX_FROM_KERNEL;
705
706 /* link into chain */
707 insque(pp, &rai->prefix);
708
709 /* counter increment */
710 rai->pfxs++;
711 }
712
713 freeifaddrs(ifap);
714 }
715
716 static void
717 makeentry(char *buf, size_t len, int id, char *string, int add)
718 {
719 strlcpy(buf, string, len);
720 if (add) {
721 char *cp;
722
723 cp = (char *)index(buf, '\0');
724 cp += snprintf(cp, len - (cp - buf), "%d", id);
725 *cp = '\0';
726 }
727 }
728
729 /*
730 * Add a prefix to the list of specified interface and reconstruct
731 * the outgoing packet.
732 * The prefix must not be in the list.
733 * XXX: other parameter of the prefix(e.g. lifetime) shoule be
734 * able to be specified.
735 */
736 static void
737 add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr)
738 {
739 struct prefix *prefix;
740 u_char ntopbuf[INET6_ADDRSTRLEN];
741
742 if ((prefix = malloc(sizeof(*prefix))) == NULL) {
743 syslog(LOG_ERR, "<%s> memory allocation failed",
744 __FUNCTION__);
745 return; /* XXX: error or exit? */
746 }
747 memset(prefix, 0, sizeof(*prefix));
748 prefix->prefix = ipr->ipr_prefix.sin6_addr;
749 prefix->prefixlen = ipr->ipr_plen;
750 prefix->validlifetime = ipr->ipr_vltime;
751 prefix->preflifetime = ipr->ipr_pltime;
752 prefix->onlinkflg = ipr->ipr_raf_onlink;
753 prefix->autoconfflg = ipr->ipr_raf_auto;
754 prefix->origin = PREFIX_FROM_DYNAMIC;
755
756 insque(prefix, &rai->prefix);
757
758 syslog(LOG_DEBUG, "<%s> new prefix %s/%d was added on %s",
759 __FUNCTION__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr,
760 (char *)ntopbuf, INET6_ADDRSTRLEN),
761 ipr->ipr_plen, rai->ifname);
762
763 /* free the previous packet */
764 free(rai->ra_data);
765 rai->ra_data = NULL;
766
767 /* reconstruct the packet */
768 rai->pfxs++;
769 make_packet(rai);
770
771 /*
772 * reset the timer so that the new prefix will be advertised quickly.
773 */
774 rai->initcounter = 0;
775 ra_timer_update((void *)rai, &rai->timer->tm);
776 rtadvd_set_timer(&rai->timer->tm, rai->timer);
777 }
778
779 /*
780 * Delete a prefix to the list of specified interface and reconstruct
781 * the outgoing packet.
782 * The prefix must be in the list.
783 */
784 void
785 delete_prefix(struct rainfo *rai, struct prefix *prefix)
786 {
787 u_char ntopbuf[INET6_ADDRSTRLEN];
788
789 remque(prefix);
790 syslog(LOG_DEBUG, "<%s> prefix %s/%d was deleted on %s",
791 __FUNCTION__, inet_ntop(AF_INET6, &prefix->prefix,
792 (char *)ntopbuf, INET6_ADDRSTRLEN),
793 prefix->prefixlen, rai->ifname);
794 free(prefix);
795 rai->pfxs--;
796 make_packet(rai);
797 }
798
799 /*
800 * Try to get an in6_prefixreq contents for a prefix which matches
801 * ipr->ipr_prefix and ipr->ipr_plen and belongs to
802 * the interface whose name is ipr->ipr_name[].
803 */
804 static int
805 init_prefix(struct in6_prefixreq *ipr)
806 {
807 int s;
808
809 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
810 syslog(LOG_ERR, "<%s> socket: %s", __FUNCTION__,
811 strerror(errno));
812 exit(1);
813 }
814
815 if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) {
816 syslog(LOG_INFO, "<%s> ioctl:SIOCGIFPREFIX %s", __FUNCTION__,
817 strerror(errno));
818
819 ipr->ipr_vltime = DEF_ADVVALIDLIFETIME;
820 ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME;
821 ipr->ipr_raf_onlink = 1;
822 ipr->ipr_raf_auto = 1;
823 /* omit other field initialization */
824 }
825 else if (ipr->ipr_origin < PR_ORIG_RR) {
826 u_char ntopbuf[INET6_ADDRSTRLEN];
827
828 syslog(LOG_WARNING, "<%s> Added prefix(%s)'s origin %d is"
829 "lower than PR_ORIG_RR(router renumbering)."
830 "This should not happen if I am router", __FUNCTION__,
831 inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, (char *)ntopbuf,
832 sizeof(ntopbuf)), ipr->ipr_origin);
833 close(s);
834 return 1;
835 }
836
837 close(s);
838 return 0;
839 }
840
841 void
842 make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen)
843 {
844 struct in6_prefixreq ipr;
845
846 memset(&ipr, 0, sizeof(ipr));
847 if (if_indextoname(ifindex, ipr.ipr_name) == NULL) {
848 syslog(LOG_ERR, "<%s> Prefix added interface No.%d doesn't"
849 "exist. This should not happen! %s", __FUNCTION__,
850 ifindex, strerror(errno));
851 exit(1);
852 }
853 ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix);
854 ipr.ipr_prefix.sin6_family = AF_INET6;
855 ipr.ipr_prefix.sin6_addr = *addr;
856 ipr.ipr_plen = plen;
857
858 if (init_prefix(&ipr))
859 return; /* init failed by some error */
860 add_prefix(rai, &ipr);
861 }
862
863 void
864 make_packet(struct rainfo *rainfo)
865 {
866 size_t packlen, lladdroptlen = 0;
867 char *buf;
868 struct nd_router_advert *ra;
869 struct nd_opt_prefix_info *ndopt_pi;
870 struct nd_opt_mtu *ndopt_mtu;
871 #ifdef MIP6
872 struct nd_opt_advinterval *ndopt_advint;
873 struct nd_opt_homeagent_info *ndopt_hai;
874 #endif
875 struct nd_opt_route_info *ndopt_rti;
876 struct prefix *pfx;
877 struct rtinfo *rti;
878
879 /* calculate total length */
880 packlen = sizeof(struct nd_router_advert);
881 if (rainfo->advlinkopt) {
882 if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) {
883 syslog(LOG_INFO,
884 "<%s> link-layer address option has"
885 " null length on %s."
886 " Treat as not included.",
887 __FUNCTION__, rainfo->ifname);
888 rainfo->advlinkopt = 0;
889 }
890 packlen += lladdroptlen;
891 }
892 if (rainfo->pfxs)
893 packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs;
894 if (rainfo->linkmtu)
895 packlen += sizeof(struct nd_opt_mtu);
896 #ifdef MIP6
897 if (mobileip6 && rainfo->maxinterval)
898 packlen += sizeof(struct nd_opt_advinterval);
899 if (mobileip6 && rainfo->hatime)
900 packlen += sizeof(struct nd_opt_homeagent_info);
901 #endif
902 #ifdef ND_OPT_ROUTE_INFO
903 for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next)
904 packlen += sizeof(struct nd_opt_route_info) +
905 ((rti->prefixlen + 0x3f) >> 6) * 8;
906 #endif
907 if (rainfo->rdnss_length > 0)
908 packlen += 8 + sizeof(struct in6_addr) * rainfo->rdnss_length;
909
910 /* allocate memory for the packet */
911 if ((buf = malloc(packlen)) == NULL) {
912 syslog(LOG_ERR,
913 "<%s> can't get enough memory for an RA packet",
914 __FUNCTION__);
915 exit(1);
916 }
917 if (rainfo->ra_data) {
918 /* free the previous packet */
919 free(rainfo->ra_data);
920 rainfo->ra_data = NULL;
921 }
922 rainfo->ra_data = (u_char *)buf;
923 /* XXX: what if packlen > 576? */
924 rainfo->ra_datalen = packlen;
925
926 /*
927 * construct the packet
928 */
929 ra = (struct nd_router_advert *)buf;
930 ra->nd_ra_type = ND_ROUTER_ADVERT;
931 ra->nd_ra_code = 0;
932 ra->nd_ra_cksum = 0;
933 ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit);
934 ra->nd_ra_flags_reserved = 0; /* just in case */
935 /*
936 * XXX: the router preference field, which is a 2-bit field, should be
937 * initialized before other fields.
938 */
939 ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref;
940 ra->nd_ra_flags_reserved |=
941 rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0;
942 ra->nd_ra_flags_reserved |=
943 rainfo->otherflg ? ND_RA_FLAG_OTHER : 0;
944 #ifdef MIP6
945 ra->nd_ra_flags_reserved |=
946 rainfo->haflg ? ND_RA_FLAG_HA : 0;
947 #endif
948 ra->nd_ra_router_lifetime = htons(rainfo->lifetime);
949 ra->nd_ra_reachable = htonl(rainfo->reachabletime);
950 ra->nd_ra_retransmit = htonl(rainfo->retranstimer);
951 buf += sizeof(*ra);
952
953 if (rainfo->advlinkopt) {
954 lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf);
955 buf += lladdroptlen;
956 }
957
958 if (rainfo->linkmtu) {
959 ndopt_mtu = (struct nd_opt_mtu *)buf;
960 ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU;
961 ndopt_mtu->nd_opt_mtu_len = 1;
962 ndopt_mtu->nd_opt_mtu_reserved = 0;
963 ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu);
964 buf += sizeof(struct nd_opt_mtu);
965 }
966
967 #ifdef MIP6
968 if (mobileip6 && rainfo->maxinterval) {
969 ndopt_advint = (struct nd_opt_advinterval *)buf;
970 ndopt_advint->nd_opt_adv_type = ND_OPT_ADVINTERVAL;
971 ndopt_advint->nd_opt_adv_len = 1;
972 ndopt_advint->nd_opt_adv_reserved = 0;
973 ndopt_advint->nd_opt_adv_interval = htonl(rainfo->maxinterval *
974 1000);
975 buf += sizeof(struct nd_opt_advinterval);
976 }
977 #endif
978
979 #ifdef MIP6
980 if (rainfo->hatime) {
981 ndopt_hai = (struct nd_opt_homeagent_info *)buf;
982 ndopt_hai->nd_opt_hai_type = ND_OPT_HOMEAGENT_INFO;
983 ndopt_hai->nd_opt_hai_len = 1;
984 ndopt_hai->nd_opt_hai_reserved = 0;
985 ndopt_hai->nd_opt_hai_preference = htons(rainfo->hapref);
986 ndopt_hai->nd_opt_hai_lifetime = htons(rainfo->hatime);
987 buf += sizeof(struct nd_opt_homeagent_info);
988 }
989 #endif
990
991 for (pfx = rainfo->prefix.next;
992 pfx != &rainfo->prefix; pfx = pfx->next) {
993 u_int32_t vltime, pltime;
994 struct timeval now;
995
996 ndopt_pi = (struct nd_opt_prefix_info *)buf;
997 ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
998 ndopt_pi->nd_opt_pi_len = 4;
999 ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen;
1000 ndopt_pi->nd_opt_pi_flags_reserved = 0;
1001 if (pfx->onlinkflg)
1002 ndopt_pi->nd_opt_pi_flags_reserved |=
1003 ND_OPT_PI_FLAG_ONLINK;
1004 if (pfx->autoconfflg)
1005 ndopt_pi->nd_opt_pi_flags_reserved |=
1006 ND_OPT_PI_FLAG_AUTO;
1007 #ifdef MIP6
1008 if (pfx->routeraddr)
1009 ndopt_pi->nd_opt_pi_flags_reserved |=
1010 ND_OPT_PI_FLAG_ROUTER;
1011 #endif
1012 if (pfx->vltimeexpire || pfx->pltimeexpire)
1013 gettimeofday(&now, NULL);
1014 if (pfx->vltimeexpire == 0)
1015 vltime = pfx->validlifetime;
1016 else
1017 vltime = (pfx->vltimeexpire > now.tv_sec) ?
1018 pfx->vltimeexpire - now.tv_sec : 0;
1019 if (pfx->pltimeexpire == 0)
1020 pltime = pfx->preflifetime;
1021 else
1022 pltime = (pfx->pltimeexpire > now.tv_sec) ?
1023 pfx->pltimeexpire - now.tv_sec : 0;
1024 if (vltime < pltime) {
1025 /*
1026 * this can happen if vltime is decrement but pltime
1027 * is not.
1028 */
1029 pltime = vltime;
1030 }
1031 ndopt_pi->nd_opt_pi_valid_time = htonl(vltime);
1032 ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime);
1033 ndopt_pi->nd_opt_pi_reserved2 = 0;
1034 ndopt_pi->nd_opt_pi_prefix = pfx->prefix;
1035
1036 buf += sizeof(struct nd_opt_prefix_info);
1037 }
1038
1039 #ifdef ND_OPT_ROUTE_INFO
1040 for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) {
1041 u_int8_t psize = (rti->prefixlen + 0x3f) >> 6;
1042
1043 ndopt_rti = (struct nd_opt_route_info *)buf;
1044 ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO;
1045 ndopt_rti->nd_opt_rti_len = 1 + psize;
1046 ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen;
1047 ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref;
1048 ndopt_rti->nd_opt_rti_lifetime = rti->ltime;
1049 memcpy(ndopt_rti + 1, &rti->prefix, psize * 8);
1050 buf += sizeof(struct nd_opt_route_info) + psize * 8;
1051 }
1052 #endif
1053
1054 if (rainfo->rdnss_length > 0) {
1055 struct nd_opt_rdnss * ndopt_rdnss;
1056 struct rdnss * rdnss;
1057
1058 ndopt_rdnss = (struct nd_opt_rdnss*) buf;
1059 ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
1060 ndopt_rdnss->nd_opt_rdnss_len = 1 + (rainfo->rdnss_length * 2);
1061 ndopt_rdnss->nd_opt_rdnss_reserved = 0;
1062 ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rainfo->rdnss_lifetime);
1063 buf += 8;
1064
1065 for (rdnss = rainfo->rdnss_list.next;
1066 rdnss != &rainfo->rdnss_list;
1067 rdnss = rdnss->next)
1068 {
1069 struct in6_addr* addr6 = (struct in6_addr*) buf;
1070 *addr6 = rdnss->addr;
1071 buf += sizeof *addr6;
1072 }
1073 }
1074
1075 return;
1076 }
1077
1078 static int
1079 getinet6sysctl(int code)
1080 {
1081 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
1082 int value;
1083 size_t size;
1084
1085 mib[3] = code;
1086 size = sizeof(value);
1087 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0)
1088 < 0) {
1089 syslog(LOG_ERR, "<%s>: failed to get ip6 sysctl(%d): %s",
1090 __FUNCTION__, code,
1091 strerror(errno));
1092 return(-1);
1093 }
1094 else
1095 return(value);
1096 }