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