1 /* $OpenBSD: rtr_proto.c,v 1.19 2023/10/19 13:14:19 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 #include <sys/tree.h> 19 #include <errno.h> 20 #include <stdint.h> 21 #include <poll.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <unistd.h> 26 27 #include "bgpd.h" 28 #include "session.h" 29 #include "log.h" 30 31 struct rtr_header { 32 uint8_t version; 33 uint8_t type; 34 uint16_t session_id; /* or error code */ 35 uint32_t length; 36 }; 37 38 #define RTR_MAX_VERSION 2 39 #define RTR_MAX_LEN 2048 40 #define RTR_DEFAULT_REFRESH 3600 41 #define RTR_DEFAULT_RETRY 600 42 #define RTR_DEFAULT_EXPIRE 7200 43 #define RTR_DEFAULT_ACTIVE 60 44 45 enum rtr_pdu_type { 46 SERIAL_NOTIFY = 0, 47 SERIAL_QUERY, 48 RESET_QUERY, 49 CACHE_RESPONSE, 50 IPV4_PREFIX, 51 IPV6_PREFIX = 6, 52 END_OF_DATA = 7, 53 CACHE_RESET = 8, 54 ROUTER_KEY = 9, 55 ERROR_REPORT = 10, 56 ASPA = 11, 57 }; 58 59 #define FLAG_ANNOUNCE 0x1 60 #define FLAG_MASK FLAG_ANNOUNCE 61 struct rtr_ipv4 { 62 uint8_t flags; 63 uint8_t prefixlen; 64 uint8_t maxlen; 65 uint8_t zero; 66 uint32_t prefix; 67 uint32_t asnum; 68 }; 69 70 struct rtr_ipv6 { 71 uint8_t flags; 72 uint8_t prefixlen; 73 uint8_t maxlen; 74 uint8_t zero; 75 uint32_t prefix[4]; 76 uint32_t asnum; 77 }; 78 79 #define FLAG_AFI_V6 0x1 80 #define FLAG_AFI_MASK FLAG_AFI_V6 81 struct rtr_aspa { 82 uint8_t flags; 83 uint8_t afi_flags; 84 uint16_t cnt; 85 uint32_t cas; 86 /* array of spas with cnt elements follows */ 87 }; 88 89 struct rtr_endofdata { 90 uint32_t serial; 91 uint32_t refresh; 92 uint32_t retry; 93 uint32_t expire; 94 }; 95 96 enum rtr_event { 97 RTR_EVNT_START, 98 RTR_EVNT_CON_OPEN, 99 RTR_EVNT_CON_CLOSE, 100 RTR_EVNT_TIMER_REFRESH, 101 RTR_EVNT_TIMER_RETRY, 102 RTR_EVNT_TIMER_EXPIRE, 103 RTR_EVNT_TIMER_ACTIVE, 104 RTR_EVNT_SEND_ERROR, 105 RTR_EVNT_SERIAL_NOTIFY, 106 RTR_EVNT_CACHE_RESPONSE, 107 RTR_EVNT_END_OF_DATA, 108 RTR_EVNT_CACHE_RESET, 109 RTR_EVNT_NO_DATA, 110 RTR_EVNT_RESET_AND_CLOSE, 111 RTR_EVNT_UNSUPP_PROTO_VERSION, 112 }; 113 114 static const char *rtr_eventnames[] = { 115 "start", 116 "connection open", 117 "connection closed", 118 "refresh timer expired", 119 "retry timer expired", 120 "expire timer expired", 121 "activity timer expired", 122 "sent error", 123 "serial notify received", 124 "cache response received", 125 "end of data received", 126 "cache reset received", 127 "no data", 128 "connection closed with reset", 129 "unsupported protocol version", 130 }; 131 132 enum rtr_state { 133 RTR_STATE_CLOSED, 134 RTR_STATE_ERROR, 135 /* sessions with a state below this line will poll for incoming data */ 136 RTR_STATE_IDLE, 137 RTR_STATE_ACTIVE, 138 RTR_STATE_NEGOTIATION, 139 }; 140 141 static const char *rtr_statenames[] = { 142 "closed", 143 "error", 144 "idle", 145 "active", 146 "negotiation", 147 }; 148 149 struct rtr_session { 150 TAILQ_ENTRY(rtr_session) entry; 151 char descr[PEER_DESCR_LEN]; 152 struct roa_tree roa_set; 153 struct aspa_tree aspa; 154 struct aspa_tree aspa_oldv6; 155 struct ibuf_read r; 156 struct msgbuf w; 157 struct timer_head timers; 158 uint32_t id; /* rtr_config id */ 159 uint32_t serial; 160 uint32_t refresh; 161 uint32_t retry; 162 uint32_t expire; 163 uint32_t active; 164 int session_id; 165 int fd; 166 int active_lock; 167 enum rtr_state state; 168 enum reconf_action reconf_action; 169 enum rtr_error last_sent_error; 170 enum rtr_error last_recv_error; 171 char last_sent_msg[REASON_LEN]; 172 char last_recv_msg[REASON_LEN]; 173 uint8_t version; 174 }; 175 176 TAILQ_HEAD(, rtr_session) rtrs = TAILQ_HEAD_INITIALIZER(rtrs); 177 178 static void rtr_fsm(struct rtr_session *, enum rtr_event); 179 180 static const char * 181 log_rtr(struct rtr_session *rs) 182 { 183 return rs->descr; 184 } 185 186 static const char * 187 log_rtr_type(enum rtr_pdu_type type) 188 { 189 static char buf[20]; 190 191 switch (type) { 192 case SERIAL_NOTIFY: 193 return "serial notify"; 194 case SERIAL_QUERY: 195 return "serial query"; 196 case RESET_QUERY: 197 return "reset query"; 198 case CACHE_RESPONSE: 199 return "cache response"; 200 case IPV4_PREFIX: 201 return "IPv4 prefix"; 202 case IPV6_PREFIX: 203 return "IPv6 prefix"; 204 case END_OF_DATA: 205 return "end of data"; 206 case CACHE_RESET: 207 return "cache reset"; 208 case ROUTER_KEY: 209 return "router key"; 210 case ERROR_REPORT: 211 return "error report"; 212 case ASPA: 213 return "aspa pdu"; 214 default: 215 snprintf(buf, sizeof(buf), "unknown %u", type); 216 return buf; 217 } 218 }; 219 220 static void 221 rtr_reset_cache(struct rtr_session *rs) 222 { 223 /* reset session */ 224 rs->session_id = -1; 225 timer_stop(&rs->timers, Timer_Rtr_Expire); 226 free_roatree(&rs->roa_set); 227 free_aspatree(&rs->aspa); 228 free_aspatree(&rs->aspa_oldv6); 229 } 230 231 static struct ibuf * 232 rtr_newmsg(struct rtr_session *rs, enum rtr_pdu_type type, uint32_t len, 233 uint16_t session_id) 234 { 235 struct ibuf *buf; 236 int saved_errno; 237 238 if (len > RTR_MAX_LEN) { 239 errno = ERANGE; 240 return NULL; 241 } 242 len += sizeof(struct rtr_header); 243 if ((buf = ibuf_open(len)) == NULL) 244 goto fail; 245 if (ibuf_add_n8(buf, rs->version) == -1) 246 goto fail; 247 if (ibuf_add_n8(buf, type) == -1) 248 goto fail; 249 if (ibuf_add_n16(buf, session_id) == -1) 250 goto fail; 251 if (ibuf_add_n32(buf, len) == -1) 252 goto fail; 253 254 return buf; 255 256 fail: 257 saved_errno = errno; 258 ibuf_free(buf); 259 errno = saved_errno; 260 return NULL; 261 } 262 263 /* 264 * Try to send an error PDU to cache, put connection into error 265 * state. 266 */ 267 static void 268 rtr_send_error(struct rtr_session *rs, enum rtr_error err, char *msg, 269 void *pdu, size_t len) 270 { 271 struct ibuf *buf; 272 size_t mlen = 0; 273 274 rs->last_sent_error = err; 275 if (msg) { 276 mlen = strlen(msg); 277 strlcpy(rs->last_sent_msg, msg, sizeof(rs->last_sent_msg)); 278 } else 279 memset(rs->last_sent_msg, 0, sizeof(rs->last_sent_msg)); 280 281 buf = rtr_newmsg(rs, ERROR_REPORT, 2 * sizeof(uint32_t) + len + mlen, 282 err); 283 if (buf == NULL) 284 goto fail; 285 if (ibuf_add_n32(buf, len) == -1) 286 goto fail; 287 if (ibuf_add(buf, pdu, len) == -1) 288 goto fail; 289 if (ibuf_add_n32(buf, mlen) == -1) 290 goto fail; 291 if (ibuf_add(buf, msg, mlen) == -1) 292 goto fail; 293 ibuf_close(&rs->w, buf); 294 295 log_warnx("rtr %s: sending error report[%u] %s", log_rtr(rs), err, 296 msg ? msg : ""); 297 298 rtr_fsm(rs, RTR_EVNT_SEND_ERROR); 299 return; 300 301 fail: 302 log_warn("rtr %s: send error report", log_rtr(rs)); 303 ibuf_free(buf); 304 } 305 306 static void 307 rtr_send_reset_query(struct rtr_session *rs) 308 { 309 struct ibuf *buf; 310 311 buf = rtr_newmsg(rs, RESET_QUERY, 0, 0); 312 if (buf == NULL) { 313 log_warn("rtr %s: send reset query", log_rtr(rs)); 314 rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL, 0); 315 return; 316 } 317 ibuf_close(&rs->w, buf); 318 } 319 320 static void 321 rtr_send_serial_query(struct rtr_session *rs) 322 { 323 struct ibuf *buf; 324 325 buf = rtr_newmsg(rs, SERIAL_QUERY, sizeof(uint32_t), rs->session_id); 326 if (buf == NULL) 327 goto fail; 328 if (ibuf_add_n32(buf, rs->serial) == -1) 329 goto fail; 330 ibuf_close(&rs->w, buf); 331 return; 332 333 fail: 334 log_warn("rtr %s: send serial query", log_rtr(rs)); 335 ibuf_free(buf); 336 rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL, 0); 337 } 338 339 /* 340 * Validate the common rtr header (first 8 bytes) including the 341 * included length field. 342 * Returns -1 on failure. On success msgtype and msglen are set 343 * and the function return 0. 344 */ 345 static int 346 rtr_parse_header(struct rtr_session *rs, void *buf, 347 size_t *msglen, enum rtr_pdu_type *msgtype) 348 { 349 struct rtr_header rh; 350 uint32_t len = 16; /* default for ERROR_REPORT */ 351 int session_id; 352 353 memcpy(&rh, buf, sizeof(rh)); 354 355 if (rh.version != rs->version && rh.type != ERROR_REPORT) { 356 badversion: 357 log_warnx("rtr %s: received %s message: unexpected version %d", 358 log_rtr(rs), log_rtr_type(rh.type), rh.version); 359 rtr_send_error(rs, UNEXP_PROTOCOL_VERS, NULL, &rh, sizeof(rh)); 360 return -1; 361 } 362 363 *msgtype = rh.type; 364 *msglen = ntohl(rh.length); 365 366 switch (rh.type) { 367 case SERIAL_NOTIFY: 368 session_id = rs->session_id; 369 len = 12; 370 break; 371 case CACHE_RESPONSE: 372 /* set session_id if not yet happened */ 373 if (rs->session_id == -1) 374 rs->session_id = ntohs(rh.session_id); 375 session_id = rs->session_id; 376 len = 8; 377 break; 378 case IPV4_PREFIX: 379 session_id = 0; 380 len = 20; 381 break; 382 case IPV6_PREFIX: 383 session_id = 0; 384 len = 32; 385 break; 386 case END_OF_DATA: 387 session_id = rs->session_id; 388 len = 24; 389 break; 390 case CACHE_RESET: 391 session_id = 0; 392 len = 8; 393 break; 394 case ROUTER_KEY: 395 if (rs->version < 1) 396 goto badversion; 397 len = 36; /* XXX probably too small, but we ignore it */ 398 /* FALLTHROUGH */ 399 case ERROR_REPORT: 400 if (*msglen > RTR_MAX_LEN) { 401 toobig: 402 log_warnx("rtr %s: received %s: msg too big: %zu byte", 403 log_rtr(rs), log_rtr_type(rh.type), *msglen); 404 rtr_send_error(rs, CORRUPT_DATA, "too big", 405 &rh, sizeof(rh)); 406 return -1; 407 } 408 if (*msglen < len) { 409 toosmall: 410 log_warnx("rtr %s: received %s: msg too small: " 411 "%zu byte", log_rtr(rs), log_rtr_type(rh.type), 412 *msglen); 413 rtr_send_error(rs, CORRUPT_DATA, "too small", 414 &rh, sizeof(rh)); 415 return -1; 416 } 417 /* 418 * session_id check omitted since ROUTER_KEY and ERROR_REPORT 419 * use the field for different things. 420 */ 421 return 0; 422 case ASPA: 423 if (rs->version < 2) 424 goto badversion; 425 session_id = 0; 426 /* unlike all other messages ASPA is variable sized */ 427 if (*msglen > RTR_MAX_LEN) 428 goto toobig; 429 if (*msglen < sizeof(struct rtr_aspa)) 430 goto toosmall; 431 /* len must be a multiple of 4 */ 432 len = *msglen & ~0x3; 433 break; 434 default: 435 log_warnx("rtr %s: received unknown message: type %s", 436 log_rtr(rs), log_rtr_type(rh.type)); 437 rtr_send_error(rs, UNSUPP_PDU_TYPE, NULL, &rh, sizeof(rh)); 438 return -1; 439 } 440 441 if (len != *msglen) { 442 log_warnx("rtr %s: received %s: illegal len: %zu byte not %u", 443 log_rtr(rs), log_rtr_type(rh.type), *msglen, len); 444 rtr_send_error(rs, CORRUPT_DATA, "bad length", 445 &rh, sizeof(rh)); 446 return -1; 447 } 448 449 if (session_id != ntohs(rh.session_id)) { 450 /* ignore SERIAL_NOTIFY during startup */ 451 if (rs->session_id == -1 && rh.type == SERIAL_NOTIFY) 452 return 0; 453 454 log_warnx("rtr %s: received %s: bad session_id: %d != %d", 455 log_rtr(rs), log_rtr_type(rh.type), ntohs(rh.session_id), 456 session_id); 457 rtr_send_error(rs, CORRUPT_DATA, "bad session_id", 458 &rh, sizeof(rh)); 459 return -1; 460 } 461 462 return 0; 463 } 464 465 static int 466 rtr_parse_notify(struct rtr_session *rs, uint8_t *buf, size_t len) 467 { 468 if (rs->state == RTR_STATE_ACTIVE || 469 rs->state == RTR_STATE_NEGOTIATION) { 470 log_warnx("rtr %s: received %s: while in state %s (ignored)", 471 log_rtr(rs), log_rtr_type(SERIAL_NOTIFY), 472 rtr_statenames[rs->state]); 473 return 0; 474 } 475 476 rtr_fsm(rs, RTR_EVNT_SERIAL_NOTIFY); 477 return 0; 478 } 479 480 static int 481 rtr_parse_cache_response(struct rtr_session *rs, uint8_t *buf, size_t len) 482 { 483 if (rs->state != RTR_STATE_IDLE && rs->state != RTR_STATE_NEGOTIATION) { 484 log_warnx("rtr %s: received %s: out of context", 485 log_rtr(rs), log_rtr_type(CACHE_RESPONSE)); 486 return -1; 487 } 488 489 rtr_fsm(rs, RTR_EVNT_CACHE_RESPONSE); 490 return 0; 491 } 492 493 static int 494 rtr_parse_ipv4_prefix(struct rtr_session *rs, uint8_t *buf, size_t len) 495 { 496 struct rtr_ipv4 ip4; 497 struct roa *roa; 498 499 if (len != sizeof(struct rtr_header) + sizeof(ip4)) { 500 log_warnx("rtr %s: received %s: bad pdu len", 501 log_rtr(rs), log_rtr_type(IPV4_PREFIX)); 502 rtr_send_error(rs, CORRUPT_DATA, "bad len", buf, len); 503 return -1; 504 } 505 506 if (rs->state != RTR_STATE_ACTIVE) { 507 log_warnx("rtr %s: received %s: out of context", 508 log_rtr(rs), log_rtr_type(IPV4_PREFIX)); 509 rtr_send_error(rs, CORRUPT_DATA, NULL, buf, len); 510 return -1; 511 } 512 513 memcpy(&ip4, buf + sizeof(struct rtr_header), sizeof(ip4)); 514 if (ip4.prefixlen > 32 || ip4.maxlen > 32 || 515 ip4.prefixlen > ip4.maxlen) { 516 log_warnx("rtr: %s: received %s: bad prefixlen / maxlen", 517 log_rtr(rs), log_rtr_type(IPV4_PREFIX)); 518 rtr_send_error(rs, CORRUPT_DATA, "bad prefixlen / maxlen", 519 buf, len); 520 return -1; 521 } 522 523 if ((roa = calloc(1, sizeof(*roa))) == NULL) { 524 log_warn("rtr %s: received %s", 525 log_rtr(rs), log_rtr_type(IPV4_PREFIX)); 526 rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL, 0); 527 return -1; 528 } 529 roa->aid = AID_INET; 530 roa->prefixlen = ip4.prefixlen; 531 roa->maxlen = ip4.maxlen; 532 roa->asnum = ntohl(ip4.asnum); 533 roa->prefix.inet.s_addr = ip4.prefix; 534 535 if (ip4.flags & FLAG_ANNOUNCE) { 536 if (RB_INSERT(roa_tree, &rs->roa_set, roa) != NULL) { 537 log_warnx("rtr %s: received %s: duplicate announcement", 538 log_rtr(rs), log_rtr_type(IPV4_PREFIX)); 539 rtr_send_error(rs, DUP_REC_RECV, NULL, buf, len); 540 free(roa); 541 return -1; 542 } 543 } else { 544 struct roa *r; 545 546 r = RB_FIND(roa_tree, &rs->roa_set, roa); 547 if (r == NULL) { 548 log_warnx("rtr %s: received %s: unknown withdrawal", 549 log_rtr(rs), log_rtr_type(IPV4_PREFIX)); 550 rtr_send_error(rs, UNK_REC_WDRAWL, NULL, buf, len); 551 free(roa); 552 return -1; 553 } 554 RB_REMOVE(roa_tree, &rs->roa_set, r); 555 free(r); 556 free(roa); 557 } 558 559 return 0; 560 } 561 562 static int 563 rtr_parse_ipv6_prefix(struct rtr_session *rs, uint8_t *buf, size_t len) 564 { 565 struct rtr_ipv6 ip6; 566 struct roa *roa; 567 568 if (len != sizeof(struct rtr_header) + sizeof(ip6)) { 569 log_warnx("rtr %s: received %s: bad pdu len", 570 log_rtr(rs), log_rtr_type(IPV6_PREFIX)); 571 rtr_send_error(rs, CORRUPT_DATA, "bad len", buf, len); 572 return -1; 573 } 574 575 if (rs->state != RTR_STATE_ACTIVE) { 576 log_warnx("rtr %s: received %s: out of context", 577 log_rtr(rs), log_rtr_type(IPV6_PREFIX)); 578 rtr_send_error(rs, CORRUPT_DATA, NULL, buf, len); 579 return -1; 580 } 581 582 memcpy(&ip6, buf + sizeof(struct rtr_header), sizeof(ip6)); 583 if (ip6.prefixlen > 128 || ip6.maxlen > 128 || 584 ip6.prefixlen > ip6.maxlen) { 585 log_warnx("rtr: %s: received %s: bad prefixlen / maxlen", 586 log_rtr(rs), log_rtr_type(IPV6_PREFIX)); 587 rtr_send_error(rs, CORRUPT_DATA, "bad prefixlen / maxlen", 588 buf, len); 589 return -1; 590 } 591 592 if ((roa = calloc(1, sizeof(*roa))) == NULL) { 593 log_warn("rtr %s: received %s", 594 log_rtr(rs), log_rtr_type(IPV6_PREFIX)); 595 rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL, 0); 596 return -1; 597 } 598 roa->aid = AID_INET6; 599 roa->prefixlen = ip6.prefixlen; 600 roa->maxlen = ip6.maxlen; 601 roa->asnum = ntohl(ip6.asnum); 602 memcpy(&roa->prefix.inet6, ip6.prefix, sizeof(roa->prefix.inet6)); 603 604 if (ip6.flags & FLAG_ANNOUNCE) { 605 if (RB_INSERT(roa_tree, &rs->roa_set, roa) != NULL) { 606 log_warnx("rtr %s: received %s: duplicate announcement", 607 log_rtr(rs), log_rtr_type(IPV6_PREFIX)); 608 rtr_send_error(rs, DUP_REC_RECV, NULL, buf, len); 609 free(roa); 610 return -1; 611 } 612 } else { 613 struct roa *r; 614 615 r = RB_FIND(roa_tree, &rs->roa_set, roa); 616 if (r == NULL) { 617 log_warnx("rtr %s: received %s: unknown withdrawal", 618 log_rtr(rs), log_rtr_type(IPV6_PREFIX)); 619 rtr_send_error(rs, UNK_REC_WDRAWL, NULL, buf, len); 620 free(roa); 621 return -1; 622 } 623 RB_REMOVE(roa_tree, &rs->roa_set, r); 624 free(r); 625 free(roa); 626 } 627 return 0; 628 } 629 630 static int 631 rtr_parse_aspa(struct rtr_session *rs, uint8_t *buf, size_t len) 632 { 633 struct rtr_aspa rtr_aspa; 634 struct aspa_tree *aspatree; 635 struct aspa_set *aspa, *a; 636 size_t offset; 637 uint16_t cnt, i; 638 639 memcpy(&rtr_aspa, buf + sizeof(struct rtr_header), sizeof(rtr_aspa)); 640 offset = sizeof(struct rtr_header) + sizeof(rtr_aspa); 641 cnt = ntohs(rtr_aspa.cnt); 642 if (len != offset + cnt * sizeof(uint32_t)) { 643 log_warnx("rtr %s: received %s: bad pdu len", 644 log_rtr(rs), log_rtr_type(ASPA)); 645 rtr_send_error(rs, CORRUPT_DATA, "bad len", buf, len); 646 return -1; 647 } 648 649 if (rs->state != RTR_STATE_ACTIVE) { 650 log_warnx("rtr %s: received %s: out of context", 651 log_rtr(rs), log_rtr_type(ASPA)); 652 rtr_send_error(rs, CORRUPT_DATA, NULL, buf, len); 653 return -1; 654 } 655 656 if (rtr_aspa.afi_flags & FLAG_AFI_V6) { 657 aspatree = &rs->aspa_oldv6; 658 } else { 659 aspatree = &rs->aspa; 660 } 661 662 /* create aspa_set entry from the rtr aspa pdu */ 663 if ((aspa = calloc(1, sizeof(*aspa))) == NULL) { 664 log_warn("rtr %s: received %s", 665 log_rtr(rs), log_rtr_type(ASPA)); 666 rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL, 0); 667 return -1; 668 } 669 aspa->as = ntohl(rtr_aspa.cas); 670 aspa->num = cnt; 671 if (cnt > 0) { 672 if ((aspa->tas = calloc(cnt, sizeof(uint32_t))) == NULL) { 673 free_aspa(aspa); 674 log_warn("rtr %s: received %s", 675 log_rtr(rs), log_rtr_type(ASPA)); 676 rtr_send_error(rs, INTERNAL_ERROR, "out of memory", 677 NULL, 0); 678 return -1; 679 } 680 for (i = 0; i < cnt; i++) { 681 uint32_t tas; 682 memcpy(&tas, buf + offset + i * sizeof(tas), 683 sizeof(tas)); 684 aspa->tas[i] = ntohl(tas); 685 } 686 } 687 688 if (rtr_aspa.flags & FLAG_ANNOUNCE) { 689 a = RB_INSERT(aspa_tree, aspatree, aspa); 690 if (a != NULL) { 691 RB_REMOVE(aspa_tree, aspatree, a); 692 free_aspa(a); 693 694 if (RB_INSERT(aspa_tree, aspatree, aspa) != NULL) { 695 log_warnx("rtr %s: received %s: corrupt tree", 696 log_rtr(rs), log_rtr_type(ASPA)); 697 rtr_send_error(rs, INTERNAL_ERROR, 698 "corrupt aspa tree", NULL, 0); 699 free_aspa(aspa); 700 return -1; 701 } 702 } 703 } else { 704 a = RB_FIND(aspa_tree, aspatree, aspa); 705 if (a == NULL) { 706 log_warnx("rtr %s: received %s: unknown withdrawal", 707 log_rtr(rs), log_rtr_type(ASPA)); 708 rtr_send_error(rs, UNK_REC_WDRAWL, NULL, buf, len); 709 free_aspa(aspa); 710 return -1; 711 } 712 RB_REMOVE(aspa_tree, aspatree, a); 713 free_aspa(a); 714 free_aspa(aspa); 715 } 716 717 return 0; 718 } 719 720 static int 721 rtr_parse_end_of_data(struct rtr_session *rs, uint8_t *buf, size_t len) 722 { 723 struct rtr_endofdata eod; 724 uint32_t t; 725 726 buf += sizeof(struct rtr_header); 727 len -= sizeof(struct rtr_header); 728 729 if (len != sizeof(eod)) { 730 log_warnx("rtr %s: received %s: bad pdu len", 731 log_rtr(rs), log_rtr_type(END_OF_DATA)); 732 return -1; 733 } 734 735 if (rs->state != RTR_STATE_ACTIVE) { 736 log_warnx("rtr %s: received %s: out of context", 737 log_rtr(rs), log_rtr_type(END_OF_DATA)); 738 return -1; 739 } 740 741 memcpy(&eod, buf, sizeof(eod)); 742 743 rs->serial = ntohl(eod.serial); 744 /* validate timer values to be in the right range */ 745 t = ntohl(eod.refresh); 746 if (t < 1 || t > 86400) 747 goto bad; 748 rs->refresh = t; 749 t = ntohl(eod.retry); 750 if (t < 1 || t > 7200) 751 goto bad; 752 rs->retry = t; 753 t = ntohl(eod.expire); 754 if (t < 600 || t > 172800) 755 goto bad; 756 if (t <= rs->retry || t <= rs->refresh) 757 goto bad; 758 rs->expire = t; 759 760 rtr_fsm(rs, RTR_EVNT_END_OF_DATA); 761 return 0; 762 763 bad: 764 log_warnx("rtr %s: received %s: bad timeout values", 765 log_rtr(rs), log_rtr_type(END_OF_DATA)); 766 return -1; 767 } 768 769 static int 770 rtr_parse_cache_reset(struct rtr_session *rs, uint8_t *buf, size_t len) 771 { 772 if (rs->state != RTR_STATE_IDLE) { 773 log_warnx("rtr %s: received %s: out of context", 774 log_rtr(rs), log_rtr_type(CACHE_RESET)); 775 return -1; 776 } 777 778 rtr_fsm(rs, RTR_EVNT_CACHE_RESET); 779 return 0; 780 } 781 782 /* 783 * Parse an Error Response message. This function behaves a bit different 784 * from other parse functions since on error the connection needs to be 785 * dropped without sending an error response back. 786 */ 787 static int 788 rtr_parse_error(struct rtr_session *rs, uint8_t *buf, size_t len) 789 { 790 struct rtr_header rh; 791 uint32_t pdu_len, msg_len; 792 uint8_t *msg; 793 char *str = NULL; 794 uint16_t errcode; 795 796 memcpy(&rh, buf, sizeof(rh)); 797 buf += sizeof(struct rtr_header); 798 len -= sizeof(struct rtr_header); 799 errcode = ntohs(rh.session_id); 800 801 memcpy(&pdu_len, buf, sizeof(pdu_len)); 802 pdu_len = ntohl(pdu_len); 803 804 if (len < pdu_len + sizeof(pdu_len)) { 805 log_warnx("rtr %s: received %s: bad encapsulated pdu len: %u " 806 "byte", log_rtr(rs), log_rtr_type(ERROR_REPORT), pdu_len); 807 rtr_fsm(rs, RTR_EVNT_RESET_AND_CLOSE); 808 return -1; 809 } 810 811 /* for now just ignore the embedded pdu */ 812 buf += pdu_len + sizeof(pdu_len); 813 len -= pdu_len + sizeof(pdu_len); 814 815 memcpy(&msg_len, buf, sizeof(msg_len)); 816 msg_len = ntohl(msg_len); 817 818 if (len < msg_len + sizeof(msg_len)) { 819 log_warnx("rtr %s: received %s: bad msg len: %u byte", 820 log_rtr(rs), log_rtr_type(ERROR_REPORT), msg_len); 821 rtr_fsm(rs, RTR_EVNT_RESET_AND_CLOSE); 822 return -1; 823 } 824 825 msg = buf + sizeof(msg_len); 826 if (msg_len != 0) 827 /* optional error msg, no need to check for failure */ 828 str = strndup(msg, msg_len); 829 830 log_warnx("rtr %s: received error: %s%s%s", log_rtr(rs), 831 log_rtr_error(errcode), str ? ": " : "", str ? str : ""); 832 833 if (errcode == NO_DATA_AVAILABLE) { 834 rtr_fsm(rs, RTR_EVNT_NO_DATA); 835 free(str); 836 return 0; 837 } 838 if (errcode == UNSUPP_PROTOCOL_VERS) 839 rtr_fsm(rs, RTR_EVNT_UNSUPP_PROTO_VERSION); 840 else 841 rtr_fsm(rs, RTR_EVNT_RESET_AND_CLOSE); 842 rs->last_recv_error = errcode; 843 if (str) 844 strlcpy(rs->last_recv_msg, str, 845 sizeof(rs->last_recv_msg)); 846 else 847 memset(rs->last_recv_msg, 0, 848 sizeof(rs->last_recv_msg)); 849 850 free(str); 851 return -1; 852 } 853 854 /* 855 * Try to process received rtr message, it is possible that not a full 856 * message is in the buffer. In that case stop, once new data is available 857 * a retry will be done. 858 */ 859 static void 860 rtr_process_msg(struct rtr_session *rs) 861 { 862 size_t rpos, av, left; 863 void *rptr; 864 size_t msglen; 865 enum rtr_pdu_type msgtype; 866 867 rpos = 0; 868 av = rs->r.wpos; 869 870 for (;;) { 871 if (rpos + sizeof(struct rtr_header) > av) 872 break; 873 rptr = rs->r.buf + rpos; 874 if (rtr_parse_header(rs, rptr, &msglen, &msgtype) == -1) 875 return; 876 877 /* missing data */ 878 if (rpos + msglen > av) 879 break; 880 881 switch (msgtype) { 882 case SERIAL_NOTIFY: 883 if (rtr_parse_notify(rs, rptr, msglen) == -1) { 884 rtr_send_error(rs, CORRUPT_DATA, NULL, 885 rptr, msglen); 886 return; 887 } 888 break; 889 case CACHE_RESPONSE: 890 if (rtr_parse_cache_response(rs, rptr, msglen) == -1) { 891 rtr_send_error(rs, CORRUPT_DATA, NULL, 892 rptr, msglen); 893 return; 894 } 895 break; 896 case IPV4_PREFIX: 897 if (rtr_parse_ipv4_prefix(rs, rptr, msglen) == -1) { 898 return; 899 } 900 break; 901 case IPV6_PREFIX: 902 if (rtr_parse_ipv6_prefix(rs, rptr, msglen) == -1) { 903 return; 904 } 905 break; 906 case END_OF_DATA: 907 if (rtr_parse_end_of_data(rs, rptr, msglen) == -1) { 908 rtr_send_error(rs, CORRUPT_DATA, NULL, 909 rptr, msglen); 910 return; 911 } 912 break; 913 case CACHE_RESET: 914 if (rtr_parse_cache_reset(rs, rptr, msglen) == -1) { 915 rtr_send_error(rs, CORRUPT_DATA, NULL, 916 rptr, msglen); 917 return; 918 } 919 break; 920 case ROUTER_KEY: 921 /* silently ignore router key */ 922 break; 923 case ERROR_REPORT: 924 if (rtr_parse_error(rs, rptr, msglen) == -1) 925 /* no need to send back an error */ 926 return; 927 break; 928 case ASPA: 929 if (rtr_parse_aspa(rs, rptr, msglen) == -1) { 930 return; 931 } 932 break; 933 default: 934 log_warnx("rtr %s: received %s: unexpected pdu type", 935 log_rtr(rs), log_rtr_type(msgtype)); 936 rtr_send_error(rs, INVALID_REQUEST, NULL, rptr, msglen); 937 return; 938 } 939 rpos += msglen; 940 } 941 942 left = av - rpos; 943 memmove(&rs->r.buf, rs->r.buf + rpos, left); 944 rs->r.wpos = left; 945 } 946 947 /* 948 * Simple FSM for RTR sessions 949 */ 950 static void 951 rtr_fsm(struct rtr_session *rs, enum rtr_event event) 952 { 953 enum rtr_state prev_state = rs->state; 954 955 switch (event) { 956 case RTR_EVNT_UNSUPP_PROTO_VERSION: 957 if (rs->state == RTR_STATE_NEGOTIATION) { 958 if (rs->version > 0) 959 rs->version--; 960 else { 961 /* 962 * can't downgrade anymore, fail connection 963 * RFC requires to send the error with our 964 * highest version number. 965 */ 966 rs->version = RTR_MAX_VERSION; 967 log_warnx("rtr %s: version negotiation failed", 968 log_rtr(rs)); 969 rtr_send_error(rs, UNSUPP_PROTOCOL_VERS, 970 NULL, NULL, 0); 971 return; 972 } 973 974 if (rs->fd != -1) { 975 /* flush buffers */ 976 msgbuf_clear(&rs->w); 977 rs->r.wpos = 0; 978 close(rs->fd); 979 rs->fd = -1; 980 } 981 982 /* retry connection with lower version */ 983 timer_set(&rs->timers, Timer_Rtr_Retry, rs->retry); 984 rtr_imsg_compose(IMSG_SOCKET_CONN, rs->id, 0, NULL, 0); 985 break; 986 } 987 /* FALLTHROUGH */ 988 case RTR_EVNT_RESET_AND_CLOSE: 989 rtr_reset_cache(rs); 990 rtr_recalc(); 991 /* FALLTHROUGH */ 992 case RTR_EVNT_CON_CLOSE: 993 if (rs->state == RTR_STATE_NEGOTIATION) { 994 /* consider any close event as a version failure. */ 995 rtr_fsm(rs, RTR_EVNT_UNSUPP_PROTO_VERSION); 996 break; 997 } 998 if (rs->fd != -1) { 999 /* flush buffers */ 1000 msgbuf_clear(&rs->w); 1001 rs->r.wpos = 0; 1002 close(rs->fd); 1003 rs->fd = -1; 1004 } 1005 rs->state = RTR_STATE_CLOSED; 1006 /* try to reopen session */ 1007 timer_set(&rs->timers, Timer_Rtr_Retry, 1008 arc4random_uniform(10)); 1009 break; 1010 case RTR_EVNT_START: 1011 case RTR_EVNT_TIMER_RETRY: 1012 switch (rs->state) { 1013 case RTR_STATE_ERROR: 1014 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1015 return; 1016 case RTR_STATE_CLOSED: 1017 timer_set(&rs->timers, Timer_Rtr_Retry, rs->retry); 1018 rtr_imsg_compose(IMSG_SOCKET_CONN, rs->id, 0, NULL, 0); 1019 return; 1020 default: 1021 break; 1022 } 1023 /* FALLTHROUGH */ 1024 case RTR_EVNT_CON_OPEN: 1025 timer_stop(&rs->timers, Timer_Rtr_Retry); 1026 if (rs->session_id == -1) 1027 rtr_send_reset_query(rs); 1028 else 1029 rtr_send_serial_query(rs); 1030 break; 1031 case RTR_EVNT_SERIAL_NOTIFY: 1032 /* schedule a refresh after a quick wait */ 1033 timer_set(&rs->timers, Timer_Rtr_Refresh, 1034 arc4random_uniform(10)); 1035 break; 1036 case RTR_EVNT_TIMER_REFRESH: 1037 /* send serial query */ 1038 rtr_send_serial_query(rs); 1039 break; 1040 case RTR_EVNT_TIMER_EXPIRE: 1041 rtr_reset_cache(rs); 1042 rtr_recalc(); 1043 break; 1044 case RTR_EVNT_TIMER_ACTIVE: 1045 log_warnx("rtr %s: activity timer fired", log_rtr(rs)); 1046 rtr_sem_release(rs->active_lock); 1047 rtr_recalc(); 1048 rs->active_lock = 0; 1049 break; 1050 case RTR_EVNT_CACHE_RESPONSE: 1051 rs->state = RTR_STATE_ACTIVE; 1052 timer_stop(&rs->timers, Timer_Rtr_Refresh); 1053 timer_stop(&rs->timers, Timer_Rtr_Retry); 1054 timer_set(&rs->timers, Timer_Rtr_Active, rs->active); 1055 /* prevent rtr_recalc from running while active */ 1056 rs->active_lock = 1; 1057 rtr_sem_acquire(rs->active_lock); 1058 break; 1059 case RTR_EVNT_END_OF_DATA: 1060 /* start refresh and expire timers */ 1061 timer_set(&rs->timers, Timer_Rtr_Refresh, rs->refresh); 1062 timer_set(&rs->timers, Timer_Rtr_Expire, rs->expire); 1063 timer_stop(&rs->timers, Timer_Rtr_Active); 1064 rs->state = RTR_STATE_IDLE; 1065 rtr_sem_release(rs->active_lock); 1066 rtr_recalc(); 1067 rs->active_lock = 0; 1068 break; 1069 case RTR_EVNT_CACHE_RESET: 1070 rtr_reset_cache(rs); 1071 rtr_recalc(); 1072 /* retry after a quick wait */ 1073 timer_set(&rs->timers, Timer_Rtr_Retry, 1074 arc4random_uniform(10)); 1075 break; 1076 case RTR_EVNT_NO_DATA: 1077 /* start retry timer */ 1078 timer_set(&rs->timers, Timer_Rtr_Retry, rs->retry); 1079 /* stop refresh timer just to be sure */ 1080 timer_stop(&rs->timers, Timer_Rtr_Refresh); 1081 rs->state = RTR_STATE_IDLE; 1082 break; 1083 case RTR_EVNT_SEND_ERROR: 1084 rtr_reset_cache(rs); 1085 rtr_recalc(); 1086 rs->state = RTR_STATE_ERROR; 1087 /* flush receive buffer */ 1088 rs->r.wpos = 0; 1089 break; 1090 } 1091 1092 log_info("rtr %s: state change %s -> %s, reason: %s", 1093 log_rtr(rs), rtr_statenames[prev_state], rtr_statenames[rs->state], 1094 rtr_eventnames[event]); 1095 } 1096 1097 /* 1098 * IO handler for RTR sessions 1099 */ 1100 static void 1101 rtr_dispatch_msg(struct pollfd *pfd, struct rtr_session *rs) 1102 { 1103 ssize_t n; 1104 int error; 1105 1106 if (pfd->revents & POLLHUP) { 1107 log_warnx("rtr %s: Connection closed, hangup", log_rtr(rs)); 1108 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1109 return; 1110 } 1111 if (pfd->revents & (POLLERR|POLLNVAL)) { 1112 log_warnx("rtr %s: Connection closed, error", log_rtr(rs)); 1113 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1114 return; 1115 } 1116 if (pfd->revents & POLLOUT && rs->w.queued) { 1117 if ((error = ibuf_write(&rs->w)) == -1) { 1118 if (errno != EAGAIN) { 1119 log_warn("rtr %s: write error", log_rtr(rs)); 1120 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1121 } 1122 } 1123 if (error == 0) 1124 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1125 if (rs->w.queued == 0 && rs->state == RTR_STATE_ERROR) 1126 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1127 } 1128 if (pfd->revents & POLLIN) { 1129 if ((n = read(rs->fd, rs->r.buf + rs->r.wpos, 1130 sizeof(rs->r.buf) - rs->r.wpos)) == -1) { 1131 if (errno != EINTR && errno != EAGAIN) { 1132 log_warn("rtr %s: read error", log_rtr(rs)); 1133 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1134 } 1135 return; 1136 } 1137 if (n == 0) { 1138 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1139 return; 1140 } 1141 rs->r.wpos += n; 1142 1143 /* new data arrived, try to process it */ 1144 rtr_process_msg(rs); 1145 } 1146 1147 } 1148 1149 void 1150 rtr_check_events(struct pollfd *pfds, size_t npfds) 1151 { 1152 struct rtr_session *rs; 1153 struct timer *t; 1154 time_t now; 1155 size_t i = 0; 1156 1157 for (i = 0; i < npfds; i++) { 1158 if (pfds[i].revents == 0) 1159 continue; 1160 TAILQ_FOREACH(rs, &rtrs, entry) 1161 if (rs->fd == pfds[i].fd) { 1162 rtr_dispatch_msg(&pfds[i], rs); 1163 break; 1164 } 1165 if (rs == NULL) 1166 log_warnx("%s: unknown fd in pollfds", __func__); 1167 } 1168 1169 /* run all timers */ 1170 now = getmonotime(); 1171 TAILQ_FOREACH(rs, &rtrs, entry) 1172 if ((t = timer_nextisdue(&rs->timers, now)) != NULL) { 1173 log_debug("rtr %s: %s triggered", log_rtr(rs), 1174 timernames[t->type]); 1175 /* stop timer so it does not trigger again */ 1176 timer_stop(&rs->timers, t->type); 1177 switch (t->type) { 1178 case Timer_Rtr_Refresh: 1179 rtr_fsm(rs, RTR_EVNT_TIMER_REFRESH); 1180 break; 1181 case Timer_Rtr_Retry: 1182 rtr_fsm(rs, RTR_EVNT_TIMER_RETRY); 1183 break; 1184 case Timer_Rtr_Expire: 1185 rtr_fsm(rs, RTR_EVNT_TIMER_EXPIRE); 1186 break; 1187 case Timer_Rtr_Active: 1188 rtr_fsm(rs, RTR_EVNT_TIMER_ACTIVE); 1189 break; 1190 default: 1191 fatalx("King Bula lost in time"); 1192 } 1193 } 1194 } 1195 1196 size_t 1197 rtr_count(void) 1198 { 1199 struct rtr_session *rs; 1200 size_t count = 0; 1201 1202 TAILQ_FOREACH(rs, &rtrs, entry) 1203 count++; 1204 return count; 1205 } 1206 1207 size_t 1208 rtr_poll_events(struct pollfd *pfds, size_t npfds, time_t *timeout) 1209 { 1210 struct rtr_session *rs; 1211 time_t now = getmonotime(); 1212 size_t i = 0; 1213 1214 TAILQ_FOREACH(rs, &rtrs, entry) { 1215 time_t nextaction; 1216 struct pollfd *pfd = pfds + i++; 1217 1218 if (i > npfds) 1219 fatalx("%s: too many sessions for pollfd", __func__); 1220 1221 if ((nextaction = timer_nextduein(&rs->timers, now)) != -1 && 1222 nextaction < *timeout) 1223 *timeout = nextaction; 1224 1225 if (rs->state == RTR_STATE_CLOSED) { 1226 pfd->fd = -1; 1227 continue; 1228 } 1229 1230 pfd->fd = rs->fd; 1231 pfd->events = 0; 1232 1233 if (rs->w.queued) 1234 pfd->events |= POLLOUT; 1235 if (rs->state >= RTR_STATE_IDLE) 1236 pfd->events |= POLLIN; 1237 } 1238 1239 return i; 1240 } 1241 1242 struct rtr_session * 1243 rtr_new(uint32_t id, char *descr) 1244 { 1245 struct rtr_session *rs; 1246 1247 if ((rs = calloc(1, sizeof(*rs))) == NULL) 1248 fatal("RTR session %s", descr); 1249 1250 RB_INIT(&rs->roa_set); 1251 RB_INIT(&rs->aspa); 1252 RB_INIT(&rs->aspa_oldv6); 1253 TAILQ_INIT(&rs->timers); 1254 msgbuf_init(&rs->w); 1255 1256 strlcpy(rs->descr, descr, sizeof(rs->descr)); 1257 rs->id = id; 1258 rs->session_id = -1; 1259 rs->version = RTR_MAX_VERSION; 1260 rs->refresh = RTR_DEFAULT_REFRESH; 1261 rs->retry = RTR_DEFAULT_RETRY; 1262 rs->expire = RTR_DEFAULT_EXPIRE; 1263 rs->active = RTR_DEFAULT_ACTIVE; 1264 rs->state = RTR_STATE_CLOSED; 1265 rs->reconf_action = RECONF_REINIT; 1266 rs->last_recv_error = NO_ERROR; 1267 rs->last_sent_error = NO_ERROR; 1268 1269 /* make sure that some timer is running to abort bad sessions */ 1270 timer_set(&rs->timers, Timer_Rtr_Expire, rs->expire); 1271 1272 log_debug("rtr %s: new session, start", log_rtr(rs)); 1273 TAILQ_INSERT_TAIL(&rtrs, rs, entry); 1274 rtr_fsm(rs, RTR_EVNT_START); 1275 1276 return rs; 1277 } 1278 1279 struct rtr_session * 1280 rtr_get(uint32_t id) 1281 { 1282 struct rtr_session *rs; 1283 1284 TAILQ_FOREACH(rs, &rtrs, entry) 1285 if (rs->id == id) 1286 return rs; 1287 return NULL; 1288 } 1289 1290 void 1291 rtr_free(struct rtr_session *rs) 1292 { 1293 if (rs == NULL) 1294 return; 1295 1296 rtr_reset_cache(rs); 1297 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1298 timer_remove_all(&rs->timers); 1299 free(rs); 1300 } 1301 1302 void 1303 rtr_open(struct rtr_session *rs, int fd) 1304 { 1305 if (rs->state != RTR_STATE_CLOSED && 1306 rs->state != RTR_STATE_NEGOTIATION) { 1307 log_warnx("rtr %s: bad session state", log_rtr(rs)); 1308 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1309 } 1310 1311 if (rs->state == RTR_STATE_CLOSED) 1312 rs->version = RTR_MAX_VERSION; 1313 1314 rs->fd = rs->w.fd = fd; 1315 rs->state = RTR_STATE_NEGOTIATION; 1316 rtr_fsm(rs, RTR_EVNT_CON_OPEN); 1317 } 1318 1319 void 1320 rtr_config_prep(void) 1321 { 1322 struct rtr_session *rs; 1323 1324 TAILQ_FOREACH(rs, &rtrs, entry) 1325 rs->reconf_action = RECONF_DELETE; 1326 } 1327 1328 void 1329 rtr_config_merge(void) 1330 { 1331 struct rtr_session *rs, *nrs; 1332 1333 TAILQ_FOREACH_SAFE(rs, &rtrs, entry, nrs) 1334 if (rs->reconf_action == RECONF_DELETE) { 1335 TAILQ_REMOVE(&rtrs, rs, entry); 1336 rtr_free(rs); 1337 } 1338 } 1339 1340 void 1341 rtr_config_keep(struct rtr_session *rs) 1342 { 1343 rs->reconf_action = RECONF_KEEP; 1344 } 1345 1346 void 1347 rtr_roa_merge(struct roa_tree *rt) 1348 { 1349 struct rtr_session *rs; 1350 struct roa *roa; 1351 1352 TAILQ_FOREACH(rs, &rtrs, entry) { 1353 RB_FOREACH(roa, roa_tree, &rs->roa_set) 1354 rtr_roa_insert(rt, roa); 1355 } 1356 } 1357 1358 void 1359 rtr_aspa_merge(struct aspa_tree *at) 1360 { 1361 struct rtr_session *rs; 1362 struct aspa_set *aspa; 1363 1364 TAILQ_FOREACH(rs, &rtrs, entry) { 1365 RB_FOREACH(aspa, aspa_tree, &rs->aspa) 1366 rtr_aspa_insert(at, aspa); 1367 RB_FOREACH(aspa, aspa_tree, &rs->aspa_oldv6) 1368 rtr_aspa_insert(at, aspa); 1369 } 1370 } 1371 1372 void 1373 rtr_shutdown(void) 1374 { 1375 struct rtr_session *rs, *nrs; 1376 1377 TAILQ_FOREACH_SAFE(rs, &rtrs, entry, nrs) 1378 rtr_free(rs); 1379 } 1380 1381 void 1382 rtr_show(struct rtr_session *rs, pid_t pid) 1383 { 1384 struct ctl_show_rtr msg; 1385 struct ctl_timer ct; 1386 u_int i; 1387 time_t d; 1388 1389 memset(&msg, 0, sizeof(msg)); 1390 1391 /* descr, remote_addr, local_addr and remote_port set by parent */ 1392 msg.version = rs->version; 1393 msg.serial = rs->serial; 1394 msg.refresh = rs->refresh; 1395 msg.retry = rs->retry; 1396 msg.expire = rs->expire; 1397 msg.session_id = rs->session_id; 1398 msg.last_sent_error = rs->last_sent_error; 1399 msg.last_recv_error = rs->last_recv_error; 1400 strlcpy(msg.last_sent_msg, rs->last_sent_msg, 1401 sizeof(msg.last_sent_msg)); 1402 strlcpy(msg.last_recv_msg, rs->last_recv_msg, 1403 sizeof(msg.last_recv_msg)); 1404 1405 /* send back imsg */ 1406 rtr_imsg_compose(IMSG_CTL_SHOW_RTR, rs->id, pid, &msg, sizeof(msg)); 1407 1408 /* send back timer imsgs */ 1409 for (i = 1; i < Timer_Max; i++) { 1410 if (!timer_running(&rs->timers, i, &d)) 1411 continue; 1412 ct.type = i; 1413 ct.val = d; 1414 rtr_imsg_compose(IMSG_CTL_SHOW_TIMER, rs->id, pid, 1415 &ct, sizeof(ct)); 1416 } 1417 } 1418