1 /* $OpenBSD: mrtparser.c,v 1.20 2023/11/20 14:18:21 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 32 void *mrt_read_msg(int, struct mrt_hdr *); 33 size_t mrt_read_buf(int, void *, size_t); 34 35 struct mrt_peer *mrt_parse_v2_peer(struct mrt_hdr *, void *); 36 struct mrt_rib *mrt_parse_v2_rib(struct mrt_hdr *, void *, int); 37 int mrt_parse_dump(struct mrt_hdr *, void *, struct mrt_peer **, 38 struct mrt_rib **); 39 int mrt_parse_dump_mp(struct mrt_hdr *, void *, struct mrt_peer **, 40 struct mrt_rib **, int); 41 int mrt_extract_attr(struct mrt_rib_entry *, u_char *, int, uint8_t, int); 42 43 void mrt_free_peers(struct mrt_peer *); 44 void mrt_free_rib(struct mrt_rib *); 45 void mrt_free_bgp_state(struct mrt_bgp_state *); 46 void mrt_free_bgp_msg(struct mrt_bgp_msg *); 47 48 u_char *mrt_aspath_inflate(void *, uint16_t, uint16_t *); 49 int mrt_extract_addr(void *, u_int, struct bgpd_addr *, uint8_t); 50 int mrt_extract_prefix(void *, u_int, uint8_t, struct bgpd_addr *, 51 uint8_t *, int); 52 53 struct mrt_bgp_state *mrt_parse_state(struct mrt_hdr *, void *, int); 54 struct mrt_bgp_msg *mrt_parse_msg(struct mrt_hdr *, void *, int); 55 56 void * 57 mrt_read_msg(int fd, struct mrt_hdr *hdr) 58 { 59 void *buf; 60 61 memset(hdr, 0, sizeof(*hdr)); 62 if (mrt_read_buf(fd, hdr, sizeof(*hdr)) != sizeof(*hdr)) 63 return (NULL); 64 65 if ((buf = malloc(ntohl(hdr->length))) == NULL) 66 err(1, "malloc(%d)", hdr->length); 67 68 if (mrt_read_buf(fd, buf, ntohl(hdr->length)) != ntohl(hdr->length)) { 69 free(buf); 70 return (NULL); 71 } 72 return (buf); 73 } 74 75 size_t 76 mrt_read_buf(int fd, void *buf, size_t len) 77 { 78 char *b = buf; 79 ssize_t n; 80 81 while (len > 0) { 82 if ((n = read(fd, b, len)) == -1) { 83 if (errno == EINTR) 84 continue; 85 err(1, "read"); 86 } 87 if (n == 0) 88 break; 89 b += n; 90 len -= n; 91 } 92 93 return (b - (char *)buf); 94 } 95 96 void 97 mrt_parse(int fd, struct mrt_parser *p, int verbose) 98 { 99 struct mrt_hdr h; 100 struct mrt_peer *pctx = NULL; 101 struct mrt_rib *r; 102 struct mrt_bgp_state *s; 103 struct mrt_bgp_msg *m; 104 void *msg; 105 106 while ((msg = mrt_read_msg(fd, &h))) { 107 switch (ntohs(h.type)) { 108 case MSG_NULL: 109 case MSG_START: 110 case MSG_DIE: 111 case MSG_I_AM_DEAD: 112 case MSG_PEER_DOWN: 113 case MSG_PROTOCOL_BGP: 114 case MSG_PROTOCOL_IDRP: 115 case MSG_PROTOCOL_BGP4PLUS: 116 case MSG_PROTOCOL_BGP4PLUS1: 117 if (verbose) 118 printf("deprecated MRT type %d\n", 119 ntohs(h.type)); 120 break; 121 case MSG_PROTOCOL_RIP: 122 case MSG_PROTOCOL_RIPNG: 123 case MSG_PROTOCOL_OSPF: 124 case MSG_PROTOCOL_ISIS_ET: 125 case MSG_PROTOCOL_ISIS: 126 case MSG_PROTOCOL_OSPFV3_ET: 127 case MSG_PROTOCOL_OSPFV3: 128 if (verbose) 129 printf("unsupported MRT type %d\n", 130 ntohs(h.type)); 131 break; 132 case MSG_TABLE_DUMP: 133 switch (ntohs(h.subtype)) { 134 case MRT_DUMP_AFI_IP: 135 case MRT_DUMP_AFI_IPv6: 136 if (p->dump == NULL) 137 break; 138 if (mrt_parse_dump(&h, msg, &pctx, &r) == 0) { 139 if (p->dump) 140 p->dump(r, pctx, p->arg); 141 mrt_free_rib(r); 142 } 143 break; 144 default: 145 if (verbose) 146 printf("unknown AFI %d in table dump\n", 147 ntohs(h.subtype)); 148 break; 149 } 150 break; 151 case MSG_TABLE_DUMP_V2: 152 switch (ntohs(h.subtype)) { 153 case MRT_DUMP_V2_PEER_INDEX_TABLE: 154 if (p->dump == NULL) 155 break; 156 if (pctx) 157 mrt_free_peers(pctx); 158 pctx = mrt_parse_v2_peer(&h, msg); 159 break; 160 case MRT_DUMP_V2_RIB_IPV4_UNICAST: 161 case MRT_DUMP_V2_RIB_IPV4_MULTICAST: 162 case MRT_DUMP_V2_RIB_IPV6_UNICAST: 163 case MRT_DUMP_V2_RIB_IPV6_MULTICAST: 164 case MRT_DUMP_V2_RIB_GENERIC: 165 case MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH: 166 case MRT_DUMP_V2_RIB_IPV4_MULTICAST_ADDPATH: 167 case MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH: 168 case MRT_DUMP_V2_RIB_IPV6_MULTICAST_ADDPATH: 169 case MRT_DUMP_V2_RIB_GENERIC_ADDPATH: 170 if (p->dump == NULL) 171 break; 172 r = mrt_parse_v2_rib(&h, msg, verbose); 173 if (r) { 174 if (p->dump) 175 p->dump(r, pctx, p->arg); 176 mrt_free_rib(r); 177 } 178 break; 179 default: 180 if (verbose) 181 printf("unhandled DUMP_V2 subtype %d\n", 182 ntohs(h.subtype)); 183 break; 184 } 185 break; 186 case MSG_PROTOCOL_BGP4MP_ET: 187 case MSG_PROTOCOL_BGP4MP: 188 switch (ntohs(h.subtype)) { 189 case BGP4MP_STATE_CHANGE: 190 case BGP4MP_STATE_CHANGE_AS4: 191 if ((s = mrt_parse_state(&h, msg, verbose))) { 192 if (p->state) 193 p->state(s, p->arg); 194 free(s); 195 } 196 break; 197 case BGP4MP_MESSAGE: 198 case BGP4MP_MESSAGE_AS4: 199 case BGP4MP_MESSAGE_LOCAL: 200 case BGP4MP_MESSAGE_AS4_LOCAL: 201 case BGP4MP_MESSAGE_ADDPATH: 202 case BGP4MP_MESSAGE_AS4_ADDPATH: 203 case BGP4MP_MESSAGE_LOCAL_ADDPATH: 204 case BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH: 205 if ((m = mrt_parse_msg(&h, msg, verbose))) { 206 if (p->message) 207 p->message(m, p->arg); 208 free(m->msg); 209 free(m); 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 free(msg); 235 } 236 if (pctx) 237 mrt_free_peers(pctx); 238 } 239 240 static int 241 mrt_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 264 struct mrt_peer * 265 mrt_parse_v2_peer(struct mrt_hdr *hdr, void *msg) 266 { 267 struct mrt_peer_entry *peers = NULL; 268 struct mrt_peer *p; 269 uint8_t *b = msg; 270 uint32_t bid, as4; 271 uint16_t cnt, i, as2; 272 u_int len = ntohl(hdr->length); 273 274 if (len < 8) /* min msg size */ 275 return NULL; 276 277 p = calloc(1, sizeof(struct mrt_peer)); 278 if (p == NULL) 279 err(1, "calloc"); 280 281 /* collector bgp id */ 282 memcpy(&bid, b, sizeof(bid)); 283 b += sizeof(bid); 284 len -= sizeof(bid); 285 p->bgp_id = ntohl(bid); 286 287 /* view name length */ 288 memcpy(&cnt, b, sizeof(cnt)); 289 b += sizeof(cnt); 290 len -= sizeof(cnt); 291 cnt = ntohs(cnt); 292 293 /* view name */ 294 if (cnt > len) 295 goto fail; 296 if (cnt != 0) { 297 if ((p->view = malloc(cnt + 1)) == NULL) 298 err(1, "malloc"); 299 memcpy(p->view, b, cnt); 300 p->view[cnt] = 0; 301 } else 302 if ((p->view = strdup("")) == NULL) 303 err(1, "strdup"); 304 b += cnt; 305 len -= cnt; 306 307 /* peer_count */ 308 if (len < sizeof(cnt)) 309 goto fail; 310 memcpy(&cnt, b, sizeof(cnt)); 311 b += sizeof(cnt); 312 len -= sizeof(cnt); 313 cnt = ntohs(cnt); 314 315 /* peer entries */ 316 if ((peers = calloc(cnt, sizeof(struct mrt_peer_entry))) == NULL) 317 err(1, "calloc"); 318 for (i = 0; i < cnt; i++) { 319 uint8_t type; 320 321 if (len < sizeof(uint8_t) + sizeof(uint32_t)) 322 goto fail; 323 type = *b++; 324 len -= 1; 325 memcpy(&bid, b, sizeof(bid)); 326 b += sizeof(bid); 327 len -= sizeof(bid); 328 peers[i].bgp_id = ntohl(bid); 329 330 if (type & MRT_DUMP_V2_PEER_BIT_I) { 331 if (mrt_extract_addr(b, len, &peers[i].addr, 332 AID_INET6) == -1) 333 goto fail; 334 b += sizeof(struct in6_addr); 335 len -= sizeof(struct in6_addr); 336 } else { 337 if (mrt_extract_addr(b, len, &peers[i].addr, 338 AID_INET) == -1) 339 goto fail; 340 b += sizeof(struct in_addr); 341 len -= sizeof(struct in_addr); 342 } 343 344 if (type & MRT_DUMP_V2_PEER_BIT_A) { 345 memcpy(&as4, b, sizeof(as4)); 346 b += sizeof(as4); 347 len -= sizeof(as4); 348 as4 = ntohl(as4); 349 } else { 350 memcpy(&as2, b, sizeof(as2)); 351 b += sizeof(as2); 352 len -= sizeof(as2); 353 as4 = ntohs(as2); 354 } 355 peers[i].asnum = as4; 356 } 357 p->peers = peers; 358 p->npeers = cnt; 359 return (p); 360 fail: 361 mrt_free_peers(p); 362 free(peers); 363 return (NULL); 364 } 365 366 struct mrt_rib * 367 mrt_parse_v2_rib(struct mrt_hdr *hdr, void *msg, int verbose) 368 { 369 struct mrt_rib_entry *entries = NULL; 370 struct mrt_rib *r; 371 uint8_t *b = msg; 372 u_int len = ntohl(hdr->length); 373 uint32_t snum, path_id = 0; 374 uint16_t cnt, i, afi; 375 uint8_t safi, aid; 376 int ret; 377 378 if (len < sizeof(snum) + 1) 379 return NULL; 380 381 r = calloc(1, sizeof(struct mrt_rib)); 382 if (r == NULL) 383 err(1, "calloc"); 384 385 /* seq_num */ 386 memcpy(&snum, b, sizeof(snum)); 387 b += sizeof(snum); 388 len -= sizeof(snum); 389 r->seqnum = ntohl(snum); 390 391 switch (ntohs(hdr->subtype)) { 392 case MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH: 393 case MRT_DUMP_V2_RIB_IPV4_MULTICAST_ADDPATH: 394 r->add_path = 1; 395 /* FALLTHROUGH */ 396 case MRT_DUMP_V2_RIB_IPV4_UNICAST: 397 case MRT_DUMP_V2_RIB_IPV4_MULTICAST: 398 /* prefix */ 399 ret = mrt_extract_prefix(b, len, AID_INET, &r->prefix, 400 &r->prefixlen, verbose); 401 if (ret == 1) 402 goto fail; 403 break; 404 case MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH: 405 case MRT_DUMP_V2_RIB_IPV6_MULTICAST_ADDPATH: 406 r->add_path = 1; 407 /* FALLTHROUGH */ 408 case MRT_DUMP_V2_RIB_IPV6_UNICAST: 409 case MRT_DUMP_V2_RIB_IPV6_MULTICAST: 410 /* prefix */ 411 ret = mrt_extract_prefix(b, len, AID_INET6, &r->prefix, 412 &r->prefixlen, verbose); 413 if (ret == 1) 414 goto fail; 415 break; 416 case MRT_DUMP_V2_RIB_GENERIC_ADDPATH: 417 /* 418 * RFC8050 handling for add-path has special handling for 419 * RIB_GENERIC_ADDPATH but nobody implements it that way. 420 * So just use the same way as for the other _ADDPATH types. 421 */ 422 r->add_path = 1; 423 /* FALLTHROUGH */ 424 case MRT_DUMP_V2_RIB_GENERIC: 425 /* fetch AFI/SAFI pair */ 426 if (len < 3) 427 goto fail; 428 memcpy(&afi, b, sizeof(afi)); 429 b += sizeof(afi); 430 len -= sizeof(afi); 431 afi = ntohs(afi); 432 433 safi = *b++; 434 len -= 1; 435 436 if ((aid = mrt_afi2aid(afi, safi, verbose)) == AID_UNSPEC) 437 goto fail; 438 439 /* prefix */ 440 ret = mrt_extract_prefix(b, len, aid, &r->prefix, 441 &r->prefixlen, verbose); 442 if (ret == 1) 443 goto fail; 444 break; 445 default: 446 errx(1, "unknown subtype %hd", ntohs(hdr->subtype)); 447 } 448 449 /* adjust length */ 450 b += ret; 451 len -= ret; 452 453 /* entries count */ 454 if (len < sizeof(cnt)) 455 goto fail; 456 memcpy(&cnt, b, sizeof(cnt)); 457 b += sizeof(cnt); 458 len -= sizeof(cnt); 459 cnt = ntohs(cnt); 460 r->nentries = cnt; 461 462 /* entries */ 463 if ((entries = calloc(cnt, sizeof(struct mrt_rib_entry))) == NULL) 464 err(1, "calloc"); 465 for (i = 0; i < cnt; i++) { 466 uint32_t otm; 467 uint16_t pix, alen; 468 if (len < 2 * sizeof(uint16_t) + sizeof(uint32_t)) 469 goto fail; 470 /* peer index */ 471 memcpy(&pix, b, sizeof(pix)); 472 b += sizeof(pix); 473 len -= sizeof(pix); 474 entries[i].peer_idx = ntohs(pix); 475 476 /* originated */ 477 memcpy(&otm, b, sizeof(otm)); 478 b += sizeof(otm); 479 len -= sizeof(otm); 480 entries[i].originated = ntohl(otm); 481 482 if (r->add_path) { 483 if (len < sizeof(path_id) + sizeof(alen)) 484 goto fail; 485 memcpy(&path_id, b, sizeof(path_id)); 486 b += sizeof(path_id); 487 len -= sizeof(path_id); 488 path_id = ntohl(path_id); 489 } 490 entries[i].path_id = path_id; 491 492 /* attr_len */ 493 memcpy(&alen, b, sizeof(alen)); 494 b += sizeof(alen); 495 len -= sizeof(alen); 496 alen = ntohs(alen); 497 498 /* attr */ 499 if (len < alen) 500 goto fail; 501 if (mrt_extract_attr(&entries[i], b, alen, 502 r->prefix.aid, 1) == -1) 503 goto fail; 504 b += alen; 505 len -= alen; 506 } 507 r->entries = entries; 508 return (r); 509 fail: 510 mrt_free_rib(r); 511 free(entries); 512 return (NULL); 513 } 514 515 int 516 mrt_parse_dump(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp, 517 struct mrt_rib **rp) 518 { 519 struct mrt_peer *p; 520 struct mrt_rib *r; 521 struct mrt_rib_entry *re; 522 uint8_t *b = msg; 523 u_int len = ntohl(hdr->length); 524 uint16_t asnum, alen; 525 526 if (*pp == NULL) { 527 *pp = calloc(1, sizeof(struct mrt_peer)); 528 if (*pp == NULL) 529 err(1, "calloc"); 530 (*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry)); 531 if ((*pp)->peers == NULL) 532 err(1, "calloc"); 533 (*pp)->npeers = 1; 534 } 535 p = *pp; 536 537 *rp = r = calloc(1, sizeof(struct mrt_rib)); 538 if (r == NULL) 539 err(1, "calloc"); 540 re = calloc(1, sizeof(struct mrt_rib_entry)); 541 if (re == NULL) 542 err(1, "calloc"); 543 r->nentries = 1; 544 r->entries = re; 545 546 if (len < 2 * sizeof(uint16_t)) 547 goto fail; 548 /* view */ 549 b += sizeof(uint16_t); 550 len -= sizeof(uint16_t); 551 /* seqnum */ 552 memcpy(&r->seqnum, b, sizeof(uint16_t)); 553 b += sizeof(uint16_t); 554 len -= sizeof(uint16_t); 555 r->seqnum = ntohs(r->seqnum); 556 557 switch (ntohs(hdr->subtype)) { 558 case MRT_DUMP_AFI_IP: 559 if (mrt_extract_addr(b, len, &r->prefix, AID_INET) == -1) 560 goto fail; 561 b += sizeof(struct in_addr); 562 len -= sizeof(struct in_addr); 563 break; 564 case MRT_DUMP_AFI_IPv6: 565 if (mrt_extract_addr(b, len, &r->prefix, AID_INET6) == -1) 566 goto fail; 567 b += sizeof(struct in6_addr); 568 len -= sizeof(struct in6_addr); 569 break; 570 } 571 if (len < 2 * sizeof(uint32_t) + 2 * sizeof(uint16_t) + 2) 572 goto fail; 573 r->prefixlen = *b++; 574 len -= 1; 575 /* status */ 576 b += 1; 577 len -= 1; 578 /* originated */ 579 memcpy(&re->originated, b, sizeof(uint32_t)); 580 b += sizeof(uint32_t); 581 len -= sizeof(uint32_t); 582 re->originated = ntohl(re->originated); 583 /* peer ip */ 584 switch (ntohs(hdr->subtype)) { 585 case MRT_DUMP_AFI_IP: 586 if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET) == -1) 587 goto fail; 588 b += sizeof(struct in_addr); 589 len -= sizeof(struct in_addr); 590 break; 591 case MRT_DUMP_AFI_IPv6: 592 if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET6) == -1) 593 goto fail; 594 b += sizeof(struct in6_addr); 595 len -= sizeof(struct in6_addr); 596 break; 597 } 598 memcpy(&asnum, b, sizeof(asnum)); 599 b += sizeof(asnum); 600 len -= sizeof(asnum); 601 p->peers->asnum = ntohs(asnum); 602 603 memcpy(&alen, b, sizeof(alen)); 604 b += sizeof(alen); 605 len -= sizeof(alen); 606 alen = ntohs(alen); 607 608 /* attr */ 609 if (len < alen) 610 goto fail; 611 if (mrt_extract_attr(re, b, alen, r->prefix.aid, 0) == -1) 612 goto fail; 613 b += alen; 614 len -= alen; 615 616 return (0); 617 fail: 618 mrt_free_rib(r); 619 return (-1); 620 } 621 622 int 623 mrt_parse_dump_mp(struct mrt_hdr *hdr, void *msg, struct mrt_peer **pp, 624 struct mrt_rib **rp, int verbose) 625 { 626 struct mrt_peer *p; 627 struct mrt_rib *r; 628 struct mrt_rib_entry *re; 629 uint8_t *b = msg; 630 u_int len = ntohl(hdr->length); 631 uint16_t asnum, alen, afi; 632 uint8_t safi, nhlen, aid; 633 int ret; 634 635 /* just ignore the microsec field for _ET header for now */ 636 if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) { 637 b = (char *)b + sizeof(uint32_t); 638 len -= sizeof(uint32_t); 639 } 640 641 if (*pp == NULL) { 642 *pp = calloc(1, sizeof(struct mrt_peer)); 643 if (*pp == NULL) 644 err(1, "calloc"); 645 (*pp)->peers = calloc(1, sizeof(struct mrt_peer_entry)); 646 if ((*pp)->peers == NULL) 647 err(1, "calloc"); 648 (*pp)->npeers = 1; 649 } 650 p = *pp; 651 652 *rp = r = calloc(1, sizeof(struct mrt_rib)); 653 if (r == NULL) 654 err(1, "calloc"); 655 re = calloc(1, sizeof(struct mrt_rib_entry)); 656 if (re == NULL) 657 err(1, "calloc"); 658 r->nentries = 1; 659 r->entries = re; 660 661 if (len < 4 * sizeof(uint16_t)) 662 goto fail; 663 /* source AS */ 664 b += sizeof(uint16_t); 665 len -= sizeof(uint16_t); 666 /* dest AS */ 667 memcpy(&asnum, b, sizeof(asnum)); 668 b += sizeof(asnum); 669 len -= sizeof(asnum); 670 p->peers->asnum = ntohs(asnum); 671 /* iface index */ 672 b += sizeof(uint16_t); 673 len -= sizeof(uint16_t); 674 /* afi */ 675 memcpy(&afi, b, sizeof(afi)); 676 b += sizeof(afi); 677 len -= sizeof(afi); 678 afi = ntohs(afi); 679 680 /* source + dest ip */ 681 switch (afi) { 682 case MRT_DUMP_AFI_IP: 683 if (len < 2 * sizeof(struct in_addr)) 684 goto fail; 685 /* source IP */ 686 b += sizeof(struct in_addr); 687 len -= sizeof(struct in_addr); 688 /* dest IP */ 689 if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET) == -1) 690 goto fail; 691 b += sizeof(struct in_addr); 692 len -= sizeof(struct in_addr); 693 break; 694 case MRT_DUMP_AFI_IPv6: 695 if (len < 2 * sizeof(struct in6_addr)) 696 goto fail; 697 /* source IP */ 698 b += sizeof(struct in6_addr); 699 len -= sizeof(struct in6_addr); 700 /* dest IP */ 701 if (mrt_extract_addr(b, len, &p->peers->addr, AID_INET6) == -1) 702 goto fail; 703 b += sizeof(struct in6_addr); 704 len -= sizeof(struct in6_addr); 705 break; 706 } 707 708 if (len < 2 * sizeof(uint16_t) + 2 * sizeof(uint32_t)) 709 goto fail; 710 /* view + status */ 711 b += 2 * sizeof(uint16_t); 712 len -= 2 * sizeof(uint16_t); 713 /* originated */ 714 memcpy(&re->originated, b, sizeof(uint32_t)); 715 b += sizeof(uint32_t); 716 len -= sizeof(uint32_t); 717 re->originated = ntohl(re->originated); 718 719 /* afi */ 720 memcpy(&afi, b, sizeof(afi)); 721 b += sizeof(afi); 722 len -= sizeof(afi); 723 afi = ntohs(afi); 724 725 /* safi */ 726 safi = *b++; 727 len -= 1; 728 729 if ((aid = mrt_afi2aid(afi, safi, verbose)) == AID_UNSPEC) 730 goto fail; 731 732 /* nhlen */ 733 nhlen = *b++; 734 len -= 1; 735 736 /* nexthop */ 737 if (mrt_extract_addr(b, len, &re->nexthop, aid) == -1) 738 goto fail; 739 if (len < nhlen) 740 goto fail; 741 b += nhlen; 742 len -= nhlen; 743 744 /* prefix */ 745 ret = mrt_extract_prefix(b, len, aid, &r->prefix, &r->prefixlen, 746 verbose); 747 if (ret == 1) 748 goto fail; 749 b += ret; 750 len -= ret; 751 752 memcpy(&alen, b, sizeof(alen)); 753 b += sizeof(alen); 754 len -= sizeof(alen); 755 alen = ntohs(alen); 756 757 /* attr */ 758 if (len < alen) 759 goto fail; 760 if (mrt_extract_attr(re, b, alen, r->prefix.aid, 0) == -1) 761 goto fail; 762 b += alen; 763 len -= alen; 764 765 return (0); 766 fail: 767 mrt_free_rib(r); 768 return (-1); 769 } 770 771 int 772 mrt_extract_attr(struct mrt_rib_entry *re, u_char *a, int alen, uint8_t aid, 773 int as4) 774 { 775 struct mrt_attr *ap; 776 uint32_t tmp; 777 uint16_t attr_len; 778 uint8_t type, flags, *attr; 779 780 do { 781 if (alen < 3) 782 return (-1); 783 attr = a; 784 flags = *a++; 785 alen -= 1; 786 type = *a++; 787 alen -= 1; 788 789 if (flags & MRT_ATTR_EXTLEN) { 790 if (alen < 2) 791 return (-1); 792 memcpy(&attr_len, a, sizeof(attr_len)); 793 attr_len = ntohs(attr_len); 794 a += sizeof(attr_len); 795 alen -= sizeof(attr_len); 796 } else { 797 attr_len = *a++; 798 alen -= 1; 799 } 800 switch (type) { 801 case MRT_ATTR_ORIGIN: 802 if (attr_len != 1) 803 return (-1); 804 re->origin = *a; 805 break; 806 case MRT_ATTR_ASPATH: 807 if (as4) { 808 re->aspath_len = attr_len; 809 if ((re->aspath = malloc(attr_len)) == NULL) 810 err(1, "malloc"); 811 memcpy(re->aspath, a, attr_len); 812 } else { 813 re->aspath = mrt_aspath_inflate(a, attr_len, 814 &re->aspath_len); 815 if (re->aspath == NULL) 816 return (-1); 817 } 818 break; 819 case MRT_ATTR_NEXTHOP: 820 if (attr_len != 4) 821 return (-1); 822 if (aid != AID_INET) 823 break; 824 memcpy(&tmp, a, sizeof(tmp)); 825 re->nexthop.aid = AID_INET; 826 re->nexthop.v4.s_addr = tmp; 827 break; 828 case MRT_ATTR_MED: 829 if (attr_len != 4) 830 return (-1); 831 memcpy(&tmp, a, sizeof(tmp)); 832 re->med = ntohl(tmp); 833 break; 834 case MRT_ATTR_LOCALPREF: 835 if (attr_len != 4) 836 return (-1); 837 memcpy(&tmp, a, sizeof(tmp)); 838 re->local_pref = ntohl(tmp); 839 break; 840 case MRT_ATTR_MP_REACH_NLRI: 841 /* 842 * XXX horrible hack: 843 * Once again IETF and the real world differ in the 844 * implementation. In short the abbreviated MP_NLRI 845 * hack in the standard is not used in real life. 846 * Detect the two cases by looking at the first byte 847 * of the payload (either the nexthop addr length (RFC) 848 * or the high byte of the AFI (old form)). If the 849 * first byte matches the expected nexthop length it 850 * is expected to be the RFC 6396 encoding. 851 */ 852 if (*a != attr_len - 1) { 853 a += 3; 854 alen -= 3; 855 attr_len -= 3; 856 } 857 switch (aid) { 858 case AID_INET6: 859 if (attr_len < sizeof(struct in6_addr) + 1) 860 return (-1); 861 re->nexthop.aid = aid; 862 memcpy(&re->nexthop.v6, a + 1, 863 sizeof(struct in6_addr)); 864 break; 865 case AID_VPN_IPv4: 866 if (attr_len < sizeof(uint64_t) + 867 sizeof(struct in_addr)) 868 return (-1); 869 re->nexthop.aid = aid; 870 memcpy(&tmp, a + 1 + sizeof(uint64_t), 871 sizeof(tmp)); 872 re->nexthop.v4.s_addr = tmp; 873 break; 874 case AID_VPN_IPv6: 875 if (attr_len < sizeof(uint64_t) + 876 sizeof(struct in6_addr)) 877 return (-1); 878 re->nexthop.aid = aid; 879 memcpy(&re->nexthop.v6, 880 a + 1 + sizeof(uint64_t), 881 sizeof(struct in6_addr)); 882 break; 883 } 884 break; 885 case MRT_ATTR_AS4PATH: 886 if (!as4) { 887 free(re->aspath); 888 re->aspath_len = attr_len; 889 if ((re->aspath = malloc(attr_len)) == NULL) 890 err(1, "malloc"); 891 memcpy(re->aspath, a, attr_len); 892 break; 893 } 894 /* FALLTHROUGH */ 895 default: 896 re->nattrs++; 897 if (re->nattrs >= UCHAR_MAX) 898 err(1, "too many attributes"); 899 ap = reallocarray(re->attrs, 900 re->nattrs, sizeof(struct mrt_attr)); 901 if (ap == NULL) 902 err(1, "realloc"); 903 re->attrs = ap; 904 ap = re->attrs + re->nattrs - 1; 905 ap->attr_len = a + attr_len - attr; 906 if ((ap->attr = malloc(ap->attr_len)) == NULL) 907 err(1, "malloc"); 908 memcpy(ap->attr, attr, ap->attr_len); 909 break; 910 } 911 a += attr_len; 912 alen -= attr_len; 913 } while (alen > 0); 914 915 return (0); 916 } 917 918 void 919 mrt_free_peers(struct mrt_peer *p) 920 { 921 free(p->peers); 922 free(p->view); 923 free(p); 924 } 925 926 void 927 mrt_free_rib(struct mrt_rib *r) 928 { 929 uint16_t i, j; 930 931 for (i = 0; i < r->nentries && r->entries; i++) { 932 for (j = 0; j < r->entries[i].nattrs; j++) 933 free(r->entries[i].attrs[j].attr); 934 free(r->entries[i].attrs); 935 free(r->entries[i].aspath); 936 } 937 938 free(r->entries); 939 free(r); 940 } 941 942 void 943 mrt_free_bgp_state(struct mrt_bgp_state *s) 944 { 945 free(s); 946 } 947 948 void 949 mrt_free_bgp_msg(struct mrt_bgp_msg *m) 950 { 951 free(m->msg); 952 free(m); 953 } 954 955 u_char * 956 mrt_aspath_inflate(void *data, uint16_t len, uint16_t *newlen) 957 { 958 uint8_t *seg, *nseg, *ndata; 959 uint16_t seg_size, olen, nlen; 960 uint8_t seg_len; 961 962 /* first calculate the length of the aspath */ 963 seg = data; 964 nlen = 0; 965 for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) { 966 seg_len = seg[1]; 967 seg_size = 2 + sizeof(uint16_t) * seg_len; 968 nlen += 2 + sizeof(uint32_t) * seg_len; 969 970 if (seg_size > olen) 971 return NULL; 972 } 973 974 *newlen = nlen; 975 if ((ndata = malloc(nlen)) == NULL) 976 err(1, "malloc"); 977 978 /* then copy the aspath */ 979 seg = data; 980 for (nseg = ndata; nseg < ndata + nlen; ) { 981 *nseg++ = *seg++; 982 *nseg++ = seg_len = *seg++; 983 for (; seg_len > 0; seg_len--) { 984 *nseg++ = 0; 985 *nseg++ = 0; 986 *nseg++ = *seg++; 987 *nseg++ = *seg++; 988 } 989 } 990 991 return (ndata); 992 } 993 994 int 995 mrt_extract_addr(void *msg, u_int len, struct bgpd_addr *addr, uint8_t aid) 996 { 997 uint8_t *b = msg; 998 999 memset(addr, 0, sizeof(*addr)); 1000 switch (aid) { 1001 case AID_INET: 1002 if (len < sizeof(struct in_addr)) 1003 return (-1); 1004 addr->aid = aid; 1005 memcpy(&addr->v4, b, sizeof(struct in_addr)); 1006 return sizeof(struct in_addr); 1007 case AID_INET6: 1008 if (len < sizeof(struct in6_addr)) 1009 return (-1); 1010 addr->aid = aid; 1011 memcpy(&addr->v6, b, sizeof(struct in6_addr)); 1012 return sizeof(struct in6_addr); 1013 case AID_VPN_IPv4: 1014 if (len < sizeof(uint64_t) + sizeof(struct in_addr)) 1015 return (-1); 1016 addr->aid = aid; 1017 /* XXX labelstack and rd missing */ 1018 memcpy(&addr->v4, b + sizeof(uint64_t), 1019 sizeof(struct in_addr)); 1020 return (sizeof(uint64_t) + sizeof(struct in_addr)); 1021 case AID_VPN_IPv6: 1022 if (len < sizeof(uint64_t) + sizeof(struct in6_addr)) 1023 return (-1); 1024 addr->aid = aid; 1025 /* XXX labelstack and rd missing */ 1026 memcpy(&addr->v6, b + sizeof(uint64_t), 1027 sizeof(struct in6_addr)); 1028 return (sizeof(uint64_t) + sizeof(struct in6_addr)); 1029 default: 1030 return (-1); 1031 } 1032 } 1033 1034 int 1035 mrt_extract_prefix(void *msg, u_int len, uint8_t aid, 1036 struct bgpd_addr *prefix, uint8_t *prefixlen, int verbose) 1037 { 1038 int r; 1039 1040 switch (aid) { 1041 case AID_INET: 1042 r = nlri_get_prefix(msg, len, prefix, prefixlen); 1043 break; 1044 case AID_INET6: 1045 r = nlri_get_prefix6(msg, len, prefix, prefixlen); 1046 break; 1047 case AID_VPN_IPv4: 1048 r = nlri_get_vpn4(msg, len, prefix, prefixlen, 0); 1049 break; 1050 case AID_VPN_IPv6: 1051 r = nlri_get_vpn6(msg, len, prefix, prefixlen, 0); 1052 break; 1053 default: 1054 if (verbose) 1055 printf("unknown prefix AID %d\n", aid); 1056 return -1; 1057 } 1058 if (r == -1 && verbose) 1059 printf("failed to parse prefix of AID %d\n", aid); 1060 return r; 1061 } 1062 1063 struct mrt_bgp_state * 1064 mrt_parse_state(struct mrt_hdr *hdr, void *msg, int verbose) 1065 { 1066 struct timespec t; 1067 struct mrt_bgp_state *s; 1068 uint8_t *b = msg; 1069 u_int len = ntohl(hdr->length); 1070 uint32_t sas, das, usec; 1071 uint16_t tmp16, afi; 1072 int r; 1073 uint8_t aid; 1074 1075 t.tv_sec = ntohl(hdr->timestamp); 1076 t.tv_nsec = 0; 1077 1078 /* handle the microsec field for _ET header */ 1079 if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) { 1080 memcpy(&usec, b, sizeof(usec)); 1081 b += sizeof(usec); 1082 len -= sizeof(usec); 1083 t.tv_nsec = ntohl(usec) * 1000; 1084 } 1085 1086 switch (ntohs(hdr->subtype)) { 1087 case BGP4MP_STATE_CHANGE: 1088 if (len < 8) 1089 return (0); 1090 /* source as */ 1091 memcpy(&tmp16, b, sizeof(tmp16)); 1092 b += sizeof(tmp16); 1093 len -= sizeof(tmp16); 1094 sas = ntohs(tmp16); 1095 /* dest as */ 1096 memcpy(&tmp16, b, sizeof(tmp16)); 1097 b += sizeof(tmp16); 1098 len -= sizeof(tmp16); 1099 das = ntohs(tmp16); 1100 /* if_index, ignored */ 1101 b += sizeof(tmp16); 1102 len -= sizeof(tmp16); 1103 /* afi */ 1104 memcpy(&tmp16, b, sizeof(tmp16)); 1105 b += sizeof(tmp16); 1106 len -= sizeof(tmp16); 1107 afi = ntohs(tmp16); 1108 break; 1109 case BGP4MP_STATE_CHANGE_AS4: 1110 if (len < 12) 1111 return (0); 1112 /* source as */ 1113 memcpy(&sas, b, sizeof(sas)); 1114 b += sizeof(sas); 1115 len -= sizeof(sas); 1116 sas = ntohl(sas); 1117 /* dest as */ 1118 memcpy(&das, b, sizeof(das)); 1119 b += sizeof(das); 1120 len -= sizeof(das); 1121 das = ntohl(das); 1122 /* if_index, ignored */ 1123 b += sizeof(tmp16); 1124 len -= sizeof(tmp16); 1125 /* afi */ 1126 memcpy(&tmp16, b, sizeof(tmp16)); 1127 b += sizeof(tmp16); 1128 len -= sizeof(tmp16); 1129 afi = ntohs(tmp16); 1130 break; 1131 default: 1132 errx(1, "mrt_parse_state: bad subtype"); 1133 } 1134 1135 /* src & dst addr */ 1136 if ((aid = mrt_afi2aid(afi, -1, verbose)) == AID_UNSPEC) 1137 return (NULL); 1138 1139 if ((s = calloc(1, sizeof(struct mrt_bgp_state))) == NULL) 1140 err(1, "calloc"); 1141 s->time = t; 1142 s->src_as = sas; 1143 s->dst_as = das; 1144 1145 if ((r = mrt_extract_addr(b, len, &s->src, aid)) == -1) 1146 goto fail; 1147 b += r; 1148 len -= r; 1149 if ((r = mrt_extract_addr(b, len, &s->dst, aid)) == -1) 1150 goto fail; 1151 b += r; 1152 len -= r; 1153 1154 /* states */ 1155 memcpy(&tmp16, b, sizeof(tmp16)); 1156 b += sizeof(tmp16); 1157 len -= sizeof(tmp16); 1158 s->old_state = ntohs(tmp16); 1159 memcpy(&tmp16, b, sizeof(tmp16)); 1160 b += sizeof(tmp16); 1161 len -= sizeof(tmp16); 1162 s->new_state = ntohs(tmp16); 1163 1164 return (s); 1165 1166 fail: 1167 free(s); 1168 return (NULL); 1169 } 1170 1171 struct mrt_bgp_msg * 1172 mrt_parse_msg(struct mrt_hdr *hdr, void *msg, int verbose) 1173 { 1174 struct timespec t; 1175 struct mrt_bgp_msg *m; 1176 uint8_t *b = msg; 1177 u_int len = ntohl(hdr->length); 1178 uint32_t sas, das, usec; 1179 uint16_t tmp16, afi; 1180 int r, addpath = 0; 1181 uint8_t aid; 1182 1183 t.tv_sec = ntohl(hdr->timestamp); 1184 t.tv_nsec = 0; 1185 1186 /* handle the microsec field for _ET header */ 1187 if (ntohs(hdr->type) == MSG_PROTOCOL_BGP4MP_ET) { 1188 memcpy(&usec, b, sizeof(usec)); 1189 b += sizeof(usec); 1190 len -= sizeof(usec); 1191 t.tv_nsec = ntohl(usec) * 1000; 1192 } 1193 1194 switch (ntohs(hdr->subtype)) { 1195 case BGP4MP_MESSAGE_ADDPATH: 1196 case BGP4MP_MESSAGE_LOCAL_ADDPATH: 1197 addpath = 1; 1198 /* FALLTHROUGH */ 1199 case BGP4MP_MESSAGE: 1200 case BGP4MP_MESSAGE_LOCAL: 1201 if (len < 8) 1202 return (0); 1203 /* source as */ 1204 memcpy(&tmp16, b, sizeof(tmp16)); 1205 b += sizeof(tmp16); 1206 len -= sizeof(tmp16); 1207 sas = ntohs(tmp16); 1208 /* dest as */ 1209 memcpy(&tmp16, b, sizeof(tmp16)); 1210 b += sizeof(tmp16); 1211 len -= sizeof(tmp16); 1212 das = ntohs(tmp16); 1213 /* if_index, ignored */ 1214 b += sizeof(tmp16); 1215 len -= sizeof(tmp16); 1216 /* afi */ 1217 memcpy(&tmp16, b, sizeof(tmp16)); 1218 b += sizeof(tmp16); 1219 len -= sizeof(tmp16); 1220 afi = ntohs(tmp16); 1221 break; 1222 case BGP4MP_MESSAGE_AS4_ADDPATH: 1223 case BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH: 1224 addpath = 1; 1225 /* FALLTHROUGH */ 1226 case BGP4MP_MESSAGE_AS4: 1227 case BGP4MP_MESSAGE_AS4_LOCAL: 1228 if (len < 12) 1229 return (0); 1230 /* source as */ 1231 memcpy(&sas, b, sizeof(sas)); 1232 b += sizeof(sas); 1233 len -= sizeof(sas); 1234 sas = ntohl(sas); 1235 /* dest as */ 1236 memcpy(&das, b, sizeof(das)); 1237 b += sizeof(das); 1238 len -= sizeof(das); 1239 das = ntohl(das); 1240 /* if_index, ignored */ 1241 b += sizeof(tmp16); 1242 len -= sizeof(tmp16); 1243 /* afi */ 1244 memcpy(&tmp16, b, sizeof(tmp16)); 1245 b += sizeof(tmp16); 1246 len -= sizeof(tmp16); 1247 afi = ntohs(tmp16); 1248 break; 1249 default: 1250 errx(1, "mrt_parse_msg: bad subtype"); 1251 } 1252 1253 /* src & dst addr */ 1254 if ((aid = mrt_afi2aid(afi, -1, verbose)) == AID_UNSPEC) 1255 return (NULL); 1256 1257 if ((m = calloc(1, sizeof(struct mrt_bgp_msg))) == NULL) 1258 err(1, "calloc"); 1259 m->time = t; 1260 m->src_as = sas; 1261 m->dst_as = das; 1262 m->add_path = addpath; 1263 1264 if ((r = mrt_extract_addr(b, len, &m->src, aid)) == -1) 1265 goto fail; 1266 b += r; 1267 len -= r; 1268 if ((r = mrt_extract_addr(b, len, &m->dst, aid)) == -1) 1269 goto fail; 1270 b += r; 1271 len -= r; 1272 1273 /* msg */ 1274 if (len > 0) { 1275 m->msg_len = len; 1276 if ((m->msg = malloc(len)) == NULL) 1277 err(1, "malloc"); 1278 memcpy(m->msg, b, len); 1279 } 1280 1281 return (m); 1282 1283 fail: 1284 free(m->msg); 1285 free(m); 1286 return (NULL); 1287 } 1288