xref: /openbsd/usr.sbin/dvmrpd/dvmrpe.c (revision 8ba96280)
1 /*	$OpenBSD: dvmrpe.c,v 1.12 2014/07/12 19:22:32 krw 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 #include <stdlib.h>
38 
39 #include "igmp.h"
40 #include "dvmrp.h"
41 #include "dvmrpd.h"
42 #include "dvmrpe.h"
43 #include "control.h"
44 #include "log.h"
45 
46 void	 dvmrpe_sig_handler(int, short, void *);
47 void	 dvmrpe_shutdown(void);
48 
49 volatile sig_atomic_t	 dvmrpe_quit = 0;
50 struct dvmrpd_conf	*deconf = NULL;
51 struct imsgev		*iev_main;
52 struct imsgev		*iev_rde;
53 struct ctl_conn		*ctl_conn;
54 
55 void
56 dvmrpe_sig_handler(int sig, short event, void *bula)
57 {
58 	switch (sig) {
59 	case SIGINT:
60 	case SIGTERM:
61 		dvmrpe_shutdown();
62 		/* NOTREACHED */
63 	default:
64 		fatalx("unexpected signal");
65 	}
66 }
67 
68 /* dvmrp engine */
69 pid_t
70 dvmrpe(struct dvmrpd_conf *xconf, int pipe_parent2dvmrpe[2],
71     int pipe_dvmrpe2rde[2], int pipe_parent2rde[2])
72 {
73 	struct iface	*iface = NULL;
74 	struct passwd	*pw;
75 	struct event	 ev_sigint, ev_sigterm;
76 	pid_t		 pid;
77 
78 	switch (pid = fork()) {
79 	case -1:
80 		fatal("cannot fork");
81 	case 0:
82 		break;
83 	default:
84 
85 		return (pid);
86 	}
87 
88 	/* create the raw ip socket */
89 	if ((xconf->dvmrp_socket = socket(AF_INET, SOCK_RAW,
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 
123 	if (setgroups(1, &pw->pw_gid) ||
124 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
125 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
126 		fatal("can't drop privileges");
127 
128 	event_init();
129 	nbr_init(NBR_HASHSIZE);
130 
131 	/* setup signal handler */
132 	signal_set(&ev_sigint, SIGINT, dvmrpe_sig_handler, NULL);
133 	signal_set(&ev_sigterm, SIGTERM, dvmrpe_sig_handler, NULL);
134 	signal_add(&ev_sigint, NULL);
135 	signal_add(&ev_sigterm, NULL);
136 	signal(SIGPIPE, SIG_IGN);
137 
138 	/* setup pipes */
139 	close(pipe_parent2dvmrpe[0]);
140 	close(pipe_dvmrpe2rde[1]);
141 	close(pipe_parent2rde[0]);
142 	close(pipe_parent2rde[1]);
143 
144 	if ((iev_rde = malloc(sizeof(struct imsgev))) == NULL ||
145 	    (iev_main = malloc(sizeof(struct imsgev))) == NULL)
146 		fatal(NULL);
147 	imsg_init(&iev_rde->ibuf, pipe_dvmrpe2rde[0]);
148 	iev_rde->handler = dvmrpe_dispatch_rde;
149 
150 	imsg_init(&iev_main->ibuf, pipe_parent2dvmrpe[1]);
151 	iev_main->handler = dvmrpe_dispatch_main;
152 
153 	/* setup event handler */
154 	iev_rde->events = EV_READ;
155 	event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events,
156 	    iev_rde->handler, iev_rde);
157 	event_add(&iev_rde->ev, NULL);
158 
159 	iev_main->events = EV_READ;
160 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
161 	    iev_main->handler, iev_main);
162 	event_add(&iev_main->ev, NULL);
163 
164 	event_set(&deconf->ev, deconf->dvmrp_socket, EV_READ|EV_PERSIST,
165 	    recv_packet, deconf);
166 	event_add(&deconf->ev, NULL);
167 
168 	/* listen on dvmrpd control socket */
169 	TAILQ_INIT(&ctl_conns);
170 	control_listen();
171 
172 	if ((pkt_ptr = calloc(1, IBUF_READ_SIZE)) == NULL)
173 		fatal("dvmrpe");
174 
175 	/* start interfaces */
176 	LIST_FOREACH(iface, &deconf->iface_list, entry) {
177 		if_init(xconf, iface);
178 		if (if_fsm(iface, IF_EVT_UP)) {
179 			log_debug("error starting interface %s", iface->name);
180 		}
181 	}
182 
183 	evtimer_set(&deconf->report_timer, report_timer, deconf);
184 	start_report_timer();
185 
186 	event_dispatch();
187 
188 	dvmrpe_shutdown();
189 	/* NOTREACHED */
190 	return (0);
191 }
192 
193 void
194 dvmrpe_shutdown(void)
195 {
196 	struct iface	*iface;
197 
198 	/* stop all interfaces and delete them */
199 	LIST_FOREACH(iface, &deconf->iface_list, entry) {
200 		if (if_fsm(iface, IF_EVT_DOWN)) {
201 			log_debug("error stopping interface %s",
202 			    iface->name);
203 		}
204 		if_del(iface);
205 	}
206 
207 	/* clean up */
208 	msgbuf_write(&iev_rde->ibuf.w);
209 	msgbuf_clear(&iev_rde->ibuf.w);
210 	free(iev_rde);
211 	msgbuf_write(&iev_main->ibuf.w);
212 	msgbuf_clear(&iev_main->ibuf.w);
213 	free(iev_main);
214 	free(pkt_ptr);
215 
216 	log_info("dvmrp engine exiting");
217 	_exit(0);
218 }
219 
220 int
221 dvmrpe_imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen)
222 {
223 	return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
224 }
225 
226 int
227 dvmrpe_imsg_compose_rde(int type, u_int32_t peerid, pid_t pid,
228     void *data, u_int16_t datalen)
229 {
230 	return (imsg_compose_event(iev_rde, type, peerid, pid,
231 	     -1, data, datalen));
232 }
233 
234 void
235 dvmrpe_dispatch_main(int fd, short event, void *bula)
236 {
237 	struct imsg	 imsg;
238 	struct imsgev	*iev = bula;
239 	struct imsgbuf  *ibuf = &iev->ibuf;
240 	struct kif	*kif;
241 	struct iface	*iface;
242 	ssize_t		 n;
243 	int		 link_ok;
244 
245 	if (event & EV_READ) {
246 		if ((n = imsg_read(ibuf)) == -1)
247 			fatal("imsg_read error");
248 		if (n == 0)	/* connection closed */
249 			fatalx("pipe closed");
250 	}
251 	if (event & EV_WRITE) {
252 		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
253 			fatal("msgbuf_write");
254 	}
255 
256 	for (;;) {
257 		if ((n = imsg_get(ibuf, &imsg)) == -1)
258 			fatal("dvmrpe_dispatch_main: imsg_read error");
259 		if (n == 0)
260 			break;
261 
262 		switch (imsg.hdr.type) {
263 		case IMSG_IFINFO:
264 			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
265 			    sizeof(struct kif))
266 				fatalx("IFINFO imsg with wrong len");
267 			kif = imsg.data;
268 			link_ok = (kif->flags & IFF_UP) &&
269 			    LINK_STATE_IS_UP(kif->link_state);
270 
271 			LIST_FOREACH(iface, &deconf->iface_list, entry) {
272 				if (kif->ifindex == iface->ifindex) {
273 					iface->flags = kif->flags;
274 					iface->linkstate = kif->link_state;
275 
276 					if (link_ok) {
277 						if_fsm(iface, IF_EVT_UP);
278 						log_warnx("interface %s up",
279 						    iface->name);
280 					} else {
281 						if_fsm(iface, IF_EVT_DOWN);
282 						log_warnx("interface %s down",
283 						    iface->name);
284 					}
285 				}
286 			}
287 			break;
288 		default:
289 			log_debug("dvmrpe_dispatch_main: error handling "
290 			    "imsg %d", imsg.hdr.type);
291 			break;
292 		}
293 		imsg_free(&imsg);
294 	}
295 	imsg_event_add(iev);
296 }
297 
298 void
299 dvmrpe_dispatch_rde(int fd, short event, void *bula)
300 {
301 	struct imsgev		*iev = bula;
302 	struct imsgbuf		*ibuf = &iev->ibuf;
303 	struct imsg		 imsg;
304 	struct nbr		*nbr;
305 	struct prune		 p;
306 	struct iface		*iface;
307 	struct route_report	*rr;
308 	ssize_t			 n;
309 
310 	 if (event & EV_READ) {
311 		if ((n = imsg_read(ibuf)) == -1)
312 			fatal("imsg_read error");
313 		if (n == 0)	/* connection closed */
314 			fatalx("pipe closed");
315 	}
316 	if (event & EV_WRITE) {
317 		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
318 			fatal("msgbuf_write");
319 	}
320 
321 	for (;;) {
322 		if ((n = imsg_get(ibuf, &imsg)) == -1)
323 			fatal("dvmrpe_dispatch_rde: imsg_read error");
324 		if (n == 0)
325 			break;
326 
327 		switch (imsg.hdr.type) {
328 		case IMSG_CTL_SHOW_RIB:
329 		case IMSG_CTL_SHOW_SUM:
330 		case IMSG_CTL_SHOW_MFC:
331 		case IMSG_CTL_END:
332 			control_imsg_relay(&imsg);
333 			break;
334 		case IMSG_FULL_ROUTE_REPORT:
335 			/* add route reports to list */
336 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(*rr))
337 				fatalx("invalid size of RDE request");
338 
339 			if ((rr = calloc(1, sizeof(*rr))) == NULL)
340 				fatal("dvmrpe_dispatch_rde");
341 
342 			memcpy(rr, imsg.data, sizeof(*rr));
343 
344 			/* general update, per interface */
345 			if (imsg.hdr.peerid == 0) {
346 				/* add to interface list */
347 				LIST_FOREACH(iface, &deconf->iface_list,
348 				    entry) {
349 					if (!if_nbr_list_empty(iface))
350 						rr_list_add(&iface->rr_list,
351 						    rr);
352 				}
353 				break;
354 			}
355 
356 			/* add to neighbor list */
357 			nbr = nbr_find_peerid(imsg.hdr.peerid);
358 			rr_list_add(&nbr->rr_list, rr);
359 			break;
360 		case IMSG_FULL_ROUTE_REPORT_END:
361 			/* transmit route report */
362 			if (imsg.hdr.peerid == 0) {
363 				/*
364 				 * send general route report on all
365 				 * interfaces with neighbors.
366 				 */
367 				LIST_FOREACH(iface, &deconf->iface_list,
368 				    entry) {
369 					rr_list_send(&iface->rr_list,
370 					    iface, NULL);
371 				}
372 				break;
373 			}
374 
375 			nbr = nbr_find_peerid(imsg.hdr.peerid);
376 			rr_list_send(&nbr->rr_list, NULL, nbr);
377 			break;
378 		case IMSG_SEND_PRUNE:
379 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(p))
380 				fatalx("invalid size of RDE request");
381 
382 			memcpy(&p, imsg.data, sizeof(p));
383 
384 			LIST_FOREACH(iface, &deconf->iface_list, entry)
385 				if (p.ifindex == iface->ifindex)
386 					break;
387 
388 			if (iface == NULL)
389 				fatalx("invalid interface in mfc");
390 
391 			nbr = nbr_find_ip(iface, p.nexthop.s_addr);
392 			if (nbr == NULL)
393 				fatalx("unknown neighbor to send prune");
394 
395 			send_prune(nbr, &p);
396 
397 			break;
398 		case IMSG_FLASH_UPDATE:
399 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(*rr))
400 				fatalx("invalid size of RDE request");
401 
402 			if ((rr = calloc(1, sizeof(*rr))) == NULL)
403 				fatal("dvmrpe_dispatch_rde");
404 
405 			memcpy(rr, imsg.data, sizeof(*rr));
406 
407 			LIST_FOREACH(iface, &deconf->iface_list, entry) {
408 				if (!if_nbr_list_empty(iface)) {
409 					rr_list_add(&iface->rr_list, rr);
410 					rr_list_send(&iface->rr_list, iface,
411 					    NULL);
412 				}
413 			}
414 			break;
415 		case IMSG_FLASH_UPDATE_DS:
416 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(*rr))
417 				fatalx("invalid size of RDE request");
418 
419 			if ((rr = calloc(1, sizeof(*rr))) == NULL)
420 				fatal("dvmrpe_dispatch_rde");
421 
422 			memcpy(rr, imsg.data, sizeof(*rr));
423 
424 			LIST_FOREACH(iface, &deconf->iface_list, entry) {
425 				if (iface->ifindex == rr->ifindex)
426 					continue;
427 				if (!if_nbr_list_empty(iface)) {
428 					rr_list_add(&iface->rr_list, rr);
429 					rr_list_send(&iface->rr_list, iface,
430 					    NULL);
431 				}
432 			}
433 			break;
434 		default:
435 			log_debug("dvmrpe_dispatch_rde: error handling imsg %d",
436 			    imsg.hdr.type);
437 			break;
438 		}
439 		imsg_free(&imsg);
440 	}
441 	imsg_event_add(iev);
442 }
443 
444 void
445 dvmrpe_iface_ctl(struct ctl_conn *c, unsigned int idx)
446 {
447 	struct iface		*iface;
448 	struct ctl_iface	*ictl;
449 
450 	LIST_FOREACH(iface, &deconf->iface_list, entry)
451 		if (idx == 0 || idx == iface->ifindex) {
452 			ictl = if_to_ctl(iface);
453 			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_IFACE,
454 			    0, 0, -1, ictl, sizeof(struct ctl_iface));
455 		}
456 }
457 
458 void
459 dvmrpe_iface_igmp_ctl(struct ctl_conn *c, unsigned int idx)
460 {
461 	struct iface		*iface;
462 	struct ctl_iface	*ictl;
463 
464 	LIST_FOREACH(iface, &deconf->iface_list, entry)
465 		if (idx == 0 || idx == iface->ifindex) {
466 			ictl = if_to_ctl(iface);
467 			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_IFACE,
468 			    0, 0, -1, ictl, sizeof(struct ctl_iface));
469 			group_list_dump(iface, c);
470 
471 		}
472 }
473 
474 void
475 dvmrpe_nbr_ctl(struct ctl_conn *c)
476 {
477 	struct iface	*iface;
478 	struct nbr	*nbr;
479 	struct ctl_nbr	*nctl;
480 
481 	LIST_FOREACH(iface, &deconf->iface_list, entry)
482 		LIST_FOREACH(nbr, &iface->nbr_list, entry) {
483 			nctl = nbr_to_ctl(nbr);
484 			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR,
485 			    0, 0, -1, nctl, sizeof(struct ctl_nbr));
486 		}
487 
488 	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
489 }
490