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