1 /* $OpenBSD: rtr_proto.c,v 1.21 2024/01/03 16:07:37 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_ESTABLISHED, 137 RTR_STATE_EXCHANGE, 138 RTR_STATE_NEGOTIATION, 139 }; 140 141 static const char *rtr_statenames[] = { 142 "closed", 143 "error", 144 "established", 145 "exchange", 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_EXCHANGE || 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_ESTABLISHED && 484 rs->state != RTR_STATE_NEGOTIATION) { 485 log_warnx("rtr %s: received %s: out of context", 486 log_rtr(rs), log_rtr_type(CACHE_RESPONSE)); 487 return -1; 488 } 489 490 rtr_fsm(rs, RTR_EVNT_CACHE_RESPONSE); 491 return 0; 492 } 493 494 static int 495 rtr_parse_ipv4_prefix(struct rtr_session *rs, uint8_t *buf, size_t len) 496 { 497 struct rtr_ipv4 ip4; 498 struct roa *roa; 499 500 if (len != sizeof(struct rtr_header) + sizeof(ip4)) { 501 log_warnx("rtr %s: received %s: bad pdu len", 502 log_rtr(rs), log_rtr_type(IPV4_PREFIX)); 503 rtr_send_error(rs, CORRUPT_DATA, "bad len", buf, len); 504 return -1; 505 } 506 507 if (rs->state != RTR_STATE_EXCHANGE) { 508 log_warnx("rtr %s: received %s: out of context", 509 log_rtr(rs), log_rtr_type(IPV4_PREFIX)); 510 rtr_send_error(rs, CORRUPT_DATA, NULL, buf, len); 511 return -1; 512 } 513 514 memcpy(&ip4, buf + sizeof(struct rtr_header), sizeof(ip4)); 515 if (ip4.prefixlen > 32 || ip4.maxlen > 32 || 516 ip4.prefixlen > ip4.maxlen) { 517 log_warnx("rtr: %s: received %s: bad prefixlen / maxlen", 518 log_rtr(rs), log_rtr_type(IPV4_PREFIX)); 519 rtr_send_error(rs, CORRUPT_DATA, "bad prefixlen / maxlen", 520 buf, len); 521 return -1; 522 } 523 524 if ((roa = calloc(1, sizeof(*roa))) == NULL) { 525 log_warn("rtr %s: received %s", 526 log_rtr(rs), log_rtr_type(IPV4_PREFIX)); 527 rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL, 0); 528 return -1; 529 } 530 roa->aid = AID_INET; 531 roa->prefixlen = ip4.prefixlen; 532 roa->maxlen = ip4.maxlen; 533 roa->asnum = ntohl(ip4.asnum); 534 roa->prefix.inet.s_addr = ip4.prefix; 535 536 if (ip4.flags & FLAG_ANNOUNCE) { 537 if (RB_INSERT(roa_tree, &rs->roa_set, roa) != NULL) { 538 log_warnx("rtr %s: received %s: duplicate announcement", 539 log_rtr(rs), log_rtr_type(IPV4_PREFIX)); 540 rtr_send_error(rs, DUP_REC_RECV, NULL, buf, len); 541 free(roa); 542 return -1; 543 } 544 } else { 545 struct roa *r; 546 547 r = RB_FIND(roa_tree, &rs->roa_set, roa); 548 if (r == NULL) { 549 log_warnx("rtr %s: received %s: unknown withdrawal", 550 log_rtr(rs), log_rtr_type(IPV4_PREFIX)); 551 rtr_send_error(rs, UNK_REC_WDRAWL, NULL, buf, len); 552 free(roa); 553 return -1; 554 } 555 RB_REMOVE(roa_tree, &rs->roa_set, r); 556 free(r); 557 free(roa); 558 } 559 560 return 0; 561 } 562 563 static int 564 rtr_parse_ipv6_prefix(struct rtr_session *rs, uint8_t *buf, size_t len) 565 { 566 struct rtr_ipv6 ip6; 567 struct roa *roa; 568 569 if (len != sizeof(struct rtr_header) + sizeof(ip6)) { 570 log_warnx("rtr %s: received %s: bad pdu len", 571 log_rtr(rs), log_rtr_type(IPV6_PREFIX)); 572 rtr_send_error(rs, CORRUPT_DATA, "bad len", buf, len); 573 return -1; 574 } 575 576 if (rs->state != RTR_STATE_EXCHANGE) { 577 log_warnx("rtr %s: received %s: out of context", 578 log_rtr(rs), log_rtr_type(IPV6_PREFIX)); 579 rtr_send_error(rs, CORRUPT_DATA, NULL, buf, len); 580 return -1; 581 } 582 583 memcpy(&ip6, buf + sizeof(struct rtr_header), sizeof(ip6)); 584 if (ip6.prefixlen > 128 || ip6.maxlen > 128 || 585 ip6.prefixlen > ip6.maxlen) { 586 log_warnx("rtr: %s: received %s: bad prefixlen / maxlen", 587 log_rtr(rs), log_rtr_type(IPV6_PREFIX)); 588 rtr_send_error(rs, CORRUPT_DATA, "bad prefixlen / maxlen", 589 buf, len); 590 return -1; 591 } 592 593 if ((roa = calloc(1, sizeof(*roa))) == NULL) { 594 log_warn("rtr %s: received %s", 595 log_rtr(rs), log_rtr_type(IPV6_PREFIX)); 596 rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL, 0); 597 return -1; 598 } 599 roa->aid = AID_INET6; 600 roa->prefixlen = ip6.prefixlen; 601 roa->maxlen = ip6.maxlen; 602 roa->asnum = ntohl(ip6.asnum); 603 memcpy(&roa->prefix.inet6, ip6.prefix, sizeof(roa->prefix.inet6)); 604 605 if (ip6.flags & FLAG_ANNOUNCE) { 606 if (RB_INSERT(roa_tree, &rs->roa_set, roa) != NULL) { 607 log_warnx("rtr %s: received %s: duplicate announcement", 608 log_rtr(rs), log_rtr_type(IPV6_PREFIX)); 609 rtr_send_error(rs, DUP_REC_RECV, NULL, buf, len); 610 free(roa); 611 return -1; 612 } 613 } else { 614 struct roa *r; 615 616 r = RB_FIND(roa_tree, &rs->roa_set, roa); 617 if (r == NULL) { 618 log_warnx("rtr %s: received %s: unknown withdrawal", 619 log_rtr(rs), log_rtr_type(IPV6_PREFIX)); 620 rtr_send_error(rs, UNK_REC_WDRAWL, NULL, buf, len); 621 free(roa); 622 return -1; 623 } 624 RB_REMOVE(roa_tree, &rs->roa_set, r); 625 free(r); 626 free(roa); 627 } 628 return 0; 629 } 630 631 static int 632 rtr_parse_aspa(struct rtr_session *rs, uint8_t *buf, size_t len) 633 { 634 struct rtr_aspa rtr_aspa; 635 struct aspa_tree *aspatree; 636 struct aspa_set *aspa, *a; 637 size_t offset; 638 uint16_t cnt, i; 639 640 memcpy(&rtr_aspa, buf + sizeof(struct rtr_header), sizeof(rtr_aspa)); 641 offset = sizeof(struct rtr_header) + sizeof(rtr_aspa); 642 cnt = ntohs(rtr_aspa.cnt); 643 if (len != offset + cnt * sizeof(uint32_t)) { 644 log_warnx("rtr %s: received %s: bad pdu len", 645 log_rtr(rs), log_rtr_type(ASPA)); 646 rtr_send_error(rs, CORRUPT_DATA, "bad len", buf, len); 647 return -1; 648 } 649 650 if (rs->state != RTR_STATE_EXCHANGE) { 651 log_warnx("rtr %s: received %s: out of context", 652 log_rtr(rs), log_rtr_type(ASPA)); 653 rtr_send_error(rs, CORRUPT_DATA, NULL, buf, len); 654 return -1; 655 } 656 657 if (rtr_aspa.afi_flags & FLAG_AFI_V6) { 658 aspatree = &rs->aspa_oldv6; 659 } else { 660 aspatree = &rs->aspa; 661 } 662 663 /* create aspa_set entry from the rtr aspa pdu */ 664 if ((aspa = calloc(1, sizeof(*aspa))) == NULL) { 665 log_warn("rtr %s: received %s", 666 log_rtr(rs), log_rtr_type(ASPA)); 667 rtr_send_error(rs, INTERNAL_ERROR, "out of memory", NULL, 0); 668 return -1; 669 } 670 aspa->as = ntohl(rtr_aspa.cas); 671 aspa->num = cnt; 672 if (cnt > 0) { 673 if ((aspa->tas = calloc(cnt, sizeof(uint32_t))) == NULL) { 674 free_aspa(aspa); 675 log_warn("rtr %s: received %s", 676 log_rtr(rs), log_rtr_type(ASPA)); 677 rtr_send_error(rs, INTERNAL_ERROR, "out of memory", 678 NULL, 0); 679 return -1; 680 } 681 for (i = 0; i < cnt; i++) { 682 uint32_t tas; 683 memcpy(&tas, buf + offset + i * sizeof(tas), 684 sizeof(tas)); 685 aspa->tas[i] = ntohl(tas); 686 } 687 } 688 689 if (rtr_aspa.flags & FLAG_ANNOUNCE) { 690 a = RB_INSERT(aspa_tree, aspatree, aspa); 691 if (a != NULL) { 692 RB_REMOVE(aspa_tree, aspatree, a); 693 free_aspa(a); 694 695 if (RB_INSERT(aspa_tree, aspatree, aspa) != NULL) { 696 log_warnx("rtr %s: received %s: corrupt tree", 697 log_rtr(rs), log_rtr_type(ASPA)); 698 rtr_send_error(rs, INTERNAL_ERROR, 699 "corrupt aspa tree", NULL, 0); 700 free_aspa(aspa); 701 return -1; 702 } 703 } 704 } else { 705 a = RB_FIND(aspa_tree, aspatree, aspa); 706 if (a == NULL) { 707 log_warnx("rtr %s: received %s: unknown withdrawal", 708 log_rtr(rs), log_rtr_type(ASPA)); 709 rtr_send_error(rs, UNK_REC_WDRAWL, NULL, buf, len); 710 free_aspa(aspa); 711 return -1; 712 } 713 RB_REMOVE(aspa_tree, aspatree, a); 714 free_aspa(a); 715 free_aspa(aspa); 716 } 717 718 return 0; 719 } 720 721 static int 722 rtr_parse_end_of_data(struct rtr_session *rs, uint8_t *buf, size_t len) 723 { 724 struct rtr_endofdata eod; 725 uint32_t t; 726 727 buf += sizeof(struct rtr_header); 728 len -= sizeof(struct rtr_header); 729 730 if (len != sizeof(eod)) { 731 log_warnx("rtr %s: received %s: bad pdu len", 732 log_rtr(rs), log_rtr_type(END_OF_DATA)); 733 return -1; 734 } 735 736 if (rs->state != RTR_STATE_EXCHANGE) { 737 log_warnx("rtr %s: received %s: out of context", 738 log_rtr(rs), log_rtr_type(END_OF_DATA)); 739 return -1; 740 } 741 742 memcpy(&eod, buf, sizeof(eod)); 743 744 rs->serial = ntohl(eod.serial); 745 /* validate timer values to be in the right range */ 746 t = ntohl(eod.refresh); 747 if (t < 1 || t > 86400) 748 goto bad; 749 rs->refresh = t; 750 t = ntohl(eod.retry); 751 if (t < 1 || t > 7200) 752 goto bad; 753 rs->retry = t; 754 t = ntohl(eod.expire); 755 if (t < 600 || t > 172800) 756 goto bad; 757 if (t <= rs->retry || t <= rs->refresh) 758 goto bad; 759 rs->expire = t; 760 761 rtr_fsm(rs, RTR_EVNT_END_OF_DATA); 762 return 0; 763 764 bad: 765 log_warnx("rtr %s: received %s: bad timeout values", 766 log_rtr(rs), log_rtr_type(END_OF_DATA)); 767 return -1; 768 } 769 770 static int 771 rtr_parse_cache_reset(struct rtr_session *rs, uint8_t *buf, size_t len) 772 { 773 if (rs->state != RTR_STATE_ESTABLISHED) { 774 log_warnx("rtr %s: received %s: out of context", 775 log_rtr(rs), log_rtr_type(CACHE_RESET)); 776 return -1; 777 } 778 779 rtr_fsm(rs, RTR_EVNT_CACHE_RESET); 780 return 0; 781 } 782 783 /* 784 * Parse an Error Response message. This function behaves a bit different 785 * from other parse functions since on error the connection needs to be 786 * dropped without sending an error response back. 787 */ 788 static int 789 rtr_parse_error(struct rtr_session *rs, uint8_t *buf, size_t len) 790 { 791 struct rtr_header rh; 792 uint32_t pdu_len, msg_len; 793 uint8_t *msg; 794 char *str = NULL; 795 uint16_t errcode; 796 int rv = -1; 797 798 memcpy(&rh, buf, sizeof(rh)); 799 buf += sizeof(struct rtr_header); 800 len -= sizeof(struct rtr_header); 801 errcode = ntohs(rh.session_id); 802 803 memcpy(&pdu_len, buf, sizeof(pdu_len)); 804 pdu_len = ntohl(pdu_len); 805 806 if (len < pdu_len + sizeof(pdu_len)) { 807 log_warnx("rtr %s: received %s: bad encapsulated pdu len: %u " 808 "byte", log_rtr(rs), log_rtr_type(ERROR_REPORT), pdu_len); 809 rtr_fsm(rs, RTR_EVNT_RESET_AND_CLOSE); 810 return -1; 811 } 812 813 /* for now just ignore the embedded pdu */ 814 buf += pdu_len + sizeof(pdu_len); 815 len -= pdu_len + sizeof(pdu_len); 816 817 memcpy(&msg_len, buf, sizeof(msg_len)); 818 msg_len = ntohl(msg_len); 819 820 if (len < msg_len + sizeof(msg_len)) { 821 log_warnx("rtr %s: received %s: bad msg len: %u byte", 822 log_rtr(rs), log_rtr_type(ERROR_REPORT), msg_len); 823 rtr_fsm(rs, RTR_EVNT_RESET_AND_CLOSE); 824 return -1; 825 } 826 827 msg = buf + sizeof(msg_len); 828 if (msg_len != 0) 829 /* optional error msg, no need to check for failure */ 830 str = strndup(msg, msg_len); 831 832 log_warnx("rtr %s: received error: %s%s%s", log_rtr(rs), 833 log_rtr_error(errcode), str ? ": " : "", str ? str : ""); 834 835 if (errcode == NO_DATA_AVAILABLE) { 836 rtr_fsm(rs, RTR_EVNT_NO_DATA); 837 rv = 0; 838 } else 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 843 rs->last_recv_error = errcode; 844 if (str) 845 strlcpy(rs->last_recv_msg, str, 846 sizeof(rs->last_recv_msg)); 847 else 848 memset(rs->last_recv_msg, 0, 849 sizeof(rs->last_recv_msg)); 850 851 free(str); 852 return rv; 853 } 854 855 /* 856 * Try to process received rtr message, it is possible that not a full 857 * message is in the buffer. In that case stop, once new data is available 858 * a retry will be done. 859 */ 860 static void 861 rtr_process_msg(struct rtr_session *rs) 862 { 863 size_t rpos, av, left; 864 void *rptr; 865 size_t msglen; 866 enum rtr_pdu_type msgtype; 867 868 rpos = 0; 869 av = rs->r.wpos; 870 871 for (;;) { 872 if (rpos + sizeof(struct rtr_header) > av) 873 break; 874 rptr = rs->r.buf + rpos; 875 if (rtr_parse_header(rs, rptr, &msglen, &msgtype) == -1) 876 return; 877 878 /* missing data */ 879 if (rpos + msglen > av) 880 break; 881 882 switch (msgtype) { 883 case SERIAL_NOTIFY: 884 if (rtr_parse_notify(rs, rptr, msglen) == -1) { 885 rtr_send_error(rs, CORRUPT_DATA, NULL, 886 rptr, msglen); 887 return; 888 } 889 break; 890 case CACHE_RESPONSE: 891 if (rtr_parse_cache_response(rs, rptr, msglen) == -1) { 892 rtr_send_error(rs, CORRUPT_DATA, NULL, 893 rptr, msglen); 894 return; 895 } 896 break; 897 case IPV4_PREFIX: 898 if (rtr_parse_ipv4_prefix(rs, rptr, msglen) == -1) { 899 return; 900 } 901 break; 902 case IPV6_PREFIX: 903 if (rtr_parse_ipv6_prefix(rs, rptr, msglen) == -1) { 904 return; 905 } 906 break; 907 case END_OF_DATA: 908 if (rtr_parse_end_of_data(rs, rptr, msglen) == -1) { 909 rtr_send_error(rs, CORRUPT_DATA, NULL, 910 rptr, msglen); 911 return; 912 } 913 break; 914 case CACHE_RESET: 915 if (rtr_parse_cache_reset(rs, rptr, msglen) == -1) { 916 rtr_send_error(rs, CORRUPT_DATA, NULL, 917 rptr, msglen); 918 return; 919 } 920 break; 921 case ROUTER_KEY: 922 /* silently ignore router key */ 923 break; 924 case ERROR_REPORT: 925 if (rtr_parse_error(rs, rptr, msglen) == -1) 926 /* no need to send back an error */ 927 return; 928 break; 929 case ASPA: 930 if (rtr_parse_aspa(rs, rptr, msglen) == -1) { 931 return; 932 } 933 break; 934 default: 935 log_warnx("rtr %s: received %s: unexpected pdu type", 936 log_rtr(rs), log_rtr_type(msgtype)); 937 rtr_send_error(rs, INVALID_REQUEST, NULL, rptr, msglen); 938 return; 939 } 940 rpos += msglen; 941 } 942 943 left = av - rpos; 944 memmove(&rs->r.buf, rs->r.buf + rpos, left); 945 rs->r.wpos = left; 946 } 947 948 /* 949 * Simple FSM for RTR sessions 950 */ 951 static void 952 rtr_fsm(struct rtr_session *rs, enum rtr_event event) 953 { 954 enum rtr_state prev_state = rs->state; 955 956 switch (event) { 957 case RTR_EVNT_UNSUPP_PROTO_VERSION: 958 if (rs->state == RTR_STATE_NEGOTIATION) { 959 if (rs->version > 0) 960 rs->version--; 961 else { 962 /* 963 * can't downgrade anymore, fail connection 964 * RFC requires to send the error with our 965 * highest version number. 966 */ 967 rs->version = RTR_MAX_VERSION; 968 log_warnx("rtr %s: version negotiation failed", 969 log_rtr(rs)); 970 rtr_send_error(rs, UNSUPP_PROTOCOL_VERS, 971 NULL, NULL, 0); 972 return; 973 } 974 975 if (rs->fd != -1) { 976 /* flush buffers */ 977 msgbuf_clear(&rs->w); 978 rs->r.wpos = 0; 979 close(rs->fd); 980 rs->fd = -1; 981 } 982 983 /* retry connection with lower version */ 984 timer_set(&rs->timers, Timer_Rtr_Retry, rs->retry); 985 rtr_imsg_compose(IMSG_SOCKET_CONN, rs->id, 0, NULL, 0); 986 break; 987 } 988 /* FALLTHROUGH */ 989 case RTR_EVNT_RESET_AND_CLOSE: 990 rtr_reset_cache(rs); 991 rtr_recalc(); 992 /* FALLTHROUGH */ 993 case RTR_EVNT_CON_CLOSE: 994 if (rs->state == RTR_STATE_NEGOTIATION) { 995 /* consider any close event as a version failure. */ 996 rtr_fsm(rs, RTR_EVNT_UNSUPP_PROTO_VERSION); 997 break; 998 } 999 if (rs->fd != -1) { 1000 /* flush buffers */ 1001 msgbuf_clear(&rs->w); 1002 rs->r.wpos = 0; 1003 close(rs->fd); 1004 rs->fd = -1; 1005 } 1006 rs->state = RTR_STATE_CLOSED; 1007 /* try to reopen session */ 1008 timer_set(&rs->timers, Timer_Rtr_Retry, 1009 arc4random_uniform(10)); 1010 break; 1011 case RTR_EVNT_START: 1012 case RTR_EVNT_TIMER_RETRY: 1013 switch (rs->state) { 1014 case RTR_STATE_ERROR: 1015 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1016 return; 1017 case RTR_STATE_CLOSED: 1018 timer_set(&rs->timers, Timer_Rtr_Retry, rs->retry); 1019 rtr_imsg_compose(IMSG_SOCKET_CONN, rs->id, 0, NULL, 0); 1020 return; 1021 default: 1022 break; 1023 } 1024 /* FALLTHROUGH */ 1025 case RTR_EVNT_CON_OPEN: 1026 timer_stop(&rs->timers, Timer_Rtr_Retry); 1027 if (rs->session_id == -1) 1028 rtr_send_reset_query(rs); 1029 else 1030 rtr_send_serial_query(rs); 1031 break; 1032 case RTR_EVNT_SERIAL_NOTIFY: 1033 /* schedule a refresh after a quick wait */ 1034 timer_set(&rs->timers, Timer_Rtr_Refresh, 1035 arc4random_uniform(10)); 1036 break; 1037 case RTR_EVNT_TIMER_REFRESH: 1038 /* send serial query */ 1039 rtr_send_serial_query(rs); 1040 break; 1041 case RTR_EVNT_TIMER_EXPIRE: 1042 rtr_reset_cache(rs); 1043 rtr_recalc(); 1044 break; 1045 case RTR_EVNT_TIMER_ACTIVE: 1046 log_warnx("rtr %s: activity timer fired", log_rtr(rs)); 1047 rtr_sem_release(rs->active_lock); 1048 rtr_recalc(); 1049 rs->active_lock = 0; 1050 break; 1051 case RTR_EVNT_CACHE_RESPONSE: 1052 rs->state = RTR_STATE_EXCHANGE; 1053 timer_stop(&rs->timers, Timer_Rtr_Refresh); 1054 timer_stop(&rs->timers, Timer_Rtr_Retry); 1055 timer_set(&rs->timers, Timer_Rtr_Active, rs->active); 1056 /* prevent rtr_recalc from running while active */ 1057 rs->active_lock = 1; 1058 rtr_sem_acquire(rs->active_lock); 1059 break; 1060 case RTR_EVNT_END_OF_DATA: 1061 /* start refresh and expire timers */ 1062 timer_set(&rs->timers, Timer_Rtr_Refresh, rs->refresh); 1063 timer_set(&rs->timers, Timer_Rtr_Expire, rs->expire); 1064 timer_stop(&rs->timers, Timer_Rtr_Active); 1065 rs->state = RTR_STATE_ESTABLISHED; 1066 rtr_sem_release(rs->active_lock); 1067 rtr_recalc(); 1068 rs->active_lock = 0; 1069 break; 1070 case RTR_EVNT_CACHE_RESET: 1071 rtr_reset_cache(rs); 1072 rtr_recalc(); 1073 /* retry after a quick wait */ 1074 timer_set(&rs->timers, Timer_Rtr_Retry, 1075 arc4random_uniform(10)); 1076 break; 1077 case RTR_EVNT_NO_DATA: 1078 /* start retry timer */ 1079 timer_set(&rs->timers, Timer_Rtr_Retry, rs->retry); 1080 /* stop refresh timer just to be sure */ 1081 timer_stop(&rs->timers, Timer_Rtr_Refresh); 1082 rs->state = RTR_STATE_ESTABLISHED; 1083 break; 1084 case RTR_EVNT_SEND_ERROR: 1085 rtr_reset_cache(rs); 1086 rtr_recalc(); 1087 rs->state = RTR_STATE_ERROR; 1088 /* flush receive buffer */ 1089 rs->r.wpos = 0; 1090 break; 1091 } 1092 1093 log_info("rtr %s: state change %s -> %s, reason: %s", 1094 log_rtr(rs), rtr_statenames[prev_state], rtr_statenames[rs->state], 1095 rtr_eventnames[event]); 1096 } 1097 1098 /* 1099 * IO handler for RTR sessions 1100 */ 1101 static void 1102 rtr_dispatch_msg(struct pollfd *pfd, struct rtr_session *rs) 1103 { 1104 ssize_t n; 1105 int error; 1106 1107 if (pfd->revents & POLLHUP) { 1108 log_warnx("rtr %s: Connection closed, hangup", log_rtr(rs)); 1109 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1110 return; 1111 } 1112 if (pfd->revents & (POLLERR|POLLNVAL)) { 1113 log_warnx("rtr %s: Connection closed, error", log_rtr(rs)); 1114 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1115 return; 1116 } 1117 if (pfd->revents & POLLOUT && rs->w.queued) { 1118 if ((error = ibuf_write(&rs->w)) == -1) { 1119 if (errno != EAGAIN) { 1120 log_warn("rtr %s: write error", log_rtr(rs)); 1121 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1122 } 1123 } 1124 if (error == 0) 1125 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1126 if (rs->w.queued == 0 && rs->state == RTR_STATE_ERROR) 1127 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1128 } 1129 if (pfd->revents & POLLIN) { 1130 if ((n = read(rs->fd, rs->r.buf + rs->r.wpos, 1131 sizeof(rs->r.buf) - rs->r.wpos)) == -1) { 1132 if (errno != EINTR && errno != EAGAIN) { 1133 log_warn("rtr %s: read error", log_rtr(rs)); 1134 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1135 } 1136 return; 1137 } 1138 if (n == 0) { 1139 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1140 return; 1141 } 1142 rs->r.wpos += n; 1143 1144 /* new data arrived, try to process it */ 1145 rtr_process_msg(rs); 1146 } 1147 1148 } 1149 1150 void 1151 rtr_check_events(struct pollfd *pfds, size_t npfds) 1152 { 1153 struct rtr_session *rs; 1154 struct timer *t; 1155 time_t now; 1156 size_t i = 0; 1157 1158 for (i = 0; i < npfds; i++) { 1159 if (pfds[i].revents == 0) 1160 continue; 1161 TAILQ_FOREACH(rs, &rtrs, entry) 1162 if (rs->fd == pfds[i].fd) { 1163 rtr_dispatch_msg(&pfds[i], rs); 1164 break; 1165 } 1166 if (rs == NULL) 1167 log_warnx("%s: unknown fd in pollfds", __func__); 1168 } 1169 1170 /* run all timers */ 1171 now = getmonotime(); 1172 TAILQ_FOREACH(rs, &rtrs, entry) 1173 if ((t = timer_nextisdue(&rs->timers, now)) != NULL) { 1174 log_debug("rtr %s: %s triggered", log_rtr(rs), 1175 timernames[t->type]); 1176 /* stop timer so it does not trigger again */ 1177 timer_stop(&rs->timers, t->type); 1178 switch (t->type) { 1179 case Timer_Rtr_Refresh: 1180 rtr_fsm(rs, RTR_EVNT_TIMER_REFRESH); 1181 break; 1182 case Timer_Rtr_Retry: 1183 rtr_fsm(rs, RTR_EVNT_TIMER_RETRY); 1184 break; 1185 case Timer_Rtr_Expire: 1186 rtr_fsm(rs, RTR_EVNT_TIMER_EXPIRE); 1187 break; 1188 case Timer_Rtr_Active: 1189 rtr_fsm(rs, RTR_EVNT_TIMER_ACTIVE); 1190 break; 1191 default: 1192 fatalx("King Bula lost in time"); 1193 } 1194 } 1195 } 1196 1197 size_t 1198 rtr_count(void) 1199 { 1200 struct rtr_session *rs; 1201 size_t count = 0; 1202 1203 TAILQ_FOREACH(rs, &rtrs, entry) 1204 count++; 1205 return count; 1206 } 1207 1208 size_t 1209 rtr_poll_events(struct pollfd *pfds, size_t npfds, time_t *timeout) 1210 { 1211 struct rtr_session *rs; 1212 time_t now = getmonotime(); 1213 size_t i = 0; 1214 1215 TAILQ_FOREACH(rs, &rtrs, entry) { 1216 time_t nextaction; 1217 struct pollfd *pfd = pfds + i++; 1218 1219 if (i > npfds) 1220 fatalx("%s: too many sessions for pollfd", __func__); 1221 1222 if ((nextaction = timer_nextduein(&rs->timers, now)) != -1 && 1223 nextaction < *timeout) 1224 *timeout = nextaction; 1225 1226 if (rs->state == RTR_STATE_CLOSED) { 1227 pfd->fd = -1; 1228 continue; 1229 } 1230 1231 pfd->fd = rs->fd; 1232 pfd->events = 0; 1233 1234 if (rs->w.queued) 1235 pfd->events |= POLLOUT; 1236 if (rs->state >= RTR_STATE_ESTABLISHED) 1237 pfd->events |= POLLIN; 1238 } 1239 1240 return i; 1241 } 1242 1243 struct rtr_session * 1244 rtr_new(uint32_t id, char *descr) 1245 { 1246 struct rtr_session *rs; 1247 1248 if ((rs = calloc(1, sizeof(*rs))) == NULL) 1249 fatal("RTR session %s", descr); 1250 1251 RB_INIT(&rs->roa_set); 1252 RB_INIT(&rs->aspa); 1253 RB_INIT(&rs->aspa_oldv6); 1254 TAILQ_INIT(&rs->timers); 1255 msgbuf_init(&rs->w); 1256 1257 strlcpy(rs->descr, descr, sizeof(rs->descr)); 1258 rs->id = id; 1259 rs->session_id = -1; 1260 rs->version = RTR_MAX_VERSION; 1261 rs->refresh = RTR_DEFAULT_REFRESH; 1262 rs->retry = RTR_DEFAULT_RETRY; 1263 rs->expire = RTR_DEFAULT_EXPIRE; 1264 rs->active = RTR_DEFAULT_ACTIVE; 1265 rs->state = RTR_STATE_CLOSED; 1266 rs->reconf_action = RECONF_REINIT; 1267 rs->last_recv_error = NO_ERROR; 1268 rs->last_sent_error = NO_ERROR; 1269 1270 /* make sure that some timer is running to abort bad sessions */ 1271 timer_set(&rs->timers, Timer_Rtr_Expire, rs->expire); 1272 1273 log_debug("rtr %s: new session, start", log_rtr(rs)); 1274 TAILQ_INSERT_TAIL(&rtrs, rs, entry); 1275 rtr_fsm(rs, RTR_EVNT_START); 1276 1277 return rs; 1278 } 1279 1280 struct rtr_session * 1281 rtr_get(uint32_t id) 1282 { 1283 struct rtr_session *rs; 1284 1285 TAILQ_FOREACH(rs, &rtrs, entry) 1286 if (rs->id == id) 1287 return rs; 1288 return NULL; 1289 } 1290 1291 void 1292 rtr_free(struct rtr_session *rs) 1293 { 1294 if (rs == NULL) 1295 return; 1296 1297 rtr_reset_cache(rs); 1298 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1299 timer_remove_all(&rs->timers); 1300 free(rs); 1301 } 1302 1303 void 1304 rtr_open(struct rtr_session *rs, int fd) 1305 { 1306 if (rs->state != RTR_STATE_CLOSED && 1307 rs->state != RTR_STATE_NEGOTIATION) { 1308 log_warnx("rtr %s: bad session state", log_rtr(rs)); 1309 rtr_fsm(rs, RTR_EVNT_CON_CLOSE); 1310 } 1311 1312 if (rs->state == RTR_STATE_CLOSED) 1313 rs->version = RTR_MAX_VERSION; 1314 1315 rs->fd = rs->w.fd = fd; 1316 rs->state = RTR_STATE_NEGOTIATION; 1317 rtr_fsm(rs, RTR_EVNT_CON_OPEN); 1318 } 1319 1320 void 1321 rtr_config_prep(void) 1322 { 1323 struct rtr_session *rs; 1324 1325 TAILQ_FOREACH(rs, &rtrs, entry) 1326 rs->reconf_action = RECONF_DELETE; 1327 } 1328 1329 void 1330 rtr_config_merge(void) 1331 { 1332 struct rtr_session *rs, *nrs; 1333 1334 TAILQ_FOREACH_SAFE(rs, &rtrs, entry, nrs) 1335 if (rs->reconf_action == RECONF_DELETE) { 1336 TAILQ_REMOVE(&rtrs, rs, entry); 1337 rtr_free(rs); 1338 } 1339 } 1340 1341 void 1342 rtr_config_keep(struct rtr_session *rs) 1343 { 1344 rs->reconf_action = RECONF_KEEP; 1345 } 1346 1347 void 1348 rtr_roa_merge(struct roa_tree *rt) 1349 { 1350 struct rtr_session *rs; 1351 struct roa *roa; 1352 1353 TAILQ_FOREACH(rs, &rtrs, entry) { 1354 RB_FOREACH(roa, roa_tree, &rs->roa_set) 1355 rtr_roa_insert(rt, roa); 1356 } 1357 } 1358 1359 void 1360 rtr_aspa_merge(struct aspa_tree *at) 1361 { 1362 struct rtr_session *rs; 1363 struct aspa_set *aspa; 1364 1365 TAILQ_FOREACH(rs, &rtrs, entry) { 1366 RB_FOREACH(aspa, aspa_tree, &rs->aspa) 1367 rtr_aspa_insert(at, aspa); 1368 RB_FOREACH(aspa, aspa_tree, &rs->aspa_oldv6) 1369 rtr_aspa_insert(at, aspa); 1370 } 1371 } 1372 1373 void 1374 rtr_shutdown(void) 1375 { 1376 struct rtr_session *rs, *nrs; 1377 1378 TAILQ_FOREACH_SAFE(rs, &rtrs, entry, nrs) 1379 rtr_free(rs); 1380 } 1381 1382 void 1383 rtr_show(struct rtr_session *rs, pid_t pid) 1384 { 1385 struct ctl_show_rtr msg; 1386 struct ctl_timer ct; 1387 u_int i; 1388 time_t d; 1389 1390 memset(&msg, 0, sizeof(msg)); 1391 1392 /* descr, remote_addr, local_addr and remote_port set by parent */ 1393 msg.version = rs->version; 1394 msg.serial = rs->serial; 1395 msg.refresh = rs->refresh; 1396 msg.retry = rs->retry; 1397 msg.expire = rs->expire; 1398 msg.session_id = rs->session_id; 1399 msg.last_sent_error = rs->last_sent_error; 1400 msg.last_recv_error = rs->last_recv_error; 1401 strlcpy(msg.last_sent_msg, rs->last_sent_msg, 1402 sizeof(msg.last_sent_msg)); 1403 strlcpy(msg.last_recv_msg, rs->last_recv_msg, 1404 sizeof(msg.last_recv_msg)); 1405 1406 /* send back imsg */ 1407 rtr_imsg_compose(IMSG_CTL_SHOW_RTR, rs->id, pid, &msg, sizeof(msg)); 1408 1409 /* send back timer imsgs */ 1410 for (i = 1; i < Timer_Max; i++) { 1411 if (!timer_running(&rs->timers, i, &d)) 1412 continue; 1413 ct.type = i; 1414 ct.val = d; 1415 rtr_imsg_compose(IMSG_CTL_SHOW_TIMER, rs->id, pid, 1416 &ct, sizeof(ct)); 1417 } 1418 } 1419