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 } 444