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