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