GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/rtadvd/config.c Lines: 0 435 0.0 %
Date: 2017-11-07 Branches: 0 240 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: config.c,v 1.62 2017/08/08 09:03:02 jca Exp $	*/
2
/*	$KAME: config.c,v 1.62 2002/05/29 10:13:10 itojun Exp $	*/
3
4
/*
5
 * Copyright (C) 1998 WIDE Project.
6
 * All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
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.
19
 *
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
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/ioctl.h>
34
#include <sys/socket.h>
35
#include <sys/time.h>
36
#include <sys/sysctl.h>
37
#include <sys/queue.h>
38
39
#include <net/if.h>
40
#include <net/route.h>
41
#include <net/if_dl.h>
42
43
#include <netinet/in.h>
44
#include <netinet6/in6_var.h>
45
#include <netinet/ip6.h>
46
#include <netinet6/ip6_var.h>
47
#include <netinet/icmp6.h>
48
49
#include <arpa/inet.h>
50
51
#include <stdio.h>
52
#include <errno.h>
53
#include <string.h>
54
#include <stdlib.h>
55
#include <unistd.h>
56
#include <ifaddrs.h>
57
#include <stdint.h>
58
#include <event.h>
59
60
#include "rtadvd.h"
61
#include "advcap.h"
62
#include "if.h"
63
#include "config.h"
64
#include "log.h"
65
66
static void makeentry(char *, size_t, int, char *);
67
static int getinet6sysctl(int);
68
69
extern struct ralist ralist;
70
71
void
72
getconfig(char *intface)
73
{
74
	int stat, i;
75
	char tbuf[BUFSIZ];
76
	struct rainfo *tmp;
77
	long val;
78
	int64_t val64;
79
	char buf[BUFSIZ];
80
	char *bp = buf;
81
	char *addr;
82
	static int forwarding = -1;
83
84
#define MUSTHAVE(var, cap)	\
85
    do {								\
86
	int64_t t;							\
87
	if ((t = agetnum(cap)) < 0) {					\
88
		fatalx("need %s for interface %s",			\
89
			cap, intface);					\
90
	}								\
91
	var = t;							\
92
     } while (0)
93
#define MAYHAVE(var, cap, def)	\
94
     do {								\
95
	if ((var = agetnum(cap)) < 0)					\
96
		var = def;						\
97
     } while (0)
98
99
	if ((stat = agetent(tbuf, intface)) <= 0) {
100
		memset(tbuf, 0, sizeof(tbuf));
101
		log_info("Could not parse configuration file for %s"
102
		    " or the configuration file doesn't exist."
103
		    " Treat it as default", intface);
104
	}
105
106
	if ((tmp = calloc(1, sizeof(*tmp))) == NULL)
107
		fatal(NULL);
108
109
	TAILQ_INIT(&tmp->prefixes);
110
	TAILQ_INIT(&tmp->rtinfos);
111
	TAILQ_INIT(&tmp->rdnsss);
112
	TAILQ_INIT(&tmp->dnssls);
113
114
	/* check if we are allowed to forward packets (if not determined) */
115
	if (forwarding < 0) {
116
		if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0)
117
			exit(1);
118
	}
119
120
	/* make sure that the user-specified interface name fits */
121
	if (strlcpy(tmp->ifname, intface,
122
	    sizeof(tmp->ifname)) >= sizeof(tmp->ifname))
123
		fatalx("invalid interface name");
124
125
	/* get interface information */
126
	if (agetflag("nolladdr"))
127
		tmp->advlinkopt = 0;
128
	else
129
		tmp->advlinkopt = 1;
130
	if (tmp->advlinkopt) {
131
		if ((tmp->sdl = if_nametosdl(intface)) == NULL)
132
			fatalx("can't get information of %s", intface);
133
134
		tmp->ifindex = tmp->sdl->sdl_index;
135
	} else
136
		tmp->ifindex = if_nametoindex(intface);
137
	if ((tmp->phymtu = if_getmtu(intface)) == 0) {
138
		tmp->phymtu = IPV6_MMTU;
139
		log_warn("can't get interface mtu of %s. Treat as %d",
140
		    intface, IPV6_MMTU);
141
	}
142
143
	/*
144
	 * set router configuration variables.
145
	 */
146
	MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL);
147
	if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL)
148
		fatalx("maxinterval (%ld) on %s is invalid "
149
		    "(must be between %u and %u)", val,
150
		    intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
151
152
	tmp->maxinterval = (u_int)val;
153
	MAYHAVE(val, "mininterval", tmp->maxinterval/3);
154
	if (val < MIN_MININTERVAL || val > (tmp->maxinterval * 3) / 4)
155
		fatalx("mininterval (%ld) on %s is invalid "
156
		    "(must be between %u and %u)",
157
		    val, intface, MIN_MININTERVAL, (tmp->maxinterval * 3) / 4);
158
159
	tmp->mininterval = (u_int)val;
160
161
	MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT);
162
	tmp->hoplimit = val & 0xff;
163
164
	MAYHAVE(val, "raflags", 0);
165
	tmp->managedflg = val & ND_RA_FLAG_MANAGED;
166
	tmp->otherflg = val & ND_RA_FLAG_OTHER;
167
	tmp->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
168
	if (tmp->rtpref == ND_RA_FLAG_RTPREF_RSV)
169
		fatalx("invalid router preference (%02x) on %s",
170
		    tmp->rtpref, intface);
171
172
	MAYHAVE(val, "rltime", tmp->maxinterval * 3);
173
	if (val && (val < tmp->maxinterval || val > MAX_ROUTERLIFETIME))
174
		fatalx("router lifetime (%ld) on %s is invalid "
175
		    "(must be 0 or between %d and %d)",
176
		    val, intface,
177
		    tmp->maxinterval, MAX_ROUTERLIFETIME);
178
179
	/*
180
	 * Basically, hosts MUST NOT send Router Advertisement messages at any
181
	 * time (RFC 2461, Section 6.2.3). However, it would sometimes be
182
	 * useful to allow hosts to advertise some parameters such as prefix
183
	 * information and link MTU. Thus, we allow hosts to invoke rtadvd
184
	 * only when router lifetime (on every advertising interface) is
185
	 * explicitely set to zero. (see also the above section)
186
	 */
187
	if (val && forwarding == 0)
188
		fatalx("non zero router lifetime is specified for %s, "
189
		    "which must not be allowed for hosts.  you must "
190
		    "change router lifetime or enable IPv6 forwarding.",
191
		    intface);
192
193
	tmp->lifetime = val & 0xffff;
194
195
	MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME);
196
	if (val < 0 || val > MAX_REACHABLETIME)
197
		log_warnx("reachable time (%ld) on %s is invalid"
198
		    " (must be no greater than %d)",
199
		    val, intface, MAX_REACHABLETIME);
200
201
	tmp->reachabletime = (u_int32_t)val;
202
203
	MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER);
204
	if (val64 < 0 || val64 > 0xffffffff)
205
		fatalx("retrans time (%lld) on %s out of range",
206
		    (long long)val64, intface);
207
208
	tmp->retranstimer = (u_int32_t)val64;
209
210
	if (agetnum("hapref") != -1 || agetnum("hatime") != -1)
211
		fatalx("mobile-ip6 configuration not supported");
212
213
	/* prefix information */
214
215
	/*
216
	 * This is an implementation specific parameter to consider
217
	 * link propagation delays and poorly synchronized clocks when
218
	 * checking consistency of advertised lifetimes.
219
	 */
220
	MAYHAVE(val, "clockskew", 0);
221
	tmp->clockskew = val;
222
223
	tmp->pfxs = 0;
224
	for (i = -1; i < MAXPREFIX; i++) {
225
		struct prefix *pfx;
226
		char entbuf[256];
227
228
		makeentry(entbuf, sizeof(entbuf), i, "addr");
229
		addr = agetstr(entbuf, &bp);
230
		if (addr == NULL)
231
			continue;
232
233
		/* allocate memory to store prefix information */
234
		if ((pfx = calloc(1, sizeof(*pfx))) == NULL)
235
			fatal(NULL);
236
237
		/* link into chain */
238
		TAILQ_INSERT_TAIL(&tmp->prefixes, pfx, entry);
239
		tmp->pfxs++;
240
241
		pfx->origin = PREFIX_FROM_CONFIG;
242
243
		if (inet_pton(AF_INET6, addr, &pfx->prefix) != 1)
244
			fatal("inet_pton failed for %s", addr);
245
246
		if (IN6_IS_ADDR_MULTICAST(&pfx->prefix))
247
			fatalx("multicast prefix (%s) must"
248
			    " not be advertised on %s",
249
			    addr, intface);
250
251
		if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix))
252
			log_info("link-local prefix (%s) will be"
253
			    " advertised on %s",
254
			    addr, intface);
255
256
		makeentry(entbuf, sizeof(entbuf), i, "prefixlen");
257
		MAYHAVE(val, entbuf, 64);
258
		if (val < 0 || val > 128)
259
			fatalx("prefixlen (%ld) for %s "
260
                            "on %s out of range",
261
			    val, addr, intface);
262
263
		pfx->prefixlen = (int)val;
264
265
		makeentry(entbuf, sizeof(entbuf), i, "pinfoflags");
266
		MAYHAVE(val, entbuf,
267
			(ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO));
268
		pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK;
269
		pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO;
270
271
		makeentry(entbuf, sizeof(entbuf), i, "vltime");
272
		MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
273
		if (val64 < 0 || val64 > 0xffffffff)
274
			fatalx("vltime (%lld) for"
275
			    " %s/%d on %s is out of range",
276
			    (long long)val64,
277
			    addr, pfx->prefixlen, intface);
278
279
		pfx->validlifetime = (u_int32_t)val64;
280
281
		makeentry(entbuf, sizeof(entbuf), i, "vltimedecr");
282
		if (agetflag(entbuf)) {
283
			struct timeval now;
284
			gettimeofday(&now, 0);
285
			pfx->vltimeexpire =
286
				now.tv_sec + pfx->validlifetime;
287
		}
288
289
		makeentry(entbuf, sizeof(entbuf), i, "pltime");
290
		MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME);
291
		if (val64 < 0 || val64 > 0xffffffff)
292
			fatalx("pltime (%lld) for %s/%d on %s"
293
			    " is out of range",
294
			    (long long)val64,
295
			    addr, pfx->prefixlen, intface);
296
297
		pfx->preflifetime = (u_int32_t)val64;
298
299
		makeentry(entbuf, sizeof(entbuf), i, "pltimedecr");
300
		if (agetflag(entbuf)) {
301
			struct timeval now;
302
			gettimeofday(&now, 0);
303
			pfx->pltimeexpire =
304
				now.tv_sec + pfx->preflifetime;
305
		}
306
	}
307
	if (tmp->pfxs == 0 && !agetflag("noifprefix"))
308
		get_prefix(tmp);
309
310
	for (i = -1; i < MAXRTINFO; i++) {
311
		struct rtinfo *rti;
312
		char entbuf[256];
313
		const char *flagstr;
314
315
		makeentry(entbuf, sizeof(entbuf), i, "rtprefix");
316
		addr = agetstr(entbuf, &bp);
317
		if (addr == NULL)
318
			continue;
319
320
		rti = malloc(sizeof(struct rtinfo));
321
		if (rti == NULL)
322
			fatal(NULL);
323
324
		if (inet_pton(AF_INET6, addr, &rti->prefix) != 1)
325
			fatal("inet_pton failed for %s", addr);
326
327
		makeentry(entbuf, sizeof(entbuf), i, "rtplen");
328
		MAYHAVE(val, entbuf, 64);
329
		if (val < 0 || val > 128)
330
			fatalx("route prefixlen (%ld) for %s "
331
                            "on %s out of range",
332
			    val, addr, intface);
333
334
		rti->prefixlen = (int)val;
335
336
		makeentry(entbuf, sizeof(entbuf), i, "rtflags");
337
		if ((flagstr = agetstr(entbuf, &bp))) {
338
			val = 0;
339
			if (strchr(flagstr, 'h'))
340
				val |= ND_RA_FLAG_RTPREF_HIGH;
341
			if (strchr(flagstr, 'l')) {
342
				if (val & ND_RA_FLAG_RTPREF_HIGH)
343
					fatalx("the \'h\' and \'l\'"
344
					    " route preferences are"
345
					    " exclusive");
346
347
				val |= ND_RA_FLAG_RTPREF_LOW;
348
			}
349
		} else
350
			MAYHAVE(val, entbuf, 0);
351
352
		rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
353
		if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV)
354
			fatalx("invalid route preference (%02x)"
355
			    " for %s/%d on %s",
356
			    rti->rtpref, addr, rti->prefixlen, intface);
357
358
		makeentry(entbuf, sizeof(entbuf), i, "rtltime");
359
		MAYHAVE(val64, entbuf, -1);
360
		if (val64 == -1)
361
			val64 = tmp->lifetime;
362
		if (val64 < 0 || val64 >= 0xffffffff)
363
			fatalx("route lifetime (%d) "
364
			    " for %s/%d on %s out of range",
365
			    rti->rtpref, addr, rti->prefixlen, intface);
366
367
		rti->lifetime = (uint32_t)val64;
368
369
		TAILQ_INSERT_TAIL(&tmp->rtinfos, rti, entry);
370
	}
371
372
	for (i = -1; i < MAXRDNSS; ++i) {
373
		struct rdnss *rds;
374
		char entbuf[256];
375
		char *tmpaddr;
376
377
		makeentry(entbuf, sizeof(entbuf), i, "rdnss");
378
		addr = agetstr(entbuf, &bp);
379
		if (addr == NULL)
380
			continue;
381
382
		/* servers are separated by commas in the config file */
383
		val = 1;
384
		tmpaddr = addr;
385
		while (*tmpaddr++)
386
			if (*tmpaddr == ',')
387
				++val;
388
389
		rds = malloc(sizeof(struct rdnss) + val * sizeof(struct in6_addr));
390
		if (rds == NULL)
391
			fatal(NULL);
392
393
		TAILQ_INSERT_TAIL(&tmp->rdnsss, rds, entry);
394
395
		rds->servercnt = val;
396
397
		makeentry(entbuf, sizeof(entbuf), i, "rdnssltime");
398
		MAYHAVE(val, entbuf, (tmp->maxinterval * 3) / 2);
399
		if (val < tmp->maxinterval || val > tmp->maxinterval * 2) {
400
			log_warnx("%s (%ld) on %s is invalid "
401
			    "(should be between %d and %d)",
402
			    entbuf, val, intface, tmp->maxinterval,
403
			    tmp->maxinterval * 2);
404
		}
405
		rds->lifetime = val;
406
407
		val = 0;
408
		while ((tmpaddr = strsep(&addr, ","))) {
409
			if (inet_pton(AF_INET6, tmpaddr, &rds->servers[val]) !=
410
			    1)
411
				fatal("inet_pton failed for %s", tmpaddr);
412
413
			val++;
414
		}
415
	}
416
417
	for (i = -1; i < MAXDNSSL; ++i) {
418
		struct dnssl *dsl;
419
		char entbuf[256];
420
		char *tmpsl;
421
422
		makeentry(entbuf, sizeof(entbuf), i, "dnssl");
423
		addr = agetstr(entbuf, &bp);
424
		if (addr == NULL)
425
			continue;
426
427
		dsl = malloc(sizeof(struct dnssl));
428
		if (dsl == NULL)
429
			fatal(NULL);
430
431
		TAILQ_INIT(&dsl->dnssldoms);
432
433
		while ((tmpsl = strsep(&addr, ","))) {
434
			struct dnssldom *dnsd;
435
			size_t len;
436
437
			len = strlen(tmpsl);
438
439
			/* if the domain is not "dot-terminated", add it */
440
			if (tmpsl[len - 1] != '.')
441
				len += 1;
442
443
			dnsd = malloc(sizeof(struct dnssldom) + len + 1);
444
			if (dnsd == NULL)
445
				fatal(NULL);
446
447
			dnsd->length = len;
448
			strlcpy(dnsd->domain, tmpsl, len + 1);
449
			dnsd->domain[len - 1] = '.';
450
			dnsd->domain[len] = '\0';
451
452
			TAILQ_INSERT_TAIL(&dsl->dnssldoms, dnsd, entry);
453
		}
454
455
		TAILQ_INSERT_TAIL(&tmp->dnssls, dsl, entry);
456
457
		makeentry(entbuf, sizeof(entbuf), i, "dnsslltime");
458
		MAYHAVE(val, entbuf, (tmp->maxinterval * 3) / 2);
459
		if (val < tmp->maxinterval || val > tmp->maxinterval * 2) {
460
			log_warnx("%s (%ld) on %s is invalid "
461
			    "(should be between %d and %d)",
462
			    entbuf, val, intface, tmp->maxinterval,
463
			    tmp->maxinterval * 2);
464
		}
465
		dsl->lifetime = val;
466
	}
467
468
	MAYHAVE(val, "mtu", 0);
469
	if (val < 0 || val > 0xffffffff)
470
		fatalx("mtu (%ld) on %s out of range", val, intface);
471
472
	tmp->linkmtu = (u_int32_t)val;
473
	if (tmp->linkmtu == 0) {
474
		char *mtustr;
475
476
		if ((mtustr = agetstr("mtu", &bp)) &&
477
		    strcmp(mtustr, "auto") == 0)
478
			tmp->linkmtu = tmp->phymtu;
479
	} else if (tmp->linkmtu < IPV6_MMTU || tmp->linkmtu > tmp->phymtu)
480
		fatalx("advertised link mtu (%u) on %s is invalid (must"
481
		    " be between least MTU (%d) and physical link MTU (%d)",
482
		    tmp->linkmtu, intface, IPV6_MMTU, tmp->phymtu);
483
484
	/* route information */
485
	MAYHAVE(val, "routes", -1);
486
	if (val != -1)
487
		log_info("route information option is not available");
488
489
	/* okey */
490
	SLIST_INSERT_HEAD(&ralist, tmp, entry);
491
492
	/* construct the sending packet */
493
	make_packet(tmp);
494
495
	/* set timer */
496
	ra_timer_update(tmp);
497
}
498
499
void
500
get_prefix(struct rainfo *rai)
501
{
502
	struct ifaddrs *ifap, *ifa;
503
	struct prefix *pp;
504
	struct in6_addr *a;
505
	u_char *p, *ep, *m, *lim;
506
	u_char ntopbuf[INET6_ADDRSTRLEN];
507
508
	if (getifaddrs(&ifap) < 0)
509
		fatal("can't get interface addresses");
510
511
	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
512
		int plen;
513
514
		if (strcmp(ifa->ifa_name, rai->ifname) != 0)
515
			continue;
516
		if (ifa->ifa_addr->sa_family != AF_INET6)
517
			continue;
518
		a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
519
		if (IN6_IS_ADDR_LINKLOCAL(a))
520
			continue;
521
		/* get prefix length */
522
		m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
523
		lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len;
524
		plen = prefixlen(m, lim);
525
		if (plen <= 0 || plen > 128)
526
			fatalx("failed to get prefixlen or prefix is invalid");
527
		if (plen == 128)	/* XXX */
528
			continue;
529
		if (find_prefix(rai, a, plen)) {
530
			/* ignore a duplicated prefix. */
531
			continue;
532
		}
533
534
		/* allocate memory to store prefix info. */
535
		if ((pp = calloc(1, sizeof(*pp))) == NULL)
536
			fatal(NULL);
537
538
		/* set prefix, sweep bits outside of prefixlen */
539
		pp->prefixlen = plen;
540
		memcpy(&pp->prefix, a, sizeof(*a));
541
		if (1)
542
		{
543
			p = (u_char *)&pp->prefix;
544
			ep = (u_char *)(&pp->prefix + 1);
545
			while (m < lim && p < ep)
546
				*p++ &= *m++;
547
			while (p < ep)
548
				*p++ = 0x00;
549
		}
550
	        if (!inet_ntop(AF_INET6, &pp->prefix, ntopbuf,
551
	            sizeof(ntopbuf)))
552
			fatal("inet_ntop failed");
553
		log_debug("add %s/%d to prefix list on %s",
554
		    ntopbuf, pp->prefixlen, rai->ifname);
555
556
		/* set other fields with protocol defaults */
557
		pp->validlifetime = DEF_ADVVALIDLIFETIME;
558
		pp->preflifetime = DEF_ADVPREFERREDLIFETIME;
559
		pp->onlinkflg = 1;
560
		pp->autoconfflg = 1;
561
		pp->origin = PREFIX_FROM_KERNEL;
562
563
		/* link into chain */
564
		TAILQ_INSERT_TAIL(&rai->prefixes, pp, entry);
565
566
		/* counter increment */
567
		rai->pfxs++;
568
	}
569
570
	freeifaddrs(ifap);
571
}
572
573
static void
574
makeentry(char *buf, size_t len, int id, char *string)
575
{
576
577
	if (id < 0)
578
		strlcpy(buf, string, len);
579
	else
580
		snprintf(buf, len, "%s%d", string, id);
581
}
582
583
/*
584
 * Add a prefix to the list of specified interface and reconstruct
585
 * the outgoing packet.
586
 * The prefix must not be in the list.
587
 * XXX: other parameters of the prefix (e.g. lifetime) ought
588
 * to be specified.
589
 */
590
void
591
make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen)
592
{
593
	struct prefix *prefix;
594
	u_char ntopbuf[INET6_ADDRSTRLEN];
595
596
	if ((prefix = calloc(1, sizeof(*prefix))) == NULL) {
597
		log_warn(NULL);
598
		return;		/* XXX: error or exit? */
599
	}
600
	prefix->prefix = *addr;
601
	prefix->prefixlen = plen;
602
	prefix->validlifetime = DEF_ADVVALIDLIFETIME;
603
	prefix->preflifetime = DEF_ADVPREFERREDLIFETIME;
604
	prefix->onlinkflg = 1;
605
	prefix->autoconfflg = 1;
606
	prefix->origin = PREFIX_FROM_DYNAMIC;
607
608
	TAILQ_INSERT_TAIL(&rai->prefixes, prefix, entry);
609
610
	log_debug("new prefix %s/%d was added on %s",
611
	    inet_ntop(AF_INET6, &prefix->prefix,
612
	       ntopbuf, INET6_ADDRSTRLEN),
613
	    prefix->prefixlen, rai->ifname);
614
615
	/* free the previous packet */
616
	free(rai->ra_data);
617
	rai->ra_data = NULL;
618
619
	/* reconstruct the packet */
620
	rai->pfxs++;
621
	make_packet(rai);
622
623
	/*
624
	 * reset the timer so that the new prefix will be advertised quickly.
625
	 */
626
	rai->initcounter = 0;
627
	ra_timer_update(rai);
628
	evtimer_add(&rai->timer.ev, &rai->timer.tm);
629
}
630
631
/*
632
 * Delete a prefix to the list of specified interface and reconstruct
633
 * the outgoing packet.
634
 * The prefix must be in the list.
635
 */
636
void
637
delete_prefix(struct rainfo *rai, struct prefix *prefix)
638
{
639
	u_char ntopbuf[INET6_ADDRSTRLEN];
640
641
	TAILQ_REMOVE(&rai->prefixes, prefix, entry);
642
	log_debug("prefix %s/%d was deleted on %s",
643
	    inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, INET6_ADDRSTRLEN),
644
	    prefix->prefixlen, rai->ifname);
645
	free(prefix);
646
	rai->pfxs--;
647
	make_packet(rai);
648
}
649
650
void
651
make_packet(struct rainfo *rainfo)
652
{
653
	size_t packlen, lladdroptlen = 0;
654
	char *buf;
655
	struct nd_router_advert *ra;
656
	struct nd_opt_prefix_info *ndopt_pi;
657
	struct nd_opt_mtu *ndopt_mtu;
658
	struct nd_opt_route_info *ndopt_rti;
659
	struct nd_opt_rdnss *ndopt_rdnss;
660
	struct nd_opt_dnssl *ndopt_dnssl;
661
	struct prefix *pfx;
662
	struct rtinfo *rti;
663
	struct rdnss *rds;
664
	struct dnssl *dsl;
665
	struct dnssldom *dnsd;
666
667
	/* calculate total length */
668
	packlen = sizeof(struct nd_router_advert);
669
	if (rainfo->advlinkopt) {
670
		if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) {
671
			log_info("link-layer address option has"
672
			    " null length on %s.  Treat as not included.",
673
			    rainfo->ifname);
674
			rainfo->advlinkopt = 0;
675
		}
676
		packlen += lladdroptlen;
677
	}
678
	if (rainfo->pfxs)
679
		packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs;
680
	if (rainfo->linkmtu)
681
		packlen += sizeof(struct nd_opt_mtu);
682
	TAILQ_FOREACH(rti, &rainfo->rtinfos, entry)
683
		packlen += sizeof(struct nd_opt_route_info) +
684
		    ((rti->prefixlen + 0x3f) >> 6) * 8;
685
	TAILQ_FOREACH(rds, &rainfo->rdnsss, entry)
686
		packlen += sizeof(struct nd_opt_rdnss) + 16 * rds->servercnt;
687
	TAILQ_FOREACH(dsl, &rainfo->dnssls, entry) {
688
		size_t domains_size = 0;
689
690
		packlen += sizeof(struct nd_opt_dnssl);
691
692
		/*
693
		 * Each domain in the packet ends with a null byte. Account for
694
		 * that here.
695
		 */
696
		TAILQ_FOREACH(dnsd, &dsl->dnssldoms, entry)
697
			domains_size += dnsd->length + 1;
698
699
		domains_size = (domains_size + 7) & ~7;
700
701
		packlen += domains_size;
702
	}
703
704
	/* allocate memory for the packet */
705
	if ((buf = malloc(packlen)) == NULL)
706
		fatal(NULL);
707
	/* free the previous packet */
708
	free(rainfo->ra_data);
709
	rainfo->ra_data = buf;
710
	/* XXX: what if packlen > 576? */
711
	rainfo->ra_datalen = packlen;
712
713
	/*
714
	 * construct the packet
715
	 */
716
	ra = (struct nd_router_advert *)buf;
717
	ra->nd_ra_type = ND_ROUTER_ADVERT;
718
	ra->nd_ra_code = 0;
719
	ra->nd_ra_cksum = 0;
720
	ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit);
721
	ra->nd_ra_flags_reserved = 0; /* just in case */
722
	/*
723
	 * XXX: the router preference field, which is a 2-bit field, should be
724
	 * initialized before other fields.
725
	 */
726
	ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref;
727
	ra->nd_ra_flags_reserved |=
728
		rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0;
729
	ra->nd_ra_flags_reserved |=
730
		rainfo->otherflg ? ND_RA_FLAG_OTHER : 0;
731
	ra->nd_ra_router_lifetime = htons(rainfo->lifetime);
732
	ra->nd_ra_reachable = htonl(rainfo->reachabletime);
733
	ra->nd_ra_retransmit = htonl(rainfo->retranstimer);
734
	buf += sizeof(*ra);
735
736
	if (rainfo->advlinkopt) {
737
		lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf);
738
		buf += lladdroptlen;
739
	}
740
741
	if (rainfo->linkmtu) {
742
		ndopt_mtu = (struct nd_opt_mtu *)buf;
743
		ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU;
744
		ndopt_mtu->nd_opt_mtu_len = 1;
745
		ndopt_mtu->nd_opt_mtu_reserved = 0;
746
		ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu);
747
		buf += sizeof(struct nd_opt_mtu);
748
	}
749
750
	TAILQ_FOREACH(pfx, &rainfo->prefixes, entry) {
751
		u_int32_t vltime, pltime;
752
		struct timeval now;
753
754
		ndopt_pi = (struct nd_opt_prefix_info *)buf;
755
		ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
756
		ndopt_pi->nd_opt_pi_len = 4;
757
		ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen;
758
		ndopt_pi->nd_opt_pi_flags_reserved = 0;
759
		if (pfx->onlinkflg)
760
			ndopt_pi->nd_opt_pi_flags_reserved |=
761
				ND_OPT_PI_FLAG_ONLINK;
762
		if (pfx->autoconfflg)
763
			ndopt_pi->nd_opt_pi_flags_reserved |=
764
				ND_OPT_PI_FLAG_AUTO;
765
		if (pfx->vltimeexpire || pfx->pltimeexpire)
766
			gettimeofday(&now, NULL);
767
		if (pfx->vltimeexpire == 0)
768
			vltime = pfx->validlifetime;
769
		else
770
			vltime = (u_int32_t)(pfx->vltimeexpire > now.tv_sec ?
771
				pfx->vltimeexpire - now.tv_sec : 0);
772
		if (pfx->pltimeexpire == 0)
773
			pltime = pfx->preflifetime;
774
		else
775
			pltime = (u_int32_t)(pfx->pltimeexpire > now.tv_sec ?
776
				pfx->pltimeexpire - now.tv_sec : 0);
777
		if (vltime < pltime) {
778
			/*
779
			 * this can happen if vltime is decremented but pltime
780
			 * is not.
781
			 */
782
			pltime = vltime;
783
		}
784
		ndopt_pi->nd_opt_pi_valid_time = htonl(vltime);
785
		ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime);
786
		ndopt_pi->nd_opt_pi_reserved2 = 0;
787
		ndopt_pi->nd_opt_pi_prefix = pfx->prefix;
788
789
		buf += sizeof(struct nd_opt_prefix_info);
790
	}
791
792
	TAILQ_FOREACH(rti, &rainfo->rtinfos, entry) {
793
		uint8_t psize = (rti->prefixlen + 0x3f) >> 6;
794
795
		ndopt_rti = (struct nd_opt_route_info *)buf;
796
		ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO;
797
		ndopt_rti->nd_opt_rti_len = 1 + psize;
798
		ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen;
799
		ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref;
800
		ndopt_rti->nd_opt_rti_lifetime = htonl(rti->lifetime);
801
		memcpy(ndopt_rti + 1, &rti->prefix, psize * 8);
802
		buf += sizeof(struct nd_opt_route_info) + psize * 8;
803
	}
804
805
	TAILQ_FOREACH(rds, &rainfo->rdnsss, entry) {
806
		ndopt_rdnss = (struct nd_opt_rdnss *)buf;
807
		ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
808
		/*
809
		 * An IPv6 address is 16 bytes, so multiply the number of
810
		 * addresses by two to get a size in units of 8 bytes.
811
		 */
812
		ndopt_rdnss->nd_opt_rdnss_len = 1 + rds->servercnt * 2;
813
		ndopt_rdnss->nd_opt_rdnss_reserved = 0;
814
		ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rds->lifetime);
815
816
		buf += sizeof(struct nd_opt_rdnss);
817
818
		memcpy(buf, rds->servers, rds->servercnt * 16);
819
		buf += rds->servercnt * 16;
820
	}
821
822
	TAILQ_FOREACH(dsl, &rainfo->dnssls, entry) {
823
		u_int32_t size;
824
825
		ndopt_dnssl = (struct nd_opt_dnssl *)buf;
826
		ndopt_dnssl->nd_opt_dnssl_type = ND_OPT_DNSSL;
827
		ndopt_dnssl->nd_opt_dnssl_reserved = 0;
828
		ndopt_dnssl->nd_opt_dnssl_lifetime = htonl(dsl->lifetime);
829
830
		size = 0;
831
		TAILQ_FOREACH(dnsd, &dsl->dnssldoms, entry)
832
			size += dnsd->length + 1;
833
		/* align size on the next 8 byte boundary */
834
		size = (size + 7) & ~7;
835
		ndopt_dnssl->nd_opt_dnssl_len = 1 + size / 8;
836
837
		buf += sizeof(struct nd_opt_dnssl);
838
839
		TAILQ_FOREACH(dnsd, &dsl->dnssldoms, entry) {
840
			char *curlabel_begin;
841
			char *curlabel_end;
842
843
			curlabel_begin = dnsd->domain;
844
			while ((curlabel_end = strchr(curlabel_begin, '.'))
845
			    != NULL && curlabel_end > curlabel_begin)
846
			{
847
				size_t curlabel_size;
848
849
				curlabel_size = curlabel_end - curlabel_begin;
850
				*buf++ = curlabel_size;
851
				memcpy(buf, curlabel_begin, curlabel_size);
852
				buf += curlabel_size;
853
				curlabel_begin = curlabel_end + 1;
854
			}
855
856
			/* null-terminate the current domain */
857
			*buf++ = '\0';
858
		}
859
860
		/* zero out the end of the current option */
861
		while (((uintptr_t)buf) % 8 != 0)
862
			*buf++ = '\0';
863
	}
864
}
865
866
static int
867
getinet6sysctl(int code)
868
{
869
	int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
870
	int value;
871
	size_t size;
872
873
	mib[3] = code;
874
	size = sizeof(value);
875
	if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0)
876
	    < 0) {
877
		log_warn("failed to get ip6 sysctl(%d)", code);
878
		return(-1);
879
	} else
880
		return(value);
881
}