1/* $OpenBSD: mrtparser.c,v 1.22 2024/02/01 11:37:10 claudio Exp $ */ 2/* 3 * Copyright (c) 2011 Claudio Jeker <claudio@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17#include <sys/types.h> 18#include <sys/socket.h> 19#include <netinet/in.h> 20#include <err.h> 21#include <errno.h> 22#include <limits.h> 23#include <stdlib.h> 24#include <stdio.h> 25#include <string.h> 26#include <time.h> 27#include <unistd.h> 28 29#include "mrt.h" 30#include "mrtparser.h" 31 32struct mrt_peer *mrt_parse_v2_peer(struct mrt_hdr *, struct ibuf *); 33struct mrt_rib *mrt_parse_v2_rib(struct mrt_hdr *, struct ibuf *, int); 34int mrt_parse_dump(struct mrt_hdr *, struct ibuf *, struct mrt_peer **, 35 struct mrt_rib **); 36int mrt_parse_dump_mp(struct mrt_hdr *, struct ibuf *, struct mrt_peer **, 37 struct mrt_rib **, int); 38int mrt_extract_attr(struct mrt_rib_entry *, struct ibuf *, uint8_t, int); 39 40void mrt_free_peers(struct mrt_peer *); 41void mrt_free_rib(struct mrt_rib *); 42 43u_char *mrt_aspath_inflate(struct ibuf *, uint16_t *); 44int mrt_extract_addr(struct ibuf *, struct bgpd_addr *, uint8_t); 45int mrt_extract_prefix(struct ibuf *, uint8_t, struct bgpd_addr *, 46 uint8_t *, int); 47 48int mrt_parse_state(struct mrt_bgp_state *, struct mrt_hdr *, 49 struct ibuf *, int); 50int mrt_parse_msg(struct mrt_bgp_msg *, struct mrt_hdr *, 51 struct ibuf *, int); 52 53static size_t 54mrt_read_buf(int fd, void *buf, size_t len) 55{ 56 char *b = buf; 57 ssize_t n; 58 59 while (len > 0) { 60 if ((n = read(fd, b, len)) == -1) { 61 if (errno == EINTR) 62 continue; 63 err(1, "read"); 64 } 65 if (n == 0) 66 break; 67 b += n; 68 len -= n; 69 } 70 71 return (b - (char *)buf); 72} 73 74static struct ibuf * 75mrt_read_msg(int fd, struct mrt_hdr *hdr) 76{ 77 struct ibuf *buf; 78 size_t len; 79 80 memset(hdr, 0, sizeof(*hdr)); 81 if (mrt_read_buf(fd, hdr, sizeof(*hdr)) != sizeof(*hdr)) 82 return (NULL); 83 84 len = ntohl(hdr->length); 85 if ((buf = ibuf_open(len)) == NULL) 86 err(1, "ibuf_open(%zu)", len); 87 88 if (mrt_read_buf(fd, ibuf_reserve(buf, len), len) != len) { 89 ibuf_free(buf); 90 return (NULL); 91 } 92 return (buf); 93} 94 95void 96mrt_parse(int fd, struct mrt_parser *p, int verbose) 97{ 98 struct mrt_hdr h; 99 struct mrt_bgp_state s; 100 struct mrt_bgp_msg m; 101 struct mrt_peer *pctx = NULL; 102 struct mrt_rib *r; 103 struct ibuf *msg; 104 105 while ((msg = mrt_read_msg(fd, &h)) != NULL) { 106 if (ibuf_size(msg) != ntohl(h.length)) 107 errx(1, "corrupt message, %zu vs %u", ibuf_size(msg), 108 ntohl(h.length)); 109 switch (ntohs(h.type)) { 110 case MSG_NULL: 111 case MSG_START: 112 case MSG_DIE: 113 case MSG_I_AM_DEAD: 114 case MSG_PEER_DOWN: 115 case MSG_PROTOCOL_BGP: 116 case MSG_PROTOCOL_IDRP: 117 case MSG_PROTOCOL_BGP4PLUS: 118 case MSG_PROTOCOL_BGP4PLUS1: 119 if (verbose) 120 printf("deprecated MRT type %d\n", 121 ntohs(h.type)); 122 break; 123 case MSG_PROTOCOL_RIP: 124 case MSG_PROTOCOL_RIPNG: 125 case MSG_PROTOCOL_OSPF: 126 case MSG_PROTOCOL_ISIS_ET: 127 case MSG_PROTOCOL_ISIS: 128 case MSG_PROTOCOL_OSPFV3_ET: 129 case MSG_PROTOCOL_OSPFV3: 130 if (verbose) 131 printf("unsupported MRT type %d\n", 132 ntohs(h.type)); 133 break; 134 case MSG_TABLE_DUMP: 135 switch (ntohs(h.subtype)) { 136 case MRT_DUMP_AFI_IP: 137 case MRT_DUMP_AFI_IPv6: 138 if (p->dump == NULL) 139 break; 140 if (mrt_parse_dump(&h, msg, &pctx, &r) == 0) { 141 if (p->dump) 142 p->dump(r, pctx, p->arg); 143 mrt_free_rib(r); 144 } 145 break; 146 default: 147 if (verbose) 148 printf("unknown AFI %d in table dump\n", 149 ntohs(h.subtype)); 150 break; 151 } 152 break; 153 case MSG_TABLE_DUMP_V2: 154 switch (ntohs(h.subtype)) { 155 case MRT_DUMP_V2_PEER_INDEX_TABLE: 156 if (p->dump == NULL) 157 break; 158 if (pctx) 159 mrt_free_peers(pctx); 160 pctx = mrt_parse_v2_peer(&h, msg); 161 break; 162 case MRT_DUMP_V2_RIB_IPV4_UNICAST: 163 case MRT_DUMP_V2_RIB_IPV4_MULTICAST: 164 case MRT_DUMP_V2_RIB_IPV6_UNICAST: 165 case MRT_DUMP_V2_RIB_IPV6_MULTICAST: 166 case MRT_DUMP_V2_RIB_GENERIC: 167 case MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH: 168 case MRT_DUMP_V2_RIB_IPV4_MULTICAST_ADDPATH: 169 case MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH: 170 case MRT_DUMP_V2_RIB_IPV6_MULTICAST_ADDPATH: 171 case MRT_DUMP_V2_RIB_GENERIC_ADDPATH: 172 if (p->dump == NULL) 173 break; 174 r = mrt_parse_v2_rib(&h, msg, verbose); 175 if (r) { 176 if (p->dump) 177 p->dump(r, pctx, p->arg); 178 mrt_free_rib(r); 179 } 180 break; 181 default: 182 if (verbose) 183 printf("unhandled DUMP_V2 subtype %d\n", 184 ntohs(h.subtype)); 185 break; 186 } 187 break; 188 case MSG_PROTOCOL_BGP4MP_ET: 189 case MSG_PROTOCOL_BGP4MP: 190 switch (ntohs(h.subtype)) { 191 case BGP4MP_STATE_CHANGE: 192 case BGP4MP_STATE_CHANGE_AS4: 193 if (mrt_parse_state(&s, &h, msg, 194 verbose) != -1) { 195 if (p->state) 196 p->state(&s, p->arg); 197 } 198 break; 199 case BGP4MP_MESSAGE: 200 case BGP4MP_MESSAGE_AS4: 201 case BGP4MP_MESSAGE_LOCAL: 202 case BGP4MP_MESSAGE_AS4_LOCAL: 203 case BGP4MP_MESSAGE_ADDPATH: 204 case BGP4MP_MESSAGE_AS4_ADDPATH: 205 case BGP4MP_MESSAGE_LOCAL_ADDPATH: 206 case BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH: 207 if (mrt_parse_msg(&m, &h, msg, verbose) != -1) { 208 if (p->message) 209 p->message(&m, p->arg); 210 } 211 break; 212 case BGP4MP_ENTRY: 213 if (p->dump == NULL) 214 break; 215 if (mrt_parse_dump_mp(&h, msg, &pctx, &r, 216 verbose) == 0) { 217 if (p->dump) 218 p->dump(r, pctx, p->arg); 219 mrt_free_rib(r); 220 } 221 break; 222 default: 223 if (verbose) 224 printf("unhandled BGP4MP subtype %d\n", 225 ntohs(h.subtype)); 226 break; 227 } 228 break; 229 default: 230 if (verbose) 231 printf("unknown MRT type %d\n", ntohs(h.type)); 232 break; 233 } 234 ibuf_free(msg); 235 } 236 if (pctx) 237 mrt_free_peers(pctx); 238} 239 240static int 241mrt_afi2aid(int afi, int safi, int verbose) 242{ 243 switch (afi) { 244 case MRT_DUMP_AFI_IP: 245 if (safi == -1 || safi == 1 || safi == 2) 246 return AID_INET; 247 else if (safi == 128) 248 return AID_VPN_IPv4; 249 break; 250 case MRT_DUMP_AFI_IPv6: 251 if (safi == -1 || safi == 1 || safi == 2) 252 return AID_INET6; 253 else if (safi == 128) 254 return AID_VPN_IPv6; 255 break; 256 default: 257 break; 258 } 259 if (verbose) 260 printf("unhandled AFI/SAFI %d/%d\n", afi, safi); 261 return AID_UNSPEC; 262} 263 264struct mrt_peer * 265mrt_parse_v2_peer(struct mrt_hdr *hdr, struct ibuf *msg) 266{ 267 struct mrt_peer_entry *peers = NULL; 268 struct mrt_peer *p; 269 uint32_t bid; 270 uint16_t cnt, i; 271 272 if (ibuf_size(msg) < 8) /* min msg size */ 273 return NULL; 274 275 p = calloc(1, sizeof(struct mrt_peer)); 276 if (p == NULL) 277 err(1, "calloc"); 278 279 /* collector bgp id */ 280 if (ibuf_get_n32(msg, &bid) == -1 || 281 ibuf_get_n16(msg, &cnt) == -1) 282 goto fail; 283 284 /* view name */ 285 if (cnt != 0) { 286 if ((p->view = malloc(cnt + 1)) == NULL) 287 err(1, "malloc"); 288 if (ibuf_get(msg, p->view, cnt) == -1) 289 goto fail; 290 p->view[cnt] = 0; 291 } else 292 if ((p->view = strdup("")) == NULL) 293 err(1, "strdup"); 294 295 /* peer_count */ 296 if (ibuf_get_n16(msg, &cnt) == -1) 297 goto fail; 298 299 /* peer entries */ 300 if ((peers = calloc(cnt, sizeof(struct mrt_peer_entry))) == NULL) 301 err(1, "calloc"); 302 for (i = 0; i < cnt; i++) { 303 uint8_t type; 304 305 if (ibuf_get_n8(msg, &type) == -1 || 306 ibuf_get_n32(msg, &peers[i].bgp_id) == -1) 307 goto fail; 308 309 if (type & MRT_DUMP_V2_PEER_BIT_I) { 310 if (mrt_extract_addr(msg, &peers[i].addr, 311 AID_INET6) == -1) 312 goto fail; 313 } else { 314 if (mrt_extract_addr(msg, &peers[i].addr, 315 AID_INET) == -1) 316 goto fail; 317 } 318 319 if (type & MRT_DUMP_V2_PEER_BIT_A) { 320 if (ibuf_get_n32(msg, &peers[i].asnum) == -1) 321 goto fail; 322 } else { 323 uint16_t as2; 324 325 if (ibuf_get_n16(msg, &as2) == -1) 326 goto fail; 327 peers[i].asnum = as2; 328 } 329 } 330 p->peers = peers; 331 p->npeers = cnt; 332 return (p); 333fail: 334 mrt_free_peers(p); 335 free(peers); 336 return (NULL); 337} 338 339struct mrt_rib * 340mrt_parse_v2_rib(struct mrt_hdr *hdr, struct ibuf *msg, int verbose) 341{ 342 struct mrt_rib_entry *entries = NULL; 343 struct mrt_rib *r; 344 uint16_t i, afi; 345 uint8_t safi, aid; 346 347 r = calloc(1, sizeof(struct mrt_rib)); 348 if (r == NULL) 349 err(1, "calloc"); 350 351 /* seq_num */ 352 if (ibuf_get_n32(msg, &r->seqnum) == -1) 353 goto fail; 354 355 switch (ntohs(hdr->subtype)) { 356 case MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH: 357 case MRT_DUMP_V2_RIB_IPV4_MULTICAST_ADDPATH: 358 r->add_path = 1; 359 /* FALLTHROUGH */ 360 case MRT_DUMP_V2_RIB_IPV4_UNICAST: 361 case MRT_DUMP_V2_RIB_IPV4_MULTICAST: 362 /* prefix */ 363 if (mrt_extract_prefix(msg, AID_INET, &r->prefix, 364 &r->prefixlen, verbose) == -1) 365 goto fail; 366 break; 367 case MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH: 368 case MRT_DUMP_V2_RIB_IPV6_MULTICAST_ADDPATH: 369 r->add_path = 1; 370 /* FALLTHROUGH */ 371 case MRT_DUMP_V2_RIB_IPV6_UNICAST: 372 case MRT_DUMP_V2_RIB_IPV6_MULTICAST: 373 /* prefix */ 374 if (mrt_extract_prefix(msg, AID_INET6, &r->prefix, 375 &r->prefixlen, verbose) == -1) 376 goto fail; 377 break; 378 case MRT_DUMP_V2_RIB_GENERIC_ADDPATH: 379 /* 380 * RFC8050 handling for add-path has special handling for 381 * RIB_GENERIC_ADDPATH but nobody implements it that way. 382 * So just use the same way as for the other _ADDPATH types. 383 */ 384 r->add_path = 1; 385 /* FALLTHROUGH */ 386 case MRT_DUMP_V2_RIB_GENERIC: 387 /* fetch AFI/SAFI pair */ 388 if (ibuf_get_n16(msg, &afi) == -1 || 389 ibuf_get_n8(msg, &safi) == -1) 390 goto fail; 391 392 if ((aid = mrt_afi2aid(afi, safi, verbose)) == AID_UNSPEC) 393 goto fail; 394 395 /* prefix */ 396 if (mrt_extract_prefix(msg, aid, &r->prefix, 397 &r->prefixlen, verbose) == -1) 398 goto fail; 399 break; 400 default: 401 errx(1, "unknown subtype %hd", ntohs(hdr->subtype)); 402 } 403 404 /* entries count */ 405 if (ibuf_get_n16(msg, &r->nentries) == -1) 406 goto fail; 407 408 /* entries */ 409 if ((entries = calloc(r->nentries, sizeof(struct mrt_rib_entry))) == 410 NULL) 411 err(1, "calloc"); 412 for (i = 0; i < r->nentries; i++) { 413 struct ibuf abuf; 414 uint32_t otm; 415 uint16_t alen; 416 417 /* peer index */ 418 if (ibuf_get_n16(msg, &entries[i].peer_idx) == -1) 419 goto fail; 420 421 /* originated */ 422 if (ibuf_get_n32(msg, &otm) == -1) 423 goto fail; 424 entries[i].originated = otm; 425 426 if (r->add_path) { 427 if (ibuf_get_n32(msg, &entries[i].path_id) == -1) 428 goto fail; 429 } 430 431 /* attr_len */ 432 if (ibuf_get_n16(msg, &alen) == -1 || 433 ibuf_get_ibuf(msg, alen, &abuf) == -1) 434 goto fail; 435 436 /* attr */ 437 if (mrt_extract_attr(&entries[i], &abuf, r->prefix.aid, 438 1) == -1) 439 goto fail; 440 } 441 r->entries = entries; 442 return (r); 443fail: 444 mrt_free_rib(r); 445 free(entries); 446 return (NULL); 447} 448 449int 450mrt_parse_dump(struct mrt_hdr *hdr, struct ibuf *msg, struct mrt_peer **pp, 451 struct mrt_rib **rp) 452{ 453 struct ibuf abuf; 454 struct mrt_peer *p; 455 struct mrt_rib *r; 456 struct mrt_rib_entry *re; 457 uint32_t tmp32; 458 uint16_t tmp16, alen; 459 460 if (*pp == NULL) { 461 *pp = calloc(1, sizeof(struct mrt_peer)); 462 if (*pp == NULL) 463 err(1, "calloc"); 464 (*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry)); 465 if ((*pp)->peers == NULL) 466 err(1, "calloc"); 467 (*pp)->npeers = 1; 468 } 469 p = *pp; 470 471 *rp = r = calloc(1, sizeof(struct mrt_rib)); 472 if (r == NULL) 473 err(1, "calloc"); 474 re = calloc(1, sizeof(struct mrt_rib_entry)); 475 if (re == NULL) 476 err(1, "calloc"); 477 r->nentries = 1; 478 r->entries = re; 479 480 if (ibuf_skip(msg, sizeof(uint16_t)) == -1 || /* view */ 481 ibuf_get_n16(msg, &tmp16) == -1) /* seqnum */ 482 goto fail; 483 r->seqnum = tmp16; 484 485 switch (ntohs(hdr->subtype)) { 486 case MRT_DUMP_AFI_IP: 487 if (mrt_extract_addr(msg, &r->prefix, AID_INET) == -1) 488 goto fail; 489 break; 490 case MRT_DUMP_AFI_IPv6: 491 if (mrt_extract_addr(msg, &r->prefix, AID_INET6) == -1) 492 goto fail; 493 break; 494 } 495 if (ibuf_get_n8(msg, &r->prefixlen) == -1 || /* prefixlen */ 496 ibuf_skip(msg, 1) == -1 || /* status */ 497 ibuf_get_n32(msg, &tmp32) == -1) /* originated */ 498 goto fail; 499 re->originated = tmp32; 500 /* peer ip */ 501 switch (ntohs(hdr->subtype)) { 502 case MRT_DUMP_AFI_IP: 503 if (mrt_extract_addr(msg, &p->peers->addr, AID_INET) == -1) 504 goto fail; 505 break; 506 case MRT_DUMP_AFI_IPv6: 507 if (mrt_extract_addr(msg, &p->peers->addr, AID_INET6) == -1) 508 goto fail; 509 break; 510 } 511 if (ibuf_get_n16(msg, &tmp16) == -1) 512 goto fail; 513 p->peers->asnum = tmp16; 514 515 if (ibuf_get_n16(msg, &alen) == -1 || 516 ibuf_get_ibuf(msg, alen, &abuf) == -1) 517 goto fail; 518 519 /* attr */ 520 if (mrt_extract_attr(re, &abuf, r->prefix.aid, 0) == -1) 521 goto fail; 522 return (0); 523fail: 524 mrt_free_rib(r); 525 return (-1); 526} 527 528int 529mrt_parse_dump_mp(struct mrt_hdr *hdr, struct ibuf *msg, struct mrt_peer **pp, 530 struct mrt_rib **rp, int verbose) 531{ 532 struct ibuf abuf; 533 struct mrt_peer *p; 534 struct mrt_rib *r; 535 struct mrt_rib_entry *re; 536 uint32_t tmp32; 537 uint16_t asnum, alen, afi; 538 uint8_t safi, nhlen, aid; 539 540 if (*pp == NULL) { 541 *pp = calloc(1, sizeof(struct mrt_peer)); 542 if (*pp == NULL) 543 err(1, "calloc"); 544 (*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry)); 545 if ((*pp)->peers == NULL) 546 err(1, "calloc"); 547 (*pp)->npeers = 1; 548 } 549 p = *pp; 550 551 *rp = r = calloc(1, sizeof(struct mrt_rib)); 552 if (r == NULL) 553 err(1, "calloc"); 554 re = calloc(1, sizeof(struct mrt_rib_entry)); 555 if (re == NULL) 556 err(1, "calloc"); 557 r->nentries = 1; 558 r->entries = re; 559 560 /* just ignore the microsec field for _ET header for now */ 561 if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) { 562 if (ibuf_skip(msg, sizeof(uint32_t)) == -1) 563 goto fail; 564 } 565 566 if (ibuf_skip(msg, sizeof(uint16_t)) == -1 || /* source AS */ 567 ibuf_get_n16(msg, &asnum) == -1 || /* dest AS */ 568 ibuf_skip(msg, sizeof(uint16_t)) == -1 || /* iface index */ 569 ibuf_get_n16(msg, &afi) == -1) 570 goto fail; 571 p->peers->asnum = asnum; 572 573 /* source + dest ip */ 574 switch (afi) { 575 case MRT_DUMP_AFI_IP: 576 /* source IP */ 577 if (ibuf_skip(msg, sizeof(struct in_addr)) == -1) 578 goto fail; 579 /* dest IP */ 580 if (mrt_extract_addr(msg, &p->peers->addr, AID_INET) == -1) 581 goto fail; 582 break; 583 case MRT_DUMP_AFI_IPv6: 584 /* source IP */ 585 if (ibuf_skip(msg, sizeof(struct in6_addr)) == -1) 586 goto fail; 587 /* dest IP */ 588 if (mrt_extract_addr(msg, &p->peers->addr, AID_INET6) == -1) 589 goto fail; 590 break; 591 } 592 593 if (ibuf_skip(msg, sizeof(uint16_t)) == -1 || /* view */ 594 ibuf_skip(msg, sizeof(uint16_t)) == -1 || /* status */ 595 ibuf_get_n32(msg, &tmp32) == -1) /* originated */ 596 goto fail; 597 re->originated = tmp32; 598 599 if (ibuf_get_n16(msg, &afi) == -1 || /* afi */ 600 ibuf_get_n8(msg, &safi) == -1) /* safi */ 601 goto fail; 602 if ((aid = mrt_afi2aid(afi, safi, verbose)) == AID_UNSPEC) 603 goto fail; 604 605 if (ibuf_get_n8(msg, &nhlen) == -1) /* nhlen */ 606 goto fail; 607 608 /* nexthop */ 609 if (mrt_extract_addr(msg, &re->nexthop, aid) == -1) 610 goto fail; 611 612 /* prefix */ 613 if (mrt_extract_prefix(msg, aid, &r->prefix, &r->prefixlen, 614 verbose) == -1) 615 goto fail; 616 617 if (ibuf_get_n16(msg, &alen) == -1 || 618 ibuf_get_ibuf(msg, alen, &abuf) == -1) 619 goto fail; 620 if (mrt_extract_attr(re, &abuf, r->prefix.aid, 0) == -1) 621 goto fail; 622 623 return (0); 624fail: 625 mrt_free_rib(r); 626 return (-1); 627} 628 629int 630mrt_extract_attr(struct mrt_rib_entry *re, struct ibuf *buf, uint8_t aid, 631 int as4) 632{ 633 struct ibuf abuf; 634 struct mrt_attr *ap; 635 size_t alen, hlen; 636 uint8_t type, flags; 637 638 do { 639 ibuf_from_ibuf(&abuf, buf); 640 if (ibuf_get_n8(&abuf, &flags) == -1 || 641 ibuf_get_n8(&abuf, &type) == -1) 642 return (-1); 643 644 if (flags & MRT_ATTR_EXTLEN) { 645 uint16_t tmp16; 646 if (ibuf_get_n16(&abuf, &tmp16) == -1) 647 return (-1); 648 alen = tmp16; 649 hlen = 4; 650 } else { 651 uint8_t tmp8; 652 if (ibuf_get_n8(&abuf, &tmp8) == -1) 653 return (-1); 654 alen = tmp8; 655 hlen = 3; 656 } 657 if (ibuf_truncate(&abuf, alen) == -1) 658 return (-1); 659 /* consume the attribute in buf before moving forward */ 660 if (ibuf_skip(buf, hlen + alen) == -1) 661 return (-1); 662 663 switch (type) { 664 case MRT_ATTR_ORIGIN: 665 if (alen != 1) 666 return (-1); 667 if (ibuf_get_n8(&abuf, &re->origin) == -1) 668 return (-1); 669 break; 670 case MRT_ATTR_ASPATH: 671 if (as4) { 672 re->aspath_len = alen; 673 if ((re->aspath = malloc(alen)) == NULL) 674 err(1, "malloc"); 675 if (ibuf_get(&abuf, re->aspath, alen) == -1) 676 return (-1); 677 } else { 678 re->aspath = mrt_aspath_inflate(&abuf, 679 &re->aspath_len); 680 if (re->aspath == NULL) 681 return (-1); 682 } 683 break; 684 case MRT_ATTR_NEXTHOP: 685 if (alen != 4) 686 return (-1); 687 if (aid != AID_INET) 688 break; 689 if (ibuf_get(&abuf, &re->nexthop.v4, 690 sizeof(re->nexthop.v4)) == -1) 691 return (-1); 692 re->nexthop.aid = AID_INET; 693 break; 694 case MRT_ATTR_MED: 695 if (alen != 4) 696 return (-1); 697 if (ibuf_get_n32(&abuf, &re->med) == -1) 698 return (-1); 699 break; 700 case MRT_ATTR_LOCALPREF: 701 if (alen != 4) 702 return (-1); 703 if (ibuf_get_n32(&abuf, &re->local_pref) == -1) 704 return (-1); 705 break; 706 case MRT_ATTR_MP_REACH_NLRI: 707 /* 708 * XXX horrible hack: 709 * Once again IETF and the real world differ in the 710 * implementation. In short the abbreviated MP_NLRI 711 * hack in the standard is not used in real life. 712 * Detect the two cases by looking at the first byte 713 * of the payload (either the nexthop addr length (RFC) 714 * or the high byte of the AFI (old form)). If the 715 * first byte matches the expected nexthop length it 716 * is expected to be the RFC 6396 encoding. 717 * 718 * Checking for the hack skips over the nhlen. 719 */ 720 { 721 uint8_t hack; 722 if (ibuf_get_n8(&abuf, &hack) == -1) 723 return (-1); 724 if (hack != alen - 1) { 725 if (ibuf_skip(&abuf, 3) == -1) 726 return (-1); 727 } 728 } 729 switch (aid) { 730 case AID_INET6: 731 if (ibuf_get(&abuf, &re->nexthop.v6, 732 sizeof(re->nexthop.v6)) == -1) 733 return (-1); 734 re->nexthop.aid = aid; 735 break; 736 case AID_VPN_IPv4: 737 if (ibuf_skip(&abuf, sizeof(uint64_t)) == -1 || 738 ibuf_get(&abuf, &re->nexthop.v4, 739 sizeof(re->nexthop.v4)) == -1) 740 return (-1); 741 re->nexthop.aid = aid; 742 break; 743 case AID_VPN_IPv6: 744 if (ibuf_skip(&abuf, sizeof(uint64_t)) == -1 || 745 ibuf_get(&abuf, &re->nexthop.v6, 746 sizeof(re->nexthop.v6)) == -1) 747 return (-1); 748 re->nexthop.aid = aid; 749 break; 750 } 751 break; 752 case MRT_ATTR_AS4PATH: 753 if (!as4) { 754 free(re->aspath); 755 re->aspath_len = alen; 756 if ((re->aspath = malloc(alen)) == NULL) 757 err(1, "malloc"); 758 if (ibuf_get(&abuf, re->aspath, alen) == -1) 759 return (-1); 760 break; 761 } 762 /* FALLTHROUGH */ 763 default: 764 re->nattrs++; 765 if (re->nattrs >= UCHAR_MAX) 766 err(1, "too many attributes"); 767 ap = reallocarray(re->attrs, 768 re->nattrs, sizeof(struct mrt_attr)); 769 if (ap == NULL) 770 err(1, "realloc"); 771 re->attrs = ap; 772 ap = re->attrs + re->nattrs - 1; 773 ibuf_rewind(&abuf); 774 ap->attr_len = ibuf_size(&abuf); 775 if ((ap->attr = malloc(ap->attr_len)) == NULL) 776 err(1, "malloc"); 777 if (ibuf_get(&abuf, ap->attr, ap->attr_len) == -1) 778 return (-1); 779 break; 780 } 781 } while (ibuf_size(buf) > 0); 782 783 return (0); 784} 785 786void 787mrt_free_peers(struct mrt_peer *p) 788{ 789 free(p->peers); 790 free(p->view); 791 free(p); 792} 793 794void 795mrt_free_rib(struct mrt_rib *r) 796{ 797 uint16_t i, j; 798 799 for (i = 0; i < r->nentries && r->entries; i++) { 800 for (j = 0; j < r->entries[i].nattrs; j++) 801 free(r->entries[i].attrs[j].attr); 802 free(r->entries[i].attrs); 803 free(r->entries[i].aspath); 804 } 805 806 free(r->entries); 807 free(r); 808} 809 810u_char * 811mrt_aspath_inflate(struct ibuf *buf, uint16_t *newlen) 812{ 813 struct ibuf *asbuf; 814 u_char *data; 815 size_t len; 816 817 *newlen = 0; 818 asbuf = aspath_inflate(buf); 819 if (asbuf == NULL) 820 return NULL; 821 822 len = ibuf_size(asbuf); 823 if ((data = malloc(len)) == NULL) 824 err(1, "malloc"); 825 if (ibuf_get(asbuf, data, len) == -1) { 826 ibuf_free(asbuf); 827 return (NULL); 828 } 829 ibuf_free(asbuf); 830 *newlen = len; 831 return (data); 832} 833 834int 835mrt_extract_addr(struct ibuf *msg, struct bgpd_addr *addr, uint8_t aid) 836{ 837 memset(addr, 0, sizeof(*addr)); 838 switch (aid) { 839 case AID_INET: 840 if (ibuf_get(msg, &addr->v4, sizeof(addr->v4)) == -1) 841 return (-1); 842 break; 843 case AID_INET6: 844 if (ibuf_get(msg, &addr->v6, sizeof(addr->v6)) == -1) 845 return (-1); 846 break; 847 case AID_VPN_IPv4: 848 /* XXX labelstack and rd missing */ 849 if (ibuf_skip(msg, sizeof(uint64_t)) == -1 || 850 ibuf_get(msg, &addr->v4, sizeof(addr->v4)) == -1) 851 return (-1); 852 break; 853 case AID_VPN_IPv6: 854 /* XXX labelstack and rd missing */ 855 if (ibuf_skip(msg, sizeof(uint64_t)) == -1 || 856 ibuf_get(msg, &addr->v6, sizeof(addr->v6)) == -1) 857 return (-1); 858 break; 859 default: 860 return (-1); 861 } 862 addr->aid = aid; 863 return 0; 864} 865 866int 867mrt_extract_prefix(struct ibuf *msg, uint8_t aid, struct bgpd_addr *prefix, 868 uint8_t *prefixlen, int verbose) 869{ 870 int r; 871 872 switch (aid) { 873 case AID_INET: 874 r = nlri_get_prefix(msg, prefix, prefixlen); 875 break; 876 case AID_INET6: 877 r = nlri_get_prefix6(msg, prefix, prefixlen); 878 break; 879 case AID_VPN_IPv4: 880 r = nlri_get_vpn4(msg, prefix, prefixlen, 0); 881 break; 882 case AID_VPN_IPv6: 883 r = nlri_get_vpn6(msg, prefix, prefixlen, 0); 884 break; 885 default: 886 if (verbose) 887 printf("unknown prefix AID %d\n", aid); 888 return -1; 889 } 890 if (r == -1 && verbose) 891 printf("failed to parse prefix of AID %d\n", aid); 892 return r; 893} 894 895int 896mrt_parse_state(struct mrt_bgp_state *s, struct mrt_hdr *hdr, struct ibuf *msg, 897 int verbose) 898{ 899 struct timespec t; 900 uint32_t sas, das, usec; 901 uint16_t sas16, das16, afi; 902 uint8_t aid; 903 904 t.tv_sec = ntohl(hdr->timestamp); 905 t.tv_nsec = 0; 906 907 /* handle the microsec field for _ET header */ 908 if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) { 909 if (ibuf_get_n32(msg, &usec) == -1) 910 return (-1); 911 t.tv_nsec = usec * 1000; 912 } 913 914 switch (ntohs(hdr->subtype)) { 915 case BGP4MP_STATE_CHANGE: 916 if (ibuf_get_n16(msg, &sas16) == -1 || /* source as */ 917 ibuf_get_n16(msg, &das16) == -1 || /* dest as */ 918 ibuf_skip(msg, 2) == -1 || /* if_index */ 919 ibuf_get_n16(msg, &afi) == -1) /* afi */ 920 return (-1); 921 sas = sas16; 922 das = das16; 923 break; 924 case BGP4MP_STATE_CHANGE_AS4: 925 if (ibuf_get_n32(msg, &sas) == -1 || /* source as */ 926 ibuf_get_n32(msg, &das) == -1 || /* dest as */ 927 ibuf_skip(msg, 2) == -1 || /* if_index */ 928 ibuf_get_n16(msg, &afi) == -1) /* afi */ 929 return (-1); 930 break; 931 default: 932 errx(1, "mrt_parse_state: bad subtype"); 933 } 934 935 /* src & dst addr */ 936 if ((aid = mrt_afi2aid(afi, -1, verbose)) == AID_UNSPEC) 937 return (-1); 938 939 memset(s, 0, sizeof(*s)); 940 s->time = t; 941 s->src_as = sas; 942 s->dst_as = das; 943 944 if (mrt_extract_addr(msg, &s->src, aid) == -1) 945 return (-1); 946 if (mrt_extract_addr(msg, &s->dst, aid) == -1) 947 return (-1); 948 949 /* states */ 950 if (ibuf_get_n16(msg, &s->old_state) == -1 || 951 ibuf_get_n16(msg, &s->new_state) == -1) 952 return (-1); 953 954 return (0); 955} 956 957int 958mrt_parse_msg(struct mrt_bgp_msg *m, struct mrt_hdr *hdr, struct ibuf *msg, 959 int verbose) 960{ 961 struct timespec t; 962 uint32_t sas, das, usec; 963 uint16_t sas16, das16, afi; 964 int addpath = 0; 965 uint8_t aid; 966 967 t.tv_sec = ntohl(hdr->timestamp); 968 t.tv_nsec = 0; 969 970 /* handle the microsec field for _ET header */ 971 if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) { 972 if (ibuf_get_n32(msg, &usec) == -1) 973 return (-1); 974 t.tv_nsec = usec * 1000; 975 } 976 977 switch (ntohs(hdr->subtype)) { 978 case BGP4MP_MESSAGE_ADDPATH: 979 case BGP4MP_MESSAGE_LOCAL_ADDPATH: 980 addpath = 1; 981 /* FALLTHROUGH */ 982 case BGP4MP_MESSAGE: 983 case BGP4MP_MESSAGE_LOCAL: 984 if (ibuf_get_n16(msg, &sas16) == -1 || /* source as */ 985 ibuf_get_n16(msg, &das16) == -1 || /* dest as */ 986 ibuf_skip(msg, 2) == -1 || /* if_index */ 987 ibuf_get_n16(msg, &afi) == -1) /* afi */ 988 return (-1); 989 sas = sas16; 990 das = das16; 991 break; 992 case BGP4MP_MESSAGE_AS4_ADDPATH: 993 case BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH: 994 addpath = 1; 995 /* FALLTHROUGH */ 996 case BGP4MP_MESSAGE_AS4: 997 case BGP4MP_MESSAGE_AS4_LOCAL: 998 if (ibuf_get_n32(msg, &sas) == -1 || /* source as */ 999 ibuf_get_n32(msg, &das) == -1 || /* dest as */ 1000 ibuf_skip(msg, 2) == -1 || /* if_index */ 1001 ibuf_get_n16(msg, &afi) == -1) /* afi */ 1002 return (-1); 1003 break; 1004 default: 1005 errx(1, "mrt_parse_msg: bad subtype"); 1006 } 1007 1008 /* src & dst addr */ 1009 if ((aid = mrt_afi2aid(afi, -1, verbose)) == AID_UNSPEC) 1010 return (-1); 1011 1012 memset(m, 0, sizeof(*m)); 1013 m->time = t; 1014 m->src_as = sas; 1015 m->dst_as = das; 1016 m->add_path = addpath; 1017 1018 if (mrt_extract_addr(msg, &m->src, aid) == -1 || 1019 mrt_extract_addr(msg, &m->dst, aid) == -1) 1020 return (-1); 1021 1022 /* msg */ 1023 ibuf_from_ibuf(&m->msg, msg); 1024 return (0); 1025} 1026