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

Line Branch Exec Source
1
/*	$OpenBSD: rde.c,v 1.29 2016/09/02 16:20:34 benno Exp $ */
2
3
/*
4
 * Copyright (c) 2004, 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 <err.h>
27
#include <errno.h>
28
#include <stdlib.h>
29
#include <signal.h>
30
#include <string.h>
31
#include <pwd.h>
32
#include <unistd.h>
33
#include <event.h>
34
35
#include "igmp.h"
36
#include "dvmrp.h"
37
#include "dvmrpd.h"
38
#include "dvmrpe.h"
39
#include "log.h"
40
#include "rde.h"
41
42
void		 rde_sig_handler(int sig, short, void *);
43
__dead void	 rde_shutdown(void);
44
void		 rde_dispatch_imsg(int, short, void *);
45
46
int		 rde_select_ds_ifs(struct mfc *, struct iface *);
47
48
volatile sig_atomic_t	 rde_quit = 0;
49
struct dvmrpd_conf	*rdeconf = NULL;
50
struct rde_nbr		*nbrself;
51
struct imsgev		*iev_dvmrpe;
52
struct imsgev		*iev_main;
53
54
void
55
rde_sig_handler(int sig, short event, void *arg)
56
{
57
	/*
58
	 * signal handler rules don't apply, libevent decouples for us
59
	 */
60
61
	switch (sig) {
62
	case SIGINT:
63
	case SIGTERM:
64
		rde_shutdown();
65
		/* NOTREACHED */
66
	default:
67
		fatalx("unexpected signal");
68
	}
69
}
70
71
/* route decision engine */
72
pid_t
73
rde(struct dvmrpd_conf *xconf, int pipe_parent2rde[2], int pipe_dvmrpe2rde[2],
74
    int pipe_parent2dvmrpe[2])
75
{
76
	struct passwd		*pw;
77
	struct event		 ev_sigint, ev_sigterm;
78
	pid_t			 pid;
79
80
	switch (pid = fork()) {
81
	case -1:
82
		fatal("cannot fork");
83
	case 0:
84
		break;
85
	default:
86
		return (pid);
87
	}
88
89
	rdeconf = xconf;
90
91
	if ((pw = getpwnam(DVMRPD_USER)) == NULL)
92
		fatal("getpwnam");
93
94
	if (chroot(pw->pw_dir) == -1)
95
		fatal("chroot");
96
	if (chdir("/") == -1)
97
		fatal("chdir(\"/\")");
98
99
	setproctitle("route decision engine");
100
	dvmrpd_process = PROC_RDE_ENGINE;
101
	log_procname = log_procnames[dvmrpd_process];
102
103
	if (setgroups(1, &pw->pw_gid) ||
104
	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
105
	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
106
		fatal("can't drop privileges");
107
108
	event_init();
109
110
	/* setup signal handler */
111
	signal_set(&ev_sigint, SIGINT, rde_sig_handler, NULL);
112
	signal_set(&ev_sigterm, SIGTERM, rde_sig_handler, NULL);
113
	signal_add(&ev_sigint, NULL);
114
	signal_add(&ev_sigterm, NULL);
115
	signal(SIGPIPE, SIG_IGN);
116
117
	/* setup pipes */
118
	close(pipe_dvmrpe2rde[0]);
119
	close(pipe_parent2rde[0]);
120
	close(pipe_parent2dvmrpe[0]);
121
	close(pipe_parent2dvmrpe[1]);
122
123
	if ((iev_dvmrpe = malloc(sizeof(struct imsgev))) == NULL ||
124
	    (iev_main = malloc(sizeof(struct imsgev))) == NULL)
125
		fatal(NULL);
126
127
	imsg_init(&iev_dvmrpe->ibuf, pipe_dvmrpe2rde[1]);
128
	iev_dvmrpe->handler = rde_dispatch_imsg;
129
130
	imsg_init(&iev_main->ibuf, pipe_parent2rde[1]);
131
	iev_main->handler = rde_dispatch_imsg;
132
133
	/* setup event handler */
134
	iev_dvmrpe->events = EV_READ;
135
	event_set(&iev_dvmrpe->ev, iev_dvmrpe->ibuf.fd, iev_dvmrpe->events,
136
	    iev_dvmrpe->handler, iev_dvmrpe);
137
	event_add(&iev_dvmrpe->ev, NULL);
138
139
	iev_main->events = EV_READ;
140
	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
141
	    iev_main->handler, iev_main);
142
	event_add(&iev_main->ev, NULL);
143
144
	rt_init();
145
	mfc_init();
146
147
	event_dispatch();
148
149
	rde_shutdown();
150
	/* NOTREACHED */
151
	return (0);
152
}
153
154
__dead void
155
rde_shutdown(void)
156
{
157
	struct iface	*iface;
158
159
	/* close pipes */
160
	msgbuf_clear(&iev_dvmrpe->ibuf.w);
161
	close(iev_dvmrpe->ibuf.fd);
162
	msgbuf_clear(&iev_main->ibuf.w);
163
	close(iev_main->ibuf.fd);
164
165
	rt_clear();
166
	mfc_clear();
167
168
	LIST_FOREACH(iface, &rdeconf->iface_list, entry) {
169
		if_del(iface);
170
	}
171
172
	free(iev_dvmrpe);
173
	free(iev_main);
174
	free(rdeconf);
175
176
	log_info("route decision engine exiting");
177
	_exit(0);
178
}
179
180
/* imesg */
181
int
182
rde_imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen)
183
{
184
	return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
185
}
186
187
int
188
rde_imsg_compose_dvmrpe(int type, u_int32_t peerid, pid_t pid, void *data,
189
    u_int16_t datalen)
190
{
191
	return (imsg_compose_event(iev_dvmrpe, type, peerid, pid, -1,
192
	     data, datalen));
193
}
194
195
void
196
rde_dispatch_imsg(int fd, short event, void *bula)
197
{
198
	struct mfc		 mfc;
199
	struct prune		 p;
200
	struct imsgev		*iev = bula;
201
	struct imsgbuf		*ibuf = &iev->ibuf;
202
	struct imsg		 imsg;
203
	struct route_report	 rr;
204
	struct nbr_msg		 nm;
205
	int			 i, connected = 0, shut = 0, verbose;
206
	ssize_t			 n;
207
	struct iface		*iface;
208
209
	if (event & EV_READ) {
210
		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
211
			fatal("imsg_read error");
212
		if (n == 0)	/* connection closed */
213
			shut = 1;
214
	}
215
	if (event & EV_WRITE) {
216
		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
217
			fatal("msgbuf_write");
218
		if (n == 0)	/* connection closed */
219
			shut = 1;
220
	}
221
222
	for (;;) {
223
		if ((n = imsg_get(ibuf, &imsg)) == -1)
224
			fatal("rde_dispatch_imsg: imsg_get error");
225
		if (n == 0)
226
			break;
227
228
		switch (imsg.hdr.type) {
229
		case IMSG_CTL_SHOW_RIB:
230
			rt_dump(imsg.hdr.pid);
231
			imsg_compose_event(iev_dvmrpe, IMSG_CTL_END, 0,
232
			    imsg.hdr.pid, -1, NULL, 0);
233
			break;
234
		case IMSG_CTL_SHOW_MFC:
235
			mfc_dump(imsg.hdr.pid);
236
			imsg_compose_event(iev_dvmrpe, IMSG_CTL_END, 0,
237
			    imsg.hdr.pid, -1, NULL, 0);
238
			break;
239
		case IMSG_ROUTE_REPORT:
240
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rr))
241
				fatalx("invalid size of OE request");
242
			memcpy(&rr, imsg.data, sizeof(rr));
243
244
			/* directly connected networks from parent */
245
			if (imsg.hdr.peerid == 0)
246
				connected = 1;
247
248
			if (srt_check_route(&rr, connected) == -1)
249
				log_debug("rde_dispatch_imsg: "
250
				    "packet malformed");
251
			break;
252
		case IMSG_FULL_ROUTE_REPORT:
253
			rt_snap(imsg.hdr.peerid);
254
			rde_imsg_compose_dvmrpe(IMSG_FULL_ROUTE_REPORT_END,
255
			    imsg.hdr.peerid, 0, NULL, 0);
256
			break;
257
		case IMSG_MFC_ADD:
258
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(mfc))
259
				fatalx("invalid size of OE request");
260
			memcpy(&mfc, imsg.data, sizeof(mfc));
261
#if 1
262
			for (i = 0; i < MAXVIFS; i++)
263
				mfc.ttls[i] = 0;
264
265
			LIST_FOREACH(iface, &rdeconf->iface_list, entry) {
266
				if (rde_select_ds_ifs(&mfc, iface))
267
					mfc.ttls[iface->ifindex] = 1;
268
			}
269
270
			mfc_update(&mfc);
271
#endif
272
			break;
273
		case IMSG_MFC_DEL:
274
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(mfc))
275
				fatalx("invalid size of OE request");
276
			memcpy(&mfc, imsg.data, sizeof(mfc));
277
#if 1
278
			mfc_delete(&mfc);
279
#endif
280
			break;
281
		case IMSG_GROUP_ADD:
282
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(mfc))
283
				fatalx("invalid size of OE request");
284
			memcpy(&mfc, imsg.data, sizeof(mfc));
285
286
			iface = if_find_index(mfc.ifindex);
287
			if (iface == NULL) {
288
				fatalx("rde_dispatch_imsg: "
289
				    "cannot find matching interface");
290
			}
291
292
			rde_group_list_add(iface, mfc.group);
293
			break;
294
		case IMSG_GROUP_DEL:
295
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(mfc))
296
				fatalx("invalid size of OE request");
297
			memcpy(&mfc, imsg.data, sizeof(mfc));
298
299
			iface = if_find_index(mfc.ifindex);
300
			if (iface == NULL) {
301
				fatalx("rde_dispatch_imsg: "
302
				    "cannot find matching interface");
303
			}
304
305
			rde_group_list_remove(iface, mfc.group);
306
			break;
307
		case IMSG_NBR_DEL:
308
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(nm))
309
				fatalx("invalid size of OE request");
310
311
			memcpy(&nm, imsg.data, sizeof(nm));
312
313
			srt_expire_nbr(nm.address, nm.ifindex);
314
			break;
315
		case IMSG_RECV_PRUNE:
316
			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(p))
317
				fatalx("invalid size of OE request");
318
			memcpy(&p, imsg.data, sizeof(p));
319
320
			mfc_recv_prune(&p);
321
			break;
322
		case IMSG_CTL_LOG_VERBOSE:
323
			/* already checked by dvmrpe */
324
			memcpy(&verbose, imsg.data, sizeof(verbose));
325
			log_verbose(verbose);
326
			break;
327
		default:
328
			log_debug("rde_dispatch_msg: unexpected imsg %d",
329
			    imsg.hdr.type);
330
			break;
331
		}
332
		imsg_free(&imsg);
333
	}
334
	if (!shut)
335
		imsg_event_add(iev);
336
	else {
337
		/* this pipe is dead, so remove the event handler */
338
		event_del(&iev->ev);
339
		event_loopexit(NULL);
340
	}
341
}
342
343
int
344
rde_select_ds_ifs(struct mfc *mfc, struct iface *iface)
345
{
346
	struct rt_node	*rn;
347
348
	if (mfc->ifindex == iface->ifindex)
349
		return (0);
350
351
	if (rde_group_list_find(iface, mfc->group))
352
		return (1);
353
354
	rn = rt_match_origin(mfc->origin.s_addr);
355
	if (rn == NULL) {
356
		log_debug("rde_selected_ds_iface: no informations about "
357
		    "the origin %s", inet_ntoa(mfc->origin));
358
		return (0);
359
	}
360
361
	if (rn->ds_cnt[iface->ifindex] != 0)
362
		return (1);
363
364
	return (0);
365
}
366
367
/* rde group functions */
368
void
369
rde_group_list_add(struct iface *iface, struct in_addr group)
370
{
371
	struct rde_group	*rdegrp;
372
373
	/* validate group id */
374
	if (!IN_MULTICAST(htonl(group.s_addr))) {
375
		log_debug("rde_group_list_add: interface %s, %s is not a "
376
		    "multicast address", iface->name,
377
		    inet_ntoa(group));
378
		return;
379
	}
380
381
	if (rde_group_list_find(iface, group))
382
		return;
383
384
	rdegrp = calloc(1, sizeof(*rdegrp));
385
	if (rdegrp == NULL)
386
		fatal("rde_group_list_add");
387
388
	rdegrp->rde_group.s_addr = group.s_addr;
389
390
	TAILQ_INSERT_TAIL(&iface->rde_group_list, rdegrp, entry);
391
392
	log_debug("rde_group_list_add: interface %s, group %s", iface->name,
393
	    inet_ntoa(rdegrp->rde_group));
394
395
	return;
396
}
397
398
int
399
rde_group_list_find(struct iface *iface, struct in_addr group)
400
{
401
	struct rde_group	*rdegrp = NULL;
402
403
	/* validate group id */
404
	if (!IN_MULTICAST(htonl(group.s_addr))) {
405
		log_debug("rde_group_list_find: interface %s, %s is not a "
406
		    "multicast address", iface->name,
407
		    inet_ntoa(group));
408
		return (0);
409
	}
410
411
	TAILQ_FOREACH(rdegrp, &iface->rde_group_list, entry) {
412
		if (rdegrp->rde_group.s_addr == group.s_addr)
413
			return (1);
414
	}
415
416
	return (0);
417
}
418
419
void
420
rde_group_list_remove(struct iface *iface, struct in_addr group)
421
{
422
	struct rde_group	*rg;
423
	struct rt_node		*rn;
424
425
	if (TAILQ_EMPTY(&iface->rde_group_list))
426
		fatalx("rde_group_list_remove: group does not exist");
427
428
	for (rg = TAILQ_FIRST(&iface->rde_group_list); rg != NULL;
429
	    rg = TAILQ_NEXT(rg, entry)) {
430
		if (rg->rde_group.s_addr == group.s_addr) {
431
			log_debug("group_list_remove: interface %s, group %s",
432
			    iface->name, inet_ntoa(rg->rde_group));
433
			TAILQ_REMOVE(&iface->rde_group_list, rg, entry);
434
			free(rg);
435
		}
436
	}
437
438
	rn = mfc_find_origin(group);
439
	if (rn == NULL)
440
		return;
441
442
	srt_check_downstream_ifaces(rn, iface);
443
}