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

Line Branch Exec Source
1
/*	$OpenBSD: frontend.c,v 1.9 2017/11/04 17:23:05 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
				fatalx("%s: received unexpected imsg fd "
354
				    "to frontend", __func__);
355
356
			if ((fd = imsg.fd) == -1)
357
				fatalx("%s: expected to receive imsg fd to "
358
				   "frontend but didn't receive any",
359
				   __func__);
360
361
			iev_engine = malloc(sizeof(struct imsgev));
362
			if (iev_engine == NULL)
363
				fatal(NULL);
364
365
			imsg_init(&iev_engine->ibuf, fd);
366
			iev_engine->handler = frontend_dispatch_engine;
367
			iev_engine->events = EV_READ;
368
369
			event_set(&iev_engine->ev, iev_engine->ibuf.fd,
370
			iev_engine->events, iev_engine->handler, iev_engine);
371
			event_add(&iev_engine->ev, NULL);
372
373
			if (pledge("stdio inet route flock rpath cpath wpath", NULL) == -1)
374
				fatal("pledge");
375
376
			break;
377
		case IMSG_STARTUP:
378
			frontend_startup();
379
			break;
380
#ifndef	SMALL
381
		case IMSG_CTL_END:
382
			control_imsg_relay(&imsg);
383
			break;
384
#endif	/* SMALL */
385
		default:
386
			log_debug("%s: error handling imsg %d", __func__,
387
			    imsg.hdr.type);
388
			break;
389
		}
390
		imsg_free(&imsg);
391
	}
392
	if (!shut)
393
		imsg_event_add(iev);
394
	else {
395
		/* This pipe is dead. Remove its event handler. */
396
		event_del(&iev->ev);
397
		event_loopexit(NULL);
398
	}
399
}
400
401
void
402
frontend_dispatch_engine(int fd, short event, void *bula)
403
{
404
	struct imsgev		*iev = bula;
405
	struct imsgbuf		*ibuf = &iev->ibuf;
406
	struct imsg		 imsg;
407
	ssize_t			 n;
408
	int			 shut = 0;
409
	uint32_t		 if_index;
410
411
	if (event & EV_READ) {
412
		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
413
			fatal("imsg_read error");
414
		if (n == 0)	/* Connection closed. */
415
			shut = 1;
416
	}
417
	if (event & EV_WRITE) {
418
		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
419
			fatal("msgbuf_write");
420
		if (n == 0)	/* Connection closed. */
421
			shut = 1;
422
	}
423
424
	for (;;) {
425
		if ((n = imsg_get(ibuf, &imsg)) == -1)
426
			fatal("%s: imsg_get error", __func__);
427
		if (n == 0)	/* No more messages. */
428
			break;
429
430
		switch (imsg.hdr.type) {
431
#ifndef	SMALL
432
		case IMSG_CTL_END:
433
		case IMSG_CTL_SHOW_INTERFACE_INFO:
434
		case IMSG_CTL_SHOW_INTERFACE_INFO_RA:
435
		case IMSG_CTL_SHOW_INTERFACE_INFO_RA_PREFIX:
436
		case IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS:
437
		case IMSG_CTL_SHOW_INTERFACE_INFO_RA_DNSSL:
438
		case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS:
439
		case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL:
440
		case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS:
441
		case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL:
442
			control_imsg_relay(&imsg);
443
			break;
444
#endif	/* SMALL */
445
		case IMSG_CTL_SEND_SOLICITATION:
446
			if_index = *((uint32_t *)imsg.data);
447
			send_solicitation(if_index);
448
			break;
449
		case IMSG_FAKE_ACK:
450
			frontend_imsg_compose_engine(IMSG_PROPOSAL_ACK,
451
			   0, 0, imsg.data, sizeof(struct imsg_proposal_ack));
452
			break;
453
		default:
454
			log_debug("%s: error handling imsg %d", __func__,
455
			    imsg.hdr.type);
456
			break;
457
		}
458
		imsg_free(&imsg);
459
	}
460
	if (!shut)
461
		imsg_event_add(iev);
462
	else {
463
		/* This pipe is dead. Remove its event handler. */
464
		event_del(&iev->ev);
465
		event_loopexit(NULL);
466
	}
467
}
468
469
int
470
get_flags(char *if_name)
471
{
472
	struct ifreq		 ifr;
473
474
	(void) strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
475
	if (ioctl(ioctlsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
476
		fatal("SIOCGIFFLAGS");
477
	return ifr.ifr_flags;
478
}
479
480
int
481
get_xflags(char *if_name)
482
{
483
	struct ifreq		 ifr;
484
485
	(void) strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
486
	if (ioctl(ioctlsock, SIOCGIFXFLAGS, (caddr_t)&ifr) < 0)
487
		fatal("SIOCGIFXFLAGS");
488
	return ifr.ifr_flags;
489
}
490
491
void
492
update_iface(uint32_t if_index, char* if_name)
493
{
494
	struct imsg_ifinfo	 imsg_ifinfo;
495
	int			 flags, xflags;
496
497
	flags = get_flags(if_name);
498
	xflags = get_xflags(if_name);
499
500
	if (!(xflags & IFXF_AUTOCONF6))
501
		return;
502
503
	memset(&imsg_ifinfo, 0, sizeof(imsg_ifinfo));
504
505
	imsg_ifinfo.if_index = if_index;
506
	imsg_ifinfo.running = (flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP |
507
	    IFF_RUNNING);
508
	imsg_ifinfo.autoconfprivacy = !(xflags & IFXF_INET6_NOPRIVACY);
509
	get_lladdr(if_name, &imsg_ifinfo.hw_address, &imsg_ifinfo.ll_address);
510
511
	memcpy(&nd_opt_source_link_addr, &imsg_ifinfo.hw_address,
512
	    sizeof(nd_opt_source_link_addr));
513
514
	frontend_imsg_compose_main(IMSG_UPDATE_IF, 0, &imsg_ifinfo,
515
	    sizeof(imsg_ifinfo));
516
}
517
518
#ifndef	SMALL
519
void
520
update_autoconf_addresses(uint32_t if_index, char* if_name)
521
{
522
	struct in6_ifreq	 ifr6;
523
	struct imsg_addrinfo	 imsg_addrinfo;
524
	struct ifaddrs		*ifap, *ifa;
525
	struct in6_addrlifetime *lifetime;
526
	struct sockaddr_in6	*sin6;
527
	time_t			 t;
528
	int			 xflags;
529
530
	xflags = get_xflags(if_name);
531
532
	if (!(xflags & IFXF_AUTOCONF6))
533
		return;
534
535
	memset(&imsg_addrinfo, 0, sizeof(imsg_addrinfo));
536
	imsg_addrinfo.if_index = if_index;
537
	get_lladdr(if_name, &imsg_addrinfo.hw_address,
538
	    &imsg_addrinfo.ll_address);
539
540
	if (getifaddrs(&ifap) != 0)
541
		fatal("getifaddrs");
542
543
	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
544
		if (strcmp(if_name, ifa->ifa_name) != 0)
545
			continue;
546
		if (ifa->ifa_addr->sa_family != AF_INET6)
547
			continue;
548
		sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
549
		if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
550
			continue;
551
552
		log_debug("%s: IP: %s", __func__, sin6_to_str(sin6));
553
		imsg_addrinfo.addr = *sin6;
554
555
		memset(&ifr6, 0, sizeof(ifr6));
556
		(void) strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name));
557
		memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr));
558
559
		if (ioctl(ioctlsock, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) < 0) {
560
			log_warn("SIOCGIFAFLAG_IN6");
561
			continue;
562
		}
563
564
		if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF |
565
		    IN6_IFF_PRIVACY)))
566
			continue;
567
568
		imsg_addrinfo.privacy = ifr6.ifr_ifru.ifru_flags6 &
569
		    IN6_IFF_PRIVACY ? 1 : 0;
570
571
		memset(&ifr6, 0, sizeof(ifr6));
572
		(void) strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name));
573
		memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr));
574
575
		if (ioctl(ioctlsock, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) < 0) {
576
			log_warn("SIOCGIFNETMASK_IN6");
577
			continue;
578
		}
579
580
		imsg_addrinfo.mask = ((struct sockaddr_in6 *)&ifr6.ifr_addr)
581
		    ->sin6_addr;
582
583
		memset(&ifr6, 0, sizeof(ifr6));
584
		(void) strlcpy(ifr6.ifr_name, if_name, sizeof(ifr6.ifr_name));
585
		memcpy(&ifr6.ifr_addr, sin6, sizeof(ifr6.ifr_addr));
586
		lifetime = &ifr6.ifr_ifru.ifru_lifetime;
587
588
		if (ioctl(ioctlsock, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) <
589
		    0) {
590
			log_warn("SIOCGIFALIFETIME_IN6");
591
			continue;
592
		}
593
594
		imsg_addrinfo.vltime = ND6_INFINITE_LIFETIME;
595
		imsg_addrinfo.pltime = ND6_INFINITE_LIFETIME;
596
		t = time(NULL);
597
598
		if (lifetime->ia6t_preferred)
599
			imsg_addrinfo.pltime = lifetime->ia6t_preferred < t ? 0
600
			    : lifetime->ia6t_preferred - t;
601
602
		if (lifetime->ia6t_expire)
603
			imsg_addrinfo.vltime = lifetime->ia6t_expire < t ? 0 :
604
			    lifetime->ia6t_expire - t;
605
606
		frontend_imsg_compose_main(IMSG_UPDATE_ADDRESS, 0,
607
		    &imsg_addrinfo, sizeof(imsg_addrinfo));
608
609
	}
610
	freeifaddrs(ifap);
611
}
612
#endif	/* SMALL */
613
614
void
615
frontend_startup(void)
616
{
617
	struct if_nameindex	*ifnidxp, *ifnidx;
618
619
	event_add(&ev_route, NULL);
620
	event_add(&icmp6ev.ev, NULL);
621
622
	if ((ifnidxp = if_nameindex()) == NULL)
623
		fatalx("if_nameindex");
624
625
	for(ifnidx = ifnidxp; ifnidx->if_index !=0 && ifnidx->if_name != NULL;
626
	    ifnidx++) {
627
		update_iface(ifnidx->if_index, ifnidx->if_name);
628
#ifndef	SMALL
629
		update_autoconf_addresses(ifnidx->if_index, ifnidx->if_name);
630
#endif	/* SMALL */
631
	}
632
633
	if_freenameindex(ifnidxp);
634
}
635
636
void
637
route_receive(int fd, short events, void *arg)
638
{
639
	static uint8_t			 buf[ROUTE_SOCKET_BUF_SIZE];
640
641
	struct rt_msghdr		*rtm = (struct rt_msghdr *)buf;
642
	struct sockaddr			*sa, *rti_info[RTAX_MAX];
643
	ssize_t				 n;
644
645
	if ((n = read(fd, &buf, sizeof(buf))) == -1) {
646
		if (errno == EAGAIN || errno == EINTR)
647
			return;
648
		log_warn("dispatch_rtmsg: read error");
649
		return;
650
	}
651
652
	if (n == 0)
653
		fatal("routing socket closed");
654
655
	if (n < rtm->rtm_msglen) {
656
		log_warnx("partial rtm in buffer");
657
		return;
658
	}
659
660
	if (rtm->rtm_version != RTM_VERSION)
661
		return;
662
663
	sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen);
664
	get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
665
666
	handle_route_message(rtm, rti_info);
667
}
668
669
void
670
handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info)
671
{
672
	struct if_msghdr		*ifm;
673
	struct imsg_proposal_ack	 proposal_ack;
674
	struct imsg_del_addr		 del_addr;
675
	struct sockaddr_rtlabel		*rl;
676
	int64_t				 id, pid;
677
	int				 flags, xflags, if_index;
678
	char				 ifnamebuf[IFNAMSIZ];
679
	char				*if_name;
680
	char				**ap, *argv[4], *p;
681
	const char			*errstr;
682
683
	switch (rtm->rtm_type) {
684
	case RTM_IFINFO:
685
		ifm = (struct if_msghdr *)rtm;
686
		if_name = if_indextoname(ifm->ifm_index, ifnamebuf);
687
		if (if_name == NULL) {
688
			log_debug("RTM_IFINFO: lost if %d", ifm->ifm_index);
689
			if_index = ifm->ifm_index;
690
			frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0, 0,
691
			    &if_index, sizeof(if_index));
692
		} else {
693
			xflags = get_xflags(if_name);
694
			flags = get_flags(if_name);
695
			if (!(xflags & IFXF_AUTOCONF6)) {
696
				log_debug("RTM_IFINFO: %s(%d) no(longer) "
697
				   "autoconf6", if_name, ifm->ifm_index);
698
				if_index = ifm->ifm_index;
699
				frontend_imsg_compose_engine(IMSG_REMOVE_IF, 0,
700
				    0, &if_index, sizeof(if_index));
701
			} else {
702
				update_iface(ifm->ifm_index, if_name);
703
#ifndef	SMALL
704
				update_autoconf_addresses(ifm->ifm_index,
705
				    if_name);
706
#endif	/* SMALL */
707
			}
708
		}
709
		break;
710
	case RTM_NEWADDR:
711
		ifm = (struct if_msghdr *)rtm;
712
		if_name = if_indextoname(ifm->ifm_index, ifnamebuf);
713
		log_debug("RTM_NEWADDR: %s[%u]", if_name, ifm->ifm_index);
714
		update_iface(ifm->ifm_index, if_name);
715
		break;
716
	case RTM_DELADDR:
717
		ifm = (struct if_msghdr *)rtm;
718
		if_name = if_indextoname(ifm->ifm_index, ifnamebuf);
719
		if (rtm->rtm_addrs & RTA_IFA && rti_info[RTAX_IFA]->sa_family
720
		    == AF_INET6) {
721
			del_addr.if_index = ifm->ifm_index;
722
			memcpy(&del_addr.addr, rti_info[RTAX_IFA], sizeof(
723
			    del_addr.addr));
724
			frontend_imsg_compose_engine(IMSG_DEL_ADDRESS,
725
				    0, 0, &del_addr, sizeof(del_addr));
726
			log_debug("RTM_DELADDR: %s[%u]", if_name,
727
			    ifm->ifm_index);
728
		}
729
		break;
730
	case RTM_PROPOSAL:
731
		ifm = (struct if_msghdr *)rtm;
732
		if_name = if_indextoname(ifm->ifm_index, ifnamebuf);
733
734
		if ((rtm->rtm_flags & (RTF_DONE | RTF_PROTO1)) ==
735
		    (RTF_DONE | RTF_PROTO1) && rtm->rtm_addrs == RTA_LABEL) {
736
			rl = (struct sockaddr_rtlabel *)rti_info[RTAX_LABEL];
737
			/* XXX validate rl */
738
739
			p = rl->sr_label;
740
741
			for (ap = argv; ap < &argv[3] && (*ap =
742
			    strsep(&p, " ")) != NULL;) {
743
				if (**ap != '\0')
744
					ap++;
745
			}
746
			*ap = NULL;
747
748
			if (argv[0] != NULL && strncmp(argv[0], "slaacd:",
749
			    strlen("slaacd:")) == 0 && argv[1] != NULL &&
750
			    argv[2] != NULL && argv[3] == NULL) {
751
				id = strtonum(argv[1], 0, INT64_MAX, &errstr);
752
				if (errstr != NULL) {
753
					log_warn("%s: proposal seq is %s: %s",
754
					    __func__, errstr, argv[1]);
755
					break;
756
				}
757
				pid = strtonum(argv[2], 0, INT32_MAX, &errstr);
758
				if (errstr != NULL) {
759
					log_warn("%s: pid is %s: %s",
760
					    __func__, errstr, argv[2]);
761
					break;
762
				}
763
				proposal_ack.id = id;
764
				proposal_ack.pid = pid;
765
				proposal_ack.if_index = ifm->ifm_index;
766
767
				frontend_imsg_compose_engine(IMSG_PROPOSAL_ACK,
768
				    0, 0, &proposal_ack, sizeof(proposal_ack));
769
			} else {
770
				log_debug("cannot parse: %s", rl->sr_label);
771
			}
772
		} else {
773
#if 0
774
			log_debug("%s: got flags %x, expcted %x", __func__,
775
			    rtm->rtm_flags, (RTF_DONE | RTF_PROTO1));
776
#endif
777
		}
778
779
		break;
780
	default:
781
		log_debug("unexpected RTM: %d", rtm->rtm_type);
782
		break;
783
	}
784
785
}
786
787
#define ROUNDUP(a) \
788
	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
789
790
void
791
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
792
{
793
	int	i;
794
795
	for (i = 0; i < RTAX_MAX; i++) {
796
		if (addrs & (1 << i)) {
797
			rti_info[i] = sa;
798
			sa = (struct sockaddr *)((char *)(sa) +
799
			    ROUNDUP(sa->sa_len));
800
		} else
801
			rti_info[i] = NULL;
802
	}
803
}
804
805
void
806
get_lladdr(char *if_name, struct ether_addr *mac, struct sockaddr_in6 *ll)
807
{
808
	struct ifaddrs		*ifap, *ifa;
809
	struct sockaddr_dl	*sdl;
810
	struct sockaddr_in6	*sin6;
811
812
	if (getifaddrs(&ifap) != 0)
813
		fatal("getifaddrs");
814
815
	memset(mac, 0, sizeof(*mac));
816
	memset(ll, 0, sizeof(*ll));
817
818
	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
819
		if (strcmp(if_name, ifa->ifa_name) != 0)
820
			continue;
821
822
		switch(ifa->ifa_addr->sa_family) {
823
		case AF_LINK:
824
			sdl = (struct sockaddr_dl *)ifa->ifa_addr;
825
			if (sdl->sdl_type != IFT_ETHER ||
826
			    sdl->sdl_alen != ETHER_ADDR_LEN)
827
				continue;
828
829
			memcpy(mac->ether_addr_octet, LLADDR(sdl),
830
			    ETHER_ADDR_LEN);
831
			break;
832
		case AF_INET6:
833
			sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
834
			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
835
				sin6->sin6_scope_id = ntohs(*(u_int16_t *)
836
				    &sin6->sin6_addr.s6_addr[2]);
837
				sin6->sin6_addr.s6_addr[2] =
838
				    sin6->sin6_addr.s6_addr[3] = 0;
839
				memcpy(ll, sin6, sizeof(*ll));
840
			}
841
			break;
842
		default:
843
			break;
844
		}
845
	}
846
	freeifaddrs(ifap);
847
}
848
849
void
850
icmp6_receive(int fd, short events, void *arg)
851
{
852
	struct imsg_ra		 ra;
853
854
	struct in6_pktinfo	*pi = NULL;
855
	struct cmsghdr		*cm;
856
	ssize_t			 len;
857
	int			 if_index = 0, *hlimp = NULL;
858
	char			 ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
859
	uint8_t			*p;
860
861
	p = icmp6ev.answer;
862
863
	if ((len = recvmsg(fd, &icmp6ev.rcvmhdr, 0)) < 0) {
864
		log_warn("recvmsg");
865
		return;
866
	}
867
868
	/* extract optional information via Advanced API */
869
	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&icmp6ev.rcvmhdr); cm;
870
	    cm = (struct cmsghdr *)CMSG_NXTHDR(&icmp6ev.rcvmhdr, cm)) {
871
		if (cm->cmsg_level == IPPROTO_IPV6 &&
872
		    cm->cmsg_type == IPV6_PKTINFO &&
873
		    cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
874
			pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
875
			if_index = pi->ipi6_ifindex;
876
		}
877
		if (cm->cmsg_level == IPPROTO_IPV6 &&
878
		    cm->cmsg_type == IPV6_HOPLIMIT &&
879
		    cm->cmsg_len == CMSG_LEN(sizeof(int)))
880
			hlimp = (int *)CMSG_DATA(cm);
881
	}
882
883
	if (if_index == 0) {
884
		log_warnx("failed to get receiving interface");
885
		return;
886
	}
887
888
	if (hlimp == NULL) {
889
		log_warnx("failed to get receiving hop limit");
890
		return;
891
	}
892
893
	if (*hlimp != 255) {
894
		log_warnx("invalid RA with hop limit of %d from %s on %s",
895
		    *hlimp, inet_ntop(AF_INET6, &icmp6ev.from.sin6_addr,
896
		    ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index,
897
		    ifnamebuf));
898
		return;
899
	}
900
901
	if ((size_t)len > sizeof(ra.packet)) {
902
		log_warnx("invalid RA with size %ld from %s on %s",
903
		    len, inet_ntop(AF_INET6, &icmp6ev.from.sin6_addr,
904
		    ntopbuf, INET6_ADDRSTRLEN), if_indextoname(if_index,
905
		    ifnamebuf));
906
		return;
907
	}
908
909
	ra.if_index = if_index;
910
	memcpy(&ra.from,  &icmp6ev.from, sizeof(ra.from));
911
	ra.len = len;
912
	memcpy(ra.packet, icmp6ev.answer, len);
913
914
	frontend_imsg_compose_engine(IMSG_RA, 0, 0, &ra, sizeof(ra));
915
}
916
917
void
918
send_solicitation(uint32_t if_index)
919
{
920
	struct in6_pktinfo		*pi;
921
	struct cmsghdr			*cm;
922
923
	log_debug("%s(%u)", __func__, if_index);
924
925
	dst.sin6_scope_id = if_index;
926
927
	cm = CMSG_FIRSTHDR(&sndmhdr);
928
	pi = (struct in6_pktinfo *)CMSG_DATA(cm);
929
	pi->ipi6_ifindex = if_index;
930
931
	if (sendmsg(icmp6sock, &sndmhdr, 0) != sizeof(rs) +
932
	    sizeof(nd_opt_hdr) + sizeof(nd_opt_source_link_addr))
933
		log_warn("sendmsg");
934
}