1 /* $OpenBSD: ripd.c,v 1.44 2024/11/21 13:38:15 claudio Exp $ */
2
3 /*
4 * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
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
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/queue.h>
25 #include <sys/time.h>
26 #include <sys/stat.h>
27 #include <sys/wait.h>
28 #include <sys/sysctl.h>
29
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32
33 #include <event.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <pwd.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <signal.h>
41 #include <unistd.h>
42
43 #include "rip.h"
44 #include "ripd.h"
45 #include "ripe.h"
46 #include "log.h"
47 #include "control.h"
48 #include "rde.h"
49
50 __dead void usage(void);
51 void main_sig_handler(int, short, void *);
52 __dead void ripd_shutdown(void);
53 void main_dispatch_ripe(int, short, void *);
54 void main_dispatch_rde(int, short, void *);
55
56 int pipe_parent2ripe[2];
57 int pipe_parent2rde[2];
58 int pipe_ripe2rde[2];
59
60 struct ripd_conf *conf = NULL;
61 static struct imsgev *iev_ripe;
62 static struct imsgev *iev_rde;
63
64 pid_t ripe_pid = 0;
65 pid_t rde_pid = 0;
66
67 __dead void
usage(void)68 usage(void)
69 {
70 extern char *__progname;
71
72 fprintf(stderr,
73 "usage: %s [-dnv] [-D macro=value] [-f file] [-s socket]\n",
74 __progname);
75 exit(1);
76 }
77
78 void
main_sig_handler(int sig,short event,void * arg)79 main_sig_handler(int sig, short event, void *arg)
80 {
81 /* signal handler rules don't apply, libevent decouples for us */
82 switch (sig) {
83 case SIGTERM:
84 case SIGINT:
85 ripd_shutdown();
86 /* NOTREACHED */
87 case SIGHUP:
88 /* reconfigure */
89 /* ... */
90 break;
91 default:
92 fatalx("unexpected signal");
93 /* NOTREACHED */
94 }
95 }
96
97 int
main(int argc,char * argv[])98 main(int argc, char *argv[])
99 {
100 struct event ev_sigint, ev_sigterm, ev_sighup;
101 int mib[4];
102 int debug = 0;
103 int ipforwarding;
104 int ch;
105 int opts = 0;
106 char *conffile;
107 char *sockname;
108 size_t len;
109
110 conffile = CONF_FILE;
111 log_procname = "parent";
112 sockname = RIPD_SOCKET;
113
114 log_init(1); /* log to stderr until daemonized */
115 log_verbose(1);
116
117 while ((ch = getopt(argc, argv, "cdD:f:ns:v")) != -1) {
118 switch (ch) {
119 case 'c':
120 opts |= RIPD_OPT_FORCE_DEMOTE;
121 break;
122 case 'd':
123 debug = 1;
124 break;
125 case 'D':
126 if (cmdline_symset(optarg) < 0)
127 log_warnx("could not parse macro definition %s",
128 optarg);
129 break;
130 case 'f':
131 conffile = optarg;
132 break;
133 case 'n':
134 opts |= RIPD_OPT_NOACTION;
135 break;
136 case 's':
137 sockname = optarg;
138 break;
139 case 'v':
140 if (opts & RIPD_OPT_VERBOSE)
141 opts |= RIPD_OPT_VERBOSE2;
142 opts |= RIPD_OPT_VERBOSE;
143 break;
144 default:
145 usage();
146 /* NOTREACHED */
147 }
148 }
149
150 argc -= optind;
151 argv += optind;
152 if (argc > 0)
153 usage();
154
155 mib[0] = CTL_NET;
156 mib[1] = PF_INET;
157 mib[2] = IPPROTO_IP;
158 mib[3] = IPCTL_FORWARDING;
159 len = sizeof(ipforwarding);
160 if (sysctl(mib, 4, &ipforwarding, &len, NULL, 0) == -1)
161 err(1, "sysctl");
162
163 if (!ipforwarding)
164 log_warnx("WARNING: IP forwarding NOT enabled");
165
166 /* fetch interfaces early */
167 kif_init();
168
169 /* parse config file */
170 if ((conf = parse_config(conffile, opts)) == NULL )
171 exit(1);
172 conf->csock = sockname;
173
174 if (conf->opts & RIPD_OPT_NOACTION) {
175 if (conf->opts & RIPD_OPT_VERBOSE)
176 print_config(conf);
177 else
178 fprintf(stderr, "configuration OK\n");
179 exit(0);
180 }
181
182 /* check for root privileges */
183 if (geteuid())
184 errx(1, "need root privileges");
185
186 /* check for ripd user */
187 if (getpwnam(RIPD_USER) == NULL)
188 errx(1, "unknown user %s", RIPD_USER);
189
190 log_init(debug);
191 log_verbose(conf->opts & RIPD_OPT_VERBOSE);
192
193 if (!debug)
194 daemon(1, 0);
195
196 log_info("startup");
197
198 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
199 PF_UNSPEC, pipe_parent2ripe) == -1)
200 fatal("socketpair");
201 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
202 PF_UNSPEC, pipe_parent2rde) == -1)
203 fatal("socketpair");
204 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
205 PF_UNSPEC, pipe_ripe2rde) == -1)
206 fatal("socketpair");
207
208 /* start children */
209 rde_pid = rde(conf, pipe_parent2rde, pipe_ripe2rde, pipe_parent2ripe);
210 ripe_pid = ripe(conf, pipe_parent2ripe, pipe_ripe2rde, pipe_parent2rde);
211
212 /* no filesystem visibility */
213 if (unveil("/", "") == -1)
214 fatal("unveil /");
215 if (unveil(NULL, NULL) == -1)
216 fatal("unveil");
217
218 event_init();
219
220 /* setup signal handler */
221 signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL);
222 signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL);
223 signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL);
224 signal_add(&ev_sigint, NULL);
225 signal_add(&ev_sigterm, NULL);
226 signal_add(&ev_sighup, NULL);
227 signal(SIGPIPE, SIG_IGN);
228
229 /* setup pipes to children */
230 close(pipe_parent2ripe[1]);
231 close(pipe_parent2rde[1]);
232 close(pipe_ripe2rde[0]);
233 close(pipe_ripe2rde[1]);
234
235 if ((iev_ripe = malloc(sizeof(struct imsgev))) == NULL ||
236 (iev_rde = malloc(sizeof(struct imsgev))) == NULL)
237 fatal(NULL);
238 if (imsgbuf_init(&iev_ripe->ibuf, pipe_parent2ripe[0]) == -1)
239 fatal(NULL);
240 iev_ripe->handler = main_dispatch_ripe;
241 if (imsgbuf_init(&iev_rde->ibuf, pipe_parent2rde[0]) == -1)
242 fatal(NULL);
243 iev_rde->handler = main_dispatch_rde;
244
245 /* setup event handler */
246 iev_ripe->events = EV_READ;
247 event_set(&iev_ripe->ev, iev_ripe->ibuf.fd, iev_ripe->events,
248 iev_ripe->handler, iev_ripe);
249 event_add(&iev_ripe->ev, NULL);
250
251 iev_rde->events = EV_READ;
252 event_set(&iev_rde->ev, iev_rde->ibuf.fd, iev_rde->events,
253 iev_rde->handler, iev_rde);
254 event_add(&iev_rde->ev, NULL);
255
256 if (kr_init(!(conf->flags & RIPD_FLAG_NO_FIB_UPDATE),
257 conf->rdomain, conf->fib_priority) == -1)
258 fatalx("kr_init failed");
259
260 event_dispatch();
261
262 ripd_shutdown();
263 /* NOTREACHED */
264 return (0);
265 }
266
267 __dead void
ripd_shutdown(void)268 ripd_shutdown(void)
269 {
270 struct iface *i;
271 pid_t pid;
272 int status;
273
274 /* close pipes */
275 imsgbuf_clear(&iev_ripe->ibuf);
276 close(iev_ripe->ibuf.fd);
277 imsgbuf_clear(&iev_rde->ibuf);
278 close(iev_rde->ibuf.fd);
279
280 while ((i = LIST_FIRST(&conf->iface_list)) != NULL) {
281 LIST_REMOVE(i, entry);
282 if_del(i);
283 }
284
285 kr_shutdown();
286
287 log_debug("waiting for children to terminate");
288 do {
289 pid = wait(&status);
290 if (pid == -1) {
291 if (errno != EINTR && errno != ECHILD)
292 fatal("wait");
293 } else if (WIFSIGNALED(status))
294 log_warnx("%s terminated; signal %d",
295 (pid == rde_pid) ? "route decision engine" :
296 "rip engine", WTERMSIG(status));
297 } while (pid != -1 || (pid == -1 && errno == EINTR));
298
299 free(iev_ripe);
300 free(iev_rde);
301 free(conf);
302
303 log_info("terminating");
304 exit(0);
305 }
306
307 /* imsg handling */
308 void
main_dispatch_ripe(int fd,short event,void * bula)309 main_dispatch_ripe(int fd, short event, void *bula)
310 {
311 struct imsgev *iev = bula;
312 struct imsgbuf *ibuf = &iev->ibuf;
313 struct imsg imsg;
314 struct demote_msg dmsg;
315 ssize_t n;
316 int shut = 0, verbose;
317
318 if (event & EV_READ) {
319 if ((n = imsgbuf_read(ibuf)) == -1)
320 fatal("imsgbuf_read error");
321 if (n == 0) /* connection closed */
322 shut = 1;
323 }
324 if (event & EV_WRITE) {
325 if (imsgbuf_write(ibuf) == -1) {
326 if (errno == EPIPE) /* connection closed */
327 shut = 1;
328 else
329 fatal("imsgbuf_write");
330 }
331 }
332
333 for (;;) {
334 if ((n = imsg_get(ibuf, &imsg)) == -1)
335 fatal("imsg_get");
336
337 if (n == 0)
338 break;
339
340 switch (imsg.hdr.type) {
341 case IMSG_CTL_RELOAD:
342 /* XXX reconfig */
343 break;
344 case IMSG_CTL_FIB_COUPLE:
345 kr_fib_couple();
346 break;
347 case IMSG_CTL_FIB_DECOUPLE:
348 kr_fib_decouple();
349 break;
350 case IMSG_CTL_KROUTE:
351 case IMSG_CTL_KROUTE_ADDR:
352 kr_show_route(&imsg);
353 break;
354 case IMSG_CTL_IFINFO:
355 if (imsg.hdr.len == IMSG_HEADER_SIZE)
356 kr_ifinfo(NULL, imsg.hdr.pid);
357 else if (imsg.hdr.len == IMSG_HEADER_SIZE + IFNAMSIZ)
358 kr_ifinfo(imsg.data, imsg.hdr.pid);
359 else
360 log_warnx("IFINFO request with wrong len");
361 break;
362 case IMSG_DEMOTE:
363 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(dmsg))
364 fatalx("invalid size of OE request");
365 memcpy(&dmsg, imsg.data, sizeof(dmsg));
366 carp_demote_set(dmsg.demote_group, dmsg.level);
367 break;
368 case IMSG_CTL_LOG_VERBOSE:
369 /* already checked by ripe */
370 memcpy(&verbose, imsg.data, sizeof(verbose));
371 log_verbose(verbose);
372 break;
373 default:
374 log_debug("main_dispatch_ripe: error handling imsg %d",
375 imsg.hdr.type);
376 break;
377 }
378 imsg_free(&imsg);
379 }
380 if (!shut)
381 imsg_event_add(iev);
382 else {
383 /* this pipe is dead, so remove the event handler */
384 event_del(&iev->ev);
385 event_loopexit(NULL);
386 }
387 }
388
389 void
main_dispatch_rde(int fd,short event,void * bula)390 main_dispatch_rde(int fd, short event, void *bula)
391 {
392 struct imsgev *iev = bula;
393 struct imsgbuf *ibuf = &iev->ibuf;
394 struct imsg imsg;
395 ssize_t n;
396 int shut = 0;
397
398 if (event & EV_READ) {
399 if ((n = imsgbuf_read(ibuf)) == -1)
400 fatal("imsgbuf_read error");
401 if (n == 0) /* connection closed */
402 shut = 1;
403 }
404 if (event & EV_WRITE) {
405 if (imsgbuf_write(ibuf) == -1) {
406 if (errno == EPIPE) /* connection closed */
407 shut = 1;
408 else
409 fatal("imsgbuf_write");
410 }
411 }
412
413 for (;;) {
414 if ((n = imsg_get(ibuf, &imsg)) == -1)
415 fatal("imsg_get");
416
417 if (n == 0)
418 break;
419
420 switch (imsg.hdr.type) {
421 case IMSG_KROUTE_CHANGE:
422 if (kr_change(imsg.data))
423 log_warn("main_dispatch_rde: error changing "
424 "route");
425 break;
426 case IMSG_KROUTE_DELETE:
427 if (kr_delete(imsg.data))
428 log_warn("main_dispatch_rde: error deleting "
429 "route");
430 break;
431 default:
432 log_debug("main_dispatch_rde: error handling imsg %d",
433 imsg.hdr.type);
434 break;
435 }
436 imsg_free(&imsg);
437 }
438 if (!shut)
439 imsg_event_add(iev);
440 else {
441 /* this pipe is dead, so remove the event handler */
442 event_del(&iev->ev);
443 event_loopexit(NULL);
444 }
445 }
446
447 void
main_imsg_compose_ripe(int type,pid_t pid,void * data,u_int16_t datalen)448 main_imsg_compose_ripe(int type, pid_t pid, void *data, u_int16_t datalen)
449 {
450 imsg_compose_event(iev_ripe, type, 0, pid, -1, data, datalen);
451 }
452
453 void
main_imsg_compose_rde(int type,pid_t pid,void * data,u_int16_t datalen)454 main_imsg_compose_rde(int type, pid_t pid, void *data, u_int16_t datalen)
455 {
456 imsg_compose_event(iev_rde, type, 0, pid, -1, data, datalen);
457 }
458
459 int
rip_redistribute(struct kroute * kr)460 rip_redistribute(struct kroute *kr)
461 {
462 struct redistribute *r;
463 u_int8_t is_default = 0;
464
465 if (kr->flags & F_RIPD_INSERTED)
466 return (1);
467
468 /* only allow 0.0.0.0/0 via REDIST_DEFAULT */
469 if (kr->prefix.s_addr == INADDR_ANY && kr->netmask.s_addr == INADDR_ANY)
470 is_default = 1;
471
472 SIMPLEQ_FOREACH(r, &conf->redist_list, entry) {
473 switch (r->type & ~REDIST_NO) {
474 case REDIST_LABEL:
475 if (kr->rtlabel == r->label)
476 return (r->type & REDIST_NO ? 0 : 1);
477 break;
478 case REDIST_STATIC:
479 /*
480 * Dynamic routes are not redistributable. Placed here
481 * so that link local addresses can be redistributed
482 * via a rtlabel.
483 */
484 if (is_default)
485 continue;
486 if (kr->flags & F_DYNAMIC)
487 continue;
488 if (kr->flags & F_STATIC)
489 return (r->type & REDIST_NO ? 0 : 1);
490 break;
491 case REDIST_CONNECTED:
492 if (is_default)
493 continue;
494 if (kr->flags & F_DYNAMIC)
495 continue;
496 if (kr->flags & F_CONNECTED)
497 return (r->type & REDIST_NO ? 0 : 1);
498 break;
499 case REDIST_ADDR:
500 if (kr->flags & F_DYNAMIC)
501 continue;
502
503 if (r->addr.s_addr == INADDR_ANY &&
504 r->mask.s_addr == INADDR_ANY) {
505 if (is_default)
506 return (r->type & REDIST_NO? 0 : 1);
507 else
508 return (0);
509 }
510
511 if ((kr->prefix.s_addr & r->mask.s_addr) ==
512 (r->addr.s_addr & r->mask.s_addr) &&
513 (kr->netmask.s_addr & r->mask.s_addr) ==
514 r->mask.s_addr)
515 return (r->type & REDIST_NO? 0 : 1);
516 break;
517 case REDIST_DEFAULT:
518 if (is_default)
519 return (r->type & REDIST_NO? 0 : 1);
520 break;
521 }
522 }
523
524 return (0);
525 }
526
527 void
imsg_event_add(struct imsgev * iev)528 imsg_event_add(struct imsgev *iev)
529 {
530 if (iev->handler == NULL) {
531 imsgbuf_flush(&iev->ibuf);
532 return;
533 }
534
535 iev->events = EV_READ;
536 if (imsgbuf_queuelen(&iev->ibuf) > 0)
537 iev->events |= EV_WRITE;
538
539 event_del(&iev->ev);
540 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
541 event_add(&iev->ev, NULL);
542 }
543
544 int
imsg_compose_event(struct imsgev * iev,u_int16_t type,u_int32_t peerid,pid_t pid,int fd,void * data,u_int16_t datalen)545 imsg_compose_event(struct imsgev *iev, u_int16_t type,
546 u_int32_t peerid, pid_t pid, int fd, void *data, u_int16_t datalen)
547 {
548 int ret;
549
550 if ((ret = imsg_compose(&iev->ibuf, type, peerid,
551 pid, fd, data, datalen)) != -1)
552 imsg_event_add(iev);
553 return (ret);
554 }
555