]> git.saurik.com Git - apple/network_cmds.git/blob - rtadvd.tproj/config.c
network_cmds-543.270.1.tar.gz
[apple/network_cmds.git] / rtadvd.tproj / config.c
1 /*
2 * Copyright (c) 2009-2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /* $KAME: config.c,v 1.84 2003/08/05 12:34:23 itojun Exp $ */
30
31 /*
32 * Copyright (C) 1998 WIDE Project.
33 * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
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.
47 *
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
58 * SUCH DAMAGE.
59 */
60
61 #include <sys/param.h>
62 #include <sys/ioctl.h>
63 #include <sys/socket.h>
64 #include <sys/time.h>
65 #include <sys/sysctl.h>
66
67 #include <net/if.h>
68 #include <net/if_var.h>
69 #include <net/route.h>
70 #include <net/if_dl.h>
71
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>
78
79 #include <arpa/inet.h>
80
81 #include <stdio.h>
82 #include <errno.h>
83 #include <string.h>
84 #include <search.h>
85 #include <stdlib.h>
86 #include <unistd.h>
87 #include <ifaddrs.h>
88 #include <stddef.h>
89
90 #include "rtadvd.h"
91 #include "advcap.h"
92 #include "timer.h"
93 #include "if.h"
94 #include "config.h"
95
96 static time_t prefix_timo = (60 * 120); /* 2 hours.
97 * XXX: should be configurable. */
98 extern struct rainfo *ralist;
99
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 *);
104
105 void
106 getconfig(intface)
107 char *intface;
108 {
109 int stat, i;
110 int rdnss_length;
111 int dnssl_length;
112 char tbuf[BUFSIZ];
113 struct rainfo *rai;
114 long val;
115 int64_t val64;
116 char buf[BUFSIZ];
117 char *bp = buf;
118 char *addr, *flagstr;
119 static int forwarding = -1;
120
121 #define MUSTHAVE(var, cap) \
122 do { \
123 int64_t t; \
124 if ((t = agetnum(cap)) < 0) { \
125 fprintf(stderr, "rtadvd: need %s for interface %s\n", \
126 cap, intface); \
127 exit(1); \
128 } \
129 var = t; \
130 } while (0)
131 #define MAYHAVE(var, cap, def) \
132 do { \
133 if ((var = agetnum(cap)) < 0) \
134 var = def; \
135 } while (0)
136
137 if ((stat = agetent(tbuf, intface)) <= 0) {
138 memset(tbuf, 0, sizeof(tbuf));
139 errorlog("<%s> %s isn't defined in the configuration file"
140 " or the configuration file doesn't exist."
141 " Treat it as default",
142 __func__, intface);
143 }
144
145 ELM_MALLOC(rai, exit(1));
146 rai->prefix.next = rai->prefix.prev = &rai->prefix;
147 #ifdef ROUTEINFO
148 rai->route.next = rai->route.prev = &rai->route;
149 #endif
150 rai->rdnss_list.next = rai->rdnss_list.prev = &rai->rdnss_list;
151 rai->dnssl_list.next = rai->dnssl_list.prev = &rai->dnssl_list;
152
153 /* check if we are allowed to forward packets (if not determined) */
154 if (forwarding < 0) {
155 if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0)
156 exit(1);
157 }
158
159 /* get interface information */
160 if (agetflag("nolladdr"))
161 rai->advlinkopt = 0;
162 else
163 rai->advlinkopt = 1;
164 if (rai->advlinkopt) {
165 if ((rai->sdl = if_nametosdl(intface)) == NULL) {
166 errorlog("<%s> can't get information of %s",
167 __func__, intface);
168 exit(1);
169 }
170 rai->ifindex = rai->sdl->sdl_index;
171 } else
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);
178 }
179
180 /*
181 * set router configuration variables.
182 */
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);
188 exit(1);
189 }
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);
197 exit(1);
198 }
199 rai->mininterval = (u_int)val;
200
201 MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT);
202 rai->hoplimit = val & 0xff;
203
204 if ((flagstr = (char *)agetstr("raflags", &bp))) {
205 val = 0;
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__);
216 exit(1);
217 }
218 val |= ND_RA_FLAG_RTPREF_LOW;
219 }
220 } else {
221 MAYHAVE(val, "raflags", 0);
222 }
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 */
228 #endif
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);
233 exit(1);
234 }
235
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,
241 rai->maxinterval,
242 MAXROUTERLIFETIME);
243 exit(1);
244 }
245 /*
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)
252 */
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.",
257 __func__, intface);
258 exit(1);
259 }
260 rai->lifetime = val & 0xffff;
261
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);
267 exit(1);
268 }
269 rai->reachabletime = (u_int32_t)val;
270
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);
275 exit(1);
276 }
277 rai->retranstimer = (u_int32_t)val64;
278
279 if (agetnum("hapref") != -1 || agetnum("hatime") != -1) {
280 errorlog("<%s> mobile-ip6 configuration not supported",
281 __func__);
282 exit(1);
283 }
284 /* prefix information */
285
286 /*
287 * This is an implementation specific parameter to consider
288 * link propagation delays and poorly synchronized clocks when
289 * checking consistency of advertised lifetimes.
290 */
291 MAYHAVE(val, "clockskew", 0);
292 rai->clockskew = val;
293
294 rai->pfxs = 0;
295 for (i = -1; i < MAXPREFIX; i++) {
296 struct prefix *pfx;
297 char entbuf[256];
298
299 makeentry(entbuf, sizeof(entbuf), i, "addr");
300 addr = (char *)agetstr(entbuf, &bp);
301 if (addr == NULL)
302 continue;
303
304 /* allocate memory to store prefix information */
305 ELM_MALLOC(pfx, exit(1));
306
307 pfx->rainfo = rai;
308 pfx->origin = PREFIX_FROM_CONFIG;
309
310 if (inet_pton(AF_INET6, addr, &pfx->prefix) != 1) {
311 errorlog("<%s> inet_pton failed for %s",
312 __func__, addr);
313 exit(1);
314 }
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);
319 exit(1);
320 }
321 if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix))
322 noticelog("<%s> link-local prefix (%s) will be"
323 " advertised on %s",
324 __func__, addr, intface);
325
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);
332 exit(1);
333 }
334 pfx->prefixlen = (int)val;
335
336 makeentry(entbuf, sizeof(entbuf), i, "pinfoflags");
337 if ((flagstr = (char *)agetstr(entbuf, &bp))) {
338 val = 0;
339 if (strchr(flagstr, 'l'))
340 val |= ND_OPT_PI_FLAG_ONLINK;
341 if (strchr(flagstr, 'a'))
342 val |= ND_OPT_PI_FLAG_AUTO;
343 } else {
344 MAYHAVE(val, entbuf,
345 (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO));
346 }
347 pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK;
348 pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO;
349
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);
357 exit(1);
358 }
359 pfx->validlifetime = (u_int32_t)val64;
360
361 makeentry(entbuf, sizeof(entbuf), i, "vltimedecr");
362 if (agetflag(entbuf)) {
363 struct timeval now;
364 gettimeofday(&now, 0);
365 pfx->vltimeexpire =
366 now.tv_sec + pfx->validlifetime;
367 }
368
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 "
373 "is out of range",
374 __func__, (long long)val64,
375 addr, pfx->prefixlen, intface);
376 exit(1);
377 }
378 pfx->preflifetime = (u_int32_t)val64;
379
380 makeentry(entbuf, sizeof(entbuf), i, "pltimedecr");
381 if (agetflag(entbuf)) {
382 struct timeval now;
383 gettimeofday(&now, 0);
384 pfx->pltimeexpire =
385 now.tv_sec + pfx->preflifetime;
386 }
387 /* link into chain */
388 insque(pfx, &rai->prefix);
389 rai->pfxs++;
390 }
391 if (rai->pfxs == 0)
392 get_prefix(rai);
393
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);
398 exit(1);
399 }
400 rai->linkmtu = (u_int32_t)val;
401 if (rai->linkmtu == 0) {
402 char *mtustr;
403
404 if ((mtustr = (char *)agetstr("mtu", &bp)) &&
405 strcmp(mtustr, "auto") == 0)
406 rai->linkmtu = rai->phymtu;
407 }
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);
413 exit(1);
414 }
415
416 #ifdef SIOCSIFINFO_IN6
417 {
418 struct in6_ndireq ndi;
419 int s;
420
421 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
422 errorlog("<%s> socket: %s", __func__,
423 strerror(errno));
424 exit(1);
425 }
426 memset(&ndi, 0, sizeof(ndi));
427 strncpy(ndi.ifname, intface, IFNAMSIZ);
428 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&ndi) < 0) {
429 infolog("<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s",
430 __func__, intface, strerror(errno));
431 }
432
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));
440 }
441 close(s);
442 }
443 #endif
444
445 /* route information */
446 #ifdef ROUTEINFO
447 rai->routes = 0;
448 for (i = -1; i < MAXROUTE; i++) {
449 struct rtinfo *rti;
450 char entbuf[256], oentbuf[256];
451
452 makeentry(entbuf, sizeof(entbuf), i, "rtprefix");
453 addr = (char *)agetstr(entbuf, &bp);
454 if (addr == NULL) {
455 makeentry(oentbuf, sizeof(oentbuf), i, "rtrprefix");
456 addr = (char *)agetstr(oentbuf, &bp);
457 if (addr) {
458 fprintf(stderr, "%s was obsoleted. Use %s.\n",
459 oentbuf, entbuf);
460 }
461 }
462 if (addr == NULL)
463 continue;
464
465 /* allocate memory to store prefix information */
466 ELM_MALLOC(rti, exit(1));
467
468 /* link into chain */
469 insque(rti, &rai->route);
470 rai->routes++;
471
472 if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) {
473 errorlog( "<%s> inet_pton failed for %s",
474 __func__, addr);
475 exit(1);
476 }
477 #if 0
478 /*
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.
483 */
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);
489 exit(1);
490 }
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);
495 exit(1);
496 }
497 #endif
498
499 makeentry(entbuf, sizeof(entbuf), i, "rtplen");
500 /* XXX: 256 is a magic number for compatibility check. */
501 MAYHAVE(val, entbuf, 256);
502 if (val == 256) {
503 makeentry(oentbuf, sizeof(oentbuf), i, "rtrplen");
504 MAYHAVE(val, oentbuf, 256);
505 if (val != 256) {
506 fprintf(stderr, "%s was obsoleted. Use %s.\n",
507 oentbuf, entbuf);
508 } else
509 val = 64;
510 }
511 if (val < 0 || val > 128) {
512 errorlog("<%s> prefixlen (%ld) for %s on %s "
513 "out of range",
514 __func__, val, addr, intface);
515 exit(1);
516 }
517 rti->prefixlen = (int)val;
518
519 makeentry(entbuf, sizeof(entbuf), i, "rtflags");
520 if ((flagstr = (char *)agetstr(entbuf, &bp))) {
521 val = 0;
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)) {
526 errorlog(
527 "<%s> the \'h\' and \'l\' route"
528 " preferences are exclusive",
529 __func__);
530 exit(1);
531 }
532 val |= ND_RA_FLAG_RTPREF_LOW;
533 }
534 } else
535 MAYHAVE(val, entbuf, 256); /* XXX */
536 if (val == 256) {
537 makeentry(oentbuf, sizeof(oentbuf), i, "rtrflags");
538 MAYHAVE(val, oentbuf, 256);
539 if (val != 256) {
540 fprintf(stderr, "%s was obsoleted. Use %s.\n",
541 oentbuf, entbuf);
542 } else
543 val = 0;
544 }
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) "
548 "for %s/%d on %s",
549 __func__, rti->rtpref, addr,
550 rti->prefixlen, intface);
551 exit(1);
552 }
553
554 /*
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.
559 */
560 makeentry(entbuf, sizeof(entbuf), i, "rtltime");
561 MAYHAVE(val64, entbuf, -1);
562 if (val64 == -1) {
563 makeentry(oentbuf, sizeof(oentbuf), i, "rtrltime");
564 MAYHAVE(val64, oentbuf, -1);
565 if (val64 != -1) {
566 fprintf(stderr, "%s was obsoleted. Use %s.\n",
567 oentbuf, entbuf);
568 } else {
569 fprintf(stderr, "%s should be specified "
570 "for interface %s.\n",
571 entbuf, intface);
572 val64 = rai->lifetime;
573 }
574 }
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);
579 exit(1);
580 }
581 rti->ltime = (u_int32_t)val64;
582 }
583 #endif
584
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);
591 }
592 rai->rdnss_lifetime = val;
593 if ((rdnss_length = agetnum("rdnssaddrs")) < 0) {
594 rai->rdnss_length = 0;
595 }
596 else {
597 rai->rdnss_length = rdnss_length;
598
599 /* traverse in reverse order so that the queue has correct order */
600 for (i = (rdnss_length - 1); i >= 0; i--) {
601 struct rdnss *rdnss;
602 char entbuf[256];
603
604 /* allocate memory to store server address information */
605 ELM_MALLOC(rdnss, exit(1));
606 /* link into chain */
607 insque(rdnss, &rai->rdnss_list);
608
609 makeentry(entbuf, sizeof(entbuf), i, "rdnssaddr");
610 addr = (char *)agetstr(entbuf, &bp);
611
612 if (addr == NULL && rdnss_length == 1) {
613 makeentry(entbuf, sizeof(entbuf), -1, "rdnssaddr");
614 addr = agetstr(entbuf, &bp);
615 }
616
617 if (addr == NULL) {
618 errorlog("<%s> need %s as a DNS server address for "
619 "interface %s",
620 __func__, entbuf, intface);
621 exit(1);
622 }
623
624 if (inet_pton(AF_INET6, addr, &rdnss->addr) != 1) {
625 errorlog("<%s> inet_pton failed for %s",
626 __func__, addr);
627 exit(1);
628 }
629 if (IN6_IS_ADDR_MULTICAST(&rdnss->addr)) {
630 errorlog("<%s> multicast address (%s) must "
631 "not be advertised as recursive DNS server",
632 __func__, addr);
633 exit(1);
634 }
635 }
636 }
637
638 /* DNSSL option (RFC6106) */
639
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);
646 }
647 rai->dnssl_lifetime = val;
648 rai->dnssl_option_length = 8; /* 8 bytes for the option header */
649
650 /* Parse the DNSSL domain list from the config */
651 if ((dnssl_length = agetnum("dnssldomains")) < 0) {
652 rai->dnssl_length = 0;
653 } else {
654 rai->dnssl_length = dnssl_length;
655
656 for (i = (rai->dnssl_length - 1); i >= 0; i--) {
657 unsigned char *dnssl_buf;
658 struct dnssl *dnssl;
659 int dnssl_len;
660 char entbuf[sizeof("dnssldomain") + 20];
661 char *domain;
662 int domain_len;
663
664 makeentry(entbuf, sizeof(entbuf), i, "dnssldomain");
665 domain = agetstr(entbuf, &bp);
666
667 if (domain == NULL && rai->dnssl_length == 1) {
668 makeentry(entbuf, sizeof(entbuf), -1, "dnssldomain");
669 domain = agetstr(entbuf, &bp);
670 }
671
672 if (domain == NULL) {
673 errorlog("<%s> need %s as a DNS search domain for "
674 "interface %s",
675 __func__, entbuf, intface);
676 exit(1);
677 }
678
679 domain_len = strlen(domain);
680
681 /* Trim off leading dots */
682 while (domain_len > 0 && domain[0] == '.') {
683 domain++;
684 domain_len--;
685 }
686
687 /* Trim off trailing dots */
688 while (domain_len > 0 && domain[domain_len-1] == '.') {
689 domain_len--;
690 }
691
692 if (domain_len > 0) {
693 dnssl_len = sizeof(struct dnssl) + domain_len + 1;
694 dnssl_buf = (unsigned char *)malloc(dnssl_len);
695
696 memset(dnssl_buf, 0, dnssl_len);
697
698 dnssl = (struct dnssl *)dnssl_buf;
699 insque(dnssl, &rai->dnssl_list);
700
701 /* Copy the domain name in at the end of the dnssl struct */
702 memcpy(dnssl_buf + offsetof(struct dnssl, domain), domain,
703 domain_len);
704
705 /* Add 2 for leading length byte and the trailing 0 byte */
706 rai->dnssl_option_length += domain_len + 2;
707 }
708 }
709
710 /* Round up to the next multiple of 8 */
711 rai->dnssl_option_length += (8 - (rai->dnssl_option_length & 0x7));
712 }
713
714 /* okey */
715 rai->next = ralist;
716 ralist = rai;
717
718 /* construct the sending packet */
719 make_packet(rai);
720
721 /* set timer */
722 rai->timer = rtadvd_add_timer(ra_timeout, ra_timer_update,
723 rai, rai);
724 ra_timer_update((void *)rai, &rai->timer->tm);
725 rtadvd_set_timer(&rai->timer->tm, rai->timer);
726 }
727
728 void
729 get_prefix(struct rainfo *rai)
730 {
731 struct ifaddrs *ifap, *ifa;
732 struct prefix *pfx;
733 struct in6_addr *a;
734 u_char *p, *ep, *m, *lim;
735 char ntopbuf[INET6_ADDRSTRLEN];
736
737 if (getifaddrs(&ifap) < 0) {
738 errorlog(
739 "<%s> can't get interface addresses",
740 __func__);
741 exit(1);
742 }
743
744 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
745 int plen;
746
747 if (strcmp(ifa->ifa_name, rai->ifname) != 0)
748 continue;
749 if (ifa->ifa_addr->sa_family != AF_INET6)
750 continue;
751 a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
752 if (IN6_IS_ADDR_LINKLOCAL(a))
753 continue;
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",
761 __func__);
762 exit(1);
763 }
764 if (plen == 128) /* XXX */
765 continue;
766 if (find_prefix(rai, a, plen)) {
767 /* ignore a duplicated prefix. */
768 continue;
769 }
770
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)
779 *p++ &= *m++;
780 while (p < ep)
781 *p++ = 0x00;
782 if (!inet_ntop(AF_INET6, &pfx->prefix, ntopbuf,
783 sizeof(ntopbuf))) {
784 errorlog("<%s> inet_ntop failed", __func__);
785 exit(1);
786 }
787 debuglog("<%s> add %s/%d to prefix list on %s",
788 __func__, ntopbuf, pfx->prefixlen, rai->ifname);
789
790 /* set other fields with protocol defaults */
791 pfx->validlifetime = DEF_ADVVALIDLIFETIME;
792 pfx->preflifetime = DEF_ADVPREFERREDLIFETIME;
793 pfx->onlinkflg = 1;
794 pfx->autoconfflg = 1;
795 pfx->origin = PREFIX_FROM_KERNEL;
796 pfx->rainfo = rai;
797
798 /* link into chain */
799 insque(pfx, &rai->prefix);
800
801 /* counter increment */
802 rai->pfxs++;
803 }
804
805 freeifaddrs(ifap);
806 }
807
808 static void
809 makeentry(buf, len, id, string)
810 char *buf;
811 size_t len;
812 int id;
813 char *string;
814 {
815
816 if (id < 0)
817 strlcpy(buf, string, len);
818 else
819 snprintf(buf, len, "%s%d", string, id);
820 }
821
822 /*
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.
828 */
829 static void
830 add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr)
831 {
832 struct prefix *prefix;
833 char ntopbuf[INET6_ADDRSTRLEN];
834
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
844 insque(prefix, &rai->prefix);
845 prefix->rainfo = rai;
846
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);
851
852 /* free the previous packet */
853 free(rai->ra_data);
854 rai->ra_data = NULL;
855
856 /* reconstruct the packet */
857 rai->pfxs++;
858 make_packet(rai);
859 }
860
861 /*
862 * Delete a prefix to the list of specified interface and reconstruct
863 * the outgoing packet.
864 * The prefix must be in the list.
865 */
866 void
867 delete_prefix(struct prefix *prefix)
868 {
869 char ntopbuf[INET6_ADDRSTRLEN];
870 struct rainfo *rai = prefix->rainfo;
871
872 remque(prefix);
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);
877 if (prefix->timer)
878 rtadvd_remove_timer(&prefix->timer);
879 free(prefix);
880 rai->pfxs--;
881 }
882
883 void
884 invalidate_prefix(struct prefix *prefix)
885 {
886 char ntopbuf[INET6_ADDRSTRLEN];
887 struct timeval timo;
888 struct rainfo *rai = prefix->rainfo;
889
890 if (prefix->timer) { /* sanity check */
891 errorlog("<%s> assumption failure: timer already exists",
892 __func__);
893 exit(1);
894 }
895
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);
900
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);
907 return;
908 }
909 timo.tv_sec = prefix_timo;
910 timo.tv_usec = 0;
911 rtadvd_set_timer(&timo, prefix->timer);
912 }
913
914 static struct rtadvd_timer *
915 prefix_timeout(void *arg)
916 {
917 struct prefix *prefix = (struct prefix *)arg;
918
919 delete_prefix(prefix);
920
921 return(NULL);
922 }
923
924 void
925 update_prefix(struct prefix * prefix)
926 {
927 char ntopbuf[INET6_ADDRSTRLEN];
928 struct rainfo *rai = prefix->rainfo;
929
930 if (prefix->timer == NULL) { /* sanity check */
931 errorlog("<%s> assumption failure: timer does not exist",
932 __func__);
933 exit(1);
934 }
935
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);
939
940 /* stop the expiration timer */
941 rtadvd_remove_timer(&prefix->timer);
942 }
943
944 /*
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[].
948 */
949 static int
950 init_prefix(struct in6_prefixreq *ipr)
951 {
952 #if 0
953 int s;
954
955 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
956 errorlog("<%s> socket: %s", __func__,
957 strerror(errno));
958 exit(1);
959 }
960
961 if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) {
962 infolog("<%s> ioctl:SIOCGIFPREFIX %s", __func__,
963 strerror(errno));
964
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 */
970 }
971 else if (ipr->ipr_origin < PR_ORIG_RR) {
972 char ntopbuf[INET6_ADDRSTRLEN];
973
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);
979 close(s);
980 return 1;
981 }
982
983 close(s);
984 return 0;
985 #else
986 ipr->ipr_vltime = DEF_ADVVALIDLIFETIME;
987 ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME;
988 ipr->ipr_raf_onlink = 1;
989 ipr->ipr_raf_auto = 1;
990 return 0;
991 #endif
992 }
993
994 void
995 make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen)
996 {
997 struct in6_prefixreq ipr;
998
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));
1004 exit(1);
1005 }
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;
1010
1011 if (init_prefix(&ipr))
1012 return; /* init failed by some error */
1013 add_prefix(rai, &ipr);
1014 }
1015
1016 void
1017 make_packet(struct rainfo *rainfo)
1018 {
1019 size_t packlen, lladdroptlen = 0;
1020 u_char *buf;
1021 struct nd_router_advert *ra;
1022 struct nd_opt_prefix_info *ndopt_pi;
1023 struct nd_opt_mtu *ndopt_mtu;
1024 #ifdef ROUTEINFO
1025 struct nd_opt_route_info *ndopt_rti;
1026 struct rtinfo *rti;
1027 #endif
1028 struct prefix *pfx;
1029
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;
1038 }
1039 packlen += lladdroptlen;
1040 }
1041 if (rainfo->pfxs)
1042 packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs;
1043 if (rainfo->linkmtu)
1044 packlen += sizeof(struct nd_opt_mtu);
1045 #ifdef ROUTEINFO
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;
1049 #endif
1050 if (rainfo->rdnss_length > 0)
1051 packlen += 8 + sizeof(struct in6_addr) * rainfo->rdnss_length;
1052
1053 if (rainfo->dnssl_length > 0) {
1054 packlen += rainfo->dnssl_option_length;
1055 }
1056
1057 /* allocate memory for the packet */
1058 if ((buf = malloc(packlen)) == NULL) {
1059 errorlog("<%s> can't get enough memory for an RA packet",
1060 __func__);
1061 exit(1);
1062 }
1063 if (rainfo->ra_data) {
1064 /* free the previous packet */
1065 free(rainfo->ra_data);
1066 rainfo->ra_data = NULL;
1067 }
1068 rainfo->ra_data = buf;
1069 /* XXX: what if packlen > 576? */
1070 rainfo->ra_datalen = packlen;
1071
1072 /*
1073 * construct the packet
1074 */
1075 ra = (struct nd_router_advert *)buf;
1076 ra->nd_ra_type = ND_ROUTER_ADVERT;
1077 ra->nd_ra_code = 0;
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 */
1081 /*
1082 * XXX: the router preference field, which is a 2-bit field, should be
1083 * initialized before other fields.
1084 */
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);
1093 buf += sizeof(*ra);
1094
1095 if (rainfo->advlinkopt) {
1096 lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf);
1097 buf += lladdroptlen;
1098 }
1099
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);
1107 }
1108
1109 for (pfx = rainfo->prefix.next;
1110 pfx != &rainfo->prefix; pfx = pfx->next) {
1111 u_int32_t vltime, pltime;
1112 struct timeval now;
1113
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;
1119 if (pfx->onlinkflg)
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;
1125 if (pfx->timer)
1126 vltime = 0;
1127 else {
1128 if (pfx->vltimeexpire || pfx->pltimeexpire)
1129 gettimeofday(&now, NULL);
1130 if (pfx->vltimeexpire == 0)
1131 vltime = pfx->validlifetime;
1132 else
1133 vltime = (pfx->vltimeexpire > now.tv_sec) ?
1134 pfx->vltimeexpire - now.tv_sec : 0;
1135 }
1136 if (pfx->timer)
1137 pltime = 0;
1138 else {
1139 if (pfx->pltimeexpire == 0)
1140 pltime = pfx->preflifetime;
1141 else
1142 pltime = (pfx->pltimeexpire > now.tv_sec) ?
1143 pfx->pltimeexpire - now.tv_sec : 0;
1144 }
1145 if (vltime < pltime) {
1146 /*
1147 * this can happen if vltime is decrement but pltime
1148 * is not.
1149 */
1150 pltime = vltime;
1151 }
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;
1156
1157 buf += sizeof(struct nd_opt_prefix_info);
1158 }
1159
1160 #ifdef ROUTEINFO
1161 for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) {
1162 u_int8_t psize = (rti->prefixlen + 0x3f) >> 6;
1163
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;
1172 }
1173 #endif
1174
1175 if (rainfo->rdnss_length > 0) {
1176 struct nd_opt_rdnss * ndopt_rdnss;
1177 struct rdnss * rdnss;
1178
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);
1184 buf += 8;
1185
1186 for (rdnss = rainfo->rdnss_list.next;
1187 rdnss != &rainfo->rdnss_list;
1188 rdnss = rdnss->next)
1189 {
1190 struct in6_addr* addr6 = (struct in6_addr*) buf;
1191 *addr6 = rdnss->addr;
1192 buf += sizeof *addr6;
1193 }
1194 }
1195
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;
1201
1202 memset(cursor, 0, rainfo->dnssl_option_length);
1203
1204 dnssl_opt = (struct nd_opt_dnssl *)cursor;
1205 dnssl_opt->nd_opt_dnssl_type = ND_OPT_DNSSL;
1206 /*
1207 * Length is in units of 8 octets. Divide total byte length
1208 * of the option by 8.
1209 */
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);
1214
1215 cursor += offsetof(struct nd_opt_dnssl, nd_opt_dnssl_domains);
1216
1217 for (dnssl = rainfo->dnssl_list.next;
1218 dnssl != &rainfo->dnssl_list;
1219 dnssl = dnssl->next)
1220 {
1221 int encodeLen = encode_domain(dnssl->domain, cursor);
1222 cursor += encodeLen;
1223 domains_length += encodeLen;
1224 }
1225
1226 buf += rainfo->dnssl_option_length;
1227 }
1228
1229 return;
1230 }
1231
1232 static int
1233 getinet6sysctl(int code)
1234 {
1235 int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
1236 int value;
1237 size_t size;
1238
1239 mib[3] = code;
1240 size = sizeof(value);
1241 if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0)
1242 < 0) {
1243 errorlog( "<%s>: failed to get ip6 sysctl(%d): %s",
1244 __func__, code,
1245 strerror(errno));
1246 return(-1);
1247 }
1248 else
1249 return(value);
1250 }
1251
1252 /*
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.
1255 */
1256 int
1257 encode_domain(char *domain, u_char *dst)
1258 {
1259 char *domainCopy = strdup(domain);
1260 char *input = domainCopy;
1261 char *label;
1262 u_char *cursor = dst;
1263
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;
1268 cursor++;
1269 memcpy(cursor, label, label_len);
1270 cursor += label_len;
1271 }
1272 }
1273 *cursor = 0;
1274 cursor++;
1275
1276 free(domainCopy);
1277
1278 return (cursor - dst);
1279 }