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