GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/slaacd/frontend.c Lines: 0 447 0.0 %
Date: 2017-11-07 Branches: 0 254 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: frontend.c,v 1.8 2017/08/23 10:48:01 florian Exp $	*/
2
3
/*
4
 * Copyright (c) 2017 Florian Obser <florian@openbsd.org>
5
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6
 * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8
 *
9
 * Permission to use, copy, modify, and distribute this software for any
10
 * purpose with or without fee is hereby granted, provided that the above
11
 * copyright notice and this permission notice appear in all copies.
12
 *
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20
 */
21
#include <sys/types.h>
22
#include <sys/ioctl.h>
23
#include <sys/queue.h>
24
#include <sys/socket.h>
25
#include <sys/syslog.h>
26
#include <sys/uio.h>
27
28
#include <net/if.h>
29
#include <net/if_dl.h>
30
#include <net/if_types.h>
31
#include <net/route.h>
32
33
#include <arpa/inet.h>
34
35
#include <netinet/in.h>
36
#include <netinet/if_ether.h>
37
#include <netinet6/nd6.h>
38
#include <netinet6/in6_var.h>
39
#include <netinet/ip6.h>
40
#include <netinet6/ip6_var.h>
41
#include <netinet/icmp6.h>
42
43
#include <errno.h>
44
#include <event.h>
45
#include <ifaddrs.h>
46
#include <imsg.h>
47
#include <pwd.h>
48
#include <signal.h>
49
#include <stdio.h>
50
#include <stdlib.h>
51
#include <string.h>
52
#include <unistd.h>
53
54
#include "log.h"
55
#include "slaacd.h"
56
#include "frontend.h"
57
#include "control.h"
58
59
#define	ROUTE_SOCKET_BUF_SIZE	16384
60
#define	ALLROUTER		"ff02::2"
61
62
__dead void	 frontend_shutdown(void);
63
void		 frontend_sig_handler(int, short, void *);
64
void		 update_iface(uint32_t, char*);
65
void		 frontend_startup(void);
66
void		 route_receive(int, short, void *);
67
void		 handle_route_message(struct rt_msghdr *, struct sockaddr **);
68
void		 get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
69
void		 icmp6_receive(int, short, void *);
70
int		 get_flags(char *);
71
int		 get_xflags(char *);
72
void		 get_lladdr(char *, struct ether_addr *, struct sockaddr_in6 *);
73
void		 send_solicitation(uint32_t);
74
#ifndef	SMALL
75
void		 update_autoconf_addresses(uint32_t, char*);
76
#endif	/* SMALL */
77
78
struct imsgev			*iev_main;
79
struct imsgev			*iev_engine;
80
struct event			 ev_route;
81
struct msghdr			 sndmhdr;
82
struct iovec			 sndiov[4];
83
struct nd_router_solicit	 rs;
84
struct nd_opt_hdr		 nd_opt_hdr;
85
struct ether_addr		 nd_opt_source_link_addr;
86
struct sockaddr_in6		 dst;
87
int				 icmp6sock, routesock, ioctlsock;
88
89
struct icmp6_ev {
90
	struct event		 ev;
91
	uint8_t			 answer[1500];
92
	struct msghdr		 rcvmhdr;
93
	struct iovec		 rcviov[1];
94
	struct sockaddr_in6	 from;
95
} icmp6ev;
96
97
void
98
frontend_sig_handler(int sig, short event, void *bula)
99
{
100
	/*
101
	 * Normal signal handler rules don't apply because libevent
102
	 * decouples for us.
103
	 */
104
105
	switch (sig) {
106
	case SIGINT:
107
	case SIGTERM:
108
		frontend_shutdown();
109
	default:
110
		fatalx("unexpected signal");
111
	}
112
}
113
114
void
115
frontend(int debug, int verbose, char *sockname)
116
{
117
	struct event		 ev_sigint, ev_sigterm;
118
	struct passwd		*pw;
119
	struct icmp6_filter	 filt;
120
	struct in6_pktinfo	*pi;
121
	struct cmsghdr		*cm;
122
	size_t			 rcvcmsglen, sndcmsglen;
123
	int			 hoplimit = 255, on = 1, rtfilter;
124
	uint8_t			*rcvcmsgbuf, *sndcmsgbuf;
125
126
	log_init(debug, LOG_DAEMON);
127
	log_setverbose(verbose);
128
129
#ifndef	SMALL
130
	/* Create slaacd control socket outside chroot. */
131
	if (control_init(sockname) == -1)
132
		fatalx("control socket setup failed");
133
#endif	/* SMALL */
134
135
	if ((pw = getpwnam(SLAACD_USER)) == NULL)
136
		fatal("getpwnam");
137
138
	if (chroot(pw->pw_dir) == -1)
139
		fatal("chroot");
140
	if (chdir("/") == -1)
141
		fatal("chdir(\"/\")");
142
143
	slaacd_process = PROC_FRONTEND;
144
	setproctitle("%s", log_procnames[slaacd_process]);
145
	log_procinit(log_procnames[slaacd_process]);
146
147
	if ((icmp6sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
148
		fatal("ICMPv6 socket");
149
150
	if ((routesock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0)
151
		fatal("route socket");
152
153
	if ((ioctlsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
154
		fatal("socket");
155
156
	if (setgroups(1, &pw->pw_gid) ||
157
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
158
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
159
		fatal("can't drop privileges");
160
161
	if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
162
	    sizeof(on)) < 0)
163
		fatal("IPV6_RECVPKTINFO");
164
165
	if (setsockopt(icmp6sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
166
	    sizeof(on)) < 0)
167
		fatal("IPV6_RECVHOPLIMIT");
168
169
	/* only router advertisements */
170
	ICMP6_FILTER_SETBLOCKALL(&filt);
171
	ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
172
	if (setsockopt(icmp6sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
173
	    sizeof(filt)) == -1)
174
		fatal("ICMP6_FILTER");
175
176
	rtfilter = ROUTE_FILTER(RTM_IFINFO) | ROUTE_FILTER(RTM_NEWADDR) |
177
	    ROUTE_FILTER(RTM_DELADDR) | ROUTE_FILTER(RTM_PROPOSAL);
178
	if (setsockopt(routesock, PF_ROUTE, ROUTE_MSGFILTER,
179
	    &rtfilter, sizeof(rtfilter)) < 0)
180
		fatal("setsockopt(ROUTE_MSGFILTER)");
181
182
	if (pledge("stdio inet recvfd route flock rpath cpath wpath", NULL) == -1)
183
		fatal("pledge");
184
185
	event_init();
186
187
	/* Setup signal handler. */
188
	signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL);
189
	signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL);
190
	signal_add(&ev_sigint, NULL);
191
	signal_add(&ev_sigterm, NULL);
192
	signal(SIGPIPE, SIG_IGN);
193
	signal(SIGHUP, SIG_IGN);
194
195
	/* Setup pipe and event handler to the parent process. */
196
	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
197
		fatal(NULL);
198
	imsg_init(&iev_main->ibuf, 3);
199
	iev_main->handler = frontend_dispatch_main;
200
	iev_main->events = EV_READ;
201
	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
202
	    iev_main->handler, iev_main);
203
	event_add(&iev_main->ev, NULL);
204
205
#ifndef	SMALL
206
	/* Listen on control socket. */
207
	TAILQ_INIT(&ctl_conns);
208
	control_listen();
209
#endif	/* SMALL */
210
211
	event_set(&ev_route, routesock, EV_READ | EV_PERSIST, route_receive,
212
	    NULL);
213
214
	event_set(&icmp6ev.ev, icmp6sock, EV_READ | EV_PERSIST, icmp6_receive,
215
	    NULL);
216
217
	rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
218
	    CMSG_SPACE(sizeof(int));
219
	if((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL)
220
		fatal("malloc");
221
222
	icmp6ev.rcviov[0].iov_base = (caddr_t)icmp6ev.answer;
223
	icmp6ev.rcviov[0].iov_len = sizeof(icmp6ev.answer);
224
	icmp6ev.rcvmhdr.msg_name = (caddr_t)&icmp6ev.from;
225
	icmp6ev.rcvmhdr.msg_namelen = sizeof(icmp6ev.from);
226
	icmp6ev.rcvmhdr.msg_iov = icmp6ev.rcviov;
227
	icmp6ev.rcvmhdr.msg_iovlen = 1;
228
	icmp6ev.rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
229
	icmp6ev.rcvmhdr.msg_controllen = rcvcmsglen;
230
231
	sndcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
232
	    CMSG_SPACE(sizeof(int));
233
234
	if ((sndcmsgbuf = malloc(sndcmsglen)) == NULL)
235
		fatal("malloc");
236
237
	rs.nd_rs_type = ND_ROUTER_SOLICIT;
238
	rs.nd_rs_code = 0;
239
	rs.nd_rs_cksum = 0;
240
	rs.nd_rs_reserved = 0;
241
242
	nd_opt_hdr.nd_opt_type = ND_OPT_SOURCE_LINKADDR;
243
	nd_opt_hdr.nd_opt_len = 1;
244
245
	memset(&dst, 0, sizeof(dst));
246
	dst.sin6_family = AF_INET6;
247
	if (inet_pton(AF_INET6, ALLROUTER, &dst.sin6_addr.s6_addr) != 1)
248
		fatal("inet_pton");
249
250
	sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
251
	sndmhdr.msg_iov = sndiov;
252
	sndmhdr.msg_iovlen = 3;
253
	sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
254
	sndmhdr.msg_controllen = sndcmsglen;
255
256
	sndmhdr.msg_name = (caddr_t)&dst;
257
	sndmhdr.msg_iov[0].iov_base = (caddr_t)&rs;
258
	sndmhdr.msg_iov[0].iov_len = sizeof(rs);
259
	sndmhdr.msg_iov[1].iov_base = (caddr_t)&nd_opt_hdr;
260
	sndmhdr.msg_iov[1].iov_len = sizeof(nd_opt_hdr);
261
	sndmhdr.msg_iov[2].iov_base = (caddr_t)&nd_opt_source_link_addr;
262
	sndmhdr.msg_iov[2].iov_len = sizeof(nd_opt_source_link_addr);
263
264
	cm = CMSG_FIRSTHDR(&sndmhdr);
265
266
	cm->cmsg_level = IPPROTO_IPV6;
267
	cm->cmsg_type = IPV6_PKTINFO;
268
	cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
269
	pi = (struct in6_pktinfo *)CMSG_DATA(cm);
270
	memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr));
271
	pi->ipi6_ifindex = 0;
272
273
	cm = CMSG_NXTHDR(&sndmhdr, cm);
274
	cm->cmsg_level = IPPROTO_IPV6;
275
	cm->cmsg_type = IPV6_HOPLIMIT;
276
	cm->cmsg_len = CMSG_LEN(sizeof(int));
277
	memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
278
279
	event_dispatch();
280
281
	frontend_shutdown();
282
}
283
284
__dead void
285
frontend_shutdown(void)
286
{
287
	/* Close pipes. */
288
	msgbuf_write(&iev_engine->ibuf.w);
289
	msgbuf_clear(&iev_engine->ibuf.w);
290
	close(iev_engine->ibuf.fd);
291
	msgbuf_write(&iev_main->ibuf.w);
292
	msgbuf_clear(&iev_main->ibuf.w);
293
	close(iev_main->ibuf.fd);
294
295
	free(iev_engine);
296
	free(iev_main);
297
298
	log_info("frontend exiting");
299
	exit(0);
300
}
301
302
int
303
frontend_imsg_compose_main(int type, pid_t pid, void *data,
304
    uint16_t datalen)
305
{
306
	return (imsg_compose_event(iev_main, type, 0, pid, -1, data,
307
	    datalen));
308
}
309
310
int
311
frontend_imsg_compose_engine(int type, uint32_t peerid, pid_t pid,
312
    void *data, uint16_t datalen)
313
{
314
	return (imsg_compose_event(iev_engine, type, peerid, pid, -1,
315
	    data, datalen));
316
}
317
318
void
319
frontend_dispatch_main(int fd, short event, void *bula)
320
{
321
	struct imsg		 imsg;
322
	struct imsgev		*iev = bula;
323
	struct imsgbuf		*ibuf = &iev->ibuf;
324
	ssize_t			 n;
325
	int			 shut = 0;
326
327
	if (event & EV_READ) {
328
		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
329
			fatal("imsg_read error");
330
		if (n == 0)	/* Connection closed. */
331
			shut = 1;
332
	}
333
	if (event & EV_WRITE) {
334
		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
335
			fatal("msgbuf_write");
336
		if (n == 0)	/* Connection closed. */
337
			shut = 1;
338
	}
339
340
	for (;;) {
341
		if ((n = imsg_get(ibuf, &imsg)) == -1)
342
			fatal("%s: imsg_get error", __func__);
343
		if (n == 0)	/* No more messages. */
344
			break;
345
346
		switch (imsg.hdr.type) {
347
		case IMSG_SOCKET_IPC:
348
			/*
349
			 * Setup pipe and event handler to the engine
350
			 * process.
351
			 */
352
			if (iev_engine) {
353
				log_warnx("%s: received unexpected imsg fd "
354
				    "to frontend", __func__);
355
				break;
356
			}
357
			if ((fd = imsg.fd) == -1) {
358
				log_warnx("%s: expected to receive imsg fd to "
359
				   "frontend but didn't receive any",
360
				   __func__);
361
				break;
362
			}
363
364
			iev_engine = malloc(sizeof(struct imsgev));
365
			if (iev_engine == NULL)
366
				fatal(NULL);
367
368
			imsg_init(&iev_engine->ibuf, fd);
369
			iev_engine->handler = frontend_dispatch_engine;
370
			iev_engine->events = EV_READ;
371
372
			event_set(&iev_engine->ev, iev_engine->ibuf.fd,
373
			iev_engine->events, iev_engine->handler, iev_engine);
374
			event_add(&iev_engine->ev, NULL);
375
376
			if (pledge("stdio inet route flock rpath cpath wpath", NULL) == -1)
377
				fatal("pledge");
378
379
			break;
380
		case IMSG_STARTUP:
381
			frontend_startup();
382
			break;
383
#ifndef	SMALL
384
		case IMSG_CTL_END:
385
			control_imsg_relay(&imsg);
386
			break;
387
#endif	/* SMALL */
388
		default:
389
			log_debug("%s: error handling imsg %d", __func__,
390
			    imsg.hdr.type);
391
			break;
392
		}
393
		imsg_free(&imsg);
394
	}
395
	if (!shut)
396
		imsg_event_add(iev);
397
	else {
398
		/* This pipe is dead. Remove its event handler. */
399
		event_del(&iev->ev);
400
		event_loopexit(NULL);
401
	}
402
}
403
404
void
405
frontend_dispatch_engine(int fd, short event, void *bula)
406
{
407
	struct imsgev		*iev = bula;
408
	struct imsgbuf		*ibuf = &iev->ibuf;
409
	struct imsg		 imsg;
410
	ssize_t			 n;
411
	int			 shut = 0;
412
	uint32_t		 if_index;
413
414
	if (event & EV_READ) {
415
		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
416
			fatal("imsg_read error");
417
		if (n == 0)	/* Connection closed. */
418
			shut = 1;
419
	}
420
	if (event & EV_WRITE) {
421
		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
422
			fatal("msgbuf_write");
423
		if (n == 0)	/* Connection closed. */
424
			shut = 1;
425
	}
426
427
	for (;;) {
428
		if ((n = imsg_get(ibuf, &imsg)) == -1)
429
			fatal("%s: imsg_get error", __func__);
430
		if (n == 0)	/* No more messages. */
431
			break;
432
433
		switch (imsg.hdr.type) {
434
#ifndef	SMALL
435
		case IMSG_CTL_END:
436
		case IMSG_CTL_SHOW_INTERFACE_INFO:
437
		case IMSG_CTL_SHOW_INTERFACE_INFO_RA:
438
		case IMSG_CTL_SHOW_INTERFACE_INFO_RA_PREFIX:
439
		case IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS:
440
		case IMSG_CTL_SHOW_INTERFACE_INFO_RA_DNSSL:
441
		case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS:
442
		case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL:
443
		case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS:
444
		case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL:
445
			control_imsg_relay(&imsg);
446
			break;
447
#endif	/* SMALL */
448
		case IMSG_CTL_SEND_SOLICITATION:
449
			if_index = *((uint32_t *)imsg.data);
450
			send_solicitation(if_index);
451
			break;
452
		case IMSG_FAKE_ACK:
453
			frontend_imsg_compose_engine(IMSG_PROPOSAL_ACK,
454
			   0, 0, imsg.data, sizeof(struct imsg_proposal_ack));
455
			break;
456
		default:
457
			log_debug("%s: error handling imsg %d", __func__,
458
			    imsg.hdr.type);
459
			break;
460
		}
461
		imsg_free(&imsg);
462
	}
463
	if (!shut)
464
		imsg_event_add(iev);
465
	else {
466
		/* This pipe is dead. Remove its event handler. */
467
		event_del(&iev->ev);
468
		event_loopexit(NULL);
469
	}
470
}
471
472
int
473
get_flags(char *if_name)
474
{
475
	struct ifreq		 ifr;
476
477
	(void) strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
478
	if (ioctl(ioctlsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
479
		fatal("SIOCGIFFLAGS");
480
	return ifr.ifr_flags;
481
}
482
483
int
484
get_xflags(char *if_name)
485
{
486
	struct ifreq		 ifr;
487
488
	(void) strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
489
	if (ioctl(ioctlsock, SIOCGIFXFLAGS, (caddr_t)&ifr) < 0)
490
		fatal("SIOCGIFXFLAGS");
491
	return ifr.ifr_flags;
492
}
493
494
void
495
update_iface(uint32_t if_index, char* if_name)
496
{
497
	struct imsg_ifinfo	 imsg_ifinfo;
498
	int			 flags, xflags;
499
500
	flags = get_flags(if_name);
501
	xflags = get_xflags(if_name);
502
503
	if (!(xflags & IFXF_AUTOCONF6))
504
		return;
505
506
	memset(&imsg_ifinfo, 0, sizeof(imsg_ifinfo));
507
508
	imsg_ifinfo.if_index = if_index;
509
	imsg_ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP |
510
	    IFF_RUNNING);
511
	imsg_ifinfo.autoconfprivacy = !(xflags & IFXF_INET6_NOPRIVACY);
512
	get_lladdr(if_name, &imsg_ifinfo.hw_address, &imsg_ifinfo.ll_address);
513
514
	memcpy(&nd_opt_source_link_addr, &imsg_ifinfo.hw_address,
515
	    sizeof(nd_opt_source_link_addr));
516
517
	frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &imsg_ifinfo,
518
	    sizeof(imsg_ifinfo));
519
}
520
521
#ifndef	SMALL
522
void
523
update_autoconf_addresses(uint32_t if_index, char* if_name)
524
{
525
	struct in6_ifreq	 ifr6;
526
	struct imsg_addrinfo	 imsg_addrinfo;
527
	struct ifaddrs		*ifap, *ifa;
528
	struct in6_addrlifetime *lifetime;
529
	struct sockaddr_in6	*sin6;
530
	time_t			 t;
531
	int			 xflags;
532
533
	xflags = get_xflags(if_name);
534
535
	if (!(xflags & IFXF_AUTOCONF6))
536
		return;
537
538
	memset(&imsg_addrinfo, 0, sizeof(imsg_addrinfo));
539
	imsg_addrinfo.if_index = if_index;
540
	get_lladdr(if_name, &imsg_addrinfo.hw_address,
541
	    &imsg_addrinfo.ll_address);
542
543
	if (getifaddrs(&ifap) != 0)
544
		fatal("getifaddrs");
545
546
	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
547
		if (strcmp(if_name, ifa->ifa_name) != 0)
548
			continue;
549
		if (ifa->ifa_addr->sa_family != AF_INET6)
550
			continue;
551
		sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
552
		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
553
			continue;
554
555
		log_debug("%s: IP: %s", __func__, sin6_to_str(sin6));
556
		imsg_addrinfo.addr = *sin6;
557
558
		memset(&ifr6, 0, sizeof(ifr6));
559
		(void) strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name));
560
		memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr));
561
562
		if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) < 0) {
563
			log_warn("SIOCGIFAFLAG_IN6");
564
			continue;
565
		}
566
567
		if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF |
568
		    IN6_IFF_PRIVACY)))
569
			continue;
570
571
		imsg_addrinfo.privacy = ifr6.ifr_ifru.ifru_flags6 &
572
		    IN6_IFF_PRIVACY ? 1 : 0;
573
574
		memset(&ifr6, 0, sizeof(ifr6));
575
		(void) strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name));
576
		memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr));
577
578
		if (ioctl(ioctlsock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) < 0) {
579
			log_warn("SIOCGIFNETMASK_IN6");
580
			continue;
581
		}
582
583
		imsg_addrinfo.mask = ((struct sockaddr_in6 *)&ifr6.ifr_addr)
584
		    ->sin6_addr;
585
586
		memset(&ifr6, 0, sizeof(ifr6));
587
		(void) strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name));
588
		memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr));
589
		lifetime = &ifr6.ifr_ifru.ifru_lifetime;
590
591
		if (ioctl(ioctlsock, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) <
592
		    0) {
593
			log_warn("SIOCGIFALIFETIME_IN6");
594
			continue;
595
		}
596
597
		imsg_addrinfo.vltime = ND6_INFINITE_LIFETIME;
598
		imsg_addrinfo.pltime = ND6_INFINITE_LIFETIME;
599
		t = time(NULL);
600
601
		if (lifetime->ia6t_preferred)
602
			imsg_addrinfo.pltime = lifetime->ia6t_preferred < t ? 0
603
			    : lifetime->ia6t_preferred - t;
604
605
		if (lifetime->ia6t_expire)
606
			imsg_addrinfo.vltime = lifetime->ia6t_expire < t ? 0 :
607
			    lifetime->ia6t_expire - t;
608
609
		frontend_imsg_compose_main(IMSG_UPDATE_ADDRESS, 0,
610
		    &imsg_addrinfo, sizeof(imsg_addrinfo));
611
612
	}
613
	freeifaddrs(ifap);
614
}
615
#endif	/* SMALL */
616
617
void
618
frontend_startup(void)
619
{
620
	struct if_nameindex	*ifnidxp, *ifnidx;
621
622
	event_add(&ev_route, NULL);
623
	event_add(&icmp6ev.ev, NULL);
624
625
	if ((ifnidxp = if_nameindex()) == NULL)
626
		fatalx("if_nameindex");
627
628
	for(ifnidx = ifnidxp; ifnidx->if_index !=0 && ifnidx->if_name != NULL;
629
	    ifnidx++) {
630
		update_iface(ifnidx->if_index, ifnidx->if_name);
631
#ifndef	SMALL
632
		update_autoconf_addresses(ifnidx->if_index, ifnidx->if_name);
633
#endif	/* SMALL */
634
	}
635
636
	if_freenameindex(ifnidxp);
637
}
638
639
void
640
route_receive(int fd, short events, void *arg)
641
{
642
	static uint8_t			 buf[ROUTE_SOCKET_BUF_SIZE];
643
644
	struct rt_msghdr		*rtm = (struct rt_msghdr *)buf;
645
	struct sockaddr			*sa, *rti_info[RTAX_MAX];
646
	ssize_t				 n;
647
648
	if ((n = read(fd, &buf, sizeof(buf))) == -1) {
649
		if (errno == EAGAIN || errno == EINTR)
650
			return;
651
		log_warn("dispatch_rtmsg: read error");
652
		return;
653
	}
654
655
	if (n == 0)
656
		fatal("routing socket closed");
657
658
	if (n < rtm->rtm_msglen) {
659
		log_warnx("partial rtm in buffer");
660
		return;
661
	}
662
663
	if (rtm->rtm_version != RTM_VERSION)
664
		return;
665
666
	sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen);
667
	get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
668
669
	handle_route_message(rtm, rti_info);
670
}
671
672
void
673
handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info)
674
{
675
	struct if_msghdr		*ifm;
676
	struct imsg_proposal_ack	 proposal_ack;
677
	struct imsg_del_addr		 del_addr;
678
	struct sockaddr_rtlabel		*rl;
679
	int64_t				 id, pid;
680
	int				 flags, xflags, if_index;
681
	char				 ifnamebuf[IFNAMSIZ];
682
	char				*if_name;
683
	char				**ap, *argv[4], *p;
684
	const char			*errstr;
685
686
	switch (rtm->rtm_type) {
687
	case RTM_IFINFO:
688
		ifm = (struct if_msghdr *)rtm;
689
		if_name = if_indextoname(ifm->ifm_index, ifnamebuf);
690
		if (if_name == NULL) {
691
			log_debug("RTM_IFINFO: lost if %d", ifm->ifm_index);
692
			if_index = ifm->ifm_index;
693
			frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
694
			    &if_index, sizeof(if_index));
695
		} else {
696
			xflags = get_xflags(if_name);
697
			flags = get_flags(if_name);
698
			if (!(xflags & IFXF_AUTOCONF6)) {
699
				log_debug("RTM_IFINFO: %s(%d) no(longer) "
700
				   "autoconf6", if_name, ifm->ifm_index);
701
				if_index = ifm->ifm_index;
702
				frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0,
703
				    0, &if_index, sizeof(if_index));
704
			} else {
705
				update_iface(ifm->ifm_index, if_name);
706
#ifndef	SMALL
707
				update_autoconf_addresses(ifm->ifm_index,
708
				    if_name);
709
#endif	/* SMALL */
710
			}
711
		}
712
		break;
713
	case RTM_NEWADDR:
714
		ifm = (struct if_msghdr *)rtm;
715
		if_name = if_indextoname(ifm->ifm_index, ifnamebuf);
716
		log_debug("RTM_NEWADDR: %s[%u]", if_name, ifm->ifm_index);
717
		update_iface(ifm->ifm_index, if_name);
718
		break;
719
	case RTM_DELADDR:
720
		ifm = (struct if_msghdr *)rtm;
721
		if_name = if_indextoname(ifm->ifm_index, ifnamebuf);
722
		if (rtm->rtm_addrs & RTA_IFA && rti_info[RTAX_IFA]->sa_family
723
		    == AF_INET6) {
724
			del_addr.if_index = ifm->ifm_index;
725
			memcpy(&del_addr.addr, rti_info[RTAX_IFA], sizeof(
726
			    del_addr.addr));
727
			frontend_imsg_compose_engine(IMSG_DEL_ADDRESS,
728
				    0, 0, &del_addr, sizeof(del_addr));
729
			log_debug("RTM_DELADDR: %s[%u]", if_name,
730
			    ifm->ifm_index);
731
		}
732
		break;
733
	case RTM_PROPOSAL:
734
		ifm = (struct if_msghdr *)rtm;
735
		if_name = if_indextoname(ifm->ifm_index, ifnamebuf);
736
737
		if ((rtm->rtm_flags & (RTF_DONE | RTF_PROTO1)) ==
738
		    (RTF_DONE | RTF_PROTO1) && rtm->rtm_addrs == RTA_LABEL) {
739
			rl = (struct sockaddr_rtlabel *)rti_info[RTAX_LABEL];
740
			/* XXX validate rl */
741
742
			p = rl->sr_label;
743
744
			for (ap = argv; ap < &argv[3] && (*ap =
745
			    strsep(&p, " ")) != NULL;) {
746
				if (**ap != '\0')
747
					ap++;
748
			}
749
			*ap = NULL;
750
751
			if (argv[0] != NULL && strncmp(argv[0], "slaacd:",
752
			    strlen("slaacd:")) == 0 && argv[1] != NULL &&
753
			    argv[2] != NULL && argv[3] == NULL) {
754
				id = strtonum(argv[1], 0, INT64_MAX, &errstr);
755
				if (errstr != NULL) {
756
					log_warn("%s: proposal seq is %s: %s",
757
					    __func__, errstr, argv[1]);
758
					break;
759
				}
760
				pid = strtonum(argv[2], 0, INT32_MAX, &errstr);
761
				if (errstr != NULL) {
762
					log_warn("%s: pid is %s: %s",
763
					    __func__, errstr, argv[2]);
764
					break;
765
				}
766
				proposal_ack.id = id;
767
				proposal_ack.pid = pid;
768
				proposal_ack.if_index = ifm->ifm_index;
769
770
				frontend_imsg_compose_engine(IMSG_PROPOSAL_ACK,
771
				    0, 0, &proposal_ack, sizeof(proposal_ack));
772
			} else {
773
				log_debug("cannot parse: %s", rl->sr_label);
774
			}
775
		} else {
776
#if 0
777
			log_debug("%s: got flags %x, expcted %x", __func__,
778
			    rtm->rtm_flags, (RTF_DONE | RTF_PROTO1));
779
#endif
780
		}
781
782
		break;
783
	default:
784
		log_debug("unexpected RTM: %d", rtm->rtm_type);
785
		break;
786
	}
787
788
}
789
790
#define ROUNDUP(a) \
791
	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
792
793
void
794
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
795
{
796
	int	i;
797
798
	for (i = 0; i < RTAX_MAX; i++) {
799
		if (addrs & (1 << i)) {
800
			rti_info[i] = sa;
801
			sa = (struct sockaddr *)((char *)(sa) +
802
			    ROUNDUP(sa->sa_len));
803
		} else
804
			rti_info[i] = NULL;
805
	}
806
}
807
808
void
809
get_lladdr(char *if_name, struct ether_addr *mac, struct sockaddr_in6 *ll)
810
{
811
	struct ifaddrs		*ifap, *ifa;
812
	struct sockaddr_dl	*sdl;
813
	struct sockaddr_in6	*sin6;
814
815
	if (getifaddrs(&ifap) != 0)
816
		fatal("getifaddrs");
817
818
	memset(mac, 0, sizeof(*mac));
819
	memset(ll, 0, sizeof(*ll));
820
821
	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
822
		if (strcmp(if_name, ifa->ifa_name) != 0)
823
			continue;
824
825
		switch(ifa->ifa_addr->sa_family) {
826
		case AF_LINK:
827
			sdl = (struct sockaddr_dl *)ifa->ifa_addr;
828
			if (sdl->sdl_type != IFT_ETHER ||
829
			    sdl->sdl_alen != ETHER_ADDR_LEN)
830
				continue;
831
832
			memcpy(mac->ether_addr_octet, LLADDR(sdl),
833
			    ETHER_ADDR_LEN);
834
			break;
835
		case AF_INET6:
836
			sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
837
			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
838
				sin6->sin6_scope_id = ntohs(*(u_int16_t *)
839
				    &sin6->sin6_addr.s6_addr[2]);
840
				sin6->sin6_addr.s6_addr[2] =
841
				    sin6->sin6_addr.s6_addr[3] = 0;
842
				memcpy(ll, sin6, sizeof(*ll));
843
			}
844
			break;
845
		default:
846
			break;
847
		}
848
	}
849
	freeifaddrs(ifap);
850
}
851
852
void
853
icmp6_receive(int fd, short events, void *arg)
854
{
855
	struct imsg_ra		 ra;
856
857
	struct in6_pktinfo	*pi = NULL;
858
	struct cmsghdr		*cm;
859
	ssize_t			 len;
860
	int			 if_index = 0, *hlimp = NULL;
861
	char			 ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
862
	uint8_t			*p;
863
864
	p = icmp6ev.answer;
865
866
	if ((len = recvmsg(fd, &icmp6ev.rcvmhdr, 0)) < 0) {
867
		log_warn("recvmsg");
868
		return;
869
	}
870
871
	/* extract optional information via Advanced API */
872
	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&icmp6ev.rcvmhdr); cm;
873
	    cm = (struct cmsghdr *)CMSG_NXTHDR(&icmp6ev.rcvmhdr, cm)) {
874
		if (cm->cmsg_level == IPPROTO_IPV6 &&
875
		    cm->cmsg_type == IPV6_PKTINFO &&
876
		    cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
877
			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
878
			if_index = pi->ipi6_ifindex;
879
		}
880
		if (cm->cmsg_level == IPPROTO_IPV6 &&
881
		    cm->cmsg_type == IPV6_HOPLIMIT &&
882
		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
883
			hlimp = (int *)CMSG_DATA(cm);
884
	}
885
886
	if (if_index == 0) {
887
		log_warnx("failed to get receiving interface");
888
		return;
889
	}
890
891
	if (hlimp == NULL) {
892
		log_warnx("failed to get receiving hop limit");
893
		return;
894
	}
895
896
	if (*hlimp != 255) {
897
		log_warnx("invalid RA with hop limit of %d from %s on %s",
898
		    *hlimp, inet_ntop(AF_INET6, &icmp6ev.from.sin6_addr,
899
		    ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index,
900
		    ifnamebuf));
901
		return;
902
	}
903
904
	if ((size_t)len > sizeof(ra.packet)) {
905
		log_warnx("invalid RA with size %ld from %s on %s",
906
		    len, inet_ntop(AF_INET6, &icmp6ev.from.sin6_addr,
907
		    ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index,
908
		    ifnamebuf));
909
		return;
910
	}
911
912
	ra.if_index = if_index;
913
	memcpy(&ra.from,  &icmp6ev.from, sizeof(ra.from));
914
	ra.len = len;
915
	memcpy(ra.packet, icmp6ev.answer, len);
916
917
	frontend_imsg_compose_engine(IMSG_RA, 0, 0, &ra, sizeof(ra));
918
}
919
920
void
921
send_solicitation(uint32_t if_index)
922
{
923
	struct in6_pktinfo		*pi;
924
	struct cmsghdr			*cm;
925
926
	log_debug("%s(%u)", __func__, if_index);
927
928
	dst.sin6_scope_id = if_index;
929
930
	cm = CMSG_FIRSTHDR(&sndmhdr);
931
	pi = (struct in6_pktinfo *)CMSG_DATA(cm);
932
	pi->ipi6_ifindex = if_index;
933
934
	if (sendmsg(icmp6sock, &sndmhdr, 0) != sizeof(rs) +
935
	    sizeof(nd_opt_hdr) + sizeof(nd_opt_source_link_addr))
936
		log_warn("sendmsg");
937
}