1 /* $OpenBSD: ldpe.c,v 1.3 2009/06/06 08:09:43 pyr Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 2008 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 "ldp.h" 40 #include "ldpd.h" 41 #include "ldpe.h" 42 #include "lde.h" 43 #include "control.h" 44 #include "log.h" 45 46 void ldpe_sig_handler(int, short, void *); 47 void ldpe_shutdown(void); 48 49 void recv_packet(int, short, void *); 50 51 struct ldpd_conf *leconf = NULL, *nconf; 52 struct imsgev *iev_main; 53 struct imsgev *iev_lde; 54 int oe_nofib; 55 56 /* ARGSUSED */ 57 void 58 ldpe_sig_handler(int sig, short event, void *bula) 59 { 60 switch (sig) { 61 case SIGINT: 62 case SIGTERM: 63 ldpe_shutdown(); 64 /* NOTREACHED */ 65 default: 66 fatalx("unexpected signal"); 67 } 68 } 69 70 /* label distribution protocol engine */ 71 pid_t 72 ldpe(struct ldpd_conf *xconf, int pipe_parent2ldpe[2], int pipe_ldpe2lde[2], 73 int pipe_parent2lde[2]) 74 { 75 struct iface *iface; 76 struct passwd *pw; 77 struct event ev_sigint, ev_sigterm; 78 struct sockaddr_in disc_addr, sess_addr; 79 pid_t pid; 80 81 switch (pid = fork()) { 82 case -1: 83 fatal("cannot fork"); 84 case 0: 85 break; 86 default: 87 return (pid); 88 } 89 90 /* create ldpd control socket outside chroot */ 91 if (control_init() == -1) 92 fatalx("control socket setup failed"); 93 94 /* create the discovery UDP socket */ 95 disc_addr.sin_family = AF_INET; 96 disc_addr.sin_port = htons(LDP_PORT); 97 disc_addr.sin_addr.s_addr = INADDR_ANY; 98 99 if ((xconf->ldp_discovery_socket = socket(AF_INET, SOCK_DGRAM, 100 IPPROTO_UDP)) == -1) 101 fatal("error creating discovery socket"); 102 103 if (bind(xconf->ldp_discovery_socket, (struct sockaddr *)&disc_addr, 104 sizeof(disc_addr)) == -1) 105 fatal("error binding discovery socket"); 106 107 /* set some defaults */ 108 if (if_set_mcast_ttl(xconf->ldp_discovery_socket, 109 IP_DEFAULT_MULTICAST_TTL) == -1) 110 fatal("if_set_mcast_ttl"); 111 if (if_set_mcast_loop(xconf->ldp_discovery_socket) == -1) 112 fatal("if_set_mcast_loop"); 113 if (if_set_tos(xconf->ldp_discovery_socket, 114 IPTOS_PREC_INTERNETCONTROL) == -1) 115 fatal("if_set_tos"); 116 if (if_set_recvif(xconf->ldp_discovery_socket, 1) == -1) 117 fatal("if_set_recvif"); 118 if_set_recvbuf(xconf->ldp_discovery_socket); 119 120 /* create the session TCP socket */ 121 sess_addr.sin_family = AF_INET; 122 sess_addr.sin_port = htons(LDP_PORT); 123 sess_addr.sin_addr.s_addr = INADDR_ANY; 124 125 if ((xconf->ldp_session_socket = socket(AF_INET, SOCK_STREAM, 126 IPPROTO_TCP)) == -1) 127 fatal("error creating session socket"); 128 129 if (bind(xconf->ldp_session_socket, (struct sockaddr *)&sess_addr, 130 sizeof(sess_addr)) == -1) 131 fatal("error binding session socket"); 132 133 if (listen(xconf->ldp_session_socket, LDP_BACKLOG) == -1) 134 fatal("error in listen on session socket"); 135 136 /* set some defaults */ 137 if (if_set_tos(xconf->ldp_session_socket, 138 IPTOS_PREC_INTERNETCONTROL) == -1) 139 fatal("if_set_tos"); 140 if (if_set_reuse(xconf->ldp_session_socket, 1) == -1) 141 fatal("if_set_reuse"); 142 if (if_set_nonblock(xconf->ldp_session_socket) == -1) 143 fatal("if_set_nonblock"); 144 145 leconf = xconf; 146 if (leconf->flags & LDPD_FLAG_NO_LFIB_UPDATE) 147 oe_nofib = 1; 148 149 if ((pw = getpwnam(LDPD_USER)) == NULL) 150 fatal("getpwnam"); 151 152 if (chroot(pw->pw_dir) == -1) 153 fatal("chroot"); 154 if (chdir("/") == -1) 155 fatal("chdir(\"/\")"); 156 157 setproctitle("ldp engine"); 158 ldpd_process = PROC_LDP_ENGINE; 159 160 if (setgroups(1, &pw->pw_gid) || 161 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 162 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 163 fatal("can't drop privileges"); 164 165 event_init(); 166 nbr_init(NBR_HASHSIZE); 167 168 /* setup signal handler */ 169 signal_set(&ev_sigint, SIGINT, ldpe_sig_handler, NULL); 170 signal_set(&ev_sigterm, SIGTERM, ldpe_sig_handler, NULL); 171 signal_add(&ev_sigint, NULL); 172 signal_add(&ev_sigterm, NULL); 173 signal(SIGPIPE, SIG_IGN); 174 signal(SIGHUP, SIG_IGN); 175 176 /* setup pipes */ 177 close(pipe_parent2ldpe[0]); 178 close(pipe_ldpe2lde[1]); 179 close(pipe_parent2lde[0]); 180 close(pipe_parent2lde[1]); 181 182 if ((iev_lde = malloc(sizeof(struct imsgev))) == NULL || 183 (iev_main = malloc(sizeof(struct imsgev))) == NULL) 184 fatal(NULL); 185 imsg_init(&iev_lde->ibuf, pipe_ldpe2lde[0]); 186 iev_lde->handler = ldpe_dispatch_lde; 187 imsg_init(&iev_main->ibuf, pipe_parent2ldpe[1]); 188 iev_main->handler = ldpe_dispatch_main; 189 190 /* setup event handler */ 191 iev_lde->events = EV_READ; 192 event_set(&iev_lde->ev, iev_lde->ibuf.fd, iev_lde->events, 193 iev_lde->handler, iev_lde); 194 event_add(&iev_lde->ev, NULL); 195 196 iev_main->events = EV_READ; 197 event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, 198 iev_main->handler, iev_main); 199 event_add(&iev_main->ev, NULL); 200 201 event_set(&leconf->disc_ev, leconf->ldp_discovery_socket, 202 EV_READ|EV_PERSIST, disc_recv_packet, leconf); 203 event_add(&leconf->disc_ev, NULL); 204 205 event_set(&leconf->sess_ev, leconf->ldp_session_socket, 206 EV_READ|EV_PERSIST, session_recv_packet, leconf); 207 event_add(&leconf->sess_ev, NULL); 208 209 /* listen on ldpd control socket */ 210 TAILQ_INIT(&ctl_conns); 211 control_listen(); 212 213 if ((pkt_ptr = calloc(1, READ_BUF_SIZE)) == NULL) 214 fatal("ldpe"); 215 216 /* start interfaces */ 217 LIST_FOREACH(iface, &leconf->iface_list, entry) { 218 if_init(xconf, iface); 219 if (if_fsm(iface, IF_EVT_UP)) { 220 log_debug("error starting interface %s", 221 iface->name); 222 } 223 } 224 225 event_dispatch(); 226 227 ldpe_shutdown(); 228 /* NOTREACHED */ 229 return (0); 230 } 231 232 void 233 ldpe_shutdown(void) 234 { 235 struct iface *iface; 236 237 /* stop all interfaces */ 238 LIST_FOREACH(iface, &leconf->iface_list, entry) { 239 if (if_fsm(iface, IF_EVT_DOWN)) { 240 log_debug("error stopping interface %s", 241 iface->name); 242 } 243 } 244 245 close(leconf->ldp_discovery_socket); 246 247 /* clean up */ 248 msgbuf_write(&iev_lde->ibuf.w); 249 msgbuf_clear(&iev_lde->ibuf.w); 250 free(iev_lde); 251 msgbuf_write(&iev_main->ibuf.w); 252 msgbuf_clear(&iev_main->ibuf.w); 253 free(iev_main); 254 free(leconf); 255 free(pkt_ptr); 256 257 log_info("ldp engine exiting"); 258 _exit(0); 259 } 260 261 /* imesg */ 262 int 263 ldpe_imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen) 264 { 265 return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen)); 266 } 267 268 int 269 ldpe_imsg_compose_lde(int type, u_int32_t peerid, pid_t pid, 270 void *data, u_int16_t datalen) 271 { 272 return (imsg_compose_event(iev_lde, type, peerid, pid, -1, 273 data, datalen)); 274 } 275 276 /* ARGSUSED */ 277 void 278 ldpe_dispatch_main(int fd, short event, void *bula) 279 { 280 struct imsg imsg; 281 struct imsgev *iev = bula; 282 struct imsgbuf *ibuf = &iev->ibuf; 283 struct iface *iface = NULL; 284 struct kif *kif; 285 int n, link_ok, shut = 0; 286 287 if (event & EV_READ) { 288 if ((n = imsg_read(ibuf)) == -1) 289 fatal("imsg_read error"); 290 if (n == 0) /* connection closed */ 291 shut = 1; 292 } 293 if (event & EV_WRITE) { 294 if (msgbuf_write(&ibuf->w) == -1) 295 fatal("msgbuf_write"); 296 } 297 298 for (;;) { 299 if ((n = imsg_get(ibuf, &imsg)) == -1) 300 fatal("ldpe_dispatch_main: imsg_read error"); 301 if (n == 0) 302 break; 303 304 switch (imsg.hdr.type) { 305 case IMSG_IFINFO: 306 if (imsg.hdr.len != IMSG_HEADER_SIZE + 307 sizeof(struct kif)) 308 fatalx("IFINFO imsg with wrong len"); 309 kif = imsg.data; 310 link_ok = (kif->flags & IFF_UP) && 311 (LINK_STATE_IS_UP(kif->link_state) || 312 (kif->link_state == LINK_STATE_UNKNOWN && 313 kif->media_type != IFT_CARP)); 314 315 LIST_FOREACH(iface, &leconf->iface_list, entry) { 316 if (kif->ifindex == iface->ifindex && 317 iface->type != IF_TYPE_VIRTUALLINK) { 318 iface->flags = kif->flags; 319 iface->linkstate = kif->link_state; 320 321 if (link_ok) { 322 if_fsm(iface, IF_EVT_UP); 323 log_warnx("interface %s up", 324 iface->name); 325 /* XXX: send address msg */ 326 } else { 327 if_fsm(iface, IF_EVT_DOWN); 328 log_warnx("interface %s down", 329 iface->name); 330 /* XXX: send address withdraw 331 msg */ 332 } 333 } 334 } 335 break; 336 case IMSG_RECONF_CONF: 337 break; 338 case IMSG_RECONF_AREA: 339 break; 340 case IMSG_RECONF_IFACE: 341 break; 342 case IMSG_RECONF_END: 343 break; 344 case IMSG_CTL_KROUTE: 345 case IMSG_CTL_KROUTE_ADDR: 346 case IMSG_CTL_IFINFO: 347 case IMSG_CTL_END: 348 control_imsg_relay(&imsg); 349 break; 350 default: 351 log_debug("ldpe_dispatch_main: error handling imsg %d", 352 imsg.hdr.type); 353 break; 354 } 355 imsg_free(&imsg); 356 } 357 if (!shut) 358 imsg_event_add(iev); 359 else { 360 /* this pipe is dead, so remove the event handler */ 361 event_del(&iev->ev); 362 event_loopexit(NULL); 363 } 364 } 365 366 /* ARGSUSED */ 367 void 368 ldpe_dispatch_lde(int fd, short event, void *bula) 369 { 370 struct imsgev *iev = bula; 371 struct imsgbuf *ibuf = &iev->ibuf; 372 struct imsg imsg; 373 struct map map; 374 struct notify_msg nm; 375 int n, shut = 0; 376 struct nbr *nbr = NULL; 377 378 if (event & EV_READ) { 379 if ((n = imsg_read(ibuf)) == -1) 380 fatal("imsg_read error"); 381 if (n == 0) /* connection closed */ 382 shut = 1; 383 } 384 if (event & EV_WRITE) { 385 if (msgbuf_write(&ibuf->w) == -1) 386 fatal("msgbuf_write"); 387 } 388 389 for (;;) { 390 if ((n = imsg_get(ibuf, &imsg)) == -1) 391 fatal("ldpe_dispatch_lde: imsg_read error"); 392 if (n == 0) 393 break; 394 395 switch (imsg.hdr.type) { 396 case IMSG_MAPPING_ADD: 397 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map)) 398 fatalx("invalid size of OE request"); 399 memcpy(&map, imsg.data, sizeof(map)); 400 401 nbr = nbr_find_peerid(imsg.hdr.peerid); 402 if (nbr == NULL) { 403 log_debug("ldpe_dispatch_lde: cannot find " 404 "neighbor"); 405 return; 406 } 407 408 nbr_mapping_add(nbr, &nbr->mapping_list, &map); 409 break; 410 case IMSG_MAPPING_ADD_END: 411 nbr = nbr_find_peerid(imsg.hdr.peerid); 412 if (nbr == NULL) { 413 log_debug("ldpe_dispatch_lde: cannot find " 414 "neighbor"); 415 return; 416 } 417 418 send_labelmapping(nbr); 419 break; 420 case IMSG_RELEASE_ADD: 421 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map)) 422 fatalx("invalid size of OE request"); 423 memcpy(&map, imsg.data, sizeof(map)); 424 425 nbr = nbr_find_peerid(imsg.hdr.peerid); 426 if (nbr == NULL) { 427 log_debug("ldpe_dispatch_lde: cannot find " 428 "neighbor"); 429 return; 430 } 431 432 nbr_mapping_add(nbr, &nbr->release_list, &map); 433 break; 434 case IMSG_RELEASE_ADD_END: 435 nbr = nbr_find_peerid(imsg.hdr.peerid); 436 if (nbr == NULL) { 437 log_debug("ldpe_dispatch_lde: cannot find " 438 "neighbor"); 439 return; 440 } 441 send_labelrelease(nbr); 442 break; 443 case IMSG_NOTIFICATION_SEND: 444 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(nm)) 445 fatalx("invalid size of OE request"); 446 memcpy(&nm, imsg.data, sizeof(nm)); 447 448 nbr = nbr_find_peerid(imsg.hdr.peerid); 449 if (nbr == NULL) { 450 log_debug("ldpe_dispatch_lde: cannot find " 451 "neighbor"); 452 return; 453 } 454 455 send_notification_nbr(nbr, nm.status, 456 htonl(nm.messageid), htonl(nm.type)); 457 break; 458 case IMSG_REQUEST_ADD: 459 if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(map)) 460 fatalx("invalid size of OE request"); 461 memcpy(&map, imsg.data, sizeof(map)); 462 463 nbr = nbr_find_peerid(imsg.hdr.peerid); 464 if (nbr == NULL) { 465 log_debug("ldpe_dispatch_lde: cannot find " 466 "neighbor"); 467 return; 468 } 469 470 nbr_mapping_add(nbr, &nbr->request_list, &map); 471 break; 472 case IMSG_REQUEST_ADD_END: 473 nbr = nbr_find_peerid(imsg.hdr.peerid); 474 if (nbr == NULL) { 475 log_debug("ldpe_dispatch_lde: cannot find " 476 "neighbor"); 477 return; 478 } 479 send_labelrequest(nbr); 480 break; 481 case IMSG_CTL_END: 482 case IMSG_CTL_SHOW_LIB: 483 control_imsg_relay(&imsg); 484 break; 485 default: 486 log_debug("ldpe_dispatch_lde: error handling imsg %d", 487 imsg.hdr.type); 488 break; 489 } 490 imsg_free(&imsg); 491 } 492 if (!shut) 493 imsg_event_add(iev); 494 else { 495 /* this pipe is dead, so remove the event handler */ 496 event_del(&iev->ev); 497 event_loopexit(NULL); 498 } 499 } 500 501 u_int32_t 502 ldpe_router_id(void) 503 { 504 return (leconf->rtr_id.s_addr); 505 } 506 507 void 508 ldpe_fib_update(int type) 509 { 510 if (type == IMSG_CTL_LFIB_COUPLE) 511 oe_nofib = 0; 512 if (type == IMSG_CTL_LFIB_DECOUPLE) 513 oe_nofib = 1; 514 } 515 516 void 517 ldpe_iface_ctl(struct ctl_conn *c, unsigned int idx) 518 { 519 struct iface *iface; 520 struct ctl_iface *ictl; 521 522 LIST_FOREACH(iface, &leconf->iface_list, entry) { 523 if (idx == 0 || idx == iface->ifindex) { 524 ictl = if_to_ctl(iface); 525 imsg_compose_event(&c->iev, 526 IMSG_CTL_SHOW_INTERFACE, 527 0, 0, -1, ictl, sizeof(struct ctl_iface)); 528 } 529 } 530 } 531 532 void 533 ldpe_nbr_ctl(struct ctl_conn *c) 534 { 535 struct iface *iface; 536 struct nbr *nbr; 537 struct ctl_nbr *nctl; 538 539 LIST_FOREACH(iface, &leconf->iface_list, entry) { 540 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 541 if (iface->self != nbr) { 542 nctl = nbr_to_ctl(nbr); 543 imsg_compose_event(&c->iev, 544 IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl, 545 sizeof(struct ctl_nbr)); 546 } 547 } 548 } 549 550 imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); 551 } 552