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