GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/dvmrpd/dvmrpe.c Lines: 0 229 0.0 %
Date: 2017-11-07 Branches: 0 168 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: dvmrpe.c,v 1.19 2016/09/02 16:20:34 benno Exp $ */
2
3
/*
4
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5
 * Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org>
6
 * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
7
 *
8
 * Permission to use, copy, modify, and distribute this software for any
9
 * purpose with or without fee is hereby granted, provided that the above
10
 * copyright notice and this permission notice appear in all copies.
11
 *
12
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
 */
20
21
#include <sys/types.h>
22
#include <sys/socket.h>
23
#include <sys/queue.h>
24
#include <netinet/in.h>
25
#include <arpa/inet.h>
26
#include <net/if_types.h>
27
#include <stdlib.h>
28
#include <signal.h>
29
#include <string.h>
30
#include <fcntl.h>
31
#include <pwd.h>
32
#include <unistd.h>
33
#include <event.h>
34
#include <err.h>
35
#include <errno.h>
36
#include <stdio.h>
37
38
#include "igmp.h"
39
#include "dvmrp.h"
40
#include "dvmrpd.h"
41
#include "dvmrpe.h"
42
#include "control.h"
43
#include "log.h"
44
45
void		 dvmrpe_sig_handler(int, short, void *);
46
__dead void	 dvmrpe_shutdown(void);
47
48
volatile sig_atomic_t	 dvmrpe_quit = 0;
49
struct dvmrpd_conf	*deconf = NULL;
50
struct imsgev		*iev_main;
51
struct imsgev		*iev_rde;
52
struct ctl_conn		*ctl_conn;
53
54
void
55
dvmrpe_sig_handler(int sig, short event, void *bula)
56
{
57
	switch (sig) {
58
	case SIGINT:
59
	case SIGTERM:
60
		dvmrpe_shutdown();
61
		/* NOTREACHED */
62
	default:
63
		fatalx("unexpected signal");
64
	}
65
}
66
67
/* dvmrp engine */
68
pid_t
69
dvmrpe(struct dvmrpd_conf *xconf, int pipe_parent2dvmrpe[2],
70
    int pipe_dvmrpe2rde[2], int pipe_parent2rde[2])
71
{
72
	struct iface	*iface = NULL;
73
	struct passwd	*pw;
74
	struct event	 ev_sigint, ev_sigterm;
75
	pid_t		 pid;
76
77
	switch (pid = fork()) {
78
	case -1:
79
		fatal("cannot fork");
80
	case 0:
81
		break;
82
	default:
83
84
		return (pid);
85
	}
86
87
	/* create the raw ip socket */
88
	if ((xconf->dvmrp_socket = socket(AF_INET,
89
	    SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
90
	    IPPROTO_IGMP)) == -1)
91
		fatal("error creating raw socket");
92
93
	/* create dvmrpd control socket outside chroot */
94
	if (control_init() == -1)
95
		fatalx("control socket setup failed");
96
97
	/* set some defaults */
98
	if (if_set_mcast_ttl(xconf->dvmrp_socket,
99
	    IP_DEFAULT_MULTICAST_TTL) == -1)
100
		fatal("if_set_mcast_ttl");
101
102
	if (if_set_mcast_loop(xconf->dvmrp_socket) == -1)
103
		fatal("if_set_mcast_loop");
104
105
	if (if_set_tos(xconf->dvmrp_socket, IPTOS_PREC_INTERNETCONTROL) == -1)
106
		fatal("if_set_tos");
107
108
	if_set_recvbuf(xconf->dvmrp_socket);
109
110
	deconf = xconf;
111
112
	if ((pw = getpwnam(DVMRPD_USER)) == NULL)
113
		fatal("getpwnam");
114
115
	if (chroot(pw->pw_dir) == -1)
116
		fatal("chroot");
117
	if (chdir("/") == -1)
118
		fatal("chdir(\"/\")");
119
120
	setproctitle("dvmrp engine");
121
	dvmrpd_process = PROC_DVMRP_ENGINE;
122
	log_procname = log_procnames[dvmrpd_process];
123
124
	if (setgroups(1, &pw->pw_gid) ||
125
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
126
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
127
		fatal("can't drop privileges");
128
129
	event_init();
130
	nbr_init(NBR_HASHSIZE);
131
132
	/* setup signal handler */
133
	signal_set(&ev_sigint, SIGINT, dvmrpe_sig_handler, NULL);
134
	signal_set(&ev_sigterm, SIGTERM, dvmrpe_sig_handler, NULL);
135
	signal_add(&ev_sigint, NULL);
136
	signal_add(&ev_sigterm, NULL);
137
	signal(SIGPIPE, SIG_IGN);
138
139
	/* setup pipes */
140
	close(pipe_parent2dvmrpe[0]);
141
	close(pipe_dvmrpe2rde[1]);
142
	close(pipe_parent2rde[0]);
143
	close(pipe_parent2rde[1]);
144
145
	if ((iev_rde = malloc(sizeof(struct imsgev))) == NULL ||
146
	    (iev_main = malloc(sizeof(struct imsgev))) == NULL)
147
		fatal(NULL);
148
	imsg_init(&iev_rde->ibuf, pipe_dvmrpe2rde[0]);
149
	iev_rde->handler = dvmrpe_dispatch_rde;
150
151
	imsg_init(&iev_main->ibuf, pipe_parent2dvmrpe[1]);
152
	iev_main->handler = dvmrpe_dispatch_main;
153
154
	/* setup event handler */
155
	iev_rde->events = EV_READ;
156
	event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events,
157
	    iev_rde->handler, iev_rde);
158
	event_add(&iev_rde->ev, NULL);
159
160
	iev_main->events = EV_READ;
161
	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
162
	    iev_main->handler, iev_main);
163
	event_add(&iev_main->ev, NULL);
164
165
	event_set(&deconf->ev, deconf->dvmrp_socket, EV_READ|EV_PERSIST,
166
	    recv_packet, deconf);
167
	event_add(&deconf->ev, NULL);
168
169
	/* listen on dvmrpd control socket */
170
	TAILQ_INIT(&ctl_conns);
171
	control_listen();
172
173
	if ((pkt_ptr = calloc(1, IBUF_READ_SIZE)) == NULL)
174
		fatal("dvmrpe");
175
176
	/* start interfaces */
177
	LIST_FOREACH(iface, &deconf->iface_list, entry) {
178
		if_init(xconf, iface);
179
		if (if_fsm(iface, IF_EVT_UP)) {
180
			log_debug("error starting interface %s", iface->name);
181
		}
182
	}
183
184
	evtimer_set(&deconf->report_timer, report_timer, deconf);
185
	start_report_timer();
186
187
	event_dispatch();
188
189
	dvmrpe_shutdown();
190
	/* NOTREACHED */
191
	return (0);
192
}
193
194
__dead void
195
dvmrpe_shutdown(void)
196
{
197
	struct iface	*iface;
198
199
	/* close pipes */
200
	msgbuf_write(&iev_rde->ibuf.w);
201
	msgbuf_clear(&iev_rde->ibuf.w);
202
	close(iev_rde->ibuf.fd);
203
	msgbuf_write(&iev_main->ibuf.w);
204
	msgbuf_clear(&iev_main->ibuf.w);
205
	close(iev_main->ibuf.fd);
206
207
	/* stop all interfaces and delete them */
208
	LIST_FOREACH(iface, &deconf->iface_list, entry) {
209
		if (if_fsm(iface, IF_EVT_DOWN)) {
210
			log_debug("error stopping interface %s",
211
			    iface->name);
212
		}
213
		if_del(iface);
214
	}
215
216
	/* clean up */
217
	free(iev_rde);
218
	free(iev_main);
219
	free(pkt_ptr);
220
221
	log_info("dvmrp engine exiting");
222
	_exit(0);
223
}
224
225
int
226
dvmrpe_imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen)
227
{
228
	return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
229
}
230
231
int
232
dvmrpe_imsg_compose_rde(int type, u_int32_t peerid, pid_t pid,
233
    void *data, u_int16_t datalen)
234
{
235
	return (imsg_compose_event(iev_rde, type, peerid, pid,
236
	     -1, data, datalen));
237
}
238
239
void
240
dvmrpe_dispatch_main(int fd, short event, void *bula)
241
{
242
	struct imsg	 imsg;
243
	struct imsgev	*iev = bula;
244
	struct imsgbuf  *ibuf = &iev->ibuf;
245
	struct kif	*kif;
246
	struct iface	*iface;
247
	ssize_t		 n;
248
	int		 shut = 0, link_ok;
249
250
	if (event & EV_READ) {
251
		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
252
			fatal("imsg_read error");
253
		if (n == 0)	/* connection closed */
254
			shut = 1;
255
	}
256
	if (event & EV_WRITE) {
257
		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
258
			fatal("msgbuf_write");
259
		if (n == 0)	/* connection closed */
260
			shut = 1;
261
	}
262
263
	for (;;) {
264
		if ((n = imsg_get(ibuf, &imsg)) == -1)
265
			fatal("dvmrpe_dispatch_main: imsg_read error");
266
		if (n == 0)
267
			break;
268
269
		switch (imsg.hdr.type) {
270
		case IMSG_IFINFO:
271
			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
272
			    sizeof(struct kif))
273
				fatalx("IFINFO imsg with wrong len");
274
			kif = imsg.data;
275
			link_ok = (kif->flags & IFF_UP) &&
276
			    LINK_STATE_IS_UP(kif->link_state);
277
278
			LIST_FOREACH(iface, &deconf->iface_list, entry) {
279
				if (kif->ifindex == iface->ifindex) {
280
					iface->flags = kif->flags;
281
					iface->linkstate = kif->link_state;
282
283
					if (link_ok) {
284
						if_fsm(iface, IF_EVT_UP);
285
						log_warnx("interface %s up",
286
						    iface->name);
287
					} else {
288
						if_fsm(iface, IF_EVT_DOWN);
289
						log_warnx("interface %s down",
290
						    iface->name);
291
					}
292
				}
293
			}
294
			break;
295
		default:
296
			log_debug("dvmrpe_dispatch_main: error handling "
297
			    "imsg %d", imsg.hdr.type);
298
			break;
299
		}
300
		imsg_free(&imsg);
301
	}
302
	if (!shut)
303
		imsg_event_add(iev);
304
	else {
305
		/* this pipe is dead, so remove the event handler */
306
		event_del(&iev->ev);
307
		event_loopexit(NULL);
308
	}
309
}
310
311
void
312
dvmrpe_dispatch_rde(int fd, short event, void *bula)
313
{
314
	struct imsgev		*iev = bula;
315
	struct imsgbuf		*ibuf = &iev->ibuf;
316
	struct imsg		 imsg;
317
	struct nbr		*nbr;
318
	struct prune		 p;
319
	struct iface		*iface;
320
	struct route_report	*rr;
321
	ssize_t			 n;
322
	int			 shut = 0;
323
324
	 if (event & EV_READ) {
325
		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
326
			fatal("imsg_read error");
327
		if (n == 0)	/* connection closed */
328
			shut = 1;
329
	}
330
	if (event & EV_WRITE) {
331
		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
332
			fatal("msgbuf_write");
333
		if (n == 0)	/* connection closed */
334
			shut = 1;
335
	}
336
337
	for (;;) {
338
		if ((n = imsg_get(ibuf, &imsg)) == -1)
339
			fatal("dvmrpe_dispatch_rde: imsg_read error");
340
		if (n == 0)
341
			break;
342
343
		switch (imsg.hdr.type) {
344
		case IMSG_CTL_SHOW_RIB:
345
		case IMSG_CTL_SHOW_SUM:
346
		case IMSG_CTL_SHOW_MFC:
347
		case IMSG_CTL_END:
348
			control_imsg_relay(&imsg);
349
			break;
350
		case IMSG_FULL_ROUTE_REPORT:
351
			/* add route reports to list */
352
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(*rr))
353
				fatalx("invalid size of RDE request");
354
355
			if ((rr = calloc(1, sizeof(*rr))) == NULL)
356
				fatal("dvmrpe_dispatch_rde");
357
358
			memcpy(rr, imsg.data, sizeof(*rr));
359
360
			/* general update, per interface */
361
			if (imsg.hdr.peerid == 0) {
362
				/* add to interface list */
363
				LIST_FOREACH(iface, &deconf->iface_list,
364
				    entry) {
365
					if (!if_nbr_list_empty(iface))
366
						rr_list_add(&iface->rr_list,
367
						    rr);
368
				}
369
				break;
370
			}
371
372
			/* add to neighbor list */
373
			nbr = nbr_find_peerid(imsg.hdr.peerid);
374
			rr_list_add(&nbr->rr_list, rr);
375
			break;
376
		case IMSG_FULL_ROUTE_REPORT_END:
377
			/* transmit route report */
378
			if (imsg.hdr.peerid == 0) {
379
				/*
380
				 * send general route report on all
381
				 * interfaces with neighbors.
382
				 */
383
				LIST_FOREACH(iface, &deconf->iface_list,
384
				    entry) {
385
					rr_list_send(&iface->rr_list,
386
					    iface, NULL);
387
				}
388
				break;
389
			}
390
391
			nbr = nbr_find_peerid(imsg.hdr.peerid);
392
			rr_list_send(&nbr->rr_list, NULL, nbr);
393
			break;
394
		case IMSG_SEND_PRUNE:
395
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(p))
396
				fatalx("invalid size of RDE request");
397
398
			memcpy(&p, imsg.data, sizeof(p));
399
400
			LIST_FOREACH(iface, &deconf->iface_list, entry)
401
				if (p.ifindex == iface->ifindex)
402
					break;
403
404
			if (iface == NULL)
405
				fatalx("invalid interface in mfc");
406
407
			nbr = nbr_find_ip(iface, p.nexthop.s_addr);
408
			if (nbr == NULL)
409
				fatalx("unknown neighbor to send prune");
410
411
			send_prune(nbr, &p);
412
413
			break;
414
		case IMSG_FLASH_UPDATE:
415
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(*rr))
416
				fatalx("invalid size of RDE request");
417
418
			if ((rr = calloc(1, sizeof(*rr))) == NULL)
419
				fatal("dvmrpe_dispatch_rde");
420
421
			memcpy(rr, imsg.data, sizeof(*rr));
422
423
			LIST_FOREACH(iface, &deconf->iface_list, entry) {
424
				if (!if_nbr_list_empty(iface)) {
425
					rr_list_add(&iface->rr_list, rr);
426
					rr_list_send(&iface->rr_list, iface,
427
					    NULL);
428
				}
429
			}
430
			break;
431
		case IMSG_FLASH_UPDATE_DS:
432
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(*rr))
433
				fatalx("invalid size of RDE request");
434
435
			if ((rr = calloc(1, sizeof(*rr))) == NULL)
436
				fatal("dvmrpe_dispatch_rde");
437
438
			memcpy(rr, imsg.data, sizeof(*rr));
439
440
			LIST_FOREACH(iface, &deconf->iface_list, entry) {
441
				if (iface->ifindex == rr->ifindex)
442
					continue;
443
				if (!if_nbr_list_empty(iface)) {
444
					rr_list_add(&iface->rr_list, rr);
445
					rr_list_send(&iface->rr_list, iface,
446
					    NULL);
447
				}
448
			}
449
			break;
450
		default:
451
			log_debug("dvmrpe_dispatch_rde: error handling imsg %d",
452
			    imsg.hdr.type);
453
			break;
454
		}
455
		imsg_free(&imsg);
456
	}
457
	if (!shut)
458
		imsg_event_add(iev);
459
	else {
460
		/* this pipe is dead, so remove the event handler */
461
		event_del(&iev->ev);
462
		event_loopexit(NULL);
463
	}
464
}
465
466
void
467
dvmrpe_iface_ctl(struct ctl_conn *c, unsigned int idx)
468
{
469
	struct iface		*iface;
470
	struct ctl_iface	*ictl;
471
472
	LIST_FOREACH(iface, &deconf->iface_list, entry)
473
		if (idx == 0 || idx == iface->ifindex) {
474
			ictl = if_to_ctl(iface);
475
			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_IFACE,
476
			    0, 0, -1, ictl, sizeof(struct ctl_iface));
477
		}
478
}
479
480
void
481
dvmrpe_iface_igmp_ctl(struct ctl_conn *c, unsigned int idx)
482
{
483
	struct iface		*iface;
484
	struct ctl_iface	*ictl;
485
486
	LIST_FOREACH(iface, &deconf->iface_list, entry)
487
		if (idx == 0 || idx == iface->ifindex) {
488
			ictl = if_to_ctl(iface);
489
			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_IFACE,
490
			    0, 0, -1, ictl, sizeof(struct ctl_iface));
491
			group_list_dump(iface, c);
492
493
		}
494
}
495
496
void
497
dvmrpe_nbr_ctl(struct ctl_conn *c)
498
{
499
	struct iface	*iface;
500
	struct nbr	*nbr;
501
	struct ctl_nbr	*nctl;
502
503
	LIST_FOREACH(iface, &deconf->iface_list, entry)
504
		LIST_FOREACH(nbr, &iface->nbr_list, entry) {
505
			nctl = nbr_to_ctl(nbr);
506
			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR,
507
			    0, 0, -1, nctl, sizeof(struct ctl_nbr));
508
		}
509
510
	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
511
}